Lisa Schumann
Lisa Schumann

Reputation: 127

Nuxt 3 composables suddenly undefined

I set up a composable for the currentYear under composables/getCurrentYear.ts

export const getCurrentYear = () => {
    return new Date().getFullYear();
  }

in my Footer component I defined it as

<script setup>
const currentYear = getCurrentYear()
</script>

and even though it was importing perfectly fine before, I am not getting:

500
getCurrentYear is not defined

at _sfc_main.setup (./components/AppFooter.js:56:23)
at callWithErrorHandling (./node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:171:22)
at setupStatefulComponent (./node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7194:29)
at setupComponent (./node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7149:11)
at renderComponentVNode (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:628:17)
at Module.ssrRenderComponent (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:94:12)
at _sfc_ssrRender (./components/AppLayout.js:26:31)
at renderComponentSubTree (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:710:17)
at renderComponentVNode (./node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:644:16)

My dependencies did not change, so I am slightly lost on why this all of the sudden stopped working:

  "devDependencies": {
    "@nuxtjs/i18n": "^8.0.0-beta.11",
    "autoprefixer": "^10.4.13",
    "nuxt": "^3.4.3",
    "nuxt-simple-sitemap": "^2.4.23",
    "postcss": "^8.4.23",
    "tailwindcss": "^3.3.2"
  },
  "dependencies": {
    "@csstools/css-parser-algorithms": "^2.1.1",
    "@nuxtjs/google-fonts": "^3.0.0",
    "contentful": "^10.1.8",
    "contentful-rich-text-vue-renderer": "^3.1.0",
    "gsap": "file:gsap-bonus.tgz",
    "nuxt-swiper": "^1.1.0",
    "typescript": "^5.0.4"
  }

Upvotes: 4

Views: 8106

Answers (3)

Ilham Meidi
Ilham Meidi

Reputation: 1

In nuxt 3 I created new function in composable to bridging the actions like in this project https://github.com/ilhammeidi/awrora-starter/blob/main/composables/uiTheme.js

// composable/ui.js

import { useState } from '#app';

const useThemeMode = () => (useState('mode', () => 'dark'));

const states = {
  themeMode: useThemeMode,
};

// Execute state change
export function toggleDark(value) {
  const themeMode = useThemeMode();

  themeMode.value = value;
}

export default states;

<template>
  <!-- components/UiSettings.vue -->
  <div :class="themeMode">
    <button @click="switchTheme('light')">change to light</button>
    <button @click="switchTheme('dark')">change to dark</button>
  </div>
</template>

<script setup>
import ui, { toggleDark } from '@/composables/ui';

const themeMode = ui.themeMode();
function switchTheme(val) {
  toggleDark(val);
}
</script>

Upvotes: 0

Marc
Marc

Reputation: 5465

I had a similar issue but with Pinia and Just plain Vue3 where I returned an instance of an object directly, it worked at first for some reason but after a cold start it failed which led to this confusion, while it was valid code from a module perspective, it was not valid for the framework internals.

Nuxt will generate a declaration file for your composable under the hood which I think is acknowledged on next runtime, so then on next run it surfaces up as an error because you wrote it wrong but it couldn't tell you so on the first time around (some form of compilation race condition).

Concept of Pinia and composables in my view are similar in that there is a requirement for function wrapper (container) where from within you return methods an variables that are to be exposed from your container as if you where literally using different containers to store readily available resources like, one is full of nuts, another is full of bolts.

useBolts > getBolt(diameter: 4mm, length: 30mm)

useNuts > getNut(diameter: 4mm)

A nested composable would look like this:

fixings = useFixings > { bolts = useBolts(), nuts = useNuts() }

fixings.bolts.getBolt(diameter: 4mm, length: 30mm)

Your date code should look something like this in a container:


// composables/useDates.ts

export const useDates = () => { // The named container

  // A container method
  const getCurrentYear = () => new Date().getFullYear();


  return { getCurrentYear } // Expose as public interface

}

Consuming your container:

// components/myComponenet.vue

<script setup>
  const { getCurrentYear } = useDates();

  console.log(getCurrentYear())
<script>

It is my understanding that this format is required so that functionality is returned as a set of key value pairs in order for Nuxt to generate key value type declarations in a useDate.d.ts file that will appear in the .nuxt folder within your project.

Troubleshooting

From the comments:

If a matching filename with <compsoable-name>.d.ts is not generated inside the /.nuxt directory or if this direcotry missing completely in the project after running it, then make sure your project files and folders are not set to readonly ensure everything is writable on your computer in the project.

This .nuxt folder shold exist and be writable during development, it is generated when running dev or if you run nuxi prepare.

Here are some resources on .nuxt directory:

https://nuxt.com/docs/guide/directory-structure/nuxt

Nuxt uses the .nuxt/ directory in development to generate your Vue application.

You should not touch any files inside since the whole directory will be re-created when running nuxt dev.

This directory is interesting if you want to learn more about the files Nuxt generates based on your directory structure.

https://nuxt.com/docs/guide/directory-structure/composables

Be aware that you have to run nuxi prepare, nuxi dev or nuxi build in order to let Nuxt generate the types. If you create a composable without having the dev server running, TypeScript will throw an error, such as Cannot find name 'useBar'.

Upvotes: 4

nur_riyad
nur_riyad

Reputation: 1380

From Nuxt3 official doc

Nuxt 3 uses the composables/ directory to automatically import your Vue composables into your application using auto-imports!

So instead of naming composabled/getCurrentYear.ts you can try composables/getCurrentYear.ts

Upvotes: 1

Related Questions