diff --git a/src/node/build/build.ts b/src/node/build/build.ts index 8514988b..23aec78d 100644 --- a/src/node/build/build.ts +++ b/src/node/build/build.ts @@ -17,20 +17,26 @@ import { generateSitemap } from './generateSitemap' import { renderPage, type RenderPageContext } from './render' import humanizeDuration from 'humanize-duration' import { launchWorkers, waitWorkers } from '../worker' -import { registerWorkload, updateContext, dispatchWork } from '../worker' +import { registerWorkload, updateContext } from '../worker' type RenderFn = (path: string) => Promise +// Worker: workload functions will be called with `this` context +export interface WorkerContext { + config: SiteConfig + options: BuildOptions +} + // Worker proxy (worker thread) -registerWorkload( - 'build::render-page', - function workload( - this: RenderPageContext & { render: RenderFn }, - page: string - ) { +const dispatchRenderPageWork = registerWorkload( + 'build:render-page', + function (page: string) { return renderPage(this.render, page, this) }, - async function init(this: { renderEntry: string; render: RenderFn }) { + async function init( + this: WorkerContext & + RenderPageContext & { render: RenderFn; renderEntry: string } + ) { this.render = (await import(this.renderEntry)).render as RenderFn } ) @@ -46,7 +52,10 @@ export async function build( const unlinkVue = linkVue() if (siteConfig.parallel) - launchWorkers(siteConfig.concurrency, { config: siteConfig }) + launchWorkers(siteConfig.concurrency, { + config: siteConfig, + options: buildOptions + }) if (buildOptions.base) { siteConfig.site.base = buildOptions.base @@ -64,9 +73,9 @@ export async function build( } try { - const { clientResult, serverResult, pageToHashMap } = await bundle( - siteConfig, - buildOptions + const { clientResult, serverResult, pageToHashMap } = await task( + 'building client + server bundles', + () => bundle(siteConfig, buildOptions) ) if (process.env.BUNDLE_ONLY) { @@ -148,7 +157,7 @@ export async function build( if (siteConfig.parallel) { const { config, ...additionalContext } = context await updateContext({ renderEntry, ...additionalContext }) - task = (page) => dispatchWork('build::render-page', page) + task = (page) => dispatchRenderPageWork(page) } else { const { render } = await import(renderEntry) task = (page) => renderPage(render, page, context) diff --git a/src/node/build/bundle.ts b/src/node/build/bundle.ts index 9e145cb7..65d64a46 100644 --- a/src/node/build/bundle.ts +++ b/src/node/build/bundle.ts @@ -1,38 +1,59 @@ import fs from 'fs-extra' import path from 'path' -import { fileURLToPath } from 'url' -import { - build, - normalizePath, - type BuildOptions, - type Rollup, - type InlineConfig as ViteInlineConfig -} from 'vite' -import { APP_PATH } from '../alias' +import { build, type BuildOptions, type Rollup } from 'vite' import type { SiteConfig } from '../config' -import { createVitePressPlugin } from '../plugin' -import { escapeRegExp, sanitizeFileName, slash } from '../shared' -import { task } from '../utils/task' +import { updateCurrentTask } from '../utils/task' import { buildMPAClient } from './buildMPAClient' +import { registerWorkload } from '../worker' +import resolveViteConfig from './viteConfig' +import { type WorkerContext } from './build' + +const dispatchBundleWorkload = registerWorkload('build:bundle', bundleWorkload) + +async function bundleWorkload(this: WorkerContext, ssr: boolean) { + const pageToHashMap = Object.create(null) as Record + const clientJSMap = Object.create(null) as Record + const result = (await build( + await resolveViteConfig(ssr, { + config: this.config, + options: this.options, + pageToHashMap, + clientJSMap + }) + )) as Rollup.RollupOutput + return { result, pageToHashMap, clientJSMap } +} -// https://github.com/vitejs/vite/blob/d2aa0969ee316000d3b957d7e879f001e85e369e/packages/vite/src/node/plugins/splitVendorChunk.ts#L14 -const CSS_LANGS_RE = - /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/ - -const clientDir = normalizePath( - path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../client') -) - -// these deps are also being used in the client code (outside of the theme) -// exclude them from the theme chunk so there is no circular dependency -const excludedModules = [ - '/@siteData', - 'node_modules/@vueuse/core/', - 'node_modules/@vueuse/shared/', - 'node_modules/vue/', - 'node_modules/vue-demi/', - clientDir -] +async function bundleMPA( + config: SiteConfig, + serverResult: Rollup.RollupOutput, + clientJSMap: Record +) { + updateCurrentTask(0, 1, 'bundling MPA') + // in MPA mode, we need to copy over the non-js asset files from the + // server build since there is no client-side build. + await Promise.all( + serverResult.output.map(async (chunk) => { + if (!chunk.fileName.endsWith('.js')) { + const tempPath = path.resolve(config.tempDir, chunk.fileName) + const outPath = path.resolve(config.outDir, chunk.fileName) + await fs.copy(tempPath, outPath) + } + }) + ) + // also copy over public dir + const publicDir = path.resolve(config.srcDir, 'public') + if (fs.existsSync(publicDir)) { + await fs.copy(publicDir, config.outDir) + } + updateCurrentTask() + // build