Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

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

Merged
merged 1 commit into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 44 additions & 27 deletions packages/vite/src/dev-bundler.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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())
}
39 changes: 5 additions & 34 deletions packages/vite/src/server.ts
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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 changes: 23 additions & 0 deletions packages/vite/src/utils/external.ts
Original file line number Diff line number Diff line change
@@ -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)
}
26 changes: 5 additions & 21 deletions packages/vite/src/vite-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -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')
Expand Down