refactor(vite): reuse logic and improve code splitting (#6164)

This commit is contained in:
Anthony Fu 2022-07-27 17:01:25 +08:00 committed by GitHub
parent fe0b469ca9
commit d15c4727a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 82 deletions

View File

@ -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())
}

View File

@ -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))
}
}

View 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)
}

View File

@ -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')