@nuxt/cli-edge
Version:
275 lines (270 loc) • 8.52 kB
JavaScript
/*!
* @nuxt/cli-edge v2.18.2-28661769.e265ef3 (c) 2016-2024
* Released under the MIT License
* Repository: https://github.com/nuxt/nuxt.js
* Website: https://nuxtjs.org
*/
;
const utilsEdge = require('@nuxt/utils-edge');
const consola = require('consola');
const index = require('./cli-index.js');
const path = require('path');
const upath = require('upath');
const fs = require('fs-extra');
const crc32 = require('crc/crc32');
const globby = require('globby');
const destr = require('destr');
require('@nuxt/config-edge');
require('exit');
require('chalk');
require('std-env');
require('wrap-ansi');
require('boxen');
require('minimist');
require('hookable');
require('defu');
require('semver');
require('fs');
require('execa');
async function generate$1(cmd) {
const nuxt = await getNuxt({ server: true }, cmd);
const generator = await cmd.getGenerator(nuxt);
await nuxt.server.listen(0);
const { errors } = await generator.generate({ build: false });
await nuxt.close();
if (cmd.argv["fail-on-error"] && errors.length > 0) {
throw new Error("Error generating pages, exiting with non-zero code");
}
}
async function ensureBuild(cmd) {
const nuxt = await getNuxt({ _build: true, server: false }, cmd);
const { options } = nuxt;
if (options.generate.cache === false || destr(process.env.NUXT_BUILD) || cmd.argv["force-build"]) {
const builder2 = await cmd.getBuilder(nuxt);
await builder2.build();
await nuxt.close();
return;
}
const ignore = [
options.buildDir,
options.dir.static,
options.generate.dir,
"node_modules",
".**/*",
".*",
"README.md"
];
const { generate: generate2 } = options;
if (typeof generate2.cache.ignore === "function") {
generate2.cache.ignore = generate2.cache.ignore(ignore);
} else if (Array.isArray(generate2.cache.ignore)) {
generate2.cache.ignore = generate2.cache.ignore.concat(ignore);
}
await nuxt.callHook("generate:cache:ignore", generate2.cache.ignore);
const snapshotOptions = {
rootDir: options.rootDir,
ignore: generate2.cache.ignore.map(upath.normalize),
globbyOptions: generate2.cache.globbyOptions
};
const currentBuildSnapshot = await snapshot(snapshotOptions);
const processEnv = {};
if (nuxt.options._nuxtConfigFile) {
const configSrc = await fs.readFile(nuxt.options._nuxtConfigFile);
const envRegex = /process.env.(\w+)/g;
let match;
while (match = envRegex.exec(configSrc)) {
processEnv[match[1]] = process.env[match[1]];
}
}
const currentBuild = {
// @ts-ignore
nuxtVersion: nuxt.constructor.version,
ssr: nuxt.options.ssr,
target: nuxt.options.target,
snapshot: currentBuildSnapshot,
env: nuxt.options.env,
"process.env": processEnv
};
const nuxtBuildFile = path.resolve(nuxt.options.buildDir, "build.json");
if (fs.existsSync(nuxtBuildFile)) {
const previousBuild = destr(fs.readFileSync(nuxtBuildFile, "utf-8")) || {};
let needBuild = false;
const fields = ["nuxtVersion", "ssr", "target"];
if (nuxt.options.generate.ignoreEnv !== true) {
fields.push("env", "process.env");
}
for (const field of fields) {
if (JSON.stringify(previousBuild[field]) !== JSON.stringify(currentBuild[field])) {
needBuild = true;
consola.info(`Doing webpack rebuild because ${field} changed`);
break;
}
}
if (!needBuild) {
const changed = compareSnapshots(previousBuild.snapshot, currentBuild.snapshot);
if (!changed) {
consola.success("Skipping webpack build as no changes detected");
await nuxt.close();
return;
} else {
consola.info(`Doing webpack rebuild because ${changed} modified`);
}
}
}
const builder = await cmd.getBuilder(nuxt);
await builder.build();
fs.writeFileSync(nuxtBuildFile, JSON.stringify(currentBuild, null, 2), "utf-8");
await nuxt.close();
}
async function getNuxt(args, cmd) {
const config = await cmd.getNuxtConfig({ dev: false, ...args });
if (config.target === utilsEdge.TARGETS.static) {
config._export = true;
} else {
config._legacyGenerate = true;
}
config.buildDir = config.static && config.static.cacheDir || path.resolve(config.rootDir, "node_modules/.cache/nuxt");
config.build = config.build || {};
config.build.parallel = false;
config.build.transpile = config.build.transpile || [];
if (!config.static || !config.static.cacheDir) {
config.build.transpile.push(".cache/nuxt");
}
const nuxt = await cmd.getNuxt(config);
return nuxt;
}
function compareSnapshots(from, to) {
const allKeys = Array.from(/* @__PURE__ */ new Set([
...Object.keys(from).sort(),
...Object.keys(to).sort()
]));
for (const key of allKeys) {
if (JSON.stringify(from[key]) !== JSON.stringify(to[key])) {
return key;
}
}
return false;
}
async function snapshot({ globbyOptions, ignore, rootDir }) {
const snapshot2 = {};
const files = await globby("**/*.*", {
...globbyOptions,
ignore,
cwd: rootDir,
absolute: true
});
await Promise.all(files.map(async (p) => {
const key = path.relative(rootDir, p);
try {
const fileContent = await fs.readFile(p);
snapshot2[key] = {
checksum: await crc32(fileContent).toString(16)
};
} catch (e) {
snapshot2[key] = {
exists: false
};
}
}));
return snapshot2;
}
const generate = {
name: "generate",
description: "Generate a static web application (server-rendered)",
usage: "generate <dir>",
options: {
...index.common,
...index.locking,
build: {
type: "boolean",
default: true,
description: "Only generate pages for dynamic routes, used for incremental builds. Generate has to be run once without this option before using it"
},
devtools: {
type: "boolean",
default: false,
description: "Enable Vue devtools",
prepare(cmd, options, argv) {
options.vue = options.vue || {};
options.vue.config = options.vue.config || {};
if (argv.devtools) {
options.vue.config.devtools = true;
}
}
},
quiet: {
alias: "q",
type: "boolean",
description: "Disable output except for errors",
prepare(cmd, options, argv) {
options.build = options.build || {};
if (argv.quiet) {
options.build.quiet = true;
}
}
},
modern: {
...index.common.modern,
description: "Generate app in modern build (modern mode can be only client)",
prepare(cmd, options, argv) {
if (index.normalizeArg(argv.modern)) {
options.modern = "client";
}
}
},
"force-build": {
type: "boolean",
default: false,
description: "Force to build the application with webpack"
},
"fail-on-error": {
type: "boolean",
default: false,
description: "Exit with non-zero status code if there are errors when generating pages"
}
},
async run(cmd) {
const config = await cmd.getNuxtConfig({ dev: false });
config.build = config.build || {};
config.build.analyze = false;
if (config.target === utilsEdge.TARGETS.static) {
await ensureBuild(cmd);
await generate$1(cmd);
return;
}
config.target = utilsEdge.TARGETS.static;
consola.warn(`When using \`nuxt generate\`, you should set \`target: 'static'\` in your \`nuxt.config\`
\u{1F449} Learn more about it on https://go.nuxtjs.dev/static-target`);
config._legacyGenerate = true;
if (config.build) {
config.build.parallel = false;
}
const nuxt = await cmd.getNuxt(config);
if (cmd.argv.lock) {
await cmd.setLock(await index.createLock({
id: "build",
dir: nuxt.options.buildDir,
root: config.rootDir
}));
nuxt.hook("build:done", async () => {
await cmd.releaseLock();
await cmd.setLock(await index.createLock({
id: "generate",
dir: nuxt.options.generate.dir,
root: config.rootDir
}));
});
}
const generator = await cmd.getGenerator(nuxt);
await nuxt.server.listen(0);
const { errors } = await generator.generate({
init: true,
build: cmd.argv.build
});
await nuxt.close();
if (cmd.argv["fail-on-error"] && errors.length > 0) {
throw new Error("Error generating pages, exiting with non-zero code");
}
}
};
exports.default = generate;