// src/build/build.ts import { createVueServerApp, getSsrTemplate } from "@vuepress/bundlerutils"; import { colors, debug, fs as fs4, withSpinner } from "@vuepress/utils"; import { build as viteBuild } from "vite"; // src/resolveViteConfig.ts import { mergeConfig } from "vite"; // src/plugins/vuepressBuildPlugin.ts var vuepressBuildPlugin = ({ isServer }) => ({ name: "vuepress:build", generateBundle(_, bundle) { if (isServer) { Object.keys(bundle).forEach((key) => { if (bundle[key].type === "asset") { delete bundle[key]; } }); } } }); // src/plugins/vuepressConfigPlugin.ts import { fs, sanitizeFileName } from "@vuepress/utils"; import autoprefixer from "autoprefixer"; import postcssrc from "postcss-load-config"; var resolveAlias = async ({ app, isServer }) => { const alias = { "@internal": app.dir.temp("internal"), "@temp": app.dir.temp(), "@source": app.dir.source() }; const aliasResult = await app.pluginApi.hooks.alias.process(app, isServer); aliasResult.forEach((aliasObject) => { Object.assign(alias, aliasObject); }); return [ ...Object.keys(alias).sort((a, b) => b.length - a.length).map((item) => ({ find: item, replacement: alias[item] })), ...isServer ? [] : [ { find: /^vue$/, replacement: "vue/dist/vue.runtime.esm-bundler.js" }, { find: /^vue-router$/, replacement: "vue-router/dist/vue-router.esm-bundler.js" } ] ]; }; var resolveDefine = async ({ app, isBuild, isServer }) => { const define = { __VUEPRESS_VERSION__: JSON.stringify(app.version), __VUEPRESS_BASE__: JSON.stringify(app.options.base), __VUEPRESS_DEV__: JSON.stringify(!isBuild), __VUEPRESS_SSR__: JSON.stringify(isServer), // @see http://link.vuejs.org/feature-flags // enable options API by default __VUE_OPTIONS_API__: JSON.stringify(true), __VUE_PROD_DEVTOOLS__: JSON.stringify(app.env.isDebug), __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: JSON.stringify(app.env.isDebug) }; if (app.env.isDebug) { define["process.env.NODE_ENV"] = JSON.stringify("development"); } const defineResult = await app.pluginApi.hooks.define.process(app, isServer); defineResult.forEach((defineObject) => { Object.entries(defineObject).forEach(([key, value]) => { define[key] = JSON.stringify(value); }); }); return define; }; var vuepressConfigPlugin = ({ app, isBuild, isServer }) => ({ name: "vuepress:config", enforce: "pre", async config() { const clientPackages = [ // although discouraged, but users may still use `@vuepress/client` directly "@vuepress/client", "vuepress", ...app.pluginApi.plugins.filter(({ name }) => name !== "user-config").map(({ name }) => name) ]; let postcssPlugins; try { const postcssConfigResult = await postcssrc(); postcssPlugins = postcssConfigResult.plugins; } catch { postcssPlugins = [autoprefixer]; } return { root: app.dir.source(), base: app.options.base, mode: !isBuild || app.env.isDebug ? "development" : "production", define: await resolveDefine({ app, isBuild, isServer }), publicDir: app.dir.public(), cacheDir: app.dir.cache(), resolve: { alias: await resolveAlias({ app, isServer }) }, css: { postcss: { plugins: isServer ? [] : postcssPlugins }, preprocessorOptions: { scss: { charset: false } } }, server: { host: app.options.host, port: app.options.port, open: app.options.open }, build: { ssr: isServer, outDir: isServer ? app.dir.temp(".server") : app.dir.dest(), emptyOutDir: false, cssCodeSplit: false, rollupOptions: { input: app.dir.client( fs.readJsonSync(app.dir.client("package.json")).exports["./app"] ), output: { sanitizeFileName, ...isServer ? { // also add hash to ssr entry file, so that users could build multiple sites in a single process entryFileNames: `[name].[hash].mjs` } : {} }, preserveEntrySignatures: "allow-extension" }, minify: isServer ? false : !app.env.isDebug }, optimizeDeps: { exclude: clientPackages }, ssr: { format: "esm", noExternal: clientPackages } }; } }); // src/plugins/vuepressDevPlugin.ts import { fs as fs2 } from "@vuepress/utils"; import history from "connect-history-api-fallback"; var vuepressDevPlugin = ({ app }) => ({ name: "vuepress:dev", async configureServer(server) { const templateDevContent = await fs2.readFile(app.options.templateDev, { encoding: "utf-8" }); const indexHtml = templateDevContent.replace( /<\/body>/, ` ` ); return () => { server.middlewares.use( history({ rewrites: [ { from: /\.html$/, to: "/index.html" } ] }) ).use((req, res, next) => { if (!req.url?.endsWith(".html")) { next(); return; } res.statusCode = 200; res.setHeader("Content-Type", "text/html"); void server.transformIndexHtml(req.url, indexHtml, req.originalUrl).then((result) => { res.end(result); }); }); }; } }); // src/plugins/vuepressUserConfigPlugin.ts var vuepressUserConfigPlugin = ({ options }) => ({ name: "vuepress:user-config", enforce: "post", config: () => options.viteOptions ?? {} }); // src/plugins/vuepressVuePlugin.ts import vuePlugin from "@vitejs/plugin-vue"; var vuepressVuePlugin = ({ options }) => vuePlugin({ ...options.vuePluginOptions }); // src/resolveViteConfig.ts var resolveViteConfig = ({ app, options, isBuild, isServer }) => mergeConfig( { clearScreen: false, configFile: false, logLevel: !isBuild || app.env.isDebug ? "info" : "warn", esbuild: { charset: "utf8" }, plugins: [ vuepressConfigPlugin({ app, isBuild, isServer }), vuepressDevPlugin({ app }), vuepressBuildPlugin({ isServer }), vuepressVuePlugin({ options }), vuepressUserConfigPlugin({ options }) ] }, // some vite options would not take effect inside a plugin, so we still need to merge them here in addition to userConfigPlugin options.viteOptions ?? {} ); // src/build/renderPage.ts import { renderPageToString } from "@vuepress/bundlerutils"; import { fs as fs3, renderHead } from "@vuepress/utils"; // src/build/renderPagePrefetchLinks.ts var renderPagePrefetchLinks = ({ app, outputEntryChunk, pageChunkFiles }) => { const { shouldPrefetch } = app.options; if (shouldPrefetch === false) { return ""; } const prefetchFiles = outputEntryChunk.dynamicImports.filter( (item) => !pageChunkFiles.some((file) => file === item) ); return prefetchFiles.map((item) => { const type = item.endsWith(".js") ? "script" : item.endsWith(".css") ? "style" : ""; if (shouldPrefetch !== true && !shouldPrefetch(item, type)) { return ""; } return ``; }).join(""); }; // src/build/renderPagePreloadLinks.ts var renderPagePreloadLinks = ({ app, outputEntryChunk, pageChunkFiles }) => { const { shouldPreload } = app.options; if (shouldPreload === false) { return ""; } const preloadFiles = Array.from( /* @__PURE__ */ new Set([ outputEntryChunk.fileName, ...outputEntryChunk.imports, ...pageChunkFiles ]) ); return preloadFiles.map((item) => { const type = item.endsWith(".js") ? "script" : item.endsWith(".css") ? "style" : ""; if (shouldPreload === true && type !== "script" && type !== "style") { return ""; } if (shouldPreload !== true && !shouldPreload(item, type)) { return ""; } if (type === "script") { return ``; } return ``; }).join(""); }; // src/build/renderPageScripts.ts var renderPageScripts = ({ app, outputEntryChunk }) => ``; // src/build/renderPageStyles.ts var renderPageStyles = ({ app, outputCssAsset }) => outputCssAsset ? [ ``, `` ].join("") : ""; // src/build/resolvePageChunkFiles.ts var resolvePageChunkFiles = ({ page, output }) => output.filter( (item) => item.type === "chunk" && item.facadeModuleId === page.chunkFilePath ).flatMap(({ fileName, imports, dynamicImports }) => [ fileName, ...imports, ...dynamicImports ]); // src/build/renderPage.ts var renderPage = async ({ app, page, vueApp, vueRouter, ssrTemplate, output, outputEntryChunk, outputCssAsset }) => { const { ssrContext, ssrString } = await renderPageToString({ page, vueApp, vueRouter }); const pageChunkFiles = resolvePageChunkFiles({ page, output }); const html = await app.options.templateBuildRenderer(ssrTemplate, { content: ssrString, head: ssrContext.head.map(renderHead).join(""), lang: ssrContext.lang, prefetch: renderPagePrefetchLinks({ app, outputEntryChunk, pageChunkFiles }), preload: renderPagePreloadLinks({ app, outputEntryChunk, pageChunkFiles }), scripts: renderPageScripts({ app, outputEntryChunk }), styles: renderPageStyles({ app, outputCssAsset }), version: app.version }); await fs3.outputFile(page.htmlFilePath, html); }; // src/build/build.ts var log = debug("vuepress:bundler-vite/build"); var build = async (options, app) => { await app.pluginApi.hooks.extendsBundlerOptions.process(options, app); log("compiling start"); let clientOutput; let serverOutput; await withSpinner("Compiling with vite")(async () => { const clientConfig = resolveViteConfig({ app, options, isBuild: true, isServer: false }); const serverConfig = resolveViteConfig({ app, options, isBuild: true, isServer: true }); [clientOutput, serverOutput] = await Promise.all([ viteBuild(clientConfig), viteBuild(serverConfig) ]); }); log("compiling finish"); await withSpinner(`Rendering ${app.pages.length} pages`)(async (spinner) => { const clientEntryChunk = clientOutput.output.find( (item) => item.type === "chunk" && item.isEntry ); const clientCssAsset = clientOutput.output.find( (item) => item.type === "asset" && item.fileName.endsWith(".css") ); const serverEntryChunk = serverOutput.output.find( (item) => item.type === "chunk" && item.isEntry ); const { vueApp, vueRouter } = await createVueServerApp( app.dir.temp(".server", serverEntryChunk.fileName) ); const ssrTemplate = await getSsrTemplate(app); for (const page of app.pages) { if (spinner) spinner.text = `Rendering pages ${colors.magenta(page.path)}`; await renderPage({ app, page, vueApp, vueRouter, ssrTemplate, output: clientOutput.output, outputEntryChunk: clientEntryChunk, outputCssAsset: clientCssAsset }); } }); if (!app.env.isDebug) { await fs4.remove(app.dir.temp(".server")); } }; // src/dev.ts import { createRequire } from "module"; import { colors as colors2, fs as fs5 } from "@vuepress/utils"; import { createServer } from "vite"; var require2 = createRequire(import.meta.url); var dev = async (options, app) => { await app.pluginApi.hooks.extendsBundlerOptions.process(options, app); const viteConfig = resolveViteConfig({ app, options, isBuild: false, isServer: false }); const server = await createServer(viteConfig); await server.listen(); const viteVersion = fs5.readJsonSync(require2.resolve("vite/package.json")).version; server.config.logger.info( colors2.cyan(` vite v${viteVersion}`) + colors2.green(` dev server running at: `), { clear: !server.config.logger.hasWarned } ); server.printUrls(); return server.close.bind(server); }; // src/viteBundler.ts var viteBundler = (options = {}) => ({ name: "@vuepress/bundler-vite", dev: async (app) => dev(options, app), build: async (app) => build(options, app) }); // src/index.ts var index_default = viteBundler; export { index_default as default, viteBundler };