mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
refactor(vite): reuse logic and improve code splitting (#6164)
This commit is contained in:
parent
fe0b469ca9
commit
d15c4727a8
@ -1,11 +1,17 @@
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { builtinModules } from 'node:module'
|
||||
import { isAbsolute, resolve } from 'pathe'
|
||||
import { isAbsolute, normalize, resolve } from 'pathe'
|
||||
import * as vite from 'vite'
|
||||
import { ExternalsOptions, isExternal as _isExternal, ExternalsDefaults } from 'externality'
|
||||
import { isExternal } from 'externality'
|
||||
import { genDynamicImport, genObjectFromRawEntries } from 'knitwork'
|
||||
import { hashId, uniq } from './utils'
|
||||
import fse from 'fs-extra'
|
||||
import { debounce } from 'perfect-debounce'
|
||||
import { isIgnored, logger } from '@nuxt/kit'
|
||||
import { hashId, isCSS, uniq } from './utils'
|
||||
import { createIsExternal } from './utils/external'
|
||||
import { writeManifest } from './manifest'
|
||||
import { ViteBuildContext } from './vite'
|
||||
|
||||
export interface TransformChunk {
|
||||
id: string,
|
||||
@ -23,29 +29,7 @@ export interface SSRTransformResult {
|
||||
|
||||
export interface TransformOptions {
|
||||
viteServer: vite.ViteDevServer
|
||||
}
|
||||
|
||||
function isExternal (opts: TransformOptions, id: string) {
|
||||
// Externals
|
||||
const ssrConfig = (opts.viteServer.config as any).ssr
|
||||
|
||||
const externalOpts: ExternalsOptions = {
|
||||
inline: [
|
||||
/virtual:/,
|
||||
/\.ts$/,
|
||||
...ExternalsDefaults.inline,
|
||||
...ssrConfig.noExternal
|
||||
],
|
||||
external: [
|
||||
...ssrConfig.external,
|
||||
/node_modules/
|
||||
],
|
||||
resolve: {
|
||||
type: 'module',
|
||||
extensions: ['.ts', '.js', '.json', '.vue', '.mjs', '.jsx', '.tsx', '.wasm']
|
||||
}
|
||||
}
|
||||
return _isExternal(id, opts.viteServer.config.root, externalOpts)
|
||||
isExternal(id: string): ReturnType<typeof isExternal>
|
||||
}
|
||||
|
||||
async function transformRequest (opts: TransformOptions, id: string) {
|
||||
@ -74,7 +58,7 @@ async function transformRequest (opts: TransformOptions, id: string) {
|
||||
// Vite will add ?v=123 to bypass browser cache
|
||||
// Remove for externals
|
||||
const withoutVersionQuery = id.replace(/\?v=\w+$/, '')
|
||||
if (await isExternal(opts, withoutVersionQuery)) {
|
||||
if (await opts.isExternal(withoutVersionQuery)) {
|
||||
const path = builtinModules.includes(withoutVersionQuery.split('node:').pop())
|
||||
? withoutVersionQuery
|
||||
: isAbsolute(withoutVersionQuery) ? pathToFileURL(withoutVersionQuery).href : withoutVersionQuery
|
||||
@ -245,3 +229,36 @@ async function __instantiateModule__(url, urlStack) {
|
||||
ids: chunks.map(i => i.id)
|
||||
}
|
||||
}
|
||||
|
||||
export async function initViteDevBundler (ctx: ViteBuildContext, onBuild: () => Promise<any>) {
|
||||
const viteServer = ctx.ssrServer
|
||||
const options: TransformOptions = {
|
||||
viteServer,
|
||||
isExternal: createIsExternal(viteServer, ctx.nuxt.options.rootDir)
|
||||
}
|
||||
|
||||
// Build and watch
|
||||
const _doBuild = async () => {
|
||||
const start = Date.now()
|
||||
const { code, ids } = await bundleRequest(options, resolve(ctx.nuxt.options.appDir, 'entry'))
|
||||
await fse.writeFile(resolve(ctx.nuxt.options.buildDir, 'dist/server/server.mjs'), code, 'utf-8')
|
||||
// Have CSS in the manifest to prevent FOUC on dev SSR
|
||||
await writeManifest(ctx, ids.filter(isCSS).map(i => i.slice(1)))
|
||||
const time = (Date.now() - start)
|
||||
logger.success(`Vite server built in ${time}ms`)
|
||||
await onBuild()
|
||||
}
|
||||
const doBuild = debounce(_doBuild)
|
||||
|
||||
// Initial build
|
||||
await _doBuild()
|
||||
|
||||
// Watch
|
||||
viteServer.watcher.on('all', (_event, file) => {
|
||||
file = normalize(file) // Fix windows paths
|
||||
if (file.indexOf(ctx.nuxt.options.buildDir) === 0 || isIgnored(file)) { return }
|
||||
doBuild()
|
||||
})
|
||||
// ctx.nuxt.hook('builder:watch', () => doBuild())
|
||||
ctx.nuxt.hook('app:templatesGenerated', () => doBuild())
|
||||
}
|
||||
|
@ -1,22 +1,16 @@
|
||||
import { resolveTSConfig } from 'pkg-types'
|
||||
import { resolve, normalize } from 'pathe'
|
||||
import { resolve } from 'pathe'
|
||||
import * as vite from 'vite'
|
||||
import vuePlugin from '@vitejs/plugin-vue'
|
||||
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
|
||||
import { logger, resolveModule, isIgnored } from '@nuxt/kit'
|
||||
import fse from 'fs-extra'
|
||||
import { debounce } from 'perfect-debounce'
|
||||
import { logger, resolveModule } from '@nuxt/kit'
|
||||
import { joinURL, withoutLeadingSlash, withTrailingSlash } from 'ufo'
|
||||
import { ViteBuildContext, ViteOptions } from './vite'
|
||||
import { wpfs } from './utils/wpfs'
|
||||
import { cacheDirPlugin } from './plugins/cache-dir'
|
||||
import { prepareDevServerEntry } from './vite-node'
|
||||
import { isCSS } from './utils'
|
||||
import { bundleRequest } from './dev-bundler'
|
||||
import { writeManifest } from './manifest'
|
||||
|
||||
export async function buildServer (ctx: ViteBuildContext) {
|
||||
const _resolve = id => resolveModule(id, { paths: ctx.nuxt.options.modulesDir })
|
||||
const _resolve = (id: string) => resolveModule(id, { paths: ctx.nuxt.options.modulesDir })
|
||||
const serverConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
|
||||
base: ctx.nuxt.options.dev
|
||||
? joinURL(ctx.nuxt.options.app.baseURL.replace(/^\.\//, '/') || '/', ctx.nuxt.options.app.buildAssetsDir)
|
||||
@ -149,31 +143,8 @@ export async function buildServer (ctx: ViteBuildContext) {
|
||||
|
||||
if (ctx.nuxt.options.experimental.viteNode) {
|
||||
logger.info('Vite server using experimental `vite-node`...')
|
||||
await prepareDevServerEntry(ctx)
|
||||
await import('./vite-node').then(r => r.initViteNodeServer(ctx))
|
||||
} else {
|
||||
// Build and watch
|
||||
const _doBuild = async () => {
|
||||
const start = Date.now()
|
||||
const { code, ids } = await bundleRequest({ viteServer }, resolve(ctx.nuxt.options.appDir, 'entry'))
|
||||
await fse.writeFile(resolve(ctx.nuxt.options.buildDir, 'dist/server/server.mjs'), code, 'utf-8')
|
||||
// Have CSS in the manifest to prevent FOUC on dev SSR
|
||||
await writeManifest(ctx, ids.filter(isCSS).map(i => i.slice(1)))
|
||||
const time = (Date.now() - start)
|
||||
logger.success(`Vite server built in ${time}ms`)
|
||||
await onBuild()
|
||||
}
|
||||
const doBuild = debounce(_doBuild)
|
||||
|
||||
// Initial build
|
||||
await _doBuild()
|
||||
|
||||
// Watch
|
||||
viteServer.watcher.on('all', (_event, file) => {
|
||||
file = normalize(file) // Fix windows paths
|
||||
if (file.indexOf(ctx.nuxt.options.buildDir) === 0 || isIgnored(file)) { return }
|
||||
doBuild()
|
||||
})
|
||||
// ctx.nuxt.hook('builder:watch', () => doBuild())
|
||||
ctx.nuxt.hook('app:templatesGenerated', () => doBuild())
|
||||
await import('./dev-bundler').then(r => r.initViteDevBundler(ctx, onBuild))
|
||||
}
|
||||
}
|
||||
|
23
packages/vite/src/utils/external.ts
Normal file
23
packages/vite/src/utils/external.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ExternalsOptions, ExternalsDefaults, isExternal } from 'externality'
|
||||
import { ViteDevServer } from 'vite'
|
||||
|
||||
export function createIsExternal (viteServer: ViteDevServer, rootDir: string) {
|
||||
const externalOpts: ExternalsOptions = {
|
||||
inline: [
|
||||
/virtual:/,
|
||||
/\.ts$/,
|
||||
...ExternalsDefaults.inline,
|
||||
...viteServer.config.ssr.noExternal as string[]
|
||||
],
|
||||
external: [
|
||||
...viteServer.config.ssr.external,
|
||||
/node_modules/
|
||||
],
|
||||
resolve: {
|
||||
type: 'module',
|
||||
extensions: ['.ts', '.js', '.json', '.vue', '.mjs', '.jsx', '.tsx', '.wasm']
|
||||
}
|
||||
}
|
||||
|
||||
return (id:string) => isExternal(id, rootDir, externalOpts)
|
||||
}
|
@ -5,11 +5,11 @@ import fse from 'fs-extra'
|
||||
import { resolve } from 'pathe'
|
||||
import { addServerMiddleware } from '@nuxt/kit'
|
||||
import type { Plugin as VitePlugin, ViteDevServer } from 'vite'
|
||||
import { ExternalsOptions, isExternal, ExternalsDefaults } from 'externality'
|
||||
import { resolve as resolveModule } from 'mlly'
|
||||
import { distDir } from './dirs'
|
||||
import type { ViteBuildContext } from './vite'
|
||||
import { isCSS } from './utils'
|
||||
import { createIsExternal } from './utils/external'
|
||||
|
||||
// TODO: Remove this in favor of registerViteNodeMiddleware
|
||||
// after Nitropack or h3 fixed for adding middlewares after setup
|
||||
@ -72,27 +72,11 @@ function createViteNodeMiddleware (ctx: ViteBuildContext) {
|
||||
web: []
|
||||
}
|
||||
})
|
||||
const externalOpts: ExternalsOptions = {
|
||||
inline: [
|
||||
/virtual:/,
|
||||
/\.ts$/,
|
||||
...ExternalsDefaults.inline,
|
||||
...viteServer.config.ssr.noExternal as string[]
|
||||
],
|
||||
external: [
|
||||
...viteServer.config.ssr.external,
|
||||
/node_modules/
|
||||
],
|
||||
resolve: {
|
||||
type: 'module',
|
||||
extensions: ['.ts', '.js', '.json', '.vue', '.mjs', '.jsx', '.tsx', '.wasm']
|
||||
}
|
||||
}
|
||||
const rootDir = ctx.nuxt.options.rootDir
|
||||
const isExternal = createIsExternal(viteServer, ctx.nuxt.options.rootDir)
|
||||
node.shouldExternalize = async (id: string) => {
|
||||
const result = await isExternal(id, rootDir, externalOpts)
|
||||
const result = await isExternal(id)
|
||||
if (result?.external) {
|
||||
return resolveModule(result.id, { url: rootDir })
|
||||
return resolveModule(result.id, { url: ctx.nuxt.options.rootDir })
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -110,7 +94,7 @@ function createViteNodeMiddleware (ctx: ViteBuildContext) {
|
||||
return app.nodeHandler
|
||||
}
|
||||
|
||||
export async function prepareDevServerEntry (ctx: ViteBuildContext) {
|
||||
export async function initViteNodeServer (ctx: ViteBuildContext) {
|
||||
let entryPath = resolve(ctx.nuxt.options.appDir, 'entry.async.mjs')
|
||||
if (!fse.existsSync(entryPath)) {
|
||||
entryPath = resolve(ctx.nuxt.options.appDir, 'entry.async')
|
||||
|
Loading…
Reference in New Issue
Block a user