vike
Version:
The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.
227 lines (226 loc) • 10.5 kB
JavaScript
import '../../assertEnvVite.js';
export { pluginBuildConfig };
export { assertRollupInput };
export { analyzeClientEntries };
import { assert, setAssertOnBeforeLog, assertUsage } from '../../../../utils/assert.js';
import { onSetupBuild } from '../../../../utils/assertSetup.js';
import { injectRollupInputs, normalizeRollupInput } from '../../../../utils/injectRollupInputs.js';
import { assertIsImportPathNpmPackage } from '../../../../utils/parseNpmPackage.js';
import { removeFileExtension } from '../../../../utils/removeFileExtension.js';
import { requireResolveDistFile } from '../../../../utils/requireResolve.js';
import { unique } from '../../../../utils/unique.js';
import { getVikeConfigInternal } from '../../shared/resolveVikeConfigInternal.js';
import { findPageFiles } from '../../shared/findPageFiles.js';
import { generateVirtualFileId } from '../../../../shared-server-node/virtualFileId.js';
import { extractAssetsAddQuery } from '../../../../shared-server-node/extractAssetsQuery.js';
import { prependEntriesDir } from '../../../../shared-server-node/prependEntriesDir.js';
import { getFilePathResolved } from '../../shared/getFilePath.js';
import { getConfigValueBuildTime } from '../../../../shared-server-client/page-configs/getConfigValueBuildTime.js';
import { isViteServerSide_viteEnvOptional } from '../../shared/isViteServerSide.js';
import { handleAssetsManifest_assertUsageCssCodeSplit, handleAssetsManifest_getBuildConfig, handleAssetsManifest_alignCssTarget, } from './handleAssetsManifest.js';
import { resolveIncludeAssetsImportedByServer } from '../../../../server/runtime/renderPageServer/getPageAssets/retrievePageAssetsProd.js';
function pluginBuildConfig() {
return [
{
name: 'vike:build:pluginBuildConfig:post2',
apply: 'build',
enforce: 'post',
configResolved: {
order: 'post',
async handler(config) {
handleAssetsManifest_alignCssTarget(config);
onSetupBuild();
assertRollupInput(config);
const entries = await getEntries(config);
assert(Object.keys(entries).length > 0);
config.build.rollupOptions.input = injectRollupInputs(entries, config);
addLogHook();
handleAssetsManifest_assertUsageCssCodeSplit(config);
},
},
config: {
order: 'post',
async handler() {
onSetupBuild();
const build = await handleAssetsManifest_getBuildConfig();
return { build };
},
},
buildStart: {
handler() {
onSetupBuild();
},
},
},
];
}
async function getEntries(config) {
const vikeConfig = await getVikeConfigInternal();
const { _pageConfigs: pageConfigs } = vikeConfig;
// TO-DO/next-major-release: remove
const pageFileEntries = await getPageFileEntries(config, resolveIncludeAssetsImportedByServer(vikeConfig.config));
assertUsage(Object.keys(pageFileEntries).length !== 0 || pageConfigs.length !== 0, 'At least one page should be defined, see https://vike.dev/add');
if (isViteServerSide_viteEnvOptional(config)) {
const pageEntries = getPageEntries(pageConfigs);
const entries = {
...pageFileEntries,
// Ensure Rollup generates a bundle per page: https://github.com/vikejs/vike/issues/349#issuecomment-1166247275
...pageEntries,
};
return entries;
}
else {
let { hasClientRouting, hasServerRouting, clientEntries } = analyzeClientEntries(pageConfigs, config);
if (Object.entries(pageFileEntries).length > 0) {
hasClientRouting = true;
hasServerRouting = true;
}
const entries = {
...clientEntries,
...pageFileEntries,
};
const clientRoutingEntry = requireResolveDistFile('dist/client/runtime-client-routing/entry.js');
const serverRoutingEntry = requireResolveDistFile('dist/client/runtime-server-routing/entry.js');
if (hasClientRouting) {
entries['entries/entry-client-routing'] = clientRoutingEntry;
}
if (hasServerRouting) {
entries['entries/entry-server-routing'] = serverRoutingEntry;
}
return entries;
}
}
function getPageEntries(pageConfigs) {
const pageEntries = {};
pageConfigs.forEach((pageConfig) => {
const { entryName, entryTarget } = getEntryFromPageConfig(pageConfig, false);
pageEntries[entryName] = entryTarget;
});
return pageEntries;
}
function analyzeClientEntries(pageConfigs, config) {
let hasClientRouting = false;
let hasServerRouting = false;
let clientEntries = {};
let clientEntryList = [];
pageConfigs.forEach((pageConfig) => {
const configValue = getConfigValueBuildTime(pageConfig, 'clientRouting', 'boolean');
if (configValue?.value) {
hasClientRouting = true;
}
else {
hasServerRouting = true;
}
{
// Ensure Rollup generates a bundle per page: https://github.com/vikejs/vike/issues/349#issuecomment-1166247275
const { entryName, entryTarget } = getEntryFromPageConfig(pageConfig, true);
clientEntries[entryName] = entryTarget;
}
{
const clientEntry = getConfigValueBuildTime(pageConfig, 'client', 'string')?.value ?? null;
if (clientEntry) {
clientEntryList.push(clientEntry);
}
}
});
clientEntryList = unique(clientEntryList);
clientEntryList.forEach((clientEntry) => {
const { entryName, entryTarget } = getEntryFromClientEntry(clientEntry, config);
clientEntries[entryName] = entryTarget;
});
return { hasClientRouting, hasServerRouting, clientEntries };
}
// Ensure Rollup creates entries for each page file, see https://github.com/vikejs/vike/issues/350
// (Otherwise the page files may be missing in the client manifest.json)
async function getPageFileEntries(config, includeAssetsImportedByServer) {
const isForClientSide = !isViteServerSide_viteEnvOptional(config);
const fileTypes = isForClientSide ? ['.page', '.page.client'] : ['.page', '.page.server'];
if (isForClientSide && includeAssetsImportedByServer) {
fileTypes.push('.page.server');
}
let pageFiles = await findPageFiles(config, fileTypes, false);
const pageFileEntries = {};
pageFiles = unique(pageFiles);
pageFiles.forEach((pageFile) => {
let addExtractAssetsQuery = false;
if (isForClientSide && pageFile.includes('.page.server.')) {
assert(includeAssetsImportedByServer);
addExtractAssetsQuery = true;
}
const { entryName, entryTarget } = getEntryFromClientEntry(pageFile, config, addExtractAssetsQuery);
pageFileEntries[entryName] = entryTarget;
});
return pageFileEntries;
}
function getEntryFromClientEntry(clientEntry, config, addExtractAssetsQuery) {
if (!clientEntry.startsWith('/')) {
assertIsImportPathNpmPackage(clientEntry);
const entryTarget = clientEntry;
const entryName = prependEntriesDir(clientEntry);
return { entryName, entryTarget };
}
const filePathAbsoluteUserRootDir = clientEntry;
assert(filePathAbsoluteUserRootDir.startsWith('/'));
const filePath = getFilePathResolved({
filePathAbsoluteUserRootDir,
userRootDir: config.root,
});
let entryTarget = filePath.filePathAbsoluteFilesystem;
if (addExtractAssetsQuery)
entryTarget = extractAssetsAddQuery(entryTarget);
let entryName = filePathAbsoluteUserRootDir;
if (addExtractAssetsQuery)
entryName = extractAssetsAddQuery(entryName);
entryName = removeFileExtension(entryName);
entryName = prependEntriesDir(entryName);
return { entryName, entryTarget };
}
function getEntryFromPageConfig(pageConfig, isForClientSide) {
let { pageId } = pageConfig;
const entryTarget = generateVirtualFileId({ type: 'page-entry', pageId, isForClientSide });
let entryName = pageId;
// Avoid:
// ```
// dist/client/assets/entries/.Dp9wM6PK.js
// dist/server/entries/.mjs
// ```
if (entryName === '/')
entryName = 'root';
entryName = prependEntriesDir(entryName);
assert(!entryName.endsWith('/'));
return { entryName, entryTarget };
}
function addLogHook() {
const tty = process.stdout.isTTY && !process.env.CI; // Equals https://github.com/vitejs/vite/blob/193d55c7b9cbfec5b79ebfca276d4a721e7de14d/packages/vite/src/node/plugins/reporter.ts#L27
if (!tty)
return;
let lastLog = null;
['stdout', 'stderr'].forEach((stdName) => {
var methodOriginal = process[stdName].write;
process[stdName].write = function (...args) {
lastLog = String(args[0]);
return methodOriginal.apply(process[stdName], args);
};
});
// Exhaustive list extracted from writeLine() calls at https://github.com/vitejs/vite/blob/193d55c7b9cbfec5b79ebfca276d4a721e7de14d/packages/vite/src/node/plugins/reporter.ts
// prettier-ignore
// biome-ignore format:
const viteTransientLogs = [
'transforming (',
'rendering chunks (',
'computing gzip size ('
];
setAssertOnBeforeLog(() => {
// Using viteTransientLogs is very conservative as clearing the current line is low risk. (We can assume that important messages, such as errors, include a trailing new line. Usually, only transient messages have no trailing new lines.)
if (viteTransientLogs.some((s) => lastLog?.startsWith(s))) {
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
}
});
}
function assertRollupInput(config) {
const userInputs = normalizeRollupInput(config.build.rollupOptions.input);
const htmlInputs = Object.values(userInputs).filter((entry) => entry.endsWith('.html') || entry.endsWith('.htm'));
const htmlInput = htmlInputs[0];
assertUsage(htmlInput === undefined, `The entry ${htmlInput} of config build.rollupOptions.input is an HTML entry which is forbidden when using Vike, instead follow https://vike.dev/add`);
}