vite
vite copied to clipboard
Ignore browser field when bundling in library mode
Describe the bug
use vite to build a lib for nodejs
The source code in axios is like below:
function getDefaultAdapter() {
var adapter;
if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = require('../adapters/xhr.js');
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('../adapters/http');
}
return adapter;
}
After building. The result bundle is not correct. Http adapter is resolved as xhr.
function getDefaultAdapter() {
var adapter;
if (typeof XMLHttpRequest !== "undefined") {
adapter = xhr;
} else if (typeof process !== "undefined" && Object.prototype.toString.call(process) === "[object process]") {
adapter = xhr;
}
return adapter;
}
Then i got the error: UnhandledRejection ReferenceError: XMLHttpRequest is not defined
Reproduction
https://github.com/Sara2009/vite-require
System Info
"vite": "^2.9.13",
Used Package Manager
yarn
Logs
No response
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [X] The provided reproduction is a minimal reproducible example of the bug.
vite does not support require
I think the require here is still valid as it's used within a dependency (axios). Looks like the issue here is that axios specifies a browser field which Vite respects, which changed the http import to xhr.
Looks like library mode is focused on browser targets at the moment which caused this bug. It should be agnostic and leave it as is.
A workaround is to add axios as a dependency and put it in rollupOptions.external.
set resolve.browserField to false will indicate Vite to ignore browser filed when resolving packages. I think it's enough for bundling universal bundles. 🤔
set
resolve.browserFieldtofalsewill indicate Vite to ignore browser filed when resolving packages. I think it's enough for bundling universal bundles. 🤔
Now the resolve.browserField field is marked as deprecated, but the behavior of mainFields configured as [ "node", "module", "jsnext:main", "jsnext" ] is inconsistent, is there any solution?
Setting 'browserField' to false seems to not work for me. Vitest and SSR seem to avoid this problem, so it must be possible. Any ideas?
Vitest and SSR seem to avoid this problem, so it must be possible. Any ideas?
Vitest uses rollup directly :-( https://github.com/vitest-dev/vitest/blob/main/packages/vitest/rollup.config.js
Too bad, because vite has a lot better DX than rollup, and the ecosystem is growing.
That said, setting build.ssr to true and ssr: { noExternal: true } works for me. It doesn't import browser versions of dependencies.
working example:
import { nodeExternals } from 'rollup-plugin-node-externals'
export default defineConfig(({ mode }) => ({
plugins: [
// Don't bundle any nodejs builtins
nodeExternals(),
],
ssr: { noExternal: true },
build: {
ssr: true,
lib: {
entry: ['src/index.ts', 'src/bin/cli.ts'],
formats: ['cjs'],
},
target: 'node18',
outDir: 'build',
sourcemap: true,
minify: mode === 'production' && 'esbuild',
},
}))
I think this is already resolved by config:
If you build a browser-targeting library, use the default config. If you build a node-targeting library, remove browser from resolve.mainFields.
I only wish there were a more explicit way to specify that one is building a node/bun/deno library. build.target is just not suitable imho.