diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f225fd72..40150840 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,6 +81,7 @@ jobs: compatibility: ['compatibility', 'no-compatibility'] resolve: ['resolve', 'no-resolve'] typescript: ['isTSX', 'esbuild'] + vite-legacy: ['legacy', 'no-legacy'] exclude: - transpile: 'no-transpile' builder: 'vite' @@ -92,6 +93,8 @@ jobs: builder: 'vite' - compatibility: 'no-compatibility' env: 'dev' + - vite-legacy: 'no-legacy' + builder: 'webpack' steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -135,6 +138,7 @@ jobs: env: TEST_ENV: ${{ matrix.env }} TEST_BUILDER: ${{ matrix.builder }} + TEST_VITE_LEGACY: ${{ matrix.vite-legacy || 'legacy' }} TEST_TRANSPILE: ${{ matrix.transpile || 'transpile' }} TEST_COMPATIBILITY: ${{ matrix.compatibility || 'compatibility' }} TEST_RESOLVE: ${{ matrix.resolve || 'resolve' }} diff --git a/packages/bridge/src/vite/client.ts b/packages/bridge/src/vite/client.ts index 450c5b23..7365a29d 100644 --- a/packages/bridge/src/vite/client.ts +++ b/packages/bridge/src/vite/client.ts @@ -8,7 +8,6 @@ import type { ServerOptions, InlineConfig } from 'vite' import { defineEventHandler } from 'h3' import defu from 'defu' import { viteNodePlugin } from '../vite-node' -import PluginLegacy from './stub-legacy.cjs' import { mergeConfig, createServer, build } from './stub-vite.cjs' import { devStyleSSRPlugin } from './plugins/dev-ssr-css' import { jsxPlugin } from './plugins/jsx' @@ -61,7 +60,6 @@ export async function buildClient (ctx: ViteBuildContext) { plugins: [ jsxPlugin(), createVuePlugin(ctx.config.vue), - PluginLegacy(), devStyleSSRPlugin({ srcDir: ctx.nuxt.options.srcDir, buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir) @@ -74,6 +72,14 @@ export async function buildClient (ctx: ViteBuildContext) { } } as ViteOptions) + const disabledLegacy = typeof ctx.nuxt.options.bridge.vite === 'object' && ctx.nuxt.options.bridge.vite.legacy === false + + if (!disabledLegacy) { + const legacyPlugin = await import('@vitejs/plugin-legacy').then(r => r.default || r) + // @ts-expect-error + clientConfig.plugins.push(legacyPlugin()) + } + // In build mode we explicitly override any vite options that vite is relying on // to detect whether to inject production or development code (such as HMR code) if (!ctx.nuxt.options.dev) { diff --git a/packages/bridge/src/vite/manifest.ts b/packages/bridge/src/vite/manifest.ts index 89ec7eec..ec3d9673 100644 --- a/packages/bridge/src/vite/manifest.ts +++ b/packages/bridge/src/vite/manifest.ts @@ -66,55 +66,63 @@ export async function generateBuildManifest (ctx: ViteBuildContext) { } } - // Search for polyfill file, we don't include it in the client entry - const polyfillName = Object.values(clientManifest).find(entry => entry.file.startsWith('polyfills-legacy'))?.file - const polyfill = await fse.readFile(rDist('client', buildAssetsDir, polyfillName), 'utf-8') - - const clientImports = new Set() - const clientEntry: Partial>> = { - assets: new Set(), - css: new Set(), - dynamicImports: new Set() - } + const disabledLegacy = typeof ctx.nuxt.options.bridge.vite === 'object' && ctx.nuxt.options.bridge.vite.legacy === false + + let manifest + + if (disabledLegacy) { + manifest = normalizeViteManifest(clientManifest) + } else { + // Search for polyfill file, we don't include it in the client entry + const polyfillName = Object.values(clientManifest).find(entry => entry.file.startsWith('polyfills-legacy'))?.file + const polyfill = await fse.readFile(rDist('client', buildAssetsDir, polyfillName), 'utf-8') + + const clientImports = new Set() + const clientEntry: Partial>> = { + assets: new Set(), + css: new Set(), + dynamicImports: new Set() + } - for (const entry in clientManifest) { - if (!clientManifest[entry].file.startsWith('polyfills-legacy') && clientManifest[entry].file.includes('-legacy')) { - clientImports.add(clientManifest[entry].file) - for (const key of ['css', 'assets', 'dynamicImports']) { - for (const file of clientManifest[entry][key] || []) { - clientEntry[key].add(file) + for (const entry in clientManifest) { + if (!clientManifest[entry].file.startsWith('polyfills-legacy') && clientManifest[entry].file.includes('-legacy')) { + clientImports.add(clientManifest[entry].file) + for (const key of ['css', 'assets', 'dynamicImports']) { + for (const file of clientManifest[entry][key] || []) { + clientEntry[key].add(file) + } } } + delete clientManifest[entry].isEntry } - delete clientManifest[entry].isEntry - } - // @vitejs/plugin-legacy uses SystemJS which need to call `System.import` to load modules - const clientEntryCode = [ - polyfill, - 'var appConfig = window && window.__NUXT__ && window.__NUXT__.config.app || {}', - 'var publicBase = appConfig.cdnURL || appConfig.baseURL || "/"', - 'function joinURL (a, b) { return a.replace(/\\/+$/, "") + "/" + b.replace(/^\\/+/, "") }', - 'globalThis.__publicAssetsURL = function(id) { return joinURL(publicBase, id || "") }', - 'globalThis.__buildAssetsURL = function(id) { return joinURL(publicBase, joinURL(appConfig.buildAssetsDir, id || "")) }', + // @vitejs/plugin-legacy uses SystemJS which need to call `System.import` to load modules + const clientEntryCode = [ + polyfill, + 'var appConfig = window && window.__NUXT__ && window.__NUXT__.config.app || {}', + 'var publicBase = appConfig.cdnURL || appConfig.baseURL || "/"', + 'function joinURL (a, b) { return a.replace(/\\/+$/, "") + "/" + b.replace(/^\\/+/, "") }', + 'globalThis.__publicAssetsURL = function(id) { return joinURL(publicBase, id || "") }', + 'globalThis.__buildAssetsURL = function(id) { return joinURL(publicBase, joinURL(appConfig.buildAssetsDir, id || "")) }', `var imports = ${JSON.stringify([...clientImports])};`, 'imports.reduce(function(p, id){return p.then(function(){return System.import(__buildAssetsURL(id))})}, Promise.resolve())' - ].join('\n') - const clientEntryName = 'entry-legacy.' + hash(clientEntryCode) + '.js' - - await fse.writeFile(rDist('client', buildAssetsDir, clientEntryName), clientEntryCode, 'utf-8') - - const manifest = normalizeViteManifest({ - [clientEntryName]: { - file: clientEntryName, - module: true, - isEntry: true, - css: [...clientEntry.css], - assets: [...clientEntry.assets], - dynamicImports: [...clientEntry.dynamicImports] - }, - ...clientManifest - }) + ].join('\n') + const clientEntryName = 'entry-legacy.' + hash(clientEntryCode) + '.js' + + await fse.writeFile(rDist('client', buildAssetsDir, clientEntryName), clientEntryCode, 'utf-8') + + manifest = normalizeViteManifest({ + [clientEntryName]: { + file: clientEntryName, + module: true, + isEntry: true, + css: [...clientEntry.css], + assets: [...clientEntry.assets], + dynamicImports: [...clientEntry.dynamicImports] + }, + ...clientManifest + }) + } await writeClientManifest(manifest, ctx.nuxt.options.buildDir) diff --git a/packages/bridge/src/vite/stub-legacy.cjs b/packages/bridge/src/vite/stub-legacy.cjs deleted file mode 100644 index 4392c9fb..00000000 --- a/packages/bridge/src/vite/stub-legacy.cjs +++ /dev/null @@ -1,3 +0,0 @@ -// CommonJS proxy to bypass jiti transforms from nuxt 2 -/** @type {typeof import('@vitejs/plugin-legacy')['default'] } */ -module.exports = require('@vitejs/plugin-legacy') diff --git a/packages/bridge/types.d.ts b/packages/bridge/types.d.ts index 59072653..a47e798b 100644 --- a/packages/bridge/types.d.ts +++ b/packages/bridge/types.d.ts @@ -23,7 +23,12 @@ export interface NuxtSSRContext extends SSRContext { export interface BridgeConfig { nitro: boolean nitroGenerator: boolean - vite: boolean + vite: boolean | { + /** + * If set to false, `@vitejs/plugin-legacy` not used. + */ + legacy?: boolean + } app: boolean | {} capi: boolean | { legacy?: boolean diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index be3e79cc..351fbd9c 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -5,7 +5,7 @@ import { defineNuxtConfig } from '@nuxt/bridge' global.__NUXT_PREPATHS__ = (global.__NUXT_PREPATHS__ || []).concat(__dirname) const bridgeConfig = { - vite: process.env.TEST_BUILDER !== 'webpack', + vite: process.env.TEST_BUILDER !== 'webpack' ? { legacy: process.env.TEST_VITE_LEGACY !== 'no-legacy' } : false, transpile: process.env.TEST_TRANSPILE !== 'no-transpile', compatibility: process.env.TEST_COMPATIBILITY !== 'no-compatibility', resolve: process.env.TEST_RESOLVE !== 'no-resolve',