UNPKG

domco

Version:

Minimal Full-Stack JavaScript

131 lines (116 loc) 3.76 kB
import { dirNames, fileNames, ids } from "../../constants/index.js"; import type { Adapter, DomcoConfig } from "../../types/index.js"; import { findFiles, toAllScriptEndings } from "../../util/fs/index.js"; import path from "node:path"; import process from "node:process"; import { type Plugin, createLogger } from "vite"; /** * Dynamically sets the Vite config. * * @param domcoConfig * @returns Vite plugin */ export const configPlugin = async ( domcoConfig: DomcoConfig, ): Promise<Plugin> => { const adapter = await domcoConfig.adapter; return { name: "domco:config", async config(_, { isSsrBuild, command }) { const build = command === "build"; const customLogger = createLogger(); const loggerInfo = customLogger.info; customLogger.info = (msg, _options) => { if (build && msg.includes("../dist")) { // usually logs output relative to root, correct return loggerInfo(msg.split("../dist/").join("dist/")); } return loggerInfo(msg); }; return { customLogger, resolve: { alias: [{ find: "@", replacement: path.resolve(dirNames.src.base) }], }, root: dirNames.src.base, publicDir: isSsrBuild ? false : path.join(process.cwd(), dirNames.public), envDir: process.cwd(), appType: "custom", ssr: { target: adapter?.target, noExternal: build ? adapter?.noExternal : undefined, }, optimizeDeps: { // fixes TypeError when this is left undefined entries: [], }, build: { manifest: !isSsrBuild, outDir: path.join( process.cwd(), dirNames.out.base, isSsrBuild ? dirNames.out.ssr : dirNames.out.client.base, ), emptyOutDir: true, rollupOptions: { input: isSsrBuild ? serverEntry(adapter) : await clientEntry(), output: { entryFileNames({ name }) { if (name.startsWith("/")) name = name.slice(1); return `${isSsrBuild ? "" : dirNames.out.client.immutable + "/"}${name}${isSsrBuild ? "" : ".[hash]"}.js`; }, assetFileNames: `${isSsrBuild ? "" : dirNames.out.client.immutable + "/"}assets/[name].[hash][extname]`, chunkFileNames: `${isSsrBuild ? "" : dirNames.out.client.immutable + "/"}chunks/[name].[hash].js`, }, }, // `rel=modulepreload` is supported in all major browsers as of 2023 // https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload#browser_compatibility modulePreload: false, }, }; }, }; }; const serverEntry = (adapter?: Adapter) => { const entry: Record<string, string> = { [fileNames.out.entry.app.split(".")[0]!]: ids.app, }; // only create an adapter entry point if there's an adapter with entry if (adapter?.entry) { entry[adapter.entry({ appId: ids.app }).id] = ids.adapter; } return entry; }; const clientEntry = async () => { const [pages, scripts] = await Promise.all([ findFiles({ dir: path.join(dirNames.src.base, dirNames.src.client), checkEndings: [fileNames.page], }), findFiles({ dir: path.join(dirNames.src.base, dirNames.src.client), checkEndings: toAllScriptEndings(fileNames.script), }), ]); // rename "/" keys to main if (pages["/"]) { pages.main = pages["/"]; delete pages["/"]; } if (scripts["/"]) { scripts["/main"] = scripts["/"]; delete scripts["/"]; } // pages and scripts have to start with "src/" instead of just "/client" // for builds to work on Windows for (const [key, value] of Object.entries(pages)) { pages[key] = value.slice(1); // remove "/" } const scriptsEntry: Record<string, string> = {}; for (const [key, value] of Object.entries(scripts)) { scriptsEntry[`/_script${key}`] = value.slice(1); // remove "/" } return Object.assign(pages, scriptsEntry); };