How to write a simple Nuxt 3 composable that works on both the client and server

  Kiến thức lập trình

I am struggling to find a way to write a simple composable that works on both the client and server side. I have a simple function that simply gathers application preferences that I want to be able to call on both the client and server. The function has absolutely nothing that is inherently server or client side specific, i.e. is client and server side agnostic. In short I want to simple do something like this

    const preferenceType = 'MOBILE_FEATURES'
    const {appPreferences} = useApplicationPreferences()
    const mobilePreferences = appPreferences(preferenceType)

    console.log('Mobile feature make is ', mobilePreferences.make))

I have it working on the client, but I don’t know how to achieve the same thing on the server. I tried this setup:

runtime/use-preferences.ts
runtime/server/user-preferences-server // with same code

The preferences are dynamic so I cannot add them as a runtime configuration in my nuxt.config.ts. The application can set them from user choices and they get set in the user-preferences.ts composable.

Here is the code for the module.ts. The client code is code I cannot show.


     import { defineNuxtModule, createResolver, useLogger, addImportsDir, addTemplate } from '@nuxt/kit';
     import defu from 'defu';
     import { fileURLToPath } from 'url';



    export interface BasePreferences {
     deviceName?: string;
  
    }

    export interface ModuleOptions {
     basicOptions?: BasePreferences;
    }

   export default defineNuxtModule({
     meta: {
     name: 'userPreferences',
     configKey: 'userPreferencesConfig',
   },
    defaults: {
      basicOptions: {
       deviceName: 'test',
     },
   },
      setup(moduleOptions, nuxt) {
      const userPreferences = userPreferences();
      const resolver = createResolver(import.meta.url);
      const nuxtOptions = nuxt.options;

      const mergedOptions = defu(
        nuxtOptions.runtimeConfig.public.userPreferencesConfig || {},
        moduleOptions
      );

      nuxtOptions.runtimeConfig.public.userPreferencesConfig = mergedOptions;


      const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
      nuxt.options.build.transpile.push(runtimeDir)
      nuxt.options.build.transpile.push("user-preferences.js");
      nuxt.options.build.transpile.push("user-preferences-server.js");

   

        nuxt.hook('nitro:config', (nitroConfig) => {
        nitroConfig.alias = nitroConfig.alias || {}
       // Inline module runtime in Nitro bundle
        nitroConfig.externals = defu(typeof nitroConfig.externals === 'object' ? 
      nitroConfig.externals : {}, {
        inline: [resolver.resolve('./runtime/server')]
      })
      nitroConfig.alias['#user-preferences'] = resolver.resolve(runtimeDir, 
    './runtime/server')
     })
     
      addTemplate({
       filename: 'types/user-preferences.d.ts',
        getContents: () => [
         'declare module '#user-preferences' {',
         `  const usePreferences: typeof 
      import('${resolver.resolve('./runtime/server')}').UserPreferences`,
        '}'
         ].join('n')
      })

    nuxt.hook('prepare:types', (options) => {
      options.references.push({ path: resolver.resolve(nuxt.options.buildDir, 'types/user- 
     preferences.d.ts') })
    })
      addImportsDir(resolver.resolve('./runtime'));

      },
   });

The imports for #user-preferences show up in the #imports directory as ./src/…
which I know is wrong as it cannot be referenced at runtime from there. I really need some help in figuring this out. I have all the code working except that I lost how to pull it off on the server side i.e. in server/api folder as well

LEAVE A COMMENT