meteor-vite icon indicating copy to clipboard operation
meteor-vite copied to clipboard

Conditional imports aren't properly tree-shaken when using Meteor's runtime/environment variables

Open JorgenVatle opened this issue 1 year ago • 4 comments

Environment-specific conditional imports aren't handled the same way Meteor normally does.

The following snippet would result in ./server/some-module being included in the client bundle. It won't be loaded by the client during runtime, but is still available if it compiles:

if (Meteor.isServer) {
  await import('./server/some-module') // This should not be included into the client.
}

The current workaround is to use Vite's special import.meta.env variables when you need to conditionally import modules based on the current runtime.

- if (Meteor.isServer) {
+ if (import.meta.env.SSR) {
  await import('./server/some-module') // This will now be omitted outright from the client bundle.
}

References:

  • https://vite.dev/guide/env-and-mode.html#env-variables
  • https://vite.dev/guide/ssr.html#conditional-logic

Related issue:

  • https://github.com/JorgenVatle/meteor-vite/issues/279

JorgenVatle avatar Jan 21 '25 00:01 JorgenVatle

Hey, thanks for quick response! Unfortunately I stumbled into another problem, it seems that meteor bundler does not like import meta:

SyntaxError: Cannot use 'import.meta' outside a module
    at new Script (node:vm:117:7)
    at createScript (node:vm:269:10)
    at Object.runInThisContext (node:vm:317:10)
    at /tools/static-assets/server/boot.js:414:32
    at /tools/static-assets/server/boot.js:503:13
    at AsyncLocalStorage.run (node:async_hooks:346:14)
    at /tools/static-assets/server/boot.js:502:48
    at Function.run (<redacted>/.meteor/local/build/programs/server/tools/tool-env/profile.ts:315:14)
    at startServerProcess (/tools/static-assets/server/boot.js:501:17)
    at Object.<anonymous> (/tools/static-assets/server/boot.js:508:2)
    at Object.<anonymous> (/tools/static-assets/server/boot.js:512:4)
    at Module._compile (node:internal/modules/cjs/loader:1469:14)
    at Module.Mp._compile (/tools/static-assets/server/runtime.js:78:21)
    at Object.Module._extensions..js (/tools/static-assets/server/runtime.js:112:21)
    at Module.load (node:internal/modules/cjs/loader:1288:32)
    at Module.Mp.load (/tools/static-assets/server/runtime.js:35:31)

Is there a way to fix this? Seems related to https://github.com/meteor/meteor/issues/12324

alisnic avatar Jan 21 '25 07:01 alisnic

Note for other people, as a workaround you can write a Vite plugin that will transform Meteor.isServer condition to import.meta.env.SSR:

// vite.config.js
export default defineConfig({
  plugins: [meteorIsServerPlugin()]
})

function meteorIsServerPlugin() {
  return {
    name: 'meteor-isserver-plugin',
    enforce: 'pre',
    transform(code, id) {
      if (code.includes('Meteor.isServer')) {
        console.log('transforming Meteor.isServer', id);

        return {
          code: code.replace(/\bMeteor\.isServer\b/g, 'import.meta.env.SSR'),
          map: null
        };
      }
      return { code, map: null };
    }
  };
}

alisnic avatar Jan 21 '25 08:01 alisnic

@alisnic Hmm, unless I'm mistaken the import.meta blocks should be omitted from the build that's passed onto Meteor. Does your Meteor entry module contain any imports for your application code?

If you have a repository that reproduces the error message there I'd have a closer look for you. 👍

JorgenVatle avatar Jan 22 '25 14:01 JorgenVatle

I use meteor-vite only for client bundle. When Meteor builds server bundle it does not understand import.meta. But that doesn't matter because the plugin I wrote above fixes the problem

alisnic avatar Jan 23 '25 05:01 alisnic