user1658162
user1658162

Reputation: 2821

struggling to use custom fs storage plugin in nuxt3 app on nitro server

I'm trying to set up a custom storage plugin in nuxt using unstorage within nitroPlugin. I simply need to create API endpoints reading a local directory and returning files from there. It looks like a very simple stuff but I'm having hard time accomplishing it in nuxt3. Mainly because the local fs driver in nuxt seems to work only in dev environment.

In my project structure, I have the plugin under /server/plugins/my-custom-storage.ts and I'd like to consume it from /server/api/my-custom-api.get.ts the code for my-custom-storage.ts is the following:

import { createStorage } from 'unstorage';
import fsDriver from 'unstorage/drivers/fs';
import pino from 'pino';

export default defineNitroPlugin(async (nitroApp) => {
  const logger = pino();

  logger.info('mounting custom fs storage ' + process.cwd());
  const storage = createStorage({});
  storage.mount('local_db', fsDriver({ base: './.azdata' }));
  
  return storage;
});

and within my-custom-api.get.ts I'd like to use it in the simple following way:

export default defineEventHandler(async (_event) => {
  const storage = useStorage();
  try {
    
    const myFile = await storage.getItem('local_db:path:to:myfile');

    return myFile;
  } catch (err: any) {
    console.error(err);
  }
});

unfortunately, useStorage() uses default nuxt storage that can be configured in nuxt.config.ts but for file system data works only in development mode and breaks in production because the path to the directory is created at build time so pointing to a path onto the development machine.

this is the configuration in nuxt.config.ts to setup a storage:

nitro: {
    storage: {
      test_db: {
        driver: 'fs',
        base: './.test-data/'
      }
    }
  }

and It builds to

storage.mount('test_db',fsDriver({"driver":"fs","base":"C:\\Users\\mike\\Documents\\projects\\my-development-folder\\.test-data","ignore":["**/node_modules/**","**/.git/**"]}));

that is a path on my development machine. meanwhile, the custom storage generates the following code:

storage.mount("local_db", fsDriver({ base: "./.azdata" }));

that is a relative path

I've not found any info or example in the nuxt/nitro documentation, but I believe it could be straightforward like a single line of code to add. Hopefully, someone can provide a straight answer.

thanks in advance

Upvotes: 1

Views: 63

Answers (1)

user1658162
user1658162

Reputation: 2821

After some more diggin' it looks like there's no official way to use nitro plugins in API handlers, here are some references:

https://github.com/nuxt/nuxt/issues/22327

https://github.com/nuxt/nuxt/discussions/24019

It seems that nuxtApp and nitroApp are not reachable by one another.

So I've opted for a patch/hack that is not elegant nor something that would pass a code review but I've not found any other way. here is the code for nitro plugin where the custom storage is created:

import { createStorage } from 'unstorage';
import fsDriver from 'unstorage/drivers/fs';
import pino from 'pino';

export const STORE_PROVIDER = {
  storage: createStorage({})
};

export default defineNitroPlugin((_nitroApp) => {
  const logger = pino();

  logger.info('mounting custom fs storage ' + process.cwd());
  const storage = STORE_PROVIDER.storage;// createStorage({});

  storage.mount('local_db', fsDriver({ base: './.azdata' }));

  return storage;
});

this export:

export const STORE_PROVIDER = { storage: createStorage({}) };

is the patch that makes it usable in the code below:

import pino from 'pino';
import { STORE_PROVIDER } from '~/server/plugins/01-azch-storage';

export default defineEventHandler(async (_event) => {
  const logger = pino();

  const storage = STORE_PROVIDER.storage;
  logger.info('vector.get.ts');

  try {
    return await storage.getItemRaw(
      'local_db:screen_indexes:latest:US:screenIndex.f32'
    );
  } catch (err: any) {
    logger.error(err.message);
  }
});

I'm pretty sure that the store is created and mounted before the API is ready to listen for requests, as there's no point in mounting plugins before Nitro itself is ready. Some testing in development and production confirms this thesis. I hope this post will be useful to someone like me taking the first steps with Nuxt.

Upvotes: 0

Related Questions