mirror of
https://github.com/nuxt/nuxt.git
synced 2025-03-21 08:45:53 +00:00
fix(nuxt): ensure externals are resolved first (#31235)
This commit is contained in:
parent
13780d739f
commit
854d3d066b
@ -24,7 +24,7 @@ import defu from 'defu'
|
||||
import { gt, satisfies } from 'semver'
|
||||
import { hasTTY, isCI } from 'std-env'
|
||||
import { genImport } from 'knitwork'
|
||||
import { resolveModulePath, resolveModuleURL } from 'exsolve'
|
||||
import { resolveModulePath } from 'exsolve'
|
||||
|
||||
import { installNuxtModule } from '../core/features'
|
||||
import pagesModule from '../pages/module'
|
||||
@ -48,7 +48,8 @@ import schemaModule from './schema'
|
||||
import { RemovePluginMetadataPlugin } from './plugins/plugin-metadata'
|
||||
import { AsyncContextInjectionPlugin } from './plugins/async-context'
|
||||
import { ComposableKeysPlugin } from './plugins/composable-keys'
|
||||
import { resolveDeepImportsPlugin } from './plugins/resolve-deep-imports'
|
||||
import { ResolveDeepImportsPlugin } from './plugins/resolve-deep-imports'
|
||||
import { ResolveExternalsPlugin } from './plugins/resolved-externals'
|
||||
import { PrehydrateTransformPlugin } from './plugins/prehydrate'
|
||||
import { VirtualFSPlugin } from './plugins/virtual'
|
||||
|
||||
@ -374,8 +375,10 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
addWebpackPlugin(() => ImpoundPlugin.webpack(nuxtProtectionConfig))
|
||||
|
||||
// add resolver for modules used in virtual files
|
||||
addVitePlugin(() => resolveDeepImportsPlugin(nuxt), { client: false })
|
||||
addVitePlugin(() => resolveDeepImportsPlugin(nuxt), { server: false })
|
||||
addVitePlugin(() => ResolveDeepImportsPlugin(nuxt), { client: false })
|
||||
addVitePlugin(() => ResolveDeepImportsPlugin(nuxt), { server: false })
|
||||
|
||||
addVitePlugin(() => ResolveExternalsPlugin(nuxt), { client: false, prepend: true })
|
||||
|
||||
// Add transform for `onPrehydrate` lifecycle hook
|
||||
addBuildPlugin(PrehydrateTransformPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client }))
|
||||
@ -392,13 +395,12 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
}
|
||||
|
||||
nuxt.hook('modules:done', () => {
|
||||
const importPaths = nuxt.options.modulesDir.map(dir => directoryToURL((dir)))
|
||||
// Add unctx transform
|
||||
addBuildPlugin(UnctxTransformPlugin({
|
||||
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
|
||||
transformerOptions: {
|
||||
...nuxt.options.optimization.asyncTransforms,
|
||||
helperModule: resolveModuleURL('unctx', { try: true, from: importPaths }) ?? 'unctx',
|
||||
helperModule: 'unctx',
|
||||
},
|
||||
}))
|
||||
|
||||
|
@ -2,24 +2,22 @@ import { parseNodeModulePath } from 'mlly'
|
||||
import { resolveModulePath } from 'exsolve'
|
||||
import { isAbsolute, normalize, resolve } from 'pathe'
|
||||
import type { Plugin } from 'vite'
|
||||
import { directoryToURL, resolveAlias, tryImportModule } from '@nuxt/kit'
|
||||
import { directoryToURL, resolveAlias } from '@nuxt/kit'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
import type { Nitro } from 'nitro/types'
|
||||
|
||||
import { pkgDir } from '../../dirs'
|
||||
import { logger } from '../../utils'
|
||||
|
||||
const VIRTUAL_RE = /^\0?virtual:(?:nuxt:)?/
|
||||
|
||||
export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
|
||||
export function ResolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
|
||||
const exclude: string[] = ['virtual:', '\0virtual:', '/__skip_vite', '@vitest/']
|
||||
let conditions: string[]
|
||||
let external: Set<string>
|
||||
|
||||
return {
|
||||
name: 'nuxt:resolve-bare-imports',
|
||||
enforce: 'post',
|
||||
async configResolved (config) {
|
||||
configResolved (config) {
|
||||
const resolvedConditions = new Set([nuxt.options.dev ? 'development' : 'production', ...config.resolve.conditions])
|
||||
if (resolvedConditions.has('browser')) {
|
||||
resolvedConditions.add('web')
|
||||
@ -32,27 +30,12 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
|
||||
resolvedConditions.add('require')
|
||||
}
|
||||
conditions = [...resolvedConditions]
|
||||
|
||||
const { runtimeDependencies = [] } = await tryImportModule<typeof import('nitro/runtime/meta')>('nitro/runtime/meta', {
|
||||
url: new URL(import.meta.url),
|
||||
}) || {}
|
||||
|
||||
external = new Set([
|
||||
// explicit dependencies we use in our ssr renderer - these can be inlined (if necessary) in the nitro build
|
||||
'unhead', '@unhead/vue', 'unctx', 'h3', 'devalue', '@nuxt/devalue', 'radix3', 'rou3', 'unstorage', 'hookable',
|
||||
// ensure we only have one version of vue if nitro is going to inline anyway
|
||||
...((nuxt as any)._nitro as Nitro).options.inlineDynamicImports ? ['vue', '@vue/server-renderer', '@unhead/vue'] : [],
|
||||
// dependencies we might share with nitro - these can be inlined (if necessary) in the nitro build
|
||||
...runtimeDependencies,
|
||||
])
|
||||
},
|
||||
async resolveId (id, importer) {
|
||||
if (!importer || isAbsolute(id) || (!isAbsolute(importer) && !VIRTUAL_RE.test(importer)) || exclude.some(e => id.startsWith(e))) {
|
||||
return
|
||||
}
|
||||
|
||||
const overrides = external.has(id) ? { external: 'absolute' } as const : {}
|
||||
|
||||
const normalisedId = resolveAlias(normalize(id), nuxt.options.alias)
|
||||
const isNuxtTemplate = importer.startsWith('virtual:nuxt')
|
||||
const normalisedImporter = (isNuxtTemplate ? decodeURIComponent(importer) : importer).replace(VIRTUAL_RE, '')
|
||||
@ -62,10 +45,7 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
|
||||
if (template?._path) {
|
||||
const res = await this.resolve?.(normalisedId, template._path, { skipSelf: true })
|
||||
if (res !== undefined && res !== null) {
|
||||
return {
|
||||
...res,
|
||||
...overrides,
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,10 +54,7 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
|
||||
|
||||
const res = await this.resolve?.(normalisedId, dir, { skipSelf: true })
|
||||
if (res !== undefined && res !== null) {
|
||||
return {
|
||||
...res,
|
||||
...overrides,
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
const path = resolveModulePath(id, {
|
||||
@ -92,13 +69,6 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
|
||||
return null
|
||||
}
|
||||
|
||||
if (external.has(id)) {
|
||||
return {
|
||||
id: normalize(path),
|
||||
external: 'absolute',
|
||||
}
|
||||
}
|
||||
|
||||
return normalize(path)
|
||||
},
|
||||
}
|
||||
|
42
packages/nuxt/src/core/plugins/resolved-externals.ts
Normal file
42
packages/nuxt/src/core/plugins/resolved-externals.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import type { Plugin } from 'vite'
|
||||
import { tryImportModule } from '@nuxt/kit'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
import type { Nitro } from 'nitro/types'
|
||||
|
||||
export function ResolveExternalsPlugin (nuxt: Nuxt): Plugin {
|
||||
let external: Set<string> = new Set()
|
||||
|
||||
return {
|
||||
name: 'nuxt:resolve-externals',
|
||||
enforce: 'pre',
|
||||
async configResolved () {
|
||||
if (!nuxt.options.dev) {
|
||||
const { runtimeDependencies = [] } = await tryImportModule<typeof import('nitro/runtime/meta')>('nitro/runtime/meta', {
|
||||
url: new URL(import.meta.url),
|
||||
}) || {}
|
||||
|
||||
external = new Set([
|
||||
// explicit dependencies we use in our ssr renderer - these can be inlined (if necessary) in the nitro build
|
||||
'unhead', '@unhead/vue', 'unctx', 'h3', 'devalue', '@nuxt/devalue', 'radix3', 'rou3', 'unstorage', 'hookable',
|
||||
// ensure we only have one version of vue if nitro is going to inline anyway
|
||||
...((nuxt as any)._nitro as Nitro).options.inlineDynamicImports ? ['vue', '@vue/server-renderer', '@unhead/vue'] : [],
|
||||
// dependencies we might share with nitro - these can be inlined (if necessary) in the nitro build
|
||||
...runtimeDependencies,
|
||||
])
|
||||
}
|
||||
},
|
||||
async resolveId (id, importer) {
|
||||
if (!external.has(id)) {
|
||||
return
|
||||
}
|
||||
|
||||
const res = await this.resolve?.(id, importer, { skipSelf: true })
|
||||
if (res !== undefined && res !== null) {
|
||||
return {
|
||||
...res,
|
||||
external: 'absolute',
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
@ -90,6 +90,7 @@ export async function buildServer (ctx: ViteBuildContext) {
|
||||
new RegExp('^' + escapeStringRegexp(withTrailingSlash(resolve(ctx.nuxt.options.rootDir, ctx.nuxt.options.dir.shared)))),
|
||||
],
|
||||
output: {
|
||||
preserveModules: true,
|
||||
entryFileNames: '[name].mjs',
|
||||
format: 'module',
|
||||
generatedCode: {
|
||||
|
@ -58,7 +58,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
||||
const serverDir = join(rootDir, '.output/server')
|
||||
|
||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"221k"`)
|
||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"204k"`)
|
||||
|
||||
const modules = await analyzeSizes(['node_modules/**/*'], serverDir)
|
||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1397k"`)
|
||||
@ -97,7 +97,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
||||
const serverDir = join(rootDir, '.output-inline/server')
|
||||
|
||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"572k"`)
|
||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"555k"`)
|
||||
|
||||
const modules = await analyzeSizes(['node_modules/**/*'], serverDir)
|
||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"90.9k"`)
|
||||
@ -121,10 +121,10 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
||||
const serverDir = join(pagesRootDir, '.output/server')
|
||||
|
||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"318k"`)
|
||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"299k"`)
|
||||
|
||||
const modules = await analyzeSizes(['node_modules/**/*'], serverDir)
|
||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1397k"`)
|
||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1408k"`)
|
||||
|
||||
const packages = modules.files
|
||||
.filter(m => m.endsWith('package.json'))
|
||||
|
Loading…
Reference in New Issue
Block a user