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
@vitejs/plugin-legacy wrong work in nuxt #15464
Comments
Hi. Are there any updates or a known workaround for this? |
As a workaround, we ended up configuring To make configuring import browserslist from 'browserslist'
import { resolveToEsbuildTarget } from 'esbuild-plugin-browserslist'
import { defineNuxtConfig } from 'nuxt/config'
export default defineNuxtConfig({
…
vite: {
build: {
target: getBuildTarget([
'>0.1% and supports es6-module and not ios < 12 and not opera > 0',
'node >= 18.13.0'
])
}
}
})
function getBuildTarget(browsers) {
return resolveToEsbuildTarget(browserslist(browsers), {
printUnknownTargets: false
})
} |
Thanks for the quick response and for sharing your workaround, @lehni. That might worth a try, but I want to make sure one thing. How do you integrate polyfill.io (or you self-hosted version of it), into your config above? Simply by inserting your self-hosted polyfill url into a script tag? Edit: cleared up the question |
You just need to add a script tag to your app that loads the polyfill with the desired options. We have something like this in our default layout: setup() {
const script = []
const { polyfill } = useConfig()
if (polyfill) {
const version = polyfill.version || 1
const features = polyfill.features?.join(',') || ''
const flags = polyfill.flags?.join(',') || ''
script.push({
src: `/polyfill?v=${version}&features=${features}&flags=${flags}`
})
}
…
useHead({ script })
} And the config (retrieved by …
polyfill: {
version: 2, // Only used for cache busting.
features: [
'default',
'globalThis',
'es2015',
'es2016',
'es2017',
'es2018',
'es2019',
'es2020',
'es2021',
'es2022',
'es2023'
],
flags: ['gated']
}
… |
wanna help for this issue @danielroe |
@zhancheng help very welcome 😊 |
The temporary solution for this problem is to transfer the entry-legacy file to the end of the manifest file. You can solve the problem using a Nuxt hook in a module file: // modules/fixViteLegacyPlugin.ts
import {defineNuxtModule} from '@nuxt/kit';
export default defineNuxtModule({
setup(_option, nuxt) {
nuxt.hook('build:manifest', manifest => {
const keys = Object.keys(manifest);
// detect vite plugin added
if (!keys.some(key => key.includes('polyfills-legacy'))) {
return;
}
const entryKey = keys.find(key => key.includes('entry-legacy')) as string;
const entryValue = manifest[entryKey];
// remove entry
delete manifest[entryKey];
// add entry end of manifest
manifest[entryKey] = entryValue;
// fix legacy module attributes
for (const item in manifest) {
manifest[item].module = item.includes('polyfills-legacy')
? false
: !item.includes('-legacy.js');
}
});
}
}); |
Just in case if anyone lands here trying to make Nuxt work in Chrome 49 (Windows XP), I managed to achieve that by removing diff --git a/dist/runtime.mjs b/dist/runtime.mjs
index 29154e86eed636881eabc2c7fd01e9883e9e0404..736cbd0cd5dab57e71fd5dea427afc99717c4909 100644
--- a/dist/runtime.mjs
+++ b/dist/runtime.mjs
@@ -162,8 +162,7 @@ function renderScripts(ssrContext, rendererContext) {
return Object.values(scripts).map((resource) => renderScriptToString({
type: resource.module ? "module" : null,
src: rendererContext.buildAssetsURL(resource.file),
- defer: resource.module ? null : "",
- crossorigin: ""
+ crossorigin: resource.module ? "" : null
})).join("");
}
function createRenderer(createApp, renderOptions) { and then to fix this: // modules/vite-legacy-patch.ts
import { defineNuxtModule } from '@nuxt/kit'
import { pick } from 'lodash'
export default defineNuxtModule({
setup(_option, nuxt) {
nuxt.hook('build:manifest', manifest => {
// copy of manifest where polyfill is moved to 1st position
const manifest_copy: typeof manifest = {
...pick(manifest, 'vite/legacy-polyfills-legacy'),
...manifest,
}
// clear manifest
for (const key of Object.keys(manifest)) {
delete manifest[key]
}
// fill manifest again from the copy
Object.assign(manifest, manifest_copy)
// remove module attributes from legacy chunks
for (const key of Object.keys(manifest)) {
if (key.match(/-legacy(\.|$)/)) {
manifest[key].module = false
} else if (manifest[key].module) {
// remove modern chunks completely, otherwise it conflicts in modern Chrome:
// [nuxt] error caught during app initialization Error: Context conflict
//
// that could be related to defer being removed from legacy chunks
// see: patches/vue-bundle-renderer@1.0.3.patch
// but with that patch Chrome 49 wouldn't run any scripts at all
delete manifest[key]
}
}
})
},
}) and then some polyfills: export default defineNuxtConfig({
vite: {
plugins: [
// for Windows XP
// see also modules/vite-legacy-patch.ts
legacy({
targets: ['chrome 49'],
additionalLegacyPolyfills: [
'intersection-observer',
'mdn-polyfills/Element.prototype.getAttributeNames',
],
}),
],
}
}) This makes it work in Windows XP. This is all (without a doubt) very dirty and unpleasant, so if there are better workarounds please weigh in! UPDATE: see better working solution below. |
The problem is that the polyfill bundle is loaded after the entry bundle, cause polyfills should always come first. I was inspired by Ilya's comment to create a solution like this: // nuxt.config.ts
hooks: {
'build:manifest': (manifest) => {
// kinda hacky, vite polyfills are incorrectly being loaded last so we have to move them to appear first in the object.
// we can't replace `manifest` entirely, cause then we're only mutating a local variable, not the actual manifest
// which is why we have to mutate the reference.
// since ES2015 object string property order is more or less guaranteed - the order is chronological
const polyfillKey = 'vite/legacy-polyfills'
const polyfillEntry = manifest[polyfillKey]
if (!polyfillEntry) return
const oldManifest = { ...manifest }
delete oldManifest[polyfillKey]
for (const key in manifest) {
delete manifest[key]
}
manifest[polyfillKey] = polyfillEntry
for (const key in oldManifest) {
manifest[key] = oldManifest[key]
}
}
} That's the only change I needed to make, no need to adjust any build artifacts or anything. Note: The polyfill bundle key might be different depending on the settings of the legacy plugin. I'm only using it to generate polyfills for modern bundles (renderLegacyChunks: false & modernPolyfills: true) |
Just a heads up, I managed to deliver isomorphic build which runs both legacy and non-legacy code: 1. Put the polyfills chunk to 1st position and remove
|
We've discussed as a team and I think we shouldn't adopt within Nuxt itself as the incompatibility window is small and decreasing with time. However, a module implementation would very much be welcome. Feel free to ping me if there's anything you need or Nuxt does not provide as part of doing this. |
@danielroe Can you elaborate on this? It seems like this is always going to be a problem, cause the polyfill bundle is always going to be loaded after the nuxt bundle. The resolution is quite hacky as well (having to re-order the build manifest in a nuxt hook). Would be nice if there would just be a nuxt config API that would allow you to control the load order of bundles. |
@fabis94 Would you open a new issue to track the enhancement you're talking about, perhaps? |
FWIW, I published my recipe above as a Nuxt module: https://www.npmjs.com/package/nuxt-vite-legacy This collection of hacks is not something I'm exactly proud of, but it works. :) |
This is something that I feel should be documented somewhere. I have prior experience with Vite and polyfills from another project and expected to be able to add the legacy plugin to the the Quite shocked that we need to update the response on every request using the Honestly this is something I'd like to see first class support however I understand there's very little sense in re-inventing the wheel. |
It works for me,thx~ |
Environment
Linux
v16.17.1
3.0.0-rc.13
0.6.1
pnpm@7.15.0
vite
runtimeConfig
,css
,vite
-
Reproduction
Nuxt
Describe the bug
Problem is polyfills load after entry file and System variable is undefined!
i install legacy plugin in pure vite project and don't see this problem. i think nuxt problem!
Additional context
No response
Logs
Uncaught ReferenceError: System is not defined `entry-legacy.4e3349cb.js:1:12341`
The text was updated successfully, but these errors were encountered: