UNPKG

vite-plugin-react-server

Version:
208 lines (205 loc) 7.92 kB
/** * vite-plugin-react-server * Copyright (c) Nico Brinkkemper * MIT License */ import { join, dirname } from 'node:path'; import 'node:worker_threads'; import { createLogger } from 'vite'; import { checkFilesExist } from '../checkFilesExist.js'; import { resolveOptions } from '../config/resolveOptions.js'; import { resolvePages } from '../config/resolvePages.js'; import { resolveUserConfig } from '../config/resolveUserConfig.js'; import { tryManifest } from '../helpers/tryManifest.js'; import { createBuildLoader } from '../loader/createBuildLoader.js'; import { createWorker } from '../worker/createWorker.js'; import { renderPages } from '../worker/html/renderPages.js'; import { mkdir } from 'node:fs/promises'; import { collectManifestClientFiles } from '../collect-manifest-client-files.js'; import { mkdirSync, copyFileSync } from 'node:fs'; import { copyDir } from '../copy-dir.js'; let loader = null; let worker; let htmlTransform = null; let clientAssets = /* @__PURE__ */ new Set(); function reactStaticPlugin(options) { const timing = { start: Date.now() }; let files; let root = process.cwd(); let userConfig; let userOptions; let pages; let serverManifest = {}; let clientManifest = {}; const resolvedOptions = resolveOptions(options, false); if (resolvedOptions.type === "error") { throw resolvedOptions.error; } userOptions = resolvedOptions.userOptions; if (userOptions.projectRoot != root && typeof userOptions.projectRoot === "string" && userOptions.projectRoot !== process.cwd() && userOptions.projectRoot !== "") { root = userOptions.projectRoot; console.log( "[vite:plugin-react-server] Root dir changed in plugin", userOptions.projectRoot, root ); } return { name: "vite:plugin-react-server/static", enforce: "post", api: { meta: { timing } }, async config(config, configEnv) { if (typeof config.root === "string" && config.root !== root && config.root !== process.cwd() && config.root !== "") { root = config.root; } const resolvePagesResult = await resolvePages(userOptions.build.pages); if (resolvePagesResult.type === "error") { throw resolvePagesResult.error; } pages = resolvePagesResult.pages; files = await checkFilesExist(pages, userOptions, root); const resolvedConfig2 = resolveUserConfig({ isStatic: true, config, configEnv, userOptions, files }); if (resolvedConfig2.type === "error") { throw resolvedConfig2.error; } userConfig = resolvedConfig2.userConfig; timing.configResolved = Date.now(); return {}; }, async buildStart() { timing.buildStart = Date.now(); }, async closeBundle() { timing.renderStart = Date.now(); const serverManifestResult = tryManifest({ root, outDir: join(userOptions.build.outDir, userOptions.build.server), ssrManifest: false }); if (serverManifestResult.type === "error") { throw serverManifestResult.error; } serverManifest = serverManifestResult.manifest; const clientManifestResult = tryManifest({ root, outDir: join(userOptions.build.outDir, userOptions.build.client), ssrManifest: false }); if (clientManifestResult.type === "error") { throw clientManifestResult.error; } clientManifest = clientManifestResult.manifest; const staticDir = join(root, userOptions.build.outDir, userOptions.build.static); await mkdir(staticDir, { recursive: true }); worker = await createWorker({ projectRoot: root, workerPath: userOptions.htmlWorkerPath, condition: "react-server", reverseCondition: true, mode: "production" }); if (typeof loader !== "function") { loader = createBuildLoader({ root, userConfig, userOptions, pluginContext: this, serverManifest, clientManifest }); } const routeCssMap = /* @__PURE__ */ new Map(); const globalCss = /* @__PURE__ */ new Set(); await mkdir(staticDir, { recursive: true }); await copyDir(join(root, userOptions.build.outDir, userOptions.build.client), join(root, userOptions.build.outDir, userOptions.build.static)); const { cssFiles: indexCss } = collectManifestClientFiles({ manifest: clientManifest, root, pagePath: "index.html", moduleBase: userOptions.moduleBase, preserveModulesRoot: userOptions.build.preserveModulesRoot, testClient: () => true }); indexCss.forEach((css) => globalCss.add(css)); for (const route of pages) { const routeFiles = files.urlMap.get(route); if (routeFiles) { const pageCss = collectManifestClientFiles({ manifest: serverManifest, root, pagePath: routeFiles.page, moduleBase: userOptions.moduleBase, preserveModulesRoot: userOptions.build.preserveModulesRoot, onClientModule(path) { const targetPath = join(root, userOptions.build.outDir, userOptions.build.server, path); const destinationPath = join(root, userOptions.build.outDir, userOptions.build.static, path); mkdirSync(dirname(destinationPath), { recursive: true }); copyFileSync(targetPath, destinationPath); }, testClient: userOptions.autoDiscover.cssPattern, testJson: userOptions.autoDiscover.jsonPattern }); routeCssMap.set(route, /* @__PURE__ */ new Set([...globalCss, ...pageCss.cssFiles.keys()])); } } const bootstrapModules = clientManifest["index.html"]?.file ? [clientManifest["index.html"].file.startsWith("/") ? clientManifest["index.html"].file.slice(1) : clientManifest["index.html"].file] : []; const { failedRoutes, completedRoutes } = await renderPages( pages, files, { root, outDir: userOptions.build.outDir, htmlOutputPath: join(userOptions.build.outDir, userOptions.build.static, "index.html"), pipableStreamOptions: { bootstrapModules }, moduleRootPath: join(root, userOptions.build.outDir, userOptions.build.static, userOptions.moduleBasePath), moduleBasePath: userOptions.moduleBasePath, moduleBaseURL: userOptions.moduleBaseURL, inlineCss: userOptions.inlineCss, pageExportName: userOptions.pageExportName, propsExportName: userOptions.propsExportName, Html: userOptions.Html, CssCollector: userOptions.CssCollector, cssFiles: [], logger: createLogger(), moduleBase: userOptions.moduleBase, worker, clientManifest, serverManifest, loader, transformIndexHtml: htmlTransform, onClientJSFile: (url) => { if (!clientAssets.has(url)) { const clientPath = join(root, userOptions.build.outDir, userOptions.build.client, url); const targetPath = join(root, userOptions.build.outDir, userOptions.build.static, url); mkdirSync(dirname(targetPath), { recursive: true }); copyFileSync(clientPath, targetPath); clientAssets.add(url); } } } ); if (failedRoutes.size > 0) { console.error( "[vite-plugin-react-server] Failed to render routes:", failedRoutes ); } console.log(`Rendered ${completedRoutes.size} unique routes to ${join(userOptions.build.outDir, userOptions.build.static)}`); await worker.terminate(); } }; } export { reactStaticPlugin }; //# sourceMappingURL=plugin.js.map