UNPKG

@nuxt/cli-edge

Version:
275 lines (270 loc) • 8.52 kB
/*! * @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 */ 'use strict'; 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;