vite
vite copied to clipboard
'URL' named export breaks static file import in production build
Describe the bug
When using a package (react-dnd-html5-backend in my case) that exports 'URL' as a named export, it will break the static file import (which uses new URL(...)
in the production build).
Depending on the import order you will get "Cannot access 'URL' before initialization" or "'URL' is not a constructor" when running the packaged application.
It works perfectly fine in dev mode, but it breaks in production build.
Reproduction
https://stackblitz.com/edit/vitejs-vite-zguhve
Steps to reproduce
npm install
Then if you run npm run dev
you will see the vite logo and under it the "URL named export" string.
But if you run npm run build
and npm run preview
you will see a blank white page indicating a broken react application. If you open the console, you can see the "Cannot access 'URL' before initialization" error message.
System Info
System:
OS: Linux 4.19 Debian GNU/Linux 10 (buster) 10 (buster)
CPU: (8) x64 Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
Memory: 6.19 GB / 15.36 GB
Container: Yes
Shell: 5.0.3 - /bin/bash
Binaries:
Node: 16.19.0 - /usr/bin/node
npm: 8.5.0 - /usr/bin/npm
Browsers:
Chrome: 109.0.5414.119
Firefox: 102.7.0esr
npmPackages:
@vitejs/plugin-react: ^2.1.0 => 2.1.0
vite: ^3.2.5 => 3.2.5
Used Package Manager
npm
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.
As a workaround you can create a variable with the URL constructor somewhere and it will force esbuild to add a suffix for the named export.
Hey! Lemme try picking this up. Also is it cool if I ask questions for a little bit of help if I get stuck?
Waiting for an ingenious solution
Tbh just was looking into it, vite is the bundler though uses Rollup I do believe its with Rollup since the transpilation happens there! I am not sure if I am correct though!
The repro is using Vite 3, but I can confirm it happens in Vite 4 too. It's likely a bug in Rollup as it should internally alias the URL
import to something else to not conflict with the global URL
variable. It already does keep a list of known globals.
Hmm actually looks like Rollup is working fine, perhaps Vite's dynamic usage of URL confuses Rollup, but I'm not sure how.
Hmm actually looks like Rollup is working fine, perhaps Vite's dynamic usage of URL confuses Rollup, but I'm not sure how.
The problem seems vite render the new URL(...)
with const URL = ....
together, which may let rollup think they are the same variable.
...
const image = "__VITE_ASSET__24400c48__"; // __VITE_ASSET__ will be replace to new URL via asset plugin
const URL = 'xxxx'
...
https://github.com/rollup/rollup/blob/master/src/utils/deconflictChunk.ts#L210 seems rollup resolve global variable conflict with this function
Would it be acceptable to switch to new globalThis.URL(
instead of new URL(
? Gzipped, the diff in size shouldn't be that big. And we could later optimize and remove the globalThis
if there isn't a URL variable in the chunk, but I don't know if it is worth it.
This happens to me on Nuxt 3 for dependencies that use the url-parse module (in my case tus-js-client). I had to override the Vite version to 4.3.1 to get it to build properly.
Same issue when using Vite with uuid as uuid exports URL: https://github.com/uuidjs/uuid/blob/4de23a6030e65ac72b3b015680f08e7e292681ed/src/v35.js#L17
I am also experiencing this issue with a project that uses react-dnd-html5-backend
and uuid
, both export URL
. They do not collide with each other, rollup recognises that conflict, but they do collide with the global URL
.
Anyone have a work around for this issue?
Managed to workaround the issue by using @rollup-plugins/replace. It is less than ideal but got me going again.
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr'
import replace from '@rollup/plugin-replace'
export default defineConfig({
base: './',
plugins: [
react(),
svgr(),
replace({
'new URL(': 'new globalThis.URL(',
delimiters: ['', ''],
preventAssignment: true
})
],
server: {
port: 3000,
host: true
},
build: {
outDir: './build',
manifest: true,
minify: true
},
});
Managed to workaround the issue by using @rollup-plugins/replace. It is less than ideal but got me going again.
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import svgr from 'vite-plugin-svgr' import replace from '@rollup/plugin-replace' export default defineConfig({ base: './', plugins: [ react(), svgr(), replace({ 'new URL(': 'new globalThis.URL(', delimiters: ['', ''], preventAssignment: true }) ], server: { port: 3000, host: true }, build: { outDir: './build', manifest: true, minify: true }, });
This workaround worked for me, thanks!
If that helps - It happens to me with SvelteKit when importing bunch of icons from $lib. I tried to make reproduction repo but it seems to be dependent on other things that go into the bundle, when I tried to make contrived example it didn't behave like that. Vite 4.4.8 Svelte 4.1.2 SvelteKit 1.22.4
import AAA from '$lib/icons/AAA.svg';
import BBB from '$lib/icons/BBB.svg';
import CCC from '$lib/icons/CCC.svg';
import DDD from '$lib/icons/DDD.svg';
import EEE from '$lib/icons/EEE.svg';
import FFF from '$lib/icons/FFF.svg';
const iconMap: Record<string, string> = {
AAA,
BBB,
CCC,
DDD,
EEE,
FFF
};
export default iconMap;
It looks like this issue has been fixed in the latest version of Vite.
It looks like this issue has been fixed in the latest version of Vite.
Vite 5.1.6, the problem still exists.