vite: Bundling SSR Modules using CommonJS exports alias results in ReferenceError: exports is not defined
Describe the bug
When importing an SSR module, if
- it uses the
exportsalias instead ofmodule.exports, ssr.noExternalis declared with the module
Vite is unable to evaluate it. This can also happen with the more common module.exports, but seems to not be guaranteed.
While this behavior may seem esoteric due to modern proliferation of module.exports, this is a feature of Node since v0.1.16 and has not been deprecated. In addition, there are instances of various npm modules in the wild which use this method of exporting fields, including, but not limited to:
…and much, much, more searchable on GitHub. I believe this is also an output of some bundlers.
Reproduction
https://github.com/GrygrFlzr/vite-cjs-ssr
git clone https://github.com/GrygrFlzr/vite-cjs-ssr.git
cd vite-cjs-ssr
npm i
npm run dev
Visit http://localhost:3000 to trigger SSR, which consists of a very simple script that uses the cookie npm module.
The page will render exports is not defined and errors will show up in the server console:
6:29:45 PM [vite] new dependencies found: cookie, updating...
6:29:45 PM [vite] Error when evaluating SSR module /node_modules/cookie/index.js:
ReferenceError: exports is not defined
at /node_modules/cookie/index.js:15:1
at instantiateModule (C:\Users\GrygrFlzr\Documents\projects\vite-cjs\node_modules\vite\dist\node\chunks\dep-efe32886.js:68893:166)
ReferenceError: exports is not defined
at /node_modules/cookie/index.js:13:1
at instantiateModule (C:\Users\GrygrFlzr\Documents\projects\vite-cjs\node_modules\vite\dist\node\chunks\dep-efe32886.js:68893:166)
System Info
viteversion: 2.1.2- Operating System: Windows 10 10.0.19042
- Node version: 14.16.0
- Package manager and version: npm 6.14.11
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 85
- Comments: 45 (4 by maintainers)
Commits related to this issue
- feat(ssr): support commonjs in `ssrTransform` When a dependency is (1) cloned within the Vite root and (2) is listed in `optimizeDeps.exclude`, it will pass through `ssrTransform` and might be using ... — committed to aleclarson/vite by aleclarson 3 years ago
- feat: support cjs noExternal in SSR dev, fix #2579 (#8430) — committed to vitejs/vite by patak-dev 2 years ago
Vite is an integral part of SvelteKit that provides many benefits such as code changes showing up instantly, code splitting for fast loading sites, etc. The Vite team has been nothing but helpful in resolving issues and have both fixed issues for us and accepted patches from us. Vite 2.7 to be released shortly will solve the majority of issues we’re aware of and we’re already working on Vite 2.8 with additional fixes. I’m aware Vite issues have been some of the most common to encounter with SvelteKit, but that’s changing very rapidly and we’re definitely not dropping Vite. Also, the majority of 1.0 blockers are in SvelteKit itself and not in Vite.
If a package bundler called vite is ruining the reputation and preventing the release of the most loved JS framework SvelteKit for several months, then why don’t Svelte team and Rich Harris drop/discard the vite thing entirely ? They can utilize a bundler which actually works, their own rollup maybe? All the blocking issues for sveltekit belong to vite. Or is this a core issue of sveltekit way of SSR implementation?
Here’s my summary of the situation, as best I understand it:
ssr.noExternalincludes a package, it will get loaded viassrLoadModuleduring development and bundled via Vite’s plugins (plus any user plugins) during buildssrLoadModuledoesn’t have any special handling for CommonJS, nor does Vite’s internal set of pluginsnoExternalwill failIn other words I don’t think this is a bug. A lot of SvelteKit beta users hit it because we were fumbling around with the right config (to ensure that built serverless functions didn’t have dependencies that specific platforms struggled with), but not because Vite was doing anything wrong.
Perhaps instead of treating this as a bug we should be thinking in terms of providing a more useful error message — e.g. if
ssrLoadModuleresults inReferenceError: (module|require|exports|__dirname|etc) is not definedVite replaces it with something more actionable, like ‘CommonJS dependencies cannot be added tossr.noExternal— please removecookie’IMPORTANT: to be extra clear about this, any SvelteKit users that hit this and have an
ssr.noExternalin theirsvelte.config.cjsfrom project creation should remove it. The template no longer has this config and you should match what a newly created project now looks like.Is there any new progress on this issue? Most svelte components have this problem. https://github.com/idris-maps/svelte-parts https://github.com/meigo/svelte-video-player/issues/10
Thanks a lot. You might be right about that
@zerodevx/svelte-toastbut since I got it working with the above changes applied:I wouldn’t dare to check it in isolation again. 😸
Having a loader being able to recognize it as a CJS problem and hinting to
optimizeDeps.includewould have been great. I thinkoptimizeDepsname is a bit misleading in this context. Messaging or a lack of proper hinting is/was a regular problem with installation of svelte packages (dev or not to dev).For me changing to
module.exportsalso does not solve the problem: I getmodule is not definederror.I was having this issue and fixed with https://github.com/originjs/vite-plugins/tree/main/packages/vite-plugin-commonjs
Working on a sveltekit project may help someone in the future
I have working WIP sapper project that I tried to migrate into svelte-kit. The above error and couple - I assume related - hit me hard while adding any meaningful(to me with existing codebase) svelte component, namely:
I tried many possible configs mentioned here and in other topics, with no success. How could I and how could we as developers be able to use/adapt/wrap libraries using cjs? Requiring every package to add ejs support and not use any cjs packages seems unrealistic. cjs in itself is one of those billion dollars in development wasted problems but we had a decade to understand it good enough to be able to solve related issues efficiently.
How would one go about using cjs modules or ejs modules that use cjs modules with vitejs? Is it currently supported? If yes, then what are the correct settings to do that efficiently or good enough? If it isn’t currently supported then would that be supported in the future or is it intentionally not supported/out of scope of project? If so, then why?
Thank you very much in advance. Keep up the good work folks. Let me try to help you, even if that only means asking the right questions. Are those questions the right ones? 😉
If Netlify requires dependencies to be bundled then we should prefer to do that with the Netlify tooling in the SvelteKit adapter and not with Vite. I’d filed an issue for this in https://github.com/sveltejs/kit/issues/1016. I closed it because it’s unclear to me whether there are currently any issues that people are experiencing, but if there are issues then I think that would be the proper solution to try to implement
Just did a test on d3 with the latest kit, requires
ssr: { noExternal: ["d3"] }to run thebuild. I tried no options, then all the variations listed in the faq. RepoManaged to get around a similar issue by using the vite-plugin-commonjs plugin:
I have PRs pending to convert the CommonJS dependencies of first two of those libraries to ESM: https://github.com/feross/clipboard-copy/pull/49 and https://github.com/iliakan/detect-node/pull/17
In the meantime you can work around this by adding those CommonJS dependencies to
optimizeDeps.include. There are issues in the@sveltestack/svelte-queryandcarbon-components-svelterepos showing how to do this.@zerodevx/svelte-toastdoes not use CommonJS so I’m not sure what issue you’re having with that library, but it might be a little different than the other twoThat’s a good summary. Another option might be to have Vite optimize these dependencies and utilize the optimized ESM version. Svelte components need to be in
ssr.noExternal. That means if they have a CommonJS dependency they will fail unless that dependency is converted to ESM by including it inoptimizeDeps.include. It’s possible that any CommonJS dependencies innoExternalcould work if they’re inoptimizeDeps.includethough I haven’t tested that. I’m not sure whether Vite’s automatic dependency discovery can be made to work withvite-plugin-svelte, but if it’s possible that would be a nice quality of life improvement (tracked in https://github.com/vitejs/vite/issues/3024). Svelte component authors should try to make their dependencies ESM if possible in either caseIt turns out that Rollup creates output that uses just
exportsinstead ofmodule.exportsso this is probably quite common to hit. A user reported this issue withapollo-link-prismicwhich is written in ESM but then bundled to CJS with Rolluphave you tried
Probably #2157 can resolve this issue. I am looking forward to its merge.