UNPKG

@rspack/cli

Version:
726 lines (725 loc) • 32.8 kB
"use strict"; var __webpack_modules__ = { "@rspack/core": function(module) { module.exports = require("@rspack/core"); }, "node:fs": function(module) { module.exports = require("node:fs"); }, "node:inspector": function(module) { module.exports = require("node:inspector"); }, "node:path": function(module) { module.exports = require("node:path"); }, "node:url": function(module) { module.exports = require("node:url"); }, "@discoveryjs/json-ext": function(module) { module.exports = import("@discoveryjs/json-ext"); }, "@rspack/dev-server": function(module) { module.exports = import("@rspack/dev-server"); }, "exit-hook": function(module) { module.exports = import("exit-hook"); }, interpret: function(module) { module.exports = import("interpret"); }, rechoir: function(module) { module.exports = import("rechoir"); }, "webpack-bundle-analyzer": function(module) { module.exports = import("webpack-bundle-analyzer"); } }; var __webpack_module_cache__ = {}; function __webpack_require__(moduleId) { var cachedModule = __webpack_module_cache__[moduleId]; if (void 0 !== cachedModule) return cachedModule.exports; var module = __webpack_module_cache__[moduleId] = { exports: {} }; __webpack_modules__[moduleId](module, module.exports, __webpack_require__); return module.exports; } __webpack_require__.m = __webpack_modules__; (()=>{ __webpack_require__.n = (module)=>{ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module; __webpack_require__.d(getter, { a: getter }); return getter; }; })(); (()=>{ __webpack_require__.d = (exports1, definition)=>{ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, { enumerable: true, get: definition[key] }); }; })(); (()=>{ __webpack_require__.f = {}; __webpack_require__.e = (chunkId)=>Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key)=>{ __webpack_require__.f[key](chunkId, promises); return promises; }, [])); })(); (()=>{ __webpack_require__.u = (chunkId)=>"" + chunkId + ".js"; })(); (()=>{ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop); })(); (()=>{ __webpack_require__.r = function(exports1) { if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, { value: 'Module' }); Object.defineProperty(exports1, '__esModule', { value: true }); }; })(); (()=>{ var installedChunks = { 980: 1 }; var installChunk = (chunk)=>{ var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime; for(var moduleId in moreModules)if (__webpack_require__.o(moreModules, moduleId)) __webpack_require__.m[moduleId] = moreModules[moduleId]; if (runtime) runtime(__webpack_require__); for(var i = 0; i < chunkIds.length; i++)installedChunks[chunkIds[i]] = 1; }; __webpack_require__.f.require = (chunkId, promises)=>{ if (!installedChunks[chunkId]) installChunk(require("./" + __webpack_require__.u(chunkId))); }; })(); var __webpack_exports__ = {}; (()=>{ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { definePlugin: ()=>definePlugin, RspackCLI: ()=>RspackCLI, defineConfig: ()=>defineConfig }); var external_node_path_ = __webpack_require__("node:path"); var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_); const external_node_util_namespaceObject = require("node:util"); var external_node_util_default = /*#__PURE__*/ __webpack_require__.n(external_node_util_namespaceObject); var core_ = __webpack_require__("@rspack/core"); const external_colorette_namespaceObject = require("colorette"); const external_yargs_namespaceObject = require("yargs"); var external_yargs_default = /*#__PURE__*/ __webpack_require__.n(external_yargs_namespaceObject); const helpers_namespaceObject = require("yargs/helpers"); var external_node_fs_ = __webpack_require__("node:fs"); var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_); const commonOptions = (yargs)=>yargs.options({ config: { g: true, type: "string", describe: "config file", alias: "c" }, configName: { type: "array", string: true, describe: "Name of the configuration to use." }, configLoader: { type: "string", default: "register", describe: "Specify the loader to load the config file, can be `native` or `register`." }, nodeEnv: { string: true, describe: "sets `process.env.NODE_ENV` to be specified value" } }); const commonOptionsForBuildAndServe = (yargs)=>yargs.options({ entry: { type: "array", string: true, describe: "entry file" }, outputPath: { type: "string", describe: "output path dir", alias: "o" }, mode: { type: "string", describe: "mode", alias: "m" }, watch: { type: "boolean", default: false, describe: "watch", alias: "w" }, env: { type: "array", string: true, describe: "env passed to config function" }, devtool: { type: "boolean", default: false, describe: "devtool", alias: "d" } }).alias({ v: "version", h: "help" }); function normalizeEnv(argv) { function parseValue(previous, value) { const [allKeys, val] = value.split(/=(.+)/, 2); const splitKeys = allKeys.split(/\.(?!$)/); let prevRef = previous; splitKeys.forEach((key, index)=>{ let someKey = key; if (someKey.endsWith("=")) { someKey = someKey.slice(0, -1); prevRef[someKey] = void 0; return; } if (!prevRef[someKey] || "string" == typeof prevRef[someKey]) prevRef[someKey] = {}; if (index === splitKeys.length - 1) { if ("string" == typeof val) prevRef[someKey] = val; else prevRef[someKey] = true; } prevRef = prevRef[someKey]; }); return previous; } const envObj = (argv.env ?? []).reduce(parseValue, {}); argv.env = envObj; } function setBuiltinEnvArg(env, envNameSuffix, value) { const envNames = [ `RSPACK_${envNameSuffix}` ]; for (const envName of envNames)if (!(envName in env)) env[envName] = value; } function ensureEnvObject(options) { if (Array.isArray(options.env)) normalizeEnv(options); options.env = options.env || {}; return options.env; } function setDefaultNodeEnv(options, defaultEnv) { if (void 0 !== process.env.NODE_ENV) return; process.env.NODE_ENV = "string" == typeof options.nodeEnv ? options.nodeEnv : defaultEnv; } class BuildCommand { async apply(cli) { cli.program.command([ "build", "$0", "bundle", "b" ], "run the rspack build", (yargs)=>{ commonOptionsForBuildAndServe(commonOptions(yargs)).options({ analyze: { type: "boolean", default: false, describe: "analyze" }, json: { describe: "emit stats json" }, profile: { type: "boolean", default: false, describe: "capture timing information for each module" } }); }, async (options)=>{ setDefaultNodeEnv(options, "production"); const env = ensureEnvObject(options); if (options.watch) setBuiltinEnvArg(env, "WATCH", true); else { setBuiltinEnvArg(env, "BUNDLE", true); setBuiltinEnvArg(env, "BUILD", true); } const logger = cli.getLogger(); let createJsonStringifyStream; if (options.json) { const jsonExt = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "@discoveryjs/json-ext")); createJsonStringifyStream = jsonExt.default.stringifyStream; } const errorHandler = (error, stats)=>{ if (error) { logger.error(error); process.exit(2); } if (null == stats ? void 0 : stats.hasErrors()) process.exitCode = 1; if (!compiler || !stats) return; const statsOptions = cli.isMultipleCompiler(compiler) ? { children: compiler.compilers.map((compiler)=>compiler.options ? compiler.options.stats : void 0) } : compiler.options ? compiler.options.stats : void 0; if (options.json && createJsonStringifyStream) { const handleWriteError = (error)=>{ logger.error(error); process.exit(2); }; if (true === options.json) createJsonStringifyStream(stats.toJson(statsOptions)).on("error", handleWriteError).pipe(process.stdout).on("error", handleWriteError).on("close", ()=>process.stdout.write("\n")); else if ("string" == typeof options.json) createJsonStringifyStream(stats.toJson(statsOptions)).on("error", handleWriteError).pipe(external_node_fs_.createWriteStream(options.json)).on("error", handleWriteError).on("close", ()=>{ process.stderr.write(`[rspack-cli] ${cli.colors.green(`stats are successfully stored as json to ${options.json}`)}\n`); }); } else { const printedStats = stats.toString(statsOptions); if (printedStats) logger.raw(printedStats); } }; const rspackOptions = { ...options, argv: { ...options } }; const compiler = await cli.createCompiler(rspackOptions, "build", errorHandler); if (!compiler || cli.isWatch(compiler)) return; compiler.run((error, stats)=>{ if (error || (null == stats ? void 0 : stats.hasErrors())) errorHandler(error, stats); else compiler.close((closeErr)=>{ if (closeErr) logger.error(closeErr); errorHandler(error, stats); }); }); }); } } const previewOptions = (yargs)=>{ yargs.positional("dir", { type: "string", describe: "directory want to preview" }); return commonOptions(yargs).options({ publicPath: { type: "string", describe: "static resource server path" }, port: { type: "number", describe: "preview server port" }, host: { type: "string", describe: "preview server host" }, open: { type: "boolean", describe: "open browser" }, server: { type: "string", describe: "Configuration items for the server." } }); }; const defaultRoot = "dist"; class PreviewCommand { async apply(cli) { cli.program.command([ "preview [dir]", "preview", "p" ], "run the rspack server for build output", previewOptions, async (options)=>{ setDefaultNodeEnv(options, "production"); const rspackOptions = { ...options, argv: { ...options } }; const { RspackDevServer } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "@rspack/dev-server")); let config = await cli.loadConfig(rspackOptions); config = await getPreviewConfig(config, options); if (!Array.isArray(config)) config = [ config ]; config = config.find((item)=>item.devServer) || config[0]; const devServerOptions = config.devServer; try { const compiler = (0, core_.rspack)({ entry: {} }); if (!compiler) return; const server = new RspackDevServer(devServerOptions, compiler); await server.start(); } catch (error) { const logger = cli.getLogger(); logger.error(error); process.exit(2); } }); } } async function getPreviewConfig(item, options) { const internalPreviewConfig = async (item)=>{ var _item_output, _item_devServer, _item_devServer1, _item_devServer2, _item_devServer3, _item_devServer4; item.devServer = { static: { directory: options.dir ? external_node_path_default().join(item.context ?? process.cwd(), options.dir) : (null === (_item_output = item.output) || void 0 === _item_output ? void 0 : _item_output.path) ?? external_node_path_default().join(item.context ?? process.cwd(), defaultRoot), publicPath: options.publicPath ?? "/" }, port: options.port ?? 8080, proxy: null === (_item_devServer = item.devServer) || void 0 === _item_devServer ? void 0 : _item_devServer.proxy, host: options.host ?? (null === (_item_devServer1 = item.devServer) || void 0 === _item_devServer1 ? void 0 : _item_devServer1.host), open: options.open ?? (null === (_item_devServer2 = item.devServer) || void 0 === _item_devServer2 ? void 0 : _item_devServer2.open), server: options.server ?? (null === (_item_devServer3 = item.devServer) || void 0 === _item_devServer3 ? void 0 : _item_devServer3.server), historyApiFallback: null === (_item_devServer4 = item.devServer) || void 0 === _item_devServer4 ? void 0 : _item_devServer4.historyApiFallback }; return item; }; if (Array.isArray(item)) return Promise.all(item.map(internalPreviewConfig)); return internalPreviewConfig(item); } class ServeCommand { async apply(cli) { cli.program.command([ "serve", "server", "s", "dev" ], "run the rspack dev server.", (yargs)=>commonOptionsForBuildAndServe(commonOptions(yargs)).options({ hot: { coerce: (arg)=>{ if ("boolean" == typeof arg || "only" === arg) return arg; if ("false" === arg) return false; return true; }, describe: "enables hot module replacement" }, port: { type: "number", coerce: (arg)=>Number.isInteger(arg) ? arg : void 0, describe: "allows to specify a port to use" }, host: { type: "string", describe: "allows to specify a hostname to use" } }), async (options)=>{ setDefaultNodeEnv(options, "development"); setBuiltinEnvArg(ensureEnvObject(options), "SERVE", true); const rspackOptions = { ...options, argv: { ...options } }; const { RspackDevServer } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "@rspack/dev-server")); const compiler = await cli.createCompiler(rspackOptions, "serve"); if (!compiler) return; const compilers = cli.isMultipleCompiler(compiler) ? compiler.compilers : [ compiler ]; const possibleCompilers = compilers.filter((compiler)=>compiler.options.devServer); const usedPorts = []; const servers = []; const compilerForDevServer = possibleCompilers.length > 0 ? possibleCompilers[0] : compilers[0]; for (const compiler of compilers){ const devServer = compiler.options.devServer ??= {}; devServer.hot = options.hot ?? devServer.hot ?? true; if (false !== devServer.client) { if (true === devServer.client || null == devServer.client) devServer.client = {}; devServer.client = { overlay: { errors: true, warnings: false }, ...devServer.client }; } } const result = compilerForDevServer.options.devServer ??= {}; result.hot = options.hot ?? result.hot ?? true; result.host = options.host || result.host; result.port = options.port || result.port; if (false !== result.client) { if (true === result.client || null == result.client) result.client = {}; result.client = { overlay: { errors: true, warnings: false }, ...result.client }; } const devServerOptions = result; if (devServerOptions.port) { const portNumber = Number(devServerOptions.port); if (!Number.isNaN(portNumber)) { if (usedPorts.find((port)=>portNumber === port)) throw new Error("Unique ports must be specified for each devServer option in your rspack configuration. Alternatively, run only 1 devServer config using the --config-name flag to specify your desired config."); usedPorts.push(portNumber); } } try { const server = new RspackDevServer(devServerOptions, compiler); await server.start(); servers.push(server); } catch (error) { const logger = cli.getLogger(); logger.error(error); process.exit(2); } }); } } var external_node_url_ = __webpack_require__("node:url"); const readPackageUp_readPackageUp = (cwd = process.cwd())=>{ let currentDir = external_node_path_default().resolve(cwd); let packageJsonPath = external_node_path_default().join(currentDir, "package.json"); while(!external_node_fs_default().existsSync(packageJsonPath)){ const parentDir = external_node_path_default().dirname(currentDir); if (parentDir === currentDir) return null; currentDir = parentDir; packageJsonPath = external_node_path_default().join(currentDir, "package.json"); } try { return JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, "utf8")); } catch (error) { return null; } }; const readPackageUp = readPackageUp_readPackageUp; const isEsmFile = (filePath, cwd = process.cwd())=>{ const ext = external_node_path_default().extname(filePath); if (/\.(mjs|mts)$/.test(ext)) return true; if (/\.(cjs|cts)/.test(ext)) return false; const packageJson = readPackageUp(external_node_path_default().dirname(filePath)); return (null == packageJson ? void 0 : packageJson.type) === "module"; }; const utils_isEsmFile = isEsmFile; const crossImport = async (path, cwd = process.cwd())=>{ if (utils_isEsmFile(path, cwd)) { const url = (0, external_node_url_.pathToFileURL)(path).href; const { default: config } = await import(url); return config; } let result = require(path); if (result && "object" == typeof result && "default" in result) result = result.default || {}; return result; }; const DEFAULT_EXTENSIONS = [ ".js", ".ts", ".mjs", ".mts", ".cjs", ".cts" ]; const findConfig = (basePath)=>DEFAULT_EXTENSIONS.map((ext)=>basePath + ext).find(external_node_fs_default().existsSync); const utils_findConfig = findConfig; const isTsFile = (configPath)=>{ const ext = external_node_path_default().extname(configPath); return /\.(c|m)?ts$/.test(ext); }; const utils_isTsFile = isTsFile; const loadConfig_DEFAULT_CONFIG_NAME = "rspack.config"; const registerLoader = async (configPath)=>{ const ext = external_node_path_default().extname(configPath); if (utils_isEsmFile(configPath) && utils_isTsFile(configPath)) return; const { default: interpret } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "interpret")); const extensions = Object.fromEntries(Object.entries(interpret.extensions).filter(([key])=>key === ext)); if (0 === Object.keys(extensions).length) throw new Error(`config file "${configPath}" is not supported.`); try { const { default: rechoir } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "rechoir")); rechoir.prepare(extensions, configPath); } catch (error) { const failures = null == error ? void 0 : error.failures; if (failures) { const messages = failures.map((failure)=>failure.error.message); throw new Error(`${messages.join("\n")}`); } throw error; } }; async function loadRspackConfig(options, cwd = process.cwd()) { if (options.config) { const configPath = external_node_path_default().resolve(cwd, options.config); if (!external_node_fs_default().existsSync(configPath)) throw new Error(`config file "${configPath}" not found.`); if (utils_isTsFile(configPath) && "register" === options.configLoader) await registerLoader(configPath); return crossImport(configPath, cwd); } const defaultConfig = utils_findConfig(external_node_path_default().resolve(cwd, loadConfig_DEFAULT_CONFIG_NAME)); if (defaultConfig) { if (utils_isTsFile(defaultConfig) && "register" === options.configLoader) await registerLoader(defaultConfig); return crossImport(defaultConfig, cwd); } return {}; } function _define_property(obj, key, value) { if (key in obj) Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); else obj[key] = value; return obj; } class RspackCLI { async createCompiler(options, rspackCommand, callback) { process.env.RSPACK_CONFIG_VALIDATE ??= "loose"; process.env.WATCHPACK_WATCHER_LIMIT = process.env.WATCHPACK_WATCHER_LIMIT || "20"; let config = await this.loadConfig(options); config = await this.buildConfig(config, options, rspackCommand); const isWatch = Array.isArray(config) ? config.some((i)=>i.watch) : config.watch; let compiler; try { compiler = (0, core_.rspack)(config, isWatch ? callback : void 0); } catch (e) { if (e instanceof core_.ValidationError) { this.getLogger().error(e.message); process.exit(2); } else if (e instanceof Error) { if ("function" == typeof callback) callback(e); else this.getLogger().error(e); return null; } throw e; } return compiler; } createColors(useColor) { const shouldUseColor = useColor || external_colorette_namespaceObject.isColorSupported; return { ...(0, external_colorette_namespaceObject.createColors)({ useColor: shouldUseColor }), isColorSupported: shouldUseColor }; } getLogger() { return { error: (val)=>console.error(`[rspack-cli] ${this.colors.red(external_node_util_default().format(val))}`), warn: (val)=>console.warn(`[rspack-cli] ${this.colors.yellow(val)}`), info: (val)=>console.info(`[rspack-cli] ${this.colors.cyan(val)}`), success: (val)=>console.log(`[rspack-cli] ${this.colors.green(val)}`), log: (val)=>console.log(`[rspack-cli] ${val}`), raw: (val)=>console.log(val) }; } async run(argv) { this.program.showHelpOnFail(false); this.program.usage("[options]"); this.program.scriptName("rspack"); this.program.strictCommands(true).strict(true); this.program.middleware(normalizeEnv); this.registerCommands(); await this.program.parseAsync((0, helpers_namespaceObject.hideBin)(argv)); } async registerCommands() { const builtinCommands = [ new BuildCommand(), new ServeCommand(), new PreviewCommand() ]; for (const command of builtinCommands)command.apply(this); } async buildConfig(item, options, command) { const isBuild = "build" === command; const isServe = "serve" === command; const internalBuildConfig = async (item)=>{ if (options.entry) item.entry = { main: options.entry.map((x)=>external_node_path_default().resolve(process.cwd(), x))[0] }; item.output = item.output || {}; if (options.outputPath) item.output.path = external_node_path_default().resolve(process.cwd(), options.outputPath); if (options.analyze) { const { BundleAnalyzerPlugin } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "webpack-bundle-analyzer")); (item.plugins ??= []).push({ name: "rspack-bundle-analyzer", apply (compiler) { new BundleAnalyzerPlugin({ generateStatsFile: true }).apply(compiler); } }); } if (options.profile) item.profile = true; if (process.env.RSPACK_PROFILE) { const { applyProfile } = await __webpack_require__.e("390").then(__webpack_require__.bind(__webpack_require__, "./src/utils/profile.ts")); await applyProfile(process.env.RSPACK_PROFILE, item); } if (options.watch) item.watch = options.watch; if (!item.mode) item.mode = isBuild ? "production" : "development"; if (options.mode) item.mode = options.mode; if (void 0 === item.devtool) item.devtool = isBuild ? "source-map" : "cheap-module-source-map"; if (isServe) { const installed = (item.plugins ||= []).find((item)=>item instanceof core_.ProgressPlugin); if (!installed) (item.plugins ??= []).push(new core_.ProgressPlugin()); } if (void 0 === item.stats) item.stats = { preset: "errors-warnings", timings: true }; else if ("boolean" == typeof item.stats) item.stats = item.stats ? { preset: "normal" } : { preset: "none" }; else if ("string" == typeof item.stats) item.stats = { preset: item.stats }; if (this.colors.isColorSupported && void 0 === item.stats.colors) item.stats.colors = true; return item; }; if (Array.isArray(item)) return Promise.all(item.map(internalBuildConfig)); return internalBuildConfig(item); } async loadConfig(options) { let loadedConfig = await loadRspackConfig(options); if ("function" == typeof loadedConfig) { var _options_argv; loadedConfig = loadedConfig(null === (_options_argv = options.argv) || void 0 === _options_argv ? void 0 : _options_argv.env, options.argv); if ("function" == typeof loadedConfig.then) loadedConfig = await loadedConfig; } if (options.configName) { const notFoundConfigNames = []; loadedConfig = options.configName.map((configName)=>{ let found; found = Array.isArray(loadedConfig) ? loadedConfig.find((options)=>options.name === configName) : loadedConfig.name === configName ? loadedConfig : void 0; if (!found) notFoundConfigNames.push(configName); return found; }); if (notFoundConfigNames.length > 0) { this.getLogger().error(notFoundConfigNames.map((configName)=>`Configuration with the name "${configName}" was not found.`).join(" ")); process.exit(2); } } return loadedConfig; } isMultipleCompiler(compiler) { return Boolean(compiler.compilers); } isWatch(compiler) { return Boolean(this.isMultipleCompiler(compiler) ? compiler.compilers.some((compiler)=>compiler.options.watch) : compiler.options.watch); } constructor(){ _define_property(this, "colors", void 0); _define_property(this, "program", void 0); this.colors = this.createColors(); this.program = external_yargs_default()(); } } function defineConfig(config) { return config; } function definePlugin(plugin) { return plugin; } })(); var __webpack_export_target__ = exports; for(var __webpack_i__ in __webpack_exports__)__webpack_export_target__[__webpack_i__] = __webpack_exports__[__webpack_i__]; if (__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, '__esModule', { value: true });