Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to share singleton between Nitro plugin and routers #387

Closed
toakleaf opened this issue Oct 1, 2024 · 6 comments
Closed

No way to share singleton between Nitro plugin and routers #387

toakleaf opened this issue Oct 1, 2024 · 6 comments

Comments

@toakleaf
Copy link
Contributor

toakleaf commented Oct 1, 2024

As discussed in a previous issue, Nitro's storage layer is for some reason not available within vinxi. It was suggested to simply use the unstorage library directly. The issue with this approach is that unstorage needs to be instantiated in a singleton somewhere, most typically in a Nitro plugin that runs after server start up. If I want to be able to populate data in that singleton then I need to have the file under reference be consistent between the Nitro plugin file and the router entrypoint file. However, on build, for some reason these two diverge.

Here is a stackblitz example. Note how after building npm install && npm run build && npm start the keyValueStore added to the singleton in nitro-plugins/test.ts is not available in the server.tsx.

Please let me know if there is some special configuration I can do to externalize this singleton so that the build doesn't double reference the file in the runtime.mjs output. I've tried many things and the only one that works consistently is to put the singleton in a completely separate npm package. However, it would be nice if this just worked out of the box as it does when using Nitro directly.

Finally, as I think you're already aware, plugins simply don't work at all in dev mode (which is actually acceptible for my use case).

@toakleaf
Copy link
Contributor Author

toakleaf commented Oct 1, 2024

Update: The hack solution of putting the singleton in a separate package only actually works when using pnpm or yarn. Issue persists with npm

@toakleaf
Copy link
Contributor Author

toakleaf commented Oct 2, 2024

Update: Found resolution. Closing issue.

If anyone else has this issue, the solution is to configure the rollupConfig of the server to mark any files you don't want to be bundled when running vinxi build as external AND mark the same file as external in the rollupOptions of your corresponding router config. In addition I also found it necessary to configure a server.alias to these files to get the externalization to work properly. They obviously must also be javascript.

example:

export default createApp({
  server: {
    alias: {
      '@external': path.resolve(path.resolve(), '@external'),
    },
    plugins: ['./nitro-plugins/whateverPlugin.ts'],
    rollupConfig: {
      external: [path.resolve(path.resolve(), '@external', 'keyValueStore.js')],
    },
  },
  routers: [
    {
      name: 'ssr',
      type: 'http',
      handler: './app/server.tsx',
      plugins: () => {
        config('custom', {
          build: {
            rollupOptions: {
              external: [
                path.resolve(path.resolve(), '@external', 'keyValueStore.js'),
              ],
            },
          },
        });
      },
    },
  ],
});

and then in whateverPlugin.ts and app/server.tsx:

import { keyValueSingleton } from '@external/keyValueStore.js';

@toakleaf toakleaf closed this as completed Oct 2, 2024
@toakleaf
Copy link
Contributor Author

toakleaf commented Oct 2, 2024

Edit: Update

This still isn't great. The above solution I described does in fact externalize the import but it does so via hardcoding an absolute path into the built output. You can then write a custom rollup plugin to find and replace these, while also copying over the source files to built output, but it feels like no more of a solution than simply putting all your code into a separate file linked package.

I'm going to reopen this issue because I think there can be a much better flow for the incredibly common need for sharing in-memory data between Nitro plugins and routers. Without Nitro's built in implementation of unstorage, singletons are kind of a must, and they're incredibly harrowing to implement right now.

@toakleaf toakleaf reopened this Oct 2, 2024
@katywings
Copy link
Collaborator

@toakleaf I know, suboptimal workaround, but have you thought on just storing your singleton in globalThis? Thats how I am solving my singleton needs at the moment 😅

@katywings
Copy link
Collaborator

Related issue: #51

@toakleaf
Copy link
Contributor Author

toakleaf commented Oct 3, 2024

Thanks @katywings. I had totally forgot about globalThis as an option. I guess I'll go with that solution and close down the issue again. Still feels a little bit like a hack, but there are probably more pressing issues that can get the oxygen

@toakleaf toakleaf closed this as completed Oct 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants