vike
Version:
The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.
178 lines (177 loc) • 8.11 kB
JavaScript
import '../../assertEnvVite.js';
export { pluginBuildApp };
import { runPrerender_forceExit } from '../../../prerender/runPrerenderEntry.js';
import { resolveOutDir } from '../../shared/getOutDirs.js';
import { assert, assertWarning } from '../../../../utils/assert.js';
import { onSetupBuild } from '../../../../utils/assertSetup.js';
import { getGlobalObject } from '../../../../utils/getGlobalObject.js';
import { isPrerenderAutoRunEnabled, wasPrerenderRun } from '../../../prerender/context.js';
import { isViteCli, getViteConfigForBuildFromCli } from '../../shared/isViteCli.js';
import pc from '@brillout/picocolors';
import { getVikeConfigInternal } from '../../shared/resolveVikeConfigInternal.js';
import { isVikeCliOrApi } from '../../../../shared-server-node/api-context.js';
import { handleAssetsManifest, handleAssetsManifest_assertUsageCssTarget } from './handleAssetsManifest.js';
import { isViteServerSide_onlySsrEnv } from '../../shared/isViteServerSide.js';
import { runPrerenderFromAutoRun } from '../../../prerender/runPrerenderEntry.js';
import { getManifestFilePathRelative } from '../../shared/getManifestFilePathRelative.js';
import { logErrorServer } from '../../../../server/runtime/logErrorServer.js';
const globalObject = getGlobalObject('build/pluginBuildApp.ts', {
forceExit: false,
});
function pluginBuildApp() {
let config;
return [
{
name: 'vike:build:pluginBuildApp:pre',
apply: 'build',
enforce: 'pre',
config: {
order: 'pre',
handler(_config) {
return {
builder: {
// Can be overridden by another plugin e.g vike-vercel https://github.com/vikejs/vike/pull/2184#issuecomment-2659425195
async buildApp(builder) {
assert(builder.environments.client);
assert(builder.environments.ssr);
await builder.build(builder.environments.client);
await builder.build(builder.environments.ssr);
if (isPrerenderForceExit()) {
runPrerender_forceExit();
assert(false);
}
},
},
};
},
},
},
{
name: 'vike:build:pluginBuildApp',
apply: 'build',
config: {
handler(config) {
return {
environments: {
ssr: {
consumer: 'server',
build: {
outDir: resolveOutDir(config, true),
ssr: true,
},
},
client: {
consumer: 'client',
build: {
outDir: resolveOutDir(config, false),
copyPublicDir: true,
ssr: false,
},
},
},
};
},
},
},
{
name: 'vike:build:pluginBuildApp:autoFullBuild:pre',
apply: 'build',
enforce: 'pre',
configResolved: {
async handler(config_) {
config = config_;
await abortViteBuildSsr();
},
},
// TO-DO/eventually: stop using this writeBundle() hack and, instead, use the buildApp() implementation above.
// - Could it cause issues if a tool uses the writeBundle() hack together with getVikeConfig() ?
writeBundle: {
/* We can't use this because it breaks Vite's logging. TO-DO/eventually: try again with latest Vite version.
sequential: true,
order: 'pre',
*/
async handler(options, bundle) {
try {
handleAssetsManifest_assertUsageCssTarget(config, this.environment);
await handleAssetsManifest(config, this.environment, options, bundle);
await triggerPrerendering(config, this.environment, bundle);
}
catch (err) {
// We use try-catch also because:
// - Vite/Rollup swallows errors thrown inside the writeBundle() hook. (It doesn't swallow errors thrown inside the first writeBundle() hook while building the client-side, but it does swallow errors thrown inside the second writeBundle() while building the server-side triggered after Vike calls Vite's `build()` API.)
// - Avoid Rollup prefixing the error with [vike:build:pluginBuildApp], see for example https://github.com/vikejs/vike/issues/472#issuecomment-1276274203
logErrorServer(err, null);
process.exit(1);
}
},
},
},
{
name: 'vike:build:pluginBuildApp:autoFullBuild:post',
apply: 'build',
enforce: 'post',
closeBundle: {
sequential: true,
order: 'post',
handler() {
onSetupBuild();
},
},
},
];
}
async function triggerPrerendering(config, viteEnv, bundle) {
const vikeConfig = await getVikeConfigInternal();
if (!isViteServerSide_onlySsrEnv(config, viteEnv))
return;
if (isDisabled(vikeConfig))
return;
// Workaround for @vitejs/plugin-legacy
// - The legacy plugin triggers its own Rollup build for the client-side.
// - The legacy plugin doesn't generate a manifest => we can use that to detect the legacy plugin build.
// - Issue & reproduction: https://github.com/vikejs/vike/issues/1154#issuecomment-1965954636
if (!bundle[getManifestFilePathRelative(config.build.manifest)])
return;
if (!(await isPrerenderAutoRunEnabled(vikeConfig)))
return;
const configInline = getFullBuildInlineConfig(config);
const res = await runPrerenderFromAutoRun(configInline);
globalObject.forceExit = res.forceExit;
assert(wasPrerenderRun());
}
async function abortViteBuildSsr() {
const vikeConfig = await getVikeConfigInternal();
if (vikeConfig.config.disableAutoFullBuild !== true && isViteCli() && getViteConfigForBuildFromCli()?.build.ssr) {
assertWarning(false, `The CLI call ${pc.cyan('$ vite build --ssr')} is superfluous since ${pc.cyan('$ vite build')} also builds the server-side. If you want two separate build steps then use https://vike.dev/disableAutoFullBuild or use Vite's ${pc.cyan('build()')} API.`, { onlyOnce: true });
process.exit(0);
}
}
function isDisabled(vikeConfig) {
const { disableAutoFullBuild } = vikeConfig.config;
if (disableAutoFullBuild === undefined || disableAutoFullBuild === 'prerender') {
const isUserUsingViteApi = !isViteCli() && !isVikeCliOrApi();
return isUserUsingViteApi;
}
else {
return disableAutoFullBuild;
}
}
function isPrerenderForceExit() {
return globalObject.forceExit;
}
function getFullBuildInlineConfig(config) {
const configFromCli = !isViteCli() ? null : getViteConfigForBuildFromCli();
if (config._viteConfigFromUserResolved) {
return config._viteConfigFromUserResolved;
}
else {
return {
...configFromCli,
configFile: configFromCli?.configFile || config.configFile,
root: config.root,
build: {
...configFromCli?.build,
},
};
}
}