fix(vite): use resolveId from vite-node to resolve deps (#30922)

This commit is contained in:
Daniel Roe 2025-02-10 16:40:15 +00:00 committed by GitHub
parent 1cf9bd36d2
commit 72d524b25e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 45 additions and 97 deletions

View File

@ -41,7 +41,6 @@
"defu": "^6.1.4", "defu": "^6.1.4",
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"escape-string-regexp": "^5.0.0", "escape-string-regexp": "^5.0.0",
"externality": "^1.0.2",
"get-port-please": "^3.1.2", "get-port-please": "^3.1.2",
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703", "h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
"jiti": "^2.4.2", "jiti": "^2.4.2",

View File

@ -39,6 +39,9 @@ function createRunner () {
return new ViteNodeRunner({ return new ViteNodeRunner({
root: viteNodeOptions.root, // Equals to Nuxt `srcDir` root: viteNodeOptions.root, // Equals to Nuxt `srcDir`
base: viteNodeOptions.base, base: viteNodeOptions.base,
async resolveId (id, importer) {
return await viteNodeFetch('/resolve/' + encodeURIComponent(id) + (importer ? '?importer=' + encodeURIComponent(importer) : '')) ?? undefined
},
async fetchModule (id) { async fetchModule (id) {
id = id.replace(/\/\//g, '/') // TODO: fix in vite-node id = id.replace(/\/\//g, '/') // TODO: fix in vite-node
return await viteNodeFetch('/module/' + encodeURI(id)).catch((err) => { return await viteNodeFetch('/module/' + encodeURI(id)).catch((err) => {

View File

@ -1,36 +0,0 @@
import type { ExternalsOptions } from 'externality'
import { ExternalsDefaults, isExternal } from 'externality'
import type { ViteDevServer } from 'vite'
import escapeStringRegexp from 'escape-string-regexp'
import { withTrailingSlash } from 'ufo'
import type { Nuxt } from 'nuxt/schema'
import { resolve } from 'pathe'
import { toArray } from '.'
export function createIsExternal (viteServer: ViteDevServer, nuxt: Nuxt) {
const externalOpts: ExternalsOptions = {
inline: [
/virtual:/,
/\.ts$/,
...ExternalsDefaults.inline || [],
...(
viteServer.config.ssr.noExternal && viteServer.config.ssr.noExternal !== true
? toArray(viteServer.config.ssr.noExternal)
: []
),
],
external: [
'#shared',
new RegExp('^' + escapeStringRegexp(withTrailingSlash(resolve(nuxt.options.rootDir, nuxt.options.dir.shared)))),
...(viteServer.config.ssr.external as string[]) || [],
/node_modules/,
],
resolve: {
modules: nuxt.options.modulesDir,
type: 'module',
extensions: ['.ts', '.js', '.json', '.vue', '.mjs', '.jsx', '.tsx', '.wasm'],
},
}
return (id: string) => isExternal(id, nuxt.options.rootDir, externalOpts)
}

View File

@ -1,18 +1,16 @@
import { mkdir, writeFile } from 'node:fs/promises' import { mkdir, writeFile } from 'node:fs/promises'
import { pathToFileURL } from 'node:url' import { pathToFileURL } from 'node:url'
import { createApp, createError, defineEventHandler, defineLazyEventHandler, eventHandler, toNodeListener } from 'h3' import { createApp, createError, defineEventHandler, toNodeListener } from 'h3'
import { ViteNodeServer } from 'vite-node/server' import { ViteNodeServer } from 'vite-node/server'
import { isAbsolute, join, normalize, resolve } from 'pathe' import { isAbsolute, join, normalize, resolve } from 'pathe'
// import { addDevServerHandler } from '@nuxt/kit' // import { addDevServerHandler } from '@nuxt/kit'
import { isFileServingAllowed } from 'vite' import { isFileServingAllowed } from 'vite'
import type { ModuleNode, Plugin as VitePlugin } from 'vite' import type { ModuleNode, ViteDevServer, Plugin as VitePlugin } from 'vite'
import { getQuery } from 'ufo' import { getQuery } from 'ufo'
import { normalizeViteManifest } from 'vue-bundle-renderer' import { normalizeViteManifest } from 'vue-bundle-renderer'
import { resolve as resolveModule } from 'mlly'
import { distDir } from './dirs' import { distDir } from './dirs'
import type { ViteBuildContext } from './vite' import type { ViteBuildContext } from './vite'
import { isCSS } from './utils' import { isCSS } from './utils'
import { createIsExternal } from './utils/external'
// TODO: Remove this in favor of registerViteNodeMiddleware // TODO: Remove this in favor of registerViteNodeMiddleware
// after Nitropack or h3 allows adding middleware after setup // after Nitropack or h3 allows adding middleware after setup
@ -101,6 +99,19 @@ function getManifest (ctx: ViteBuildContext) {
function createViteNodeApp (ctx: ViteBuildContext, invalidates: Set<string> = new Set()) { function createViteNodeApp (ctx: ViteBuildContext, invalidates: Set<string> = new Set()) {
const app = createApp() const app = createApp()
let _node: ViteNodeServer | undefined
function getNode (server: ViteDevServer) {
return _node ||= new ViteNodeServer(server, {
deps: {
inline: [/^#/, /\?/],
},
transformMode: {
ssr: [/.*/],
web: [],
},
})
}
app.use('/manifest', defineEventHandler(() => { app.use('/manifest', defineEventHandler(() => {
const manifest = getManifest(ctx) const manifest = getManifest(ctx)
return manifest return manifest
@ -112,54 +123,38 @@ function createViteNodeApp (ctx: ViteBuildContext, invalidates: Set<string> = ne
return ids return ids
})) }))
app.use('/module', defineLazyEventHandler(() => { const RESOLVE_RE = /^\/(?<id>[^?]+)(?:\?importer=(?<importer>.*))?$/
const viteServer = ctx.ssrServer! app.use('/resolve', defineEventHandler(async (event) => {
const node = new ViteNodeServer(viteServer, { const { id, importer } = event.path.match(RESOLVE_RE)?.groups || {}
deps: { if (!id || !ctx.ssrServer) {
inline: [ throw createError({ statusCode: 400 })
// Common
/^#/,
/\?/,
],
},
transformMode: {
ssr: [/.*/],
web: [],
},
})
const isExternal = createIsExternal(viteServer, ctx.nuxt)
node.shouldExternalize = async (id: string) => {
const result = await isExternal(id)
if (result?.external) {
return resolveModule(result.id, { url: ctx.nuxt.options.modulesDir }).catch(() => false)
}
return false
} }
return await getNode(ctx.ssrServer).resolveId(decodeURIComponent(id), importer ? decodeURIComponent(importer) : undefined).catch(() => null)
}))
return eventHandler(async (event) => { app.use('/module', defineEventHandler(async (event) => {
const moduleId = decodeURI(event.path).substring(1) const moduleId = decodeURI(event.path).substring(1)
if (moduleId === '/') { if (moduleId === '/' || !ctx.ssrServer) {
throw createError({ statusCode: 400 }) throw createError({ statusCode: 400 })
}
if (isAbsolute(moduleId) && !isFileServingAllowed(ctx.ssrServer.config, moduleId)) {
throw createError({ statusCode: 403 /* Restricted */ })
}
const node = getNode(ctx.ssrServer)
const module = await node.fetchModule(moduleId).catch(async (err) => {
const errorData = {
code: 'VITE_ERROR',
id: moduleId,
stack: '',
...err,
} }
if (isAbsolute(moduleId) && !isFileServingAllowed(moduleId, viteServer)) {
throw createError({ statusCode: 403 /* Restricted */ })
}
const module = await node.fetchModule(moduleId).catch(async (err) => {
const errorData = {
code: 'VITE_ERROR',
id: moduleId,
stack: '',
...err,
}
if (!errorData.frame && errorData.code === 'PARSE_ERROR') { if (!errorData.frame && errorData.code === 'PARSE_ERROR') {
errorData.frame = await node.transformModule(moduleId, 'web').then(({ code }) => `${err.message || ''}\n${code}`).catch(() => undefined) errorData.frame = await node.transformModule(moduleId, 'web').then(({ code }) => `${err.message || ''}\n${code}`).catch(() => undefined)
} }
throw createError({ data: errorData }) throw createError({ data: errorData })
})
return module
}) })
return module
})) }))
return app return app

View File

@ -891,9 +891,6 @@ importers:
escape-string-regexp: escape-string-regexp:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.0.0 version: 5.0.0
externality:
specifier: ^1.0.2
version: 1.0.2
get-port-please: get-port-please:
specifier: ^3.1.2 specifier: ^3.1.2
version: 3.1.2 version: 3.1.2
@ -4580,9 +4577,6 @@ packages:
extend@3.0.2: extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
externality@1.0.2:
resolution: {integrity: sha512-LyExtJWKxtgVzmgtEHyQtLFpw1KFhQphF9nTG8TpAIVkiI/xQ3FJh75tRFLYl4hkn7BNIIdLJInuDAavX35pMw==}
fake-indexeddb@6.0.0: fake-indexeddb@6.0.0:
resolution: {integrity: sha512-YEboHE5VfopUclOck7LncgIqskAqnv4q0EWbYCaxKKjAvO93c+TJIaBuGy8CBFdbg9nKdpN3AuPRwVBJ4k7NrQ==} resolution: {integrity: sha512-YEboHE5VfopUclOck7LncgIqskAqnv4q0EWbYCaxKKjAvO93c+TJIaBuGy8CBFdbg9nKdpN3AuPRwVBJ4k7NrQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -11933,13 +11927,6 @@ snapshots:
extend@3.0.2: {} extend@3.0.2: {}
externality@1.0.2:
dependencies:
enhanced-resolve: 5.18.0
mlly: 1.7.4
pathe: 1.1.2
ufo: 1.5.4
fake-indexeddb@6.0.0: {} fake-indexeddb@6.0.0: {}
fast-deep-equal@3.1.3: {} fast-deep-equal@3.1.3: {}