@rspack/cli
Version:
CLI for rspack
701 lines (700 loc) • 29.7 kB
JavaScript
import * as __WEBPACK_EXTERNAL_MODULE__rspack_core_e0096ff7__ from "@rspack/core";
import * as __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__ from "node:fs";
import * as __WEBPACK_EXTERNAL_MODULE_node_inspector_dd9822d6__ from "node:inspector";
import * as __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__ from "node:path";
import * as __WEBPACK_EXTERNAL_MODULE_node_url_e96de089__ from "node:url";
import * as __WEBPACK_EXTERNAL_MODULE_node_util_1b29d436__ from "node:util";
import * as __WEBPACK_EXTERNAL_MODULE_colorette__ from "colorette";
import * as __WEBPACK_EXTERNAL_MODULE_yargs__ from "yargs";
import * as __WEBPACK_EXTERNAL_MODULE_yargs_helpers_525217b7__ from "yargs/helpers";
var __webpack_modules__ = {
"@rspack/core": function(module) {
module.exports = __WEBPACK_EXTERNAL_MODULE__rspack_core_e0096ff7__;
},
"node:fs": function(module) {
module.exports = __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__;
},
"node:inspector": function(module) {
module.exports = __WEBPACK_EXTERNAL_MODULE_node_inspector_dd9822d6__;
},
"node:path": function(module) {
module.exports = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__;
},
"node:url": function(module) {
module.exports = __WEBPACK_EXTERNAL_MODULE_node_url_e96de089__;
}
};
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__.d = (exports, definition)=>{
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, 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 + ".mjs";
})();
(()=>{
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
})();
(()=>{
var installedChunks = {
980: 0
};
var installChunk = (data)=>{
var __webpack_ids__ = data.__webpack_ids__;
var __webpack_modules__ = data.__webpack_modules__;
var __webpack_runtime__ = data.__webpack_runtime__;
var moduleId, chunkId, i = 0;
for(moduleId in __webpack_modules__)if (__webpack_require__.o(__webpack_modules__, moduleId)) __webpack_require__.m[moduleId] = __webpack_modules__[moduleId];
if (__webpack_runtime__) __webpack_runtime__(__webpack_require__);
for(; i < __webpack_ids__.length; i++){
chunkId = __webpack_ids__[i];
if (__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) installedChunks[chunkId][0]();
installedChunks[__webpack_ids__[i]] = 0;
}
};
__webpack_require__.f.j = function(chunkId, promises) {
var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : void 0;
if (0 !== installedChunkData) {
if (installedChunkData) promises.push(installedChunkData[1]);
else {
var promise = import("./" + __webpack_require__.u(chunkId)).then(installChunk, (e)=>{
if (0 !== installedChunks[chunkId]) installedChunks[chunkId] = void 0;
throw e;
});
var promise = Promise.race([
promise,
new Promise((resolve)=>{
installedChunkData = installedChunks[chunkId] = [
resolve
];
})
]);
promises.push(installedChunkData[1] = promise);
}
}
};
})();
var external_node_path_ = __webpack_require__("node:path");
var core_ = __webpack_require__("@rspack/core");
var external_node_fs_ = __webpack_require__("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 import("@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 import("@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 import("@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 import("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 import("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 || __WEBPACK_EXTERNAL_MODULE_colorette__.isColorSupported;
return {
...(0, __WEBPACK_EXTERNAL_MODULE_colorette__.createColors)({
useColor: shouldUseColor
}),
isColorSupported: shouldUseColor
};
}
getLogger() {
return {
error: (val)=>console.error(`[rspack-cli] ${this.colors.red(__WEBPACK_EXTERNAL_MODULE_node_util_1b29d436__["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, __WEBPACK_EXTERNAL_MODULE_yargs_helpers_525217b7__.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 import("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 = (0, __WEBPACK_EXTERNAL_MODULE_yargs__["default"])();
}
}
function defineConfig(config) {
return config;
}
function definePlugin(plugin) {
return plugin;
}
export { RspackCLI, defineConfig, definePlugin };