vite-ssr
Version:
Vite utility for server side rendering
134 lines (133 loc) • 7.47 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const vite_1 = require("vite");
const plugin_replace_1 = __importDefault(require("@rollup/plugin-replace"));
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const config_1 = require("../config");
async function generatePackageJson(viteConfig, clientBuildOptions, serverBuildOptions) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
if (serverBuildOptions.packageJson === false)
return;
const outputFile = (_c = (_b = (_a = serverBuildOptions.build) === null || _a === void 0 ? void 0 : _a.rollupOptions) === null || _b === void 0 ? void 0 : _b.output) === null || _c === void 0 ? void 0 : _c.file;
const ssrOutput = path_1.default.parse(outputFile ||
(((_d = viteConfig.build) === null || _d === void 0 ? void 0 : _d.ssr) || ((_e = serverBuildOptions.build) === null || _e === void 0 ? void 0 : _e.ssr)));
// Rollup options have priority over `viteConfig.ssr.format`
const moduleFormat = ((_h = (_g = (_f = viteConfig.build) === null || _f === void 0 ? void 0 : _f.rollupOptions) === null || _g === void 0 ? void 0 : _g.output) === null || _h === void 0 ? void 0 : _h.format) ||
((_l = (_k = (_j = serverBuildOptions.build) === null || _j === void 0 ? void 0 : _j.rollupOptions) === null || _k === void 0 ? void 0 : _k.output) === null || _l === void 0 ? void 0 : _l.format) ||
((_m = viteConfig.ssr) === null || _m === void 0 ? void 0 : _m.format);
const isESM = !moduleFormat || moduleFormat === 'es' || moduleFormat === 'esm';
const packageJson = {
// Vite 3+ adds '.mjs' extension to ESM files
main: outputFile
? ssrOutput.base
: ssrOutput.name + (isESM ? '.mjs' : '.js'),
type: isESM ? 'module' : 'commonjs',
ssr: {
// This can be used later to serve static assets
assets: (await fs_1.promises.readdir((_o = clientBuildOptions.build) === null || _o === void 0 ? void 0 : _o.outDir)).filter((file) => !/(index\.html|manifest\.json)$/i.test(file)),
},
...(serverBuildOptions.packageJson || {}),
};
await fs_1.promises.writeFile(path_1.default.join((_p = serverBuildOptions.build) === null || _p === void 0 ? void 0 : _p.outDir, 'package.json'), JSON.stringify(packageJson, null, 2), 'utf-8');
}
module.exports = async (inlineBuildOptions = {}, _viteConfig) => new Promise(async (resolve) => {
var _a, _b, _c, _d;
const viteConfig = _viteConfig || (await (0, config_1.resolveViteConfig)());
const distDir = (_b = (_a = viteConfig.build) === null || _a === void 0 ? void 0 : _a.outDir) !== null && _b !== void 0 ? _b : path_1.default.resolve(process.cwd(), 'dist');
const { input: inputFilePath = '', build: pluginBuildOptions = {} } = (0, config_1.getPluginOptions)(viteConfig);
const defaultFilePath = path_1.default.resolve(viteConfig.root, config_1.INDEX_HTML);
const inputFileName = inputFilePath.split('/').pop() || config_1.INDEX_HTML;
let indexHtmlTemplate = '';
const clientBuildOptions = (0, vite_1.mergeConfig)({
build: {
outDir: path_1.default.resolve(distDir, 'client'),
ssrManifest: true,
emptyOutDir: false,
// Custom input path
rollupOptions: inputFilePath && inputFilePath !== defaultFilePath
? {
input: inputFilePath,
plugins: [
inputFileName !== config_1.INDEX_HTML && {
generateBundle(options, bundle) {
// Rename custom name to index.html
const htmlAsset = bundle[inputFileName];
delete bundle[inputFileName];
htmlAsset.fileName = config_1.INDEX_HTML;
bundle[config_1.INDEX_HTML] = htmlAsset;
},
},
],
}
: {},
},
}, (0, vite_1.mergeConfig)(pluginBuildOptions.clientOptions || {}, inlineBuildOptions.clientOptions || {}));
const serverBuildOptions = (0, vite_1.mergeConfig)({
publicDir: false,
build: {
outDir: path_1.default.resolve(distDir, 'server'),
// The plugin is already changing the vite-ssr alias to point to the server-entry.
// Therefore, here we can just use the same entry point as in the index.html
ssr: await (0, config_1.getEntryPoint)(viteConfig),
emptyOutDir: false,
rollupOptions: {
plugins: [
(0, plugin_replace_1.default)({
preventAssignment: true,
values: {
__VITE_SSR_HTML__: () => indexHtmlTemplate,
},
}),
],
},
},
}, (0, vite_1.mergeConfig)(pluginBuildOptions.serverOptions || {}, inlineBuildOptions.serverOptions || {}));
const clientResult = await (0, vite_1.build)(clientBuildOptions);
const isWatching = Object.prototype.hasOwnProperty.call(clientResult, '_maxListeners');
if (isWatching) {
// This is a build watcher
const watcher = clientResult;
let resolved = false;
// @ts-ignore
watcher.on('event', async ({ result }) => {
var _a;
if (result) {
// This piece runs everytime there is
// an updated frontend bundle.
result.close();
// Re-read the index.html in case it changed.
// This content is not included in the virtual bundle.
indexHtmlTemplate = await fs_1.promises.readFile(((_a = clientBuildOptions.build) === null || _a === void 0 ? void 0 : _a.outDir) + `/${config_1.INDEX_HTML}`, 'utf-8');
// Build SSR bundle with the new index.html
await (0, vite_1.build)(serverBuildOptions);
await generatePackageJson(viteConfig, clientBuildOptions, serverBuildOptions);
if (!resolved) {
resolve(null);
resolved = true;
}
}
});
}
else {
// This is a normal one-off build
const clientOutputs = (Array.isArray(clientResult)
? clientResult
: [clientResult]).flatMap((result) => result.output);
// Get the index.html from the resulting bundle.
indexHtmlTemplate = (_c = clientOutputs.find((file) => file.type === 'asset' && file.fileName === config_1.INDEX_HTML)) === null || _c === void 0 ? void 0 : _c.source;
await (0, vite_1.build)(serverBuildOptions);
// index.html file is not used in SSR and might be
// served by mistake.
// Let's remove it unless the user overrides this behavior.
if (!pluginBuildOptions.keepIndexHtml) {
await fs_1.promises
.unlink(path_1.default.join((_d = clientBuildOptions.build) === null || _d === void 0 ? void 0 : _d.outDir, 'index.html'))
.catch(() => null);
}
await generatePackageJson(viteConfig, clientBuildOptions, serverBuildOptions);
resolve(null);
}
});