@rsbuild/core 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3101,6 +3101,122 @@ var init_esm = __esm({
3101
3101
  }
3102
3102
  });
3103
3103
 
3104
+ // src/logger.ts
3105
+ function getTime() {
3106
+ const now = /* @__PURE__ */ new Date();
3107
+ const hours = String(now.getHours()).padStart(2, "0");
3108
+ const minutes = String(now.getMinutes()).padStart(2, "0");
3109
+ const seconds = String(now.getSeconds()).padStart(2, "0");
3110
+ return `${hours}:${minutes}:${seconds}`;
3111
+ }
3112
+ var import_picocolors, import_rslog, isDebug;
3113
+ var init_logger = __esm({
3114
+ "src/logger.ts"() {
3115
+ "use strict";
3116
+ import_picocolors = __toESM(require("../compiled/picocolors/index.js"));
3117
+ import_rslog = require("../compiled/rslog/index.js");
3118
+ isDebug = () => {
3119
+ if (!process.env.DEBUG) {
3120
+ return false;
3121
+ }
3122
+ const values = process.env.DEBUG.toLocaleLowerCase().split(",");
3123
+ return ["rsbuild", "builder", "*"].some((key) => values.includes(key));
3124
+ };
3125
+ if (isDebug()) {
3126
+ import_rslog.logger.level = "verbose";
3127
+ }
3128
+ import_rslog.logger.override({
3129
+ debug: (message, ...args) => {
3130
+ if (import_rslog.logger.level !== "verbose") {
3131
+ return;
3132
+ }
3133
+ const time = import_picocolors.default.gray(`${getTime()}`);
3134
+ console.log(` ${import_picocolors.default.magenta("rsbuild")} ${time} ${message}`, ...args);
3135
+ }
3136
+ });
3137
+ }
3138
+ });
3139
+
3140
+ // src/constants.ts
3141
+ var import_node_path, ROOT_DIST_DIR, HTML_DIST_DIR, JS_DIST_DIR, CSS_DIST_DIR, SVG_DIST_DIR, FONT_DIST_DIR, WASM_DIST_DIR, IMAGE_DIST_DIR, MEDIA_DIST_DIR, LOADER_PATH, STATIC_PATH, COMPILED_PATH, TS_CONFIG_FILE, HMR_SOCKET_PATH, RSBUILD_OUTPUTS_PATH, DEFAULT_PORT, DEFAULT_DATA_URL_SIZE, DEFAULT_MOUNT_ID, DEFAULT_DEV_HOST, DEFAULT_ASSET_PREFIX, DEFAULT_WEB_BROWSERSLIST, DEFAULT_BROWSERSLIST, HTML_REGEX, JS_REGEX, SCRIPT_REGEX, CSS_REGEX, NODE_MODULES_REGEX, PLUGIN_SWC_NAME, PLUGIN_CSS_NAME, FONT_EXTENSIONS, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS, AUDIO_EXTENSIONS;
3142
+ var init_constants = __esm({
3143
+ "src/constants.ts"() {
3144
+ "use strict";
3145
+ import_node_path = require("path");
3146
+ ROOT_DIST_DIR = "dist";
3147
+ HTML_DIST_DIR = "./";
3148
+ JS_DIST_DIR = "static/js";
3149
+ CSS_DIST_DIR = "static/css";
3150
+ SVG_DIST_DIR = "static/svg";
3151
+ FONT_DIST_DIR = "static/font";
3152
+ WASM_DIST_DIR = "static/wasm";
3153
+ IMAGE_DIST_DIR = "static/image";
3154
+ MEDIA_DIST_DIR = "static/media";
3155
+ LOADER_PATH = (0, import_node_path.join)(__dirname);
3156
+ STATIC_PATH = (0, import_node_path.join)(__dirname, "../static");
3157
+ COMPILED_PATH = (0, import_node_path.join)(__dirname, "../compiled");
3158
+ TS_CONFIG_FILE = "tsconfig.json";
3159
+ HMR_SOCKET_PATH = "/rsbuild-hmr";
3160
+ RSBUILD_OUTPUTS_PATH = ".rsbuild";
3161
+ DEFAULT_PORT = 3e3;
3162
+ DEFAULT_DATA_URL_SIZE = 4096;
3163
+ DEFAULT_MOUNT_ID = "root";
3164
+ DEFAULT_DEV_HOST = "0.0.0.0";
3165
+ DEFAULT_ASSET_PREFIX = "/";
3166
+ DEFAULT_WEB_BROWSERSLIST = [
3167
+ "chrome >= 87",
3168
+ "edge >= 88",
3169
+ "firefox >= 78",
3170
+ "safari >= 14"
3171
+ ];
3172
+ DEFAULT_BROWSERSLIST = {
3173
+ web: DEFAULT_WEB_BROWSERSLIST,
3174
+ "web-worker": DEFAULT_WEB_BROWSERSLIST,
3175
+ node: ["node >= 16"]
3176
+ };
3177
+ HTML_REGEX = /\.html$/;
3178
+ JS_REGEX = /\.(?:js|mjs|cjs|jsx)$/;
3179
+ SCRIPT_REGEX = /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/;
3180
+ CSS_REGEX = /\.css$/;
3181
+ NODE_MODULES_REGEX = /[\\/]node_modules[\\/]/;
3182
+ PLUGIN_SWC_NAME = "rsbuild:swc";
3183
+ PLUGIN_CSS_NAME = "rsbuild:css";
3184
+ FONT_EXTENSIONS = [
3185
+ "woff",
3186
+ "woff2",
3187
+ "eot",
3188
+ "ttf",
3189
+ "otf",
3190
+ "ttc"
3191
+ ];
3192
+ IMAGE_EXTENSIONS = [
3193
+ "png",
3194
+ "jpg",
3195
+ "jpeg",
3196
+ "pjpeg",
3197
+ "pjp",
3198
+ "gif",
3199
+ "bmp",
3200
+ "webp",
3201
+ "ico",
3202
+ "apng",
3203
+ "avif",
3204
+ "tif",
3205
+ "tiff",
3206
+ "jfif"
3207
+ ];
3208
+ VIDEO_EXTENSIONS = ["mp4", "webm", "ogg", "mov"];
3209
+ AUDIO_EXTENSIONS = [
3210
+ "mp3",
3211
+ "wav",
3212
+ "flac",
3213
+ "aac",
3214
+ "m4a",
3215
+ "opus"
3216
+ ];
3217
+ }
3218
+ });
3219
+
3104
3220
  // ../../node_modules/.pnpm/deepmerge@4.3.1/node_modules/deepmerge/dist/cjs.js
3105
3221
  var require_cjs = __commonJS({
3106
3222
  "../../node_modules/.pnpm/deepmerge@4.3.1/node_modules/deepmerge/dist/cjs.js"(exports, module2) {
@@ -3204,122 +3320,6 @@ var require_cjs = __commonJS({
3204
3320
  }
3205
3321
  });
3206
3322
 
3207
- // src/constants.ts
3208
- var import_node_path, ROOT_DIST_DIR, HTML_DIST_DIR, JS_DIST_DIR, CSS_DIST_DIR, SVG_DIST_DIR, FONT_DIST_DIR, WASM_DIST_DIR, IMAGE_DIST_DIR, MEDIA_DIST_DIR, LOADER_PATH, STATIC_PATH, COMPILED_PATH, TS_CONFIG_FILE, HMR_SOCKET_PATH, RSBUILD_OUTPUTS_PATH, DEFAULT_PORT, DEFAULT_DATA_URL_SIZE, DEFAULT_MOUNT_ID, DEFAULT_DEV_HOST, DEFAULT_ASSET_PREFIX, DEFAULT_WEB_BROWSERSLIST, DEFAULT_BROWSERSLIST, HTML_REGEX, JS_REGEX, SCRIPT_REGEX, CSS_REGEX, NODE_MODULES_REGEX, PLUGIN_SWC_NAME, PLUGIN_CSS_NAME, FONT_EXTENSIONS, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS, AUDIO_EXTENSIONS;
3209
- var init_constants = __esm({
3210
- "src/constants.ts"() {
3211
- "use strict";
3212
- import_node_path = require("path");
3213
- ROOT_DIST_DIR = "dist";
3214
- HTML_DIST_DIR = "./";
3215
- JS_DIST_DIR = "static/js";
3216
- CSS_DIST_DIR = "static/css";
3217
- SVG_DIST_DIR = "static/svg";
3218
- FONT_DIST_DIR = "static/font";
3219
- WASM_DIST_DIR = "static/wasm";
3220
- IMAGE_DIST_DIR = "static/image";
3221
- MEDIA_DIST_DIR = "static/media";
3222
- LOADER_PATH = (0, import_node_path.join)(__dirname);
3223
- STATIC_PATH = (0, import_node_path.join)(__dirname, "../static");
3224
- COMPILED_PATH = (0, import_node_path.join)(__dirname, "../compiled");
3225
- TS_CONFIG_FILE = "tsconfig.json";
3226
- HMR_SOCKET_PATH = "/rsbuild-hmr";
3227
- RSBUILD_OUTPUTS_PATH = ".rsbuild";
3228
- DEFAULT_PORT = 3e3;
3229
- DEFAULT_DATA_URL_SIZE = 4096;
3230
- DEFAULT_MOUNT_ID = "root";
3231
- DEFAULT_DEV_HOST = "0.0.0.0";
3232
- DEFAULT_ASSET_PREFIX = "/";
3233
- DEFAULT_WEB_BROWSERSLIST = [
3234
- "chrome >= 87",
3235
- "edge >= 88",
3236
- "firefox >= 78",
3237
- "safari >= 14"
3238
- ];
3239
- DEFAULT_BROWSERSLIST = {
3240
- web: DEFAULT_WEB_BROWSERSLIST,
3241
- "web-worker": DEFAULT_WEB_BROWSERSLIST,
3242
- node: ["node >= 16"]
3243
- };
3244
- HTML_REGEX = /\.html$/;
3245
- JS_REGEX = /\.(?:js|mjs|cjs|jsx)$/;
3246
- SCRIPT_REGEX = /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/;
3247
- CSS_REGEX = /\.css$/;
3248
- NODE_MODULES_REGEX = /[\\/]node_modules[\\/]/;
3249
- PLUGIN_SWC_NAME = "rsbuild:swc";
3250
- PLUGIN_CSS_NAME = "rsbuild:css";
3251
- FONT_EXTENSIONS = [
3252
- "woff",
3253
- "woff2",
3254
- "eot",
3255
- "ttf",
3256
- "otf",
3257
- "ttc"
3258
- ];
3259
- IMAGE_EXTENSIONS = [
3260
- "png",
3261
- "jpg",
3262
- "jpeg",
3263
- "pjpeg",
3264
- "pjp",
3265
- "gif",
3266
- "bmp",
3267
- "webp",
3268
- "ico",
3269
- "apng",
3270
- "avif",
3271
- "tif",
3272
- "tiff",
3273
- "jfif"
3274
- ];
3275
- VIDEO_EXTENSIONS = ["mp4", "webm", "ogg", "mov"];
3276
- AUDIO_EXTENSIONS = [
3277
- "mp3",
3278
- "wav",
3279
- "flac",
3280
- "aac",
3281
- "m4a",
3282
- "opus"
3283
- ];
3284
- }
3285
- });
3286
-
3287
- // src/logger.ts
3288
- function getTime() {
3289
- const now = /* @__PURE__ */ new Date();
3290
- const hours = String(now.getHours()).padStart(2, "0");
3291
- const minutes = String(now.getMinutes()).padStart(2, "0");
3292
- const seconds = String(now.getSeconds()).padStart(2, "0");
3293
- return `${hours}:${minutes}:${seconds}`;
3294
- }
3295
- var import_picocolors, import_rslog, isDebug;
3296
- var init_logger = __esm({
3297
- "src/logger.ts"() {
3298
- "use strict";
3299
- import_picocolors = __toESM(require("../compiled/picocolors/index.js"));
3300
- import_rslog = require("../compiled/rslog/index.js");
3301
- isDebug = () => {
3302
- if (!process.env.DEBUG) {
3303
- return false;
3304
- }
3305
- const values = process.env.DEBUG.toLocaleLowerCase().split(",");
3306
- return ["rsbuild", "builder", "*"].some((key) => values.includes(key));
3307
- };
3308
- if (isDebug()) {
3309
- import_rslog.logger.level = "verbose";
3310
- }
3311
- import_rslog.logger.override({
3312
- debug: (message, ...args) => {
3313
- if (import_rslog.logger.level !== "verbose") {
3314
- return;
3315
- }
3316
- const time = import_picocolors.default.gray(`${getTime()}`);
3317
- console.log(` ${import_picocolors.default.magenta("rsbuild")} ${time} ${message}`, ...args);
3318
- }
3319
- });
3320
- }
3321
- });
3322
-
3323
3323
  // src/helpers/fs.ts
3324
3324
  function isEmptyDir(path21) {
3325
3325
  const files = import_node_fs.default.readdirSync(path21);
@@ -3980,12 +3980,21 @@ var init_restart = __esm({
3980
3980
  }
3981
3981
  };
3982
3982
  restartDevServer = async ({
3983
- filePath
3984
- }) => {
3985
- clearConsole();
3986
- const filename = import_node_path5.default.basename(filePath);
3987
- import_rslog.logger.info(`Restart because ${import_picocolors4.default.yellow(filename)} is changed.
3988
- `);
3983
+ filePath,
3984
+ clear = true
3985
+ } = {}) => {
3986
+ if (clear) {
3987
+ clearConsole();
3988
+ }
3989
+ if (filePath) {
3990
+ const filename = import_node_path5.default.basename(filePath);
3991
+ import_rslog.logger.info(
3992
+ `Restart server because ${import_picocolors4.default.yellow(filename)} is changed.
3993
+ `
3994
+ );
3995
+ } else {
3996
+ import_rslog.logger.info("Restarting server...\n");
3997
+ }
3989
3998
  for (const cleaner of cleaners) {
3990
3999
  await cleaner();
3991
4000
  cleaners = [];
@@ -4022,7 +4031,7 @@ function getDefaultEntry(root) {
4022
4031
  function defineConfig(config) {
4023
4032
  return config;
4024
4033
  }
4025
- async function watchFiles(files, watchOptions) {
4034
+ async function watchFilesForRestart(files, watchOptions) {
4026
4035
  if (!files.length) {
4027
4036
  return;
4028
4037
  }
@@ -4194,8 +4203,10 @@ var init_config = __esm({
4194
4203
  getDefaultDevConfig = () => ({
4195
4204
  hmr: true,
4196
4205
  liveReload: true,
4206
+ // Temporary placeholder, default: `${server.base}`
4197
4207
  assetPrefix: DEFAULT_ASSET_PREFIX,
4198
4208
  writeToDisk: false,
4209
+ cliShortcuts: false,
4199
4210
  client: {
4200
4211
  path: HMR_SOCKET_PATH,
4201
4212
  port: "",
@@ -4208,6 +4219,7 @@ var init_config = __esm({
4208
4219
  port: DEFAULT_PORT,
4209
4220
  host: DEFAULT_DEV_HOST,
4210
4221
  open: false,
4222
+ base: "/",
4211
4223
  htmlFallback: "index",
4212
4224
  compress: true,
4213
4225
  printUrls: true,
@@ -4271,6 +4283,7 @@ var init_config = __esm({
4271
4283
  image: IMAGE_DIST_DIR,
4272
4284
  media: MEDIA_DIST_DIR
4273
4285
  },
4286
+ // Temporary placeholder, default: `${server.base}`
4274
4287
  assetPrefix: DEFAULT_ASSET_PREFIX,
4275
4288
  filename: {},
4276
4289
  charset: "utf8",
@@ -4315,6 +4328,16 @@ var init_config = __esm({
4315
4328
  const merged = mergeRsbuildConfig(createDefaultConfig(), config);
4316
4329
  merged.root ||= rootPath;
4317
4330
  merged.source ||= {};
4331
+ if (merged.server?.base) {
4332
+ if (config.dev?.assetPrefix === void 0) {
4333
+ merged.dev ||= {};
4334
+ merged.dev.assetPrefix = merged.server.base;
4335
+ }
4336
+ if (config.output?.assetPrefix === void 0) {
4337
+ merged.output ||= {};
4338
+ merged.output.assetPrefix = merged.server.base;
4339
+ }
4340
+ }
4318
4341
  if (!merged.source.tsconfigPath) {
4319
4342
  const tsconfigPath = (0, import_node_path6.join)(rootPath, TS_CONFIG_FILE);
4320
4343
  if (await isFileExists(tsconfigPath)) {
@@ -5982,7 +6005,7 @@ async function createContext(options, userConfig, bundlerType) {
5982
6005
  const rsbuildConfig = await withDefaultConfig(rootPath, userConfig);
5983
6006
  const cachePath = (0, import_node_path10.join)(rootPath, "node_modules", ".cache");
5984
6007
  return {
5985
- version: "1.0.9",
6008
+ version: "1.0.11",
5986
6009
  rootPath,
5987
6010
  distPath: "",
5988
6011
  cachePath,
@@ -6860,20 +6883,110 @@ var init_createCompiler = __esm({
6860
6883
  }
6861
6884
  });
6862
6885
 
6863
- // src/server/runner/asModule.ts
6864
- var import_node_vm, SYNTHETIC_MODULES_STORE, asModule;
6865
- var init_asModule = __esm({
6866
- "src/server/runner/asModule.ts"() {
6867
- "use strict";
6868
- import_node_vm = __toESM(require("vm"));
6869
- SYNTHETIC_MODULES_STORE = "__SYNTHETIC_MODULES_STORE";
6870
- asModule = async (something, context, unlinked) => {
6871
- if (something instanceof import_node_vm.default.Module) {
6872
- return something;
6886
+ // src/server/cliShortcuts.ts
6887
+ function setupCliShortcuts({
6888
+ openPage,
6889
+ closeServer,
6890
+ printUrls,
6891
+ restartServer,
6892
+ customShortcuts
6893
+ }) {
6894
+ let shortcuts = [
6895
+ {
6896
+ key: "c",
6897
+ description: `${import_picocolors9.default.bold("c + enter")} ${import_picocolors9.default.dim("clear console")}`,
6898
+ action: () => {
6899
+ console.clear();
6873
6900
  }
6874
- context[SYNTHETIC_MODULES_STORE] = context[SYNTHETIC_MODULES_STORE] || [];
6875
- const i = context[SYNTHETIC_MODULES_STORE].length;
6876
- context[SYNTHETIC_MODULES_STORE].push(something);
6901
+ },
6902
+ {
6903
+ key: "o",
6904
+ description: `${import_picocolors9.default.bold("o + enter")} ${import_picocolors9.default.dim("open in browser")}`,
6905
+ action: openPage
6906
+ },
6907
+ {
6908
+ key: "q",
6909
+ description: `${import_picocolors9.default.bold("q + enter")} ${import_picocolors9.default.dim("quit process")}`,
6910
+ action: async () => {
6911
+ try {
6912
+ await closeServer();
6913
+ } finally {
6914
+ process.exit(0);
6915
+ }
6916
+ }
6917
+ },
6918
+ restartServer ? {
6919
+ key: "r",
6920
+ description: `${import_picocolors9.default.bold("r + enter")} ${import_picocolors9.default.dim("restart server")}`,
6921
+ action: restartServer
6922
+ } : null,
6923
+ {
6924
+ key: "u",
6925
+ description: `${import_picocolors9.default.bold("u + enter")} ${import_picocolors9.default.dim("show urls")}`,
6926
+ action: printUrls
6927
+ }
6928
+ ].filter(Boolean);
6929
+ if (customShortcuts) {
6930
+ shortcuts = customShortcuts(shortcuts);
6931
+ if (!Array.isArray(shortcuts)) {
6932
+ throw new Error("`dev.cliShortcuts` must return an array of shortcuts.");
6933
+ }
6934
+ }
6935
+ import_rslog.logger.log(
6936
+ ` ➜ ${import_picocolors9.default.dim("press")} ${import_picocolors9.default.bold("h + enter")} ${import_picocolors9.default.dim("to show shortcuts")}
6937
+ `
6938
+ );
6939
+ const rl = import_node_readline.default.createInterface({
6940
+ input: process.stdin
6941
+ });
6942
+ rl.on("line", (input) => {
6943
+ if (input === "h") {
6944
+ let message = `
6945
+ ${import_picocolors9.default.bold(import_picocolors9.default.blue("Shortcuts:"))}
6946
+ `;
6947
+ for (const shortcut of shortcuts) {
6948
+ message += ` ${shortcut.description}
6949
+ `;
6950
+ }
6951
+ import_rslog.logger.log(message);
6952
+ }
6953
+ for (const shortcut of shortcuts) {
6954
+ if (input === shortcut.key) {
6955
+ shortcut.action();
6956
+ return;
6957
+ }
6958
+ }
6959
+ });
6960
+ onBeforeRestartServer(() => {
6961
+ rl.close();
6962
+ });
6963
+ }
6964
+ var import_node_readline, import_picocolors9, isCliShortcutsEnabled;
6965
+ var init_cliShortcuts = __esm({
6966
+ "src/server/cliShortcuts.ts"() {
6967
+ "use strict";
6968
+ import_node_readline = __toESM(require("readline"));
6969
+ import_picocolors9 = __toESM(require("../compiled/picocolors/index.js"));
6970
+ init_logger();
6971
+ init_restart();
6972
+ isCliShortcutsEnabled = (devConfig) => devConfig.cliShortcuts && process.stdin.isTTY && !process.env.CI;
6973
+ }
6974
+ });
6975
+
6976
+ // src/server/runner/asModule.ts
6977
+ var import_node_vm, SYNTHETIC_MODULES_STORE, asModule;
6978
+ var init_asModule = __esm({
6979
+ "src/server/runner/asModule.ts"() {
6980
+ "use strict";
6981
+ import_node_vm = __toESM(require("vm"));
6982
+ SYNTHETIC_MODULES_STORE = "__SYNTHETIC_MODULES_STORE";
6983
+ asModule = async (something, context, unlinked) => {
6984
+ if (something instanceof import_node_vm.default.Module) {
6985
+ return something;
6986
+ }
6987
+ context[SYNTHETIC_MODULES_STORE] = context[SYNTHETIC_MODULES_STORE] || [];
6988
+ const i = context[SYNTHETIC_MODULES_STORE].length;
6989
+ context[SYNTHETIC_MODULES_STORE].push(something);
6877
6990
  const code = [.../* @__PURE__ */ new Set(["default", ...Object.keys(something)])].map(
6878
6991
  (name) => `const _${name} = ${SYNTHETIC_MODULES_STORE}[${i}]${name === "default" ? "" : `[${JSON.stringify(name)}]`}; export { _${name} as ${name}};`
6879
6992
  ).join("\n");
@@ -7279,123 +7392,471 @@ var init_environment = __esm({
7279
7392
  }
7280
7393
  });
7281
7394
 
7282
- // src/server/middlewares.ts
7283
- var import_node_path16, import_picocolors9, faviconFallbackMiddleware, getStatusCodeColor, getRequestLoggerMiddleware, notFoundMiddleware, isFileExists2, maybeHTMLRequest, postfixRE, getUrlPathname, getHtmlCompletionMiddleware, getHtmlFallbackMiddleware;
7284
- var init_middlewares = __esm({
7285
- "src/server/middlewares.ts"() {
7395
+ // src/server/helper.ts
7396
+ function getURLMessages(urls, routes) {
7397
+ if (routes.length === 1) {
7398
+ return urls.map(({ label, url: url2 }) => {
7399
+ const pathname = normalizeUrl(`${url2}${routes[0].pathname}`);
7400
+ const prefix = `➜ ${import_picocolors10.default.dim(label.padEnd(10))}`;
7401
+ return ` ${prefix}${import_picocolors10.default.cyan(pathname)}
7402
+ `;
7403
+ }).join("");
7404
+ }
7405
+ let message = "";
7406
+ const maxNameLength = Math.max(...routes.map((r) => r.entryName.length));
7407
+ urls.forEach(({ label, url: url2 }, index) => {
7408
+ if (index > 0) {
7409
+ message += "\n";
7410
+ }
7411
+ message += ` ${`➜ ${label}`}
7412
+ `;
7413
+ for (const r of routes) {
7414
+ message += ` ${import_picocolors10.default.dim("-")} ${import_picocolors10.default.dim(
7415
+ r.entryName.padEnd(maxNameLength + 4)
7416
+ )}${import_picocolors10.default.cyan(normalizeUrl(`${url2}${r.pathname}`))}
7417
+ `;
7418
+ }
7419
+ });
7420
+ return message;
7421
+ }
7422
+ function printServerURLs({
7423
+ urls: originalUrls,
7424
+ port,
7425
+ routes,
7426
+ protocol,
7427
+ printUrls,
7428
+ trailingLineBreak = true
7429
+ }) {
7430
+ if (printUrls === false) {
7431
+ return null;
7432
+ }
7433
+ let urls = originalUrls;
7434
+ if (isFunction(printUrls)) {
7435
+ const newUrls = printUrls({
7436
+ urls: urls.map((item) => item.url),
7437
+ port,
7438
+ routes,
7439
+ protocol
7440
+ });
7441
+ if (!newUrls) {
7442
+ return null;
7443
+ }
7444
+ if (!Array.isArray(newUrls)) {
7445
+ throw new Error(
7446
+ `"server.printUrls" must return an array, but got ${typeof newUrls}.`
7447
+ );
7448
+ }
7449
+ urls = newUrls.map((url2) => ({
7450
+ url: url2,
7451
+ label: getUrlLabel(url2)
7452
+ }));
7453
+ }
7454
+ if (urls.length === 0 || routes.length === 0) {
7455
+ return null;
7456
+ }
7457
+ let message = getURLMessages(urls, routes);
7458
+ if (trailingLineBreak === false && message.endsWith("\n")) {
7459
+ message = message.slice(0, -1);
7460
+ }
7461
+ import_rslog.logger.log(message);
7462
+ return message;
7463
+ }
7464
+ function getServerTerminator(server) {
7465
+ let listened = false;
7466
+ const pendingSockets = /* @__PURE__ */ new Set();
7467
+ const onConnection = (socket) => {
7468
+ pendingSockets.add(socket);
7469
+ socket.on("close", () => {
7470
+ pendingSockets.delete(socket);
7471
+ });
7472
+ };
7473
+ server.on("connection", onConnection);
7474
+ server.on("secureConnection", onConnection);
7475
+ server.once("listening", () => {
7476
+ listened = true;
7477
+ });
7478
+ return () => new Promise((resolve2, reject) => {
7479
+ for (const socket of pendingSockets) {
7480
+ socket.destroy();
7481
+ }
7482
+ if (listened) {
7483
+ server.close((err) => err ? reject(err) : resolve2());
7484
+ } else {
7485
+ resolve2();
7486
+ }
7487
+ });
7488
+ }
7489
+ var import_node_net, import_node_os, import_node_path16, import_picocolors10, normalizeUrl, formatPrefix, joinUrlSegments, stripBase, getRoutes, formatRoutes, getPort, getServerConfig, getIpv4Interfaces, isLoopbackHost, getHostInUrl, concatUrl, LOCAL_LABEL, NETWORK_LABEL, getUrlLabel, getAddressUrls, COMPILATION_ID_REGEX, getCompilationId;
7490
+ var init_helper = __esm({
7491
+ "src/server/helper.ts"() {
7286
7492
  "use strict";
7287
- import_node_path16 = __toESM(require("path"));
7288
- import_picocolors9 = __toESM(require("../compiled/picocolors/index.js"));
7493
+ import_node_net = __toESM(require("net"));
7494
+ import_node_os = __toESM(require("os"));
7495
+ import_node_path16 = require("path");
7496
+ import_picocolors10 = __toESM(require("../compiled/picocolors/index.js"));
7497
+ init_constants();
7498
+ init_helpers();
7289
7499
  init_logger();
7290
- faviconFallbackMiddleware = (req, res, next) => {
7291
- if (req.url === "/favicon.ico") {
7292
- res.statusCode = 204;
7293
- res.end();
7294
- } else {
7295
- next();
7296
- }
7297
- };
7298
- getStatusCodeColor = (status) => {
7299
- if (status >= 500) {
7300
- return import_picocolors9.default.red;
7301
- }
7302
- if (status >= 400) {
7303
- return import_picocolors9.default.yellow;
7304
- }
7305
- if (status >= 300) {
7306
- return import_picocolors9.default.cyan;
7500
+ normalizeUrl = (url2) => url2.replace(/([^:]\/)\/+/g, "$1");
7501
+ formatPrefix = (input) => {
7502
+ let prefix = input;
7503
+ if (prefix?.startsWith("./")) {
7504
+ prefix = prefix.replace("./", "");
7307
7505
  }
7308
- if (status >= 200) {
7309
- return import_picocolors9.default.green;
7506
+ if (!prefix) {
7507
+ return "/";
7310
7508
  }
7311
- return (res) => res;
7312
- };
7313
- getRequestLoggerMiddleware = async () => {
7314
- const { default: onFinished } = await import("../compiled/on-finished/index.js");
7315
- return (req, res, next) => {
7316
- const _startAt = process.hrtime();
7317
- const logRequest = () => {
7318
- const method = req.method;
7319
- const url2 = req.originalUrl || req.url;
7320
- const status = Number(res.statusCode);
7321
- const statusColor = getStatusCodeColor(status);
7322
- const endAt = process.hrtime();
7323
- const totalTime = (endAt[0] - _startAt[0]) * 1e3 + (endAt[1] - _startAt[1]) * 1e-6;
7324
- import_rslog.logger.debug(
7325
- `${statusColor(status)} ${method} ${import_picocolors9.default.gray(url2)} ${import_picocolors9.default.gray(
7326
- `${totalTime.toFixed(3)} ms`
7327
- )}`
7328
- );
7329
- };
7330
- onFinished(res, logRequest);
7331
- next();
7332
- };
7509
+ const hasLeadingSlash = prefix.startsWith("/");
7510
+ const hasTailSlash = prefix.endsWith("/");
7511
+ return `${hasLeadingSlash ? "" : "/"}${prefix}${hasTailSlash ? "" : "/"}`;
7333
7512
  };
7334
- notFoundMiddleware = (_req, res, _next) => {
7335
- res.statusCode = 404;
7336
- res.end();
7513
+ joinUrlSegments = (s1, s2) => {
7514
+ if (!s1 || !s2) {
7515
+ return s1 || s2 || "";
7516
+ }
7517
+ return addTrailingSlash(s1) + removeLeadingSlash(s2);
7337
7518
  };
7338
- isFileExists2 = async (filePath, outputFileSystem) => new Promise((resolve2) => {
7339
- outputFileSystem.stat(filePath, (_error, stats) => {
7340
- resolve2(stats?.isFile());
7341
- });
7342
- });
7343
- maybeHTMLRequest = (req) => {
7344
- if (
7345
- // require headers and url
7346
- !req.url || !req.headers || // only accept GET or HEAD
7347
- req.method !== "GET" && req.method !== "HEAD"
7348
- ) {
7349
- return false;
7519
+ stripBase = (path21, base) => {
7520
+ if (path21 === base) {
7521
+ return "/";
7350
7522
  }
7351
- const { accept } = req.headers;
7352
- return typeof accept === "string" && (accept.includes("text/html") || accept.includes("*/*"));
7523
+ const trailingSlashBase = addTrailingSlash(base);
7524
+ return path21.startsWith(trailingSlashBase) ? path21.slice(trailingSlashBase.length - 1) : path21;
7353
7525
  };
7354
- postfixRE = /[?#].*$/;
7355
- getUrlPathname = (url2) => {
7356
- return url2.replace(postfixRE, "");
7526
+ getRoutes = (context) => {
7527
+ return Object.values(context.environments).reduce(
7528
+ (prev, environmentContext) => {
7529
+ const { distPath, config } = environmentContext;
7530
+ const distPrefix = import_node_path16.posix.relative(context.distPath, distPath);
7531
+ const routes = formatRoutes(
7532
+ environmentContext.htmlPaths,
7533
+ context.normalizedConfig.server.base,
7534
+ import_node_path16.posix.join(distPrefix, config.output.distPath.html),
7535
+ config.html.outputStructure
7536
+ );
7537
+ return prev.concat(...routes);
7538
+ },
7539
+ []
7540
+ );
7357
7541
  };
7358
- getHtmlCompletionMiddleware = ({ distPath, callback, outputFileSystem }) => {
7359
- return async (req, res, next) => {
7360
- if (!maybeHTMLRequest(req)) {
7361
- return next();
7362
- }
7363
- const url2 = req.url;
7364
- const pathname = getUrlPathname(url2);
7365
- const rewrite = (newUrl) => {
7366
- req.url = newUrl;
7367
- return callback(req, res, (...args) => {
7368
- next(...args);
7369
- });
7542
+ formatRoutes = (entry, base, distPathPrefix, outputStructure) => {
7543
+ const prefix = joinUrlSegments(base, formatPrefix(distPathPrefix));
7544
+ return Object.keys(entry).map((entryName) => {
7545
+ const isIndex = entryName === "index" && outputStructure !== "nested";
7546
+ const displayName = isIndex ? "" : entryName;
7547
+ return {
7548
+ entryName,
7549
+ pathname: prefix + displayName
7370
7550
  };
7371
- if (pathname.endsWith("/")) {
7372
- const newUrl = `${pathname}index.html`;
7373
- const filePath = import_node_path16.default.join(distPath, newUrl);
7374
- if (await isFileExists2(filePath, outputFileSystem)) {
7375
- return rewrite(newUrl);
7376
- }
7377
- } else if (!import_node_path16.default.extname(pathname)) {
7378
- const newUrl = `${pathname}.html`;
7379
- const filePath = import_node_path16.default.join(distPath, newUrl);
7380
- if (await isFileExists2(filePath, outputFileSystem)) {
7381
- return rewrite(newUrl);
7382
- }
7383
- }
7384
- next();
7385
- };
7551
+ }).sort((a) => a.entryName === "index" ? -1 : 1);
7386
7552
  };
7387
- getHtmlFallbackMiddleware = ({ htmlFallback, distPath, callback, outputFileSystem }) => {
7388
- return async (req, res, next) => {
7389
- if (!maybeHTMLRequest(req) || "/favicon.ico" === req.url || htmlFallback !== "index") {
7390
- return next();
7391
- }
7392
- const filePath = import_node_path16.default.join(distPath, "index.html");
7553
+ getPort = async ({
7554
+ host,
7555
+ port,
7556
+ strictPort,
7557
+ tryLimits = 20
7558
+ }) => {
7559
+ if (typeof port === "string") {
7560
+ port = Number.parseInt(port, 10);
7561
+ }
7562
+ if (strictPort) {
7563
+ tryLimits = 1;
7564
+ }
7565
+ const original = port;
7566
+ let found = false;
7567
+ let attempts = 0;
7568
+ while (!found && attempts <= tryLimits) {
7569
+ try {
7570
+ await new Promise((resolve2, reject) => {
7571
+ const server = import_node_net.default.createServer();
7572
+ server.unref();
7573
+ server.on("error", reject);
7574
+ server.listen({ port, host }, () => {
7575
+ found = true;
7576
+ server.close(resolve2);
7577
+ });
7578
+ });
7579
+ } catch (e) {
7580
+ if (e.code !== "EADDRINUSE") {
7581
+ throw e;
7582
+ }
7583
+ port++;
7584
+ attempts++;
7585
+ }
7586
+ }
7587
+ if (port !== original) {
7588
+ if (strictPort) {
7589
+ throw new Error(
7590
+ `Port "${original}" is occupied, please choose another one.`
7591
+ );
7592
+ }
7593
+ }
7594
+ return port;
7595
+ };
7596
+ getServerConfig = async ({
7597
+ config
7598
+ }) => {
7599
+ const host = config.server.host || DEFAULT_DEV_HOST;
7600
+ const originalPort = config.server.port || DEFAULT_PORT;
7601
+ const port = await getPort({
7602
+ host,
7603
+ port: originalPort,
7604
+ strictPort: config.server.strictPort || false
7605
+ });
7606
+ const https = Boolean(config.server.https) || false;
7607
+ const portTip = port !== originalPort ? `Port ${originalPort} is in use, ${import_picocolors10.default.yellow(`using port ${port}.`)}` : void 0;
7608
+ return {
7609
+ port,
7610
+ host,
7611
+ https,
7612
+ portTip
7613
+ };
7614
+ };
7615
+ getIpv4Interfaces = () => {
7616
+ const interfaces = import_node_os.default.networkInterfaces();
7617
+ const ipv4Interfaces = /* @__PURE__ */ new Map();
7618
+ for (const key of Object.keys(interfaces)) {
7619
+ for (const detail of interfaces[key]) {
7620
+ const familyV4Value = typeof detail.family === "string" ? "IPv4" : 4;
7621
+ if (detail.family === familyV4Value && !ipv4Interfaces.has(detail.address)) {
7622
+ ipv4Interfaces.set(detail.address, detail);
7623
+ }
7624
+ }
7625
+ }
7626
+ return Array.from(ipv4Interfaces.values());
7627
+ };
7628
+ isLoopbackHost = (host) => {
7629
+ const loopbackHosts = [
7630
+ "localhost",
7631
+ "127.0.0.1",
7632
+ "::1",
7633
+ "0000:0000:0000:0000:0000:0000:0000:0001"
7634
+ ];
7635
+ return loopbackHosts.includes(host);
7636
+ };
7637
+ getHostInUrl = (host) => {
7638
+ if (import_node_net.default.isIPv6(host)) {
7639
+ return host === "::" ? "[::1]" : `[${host}]`;
7640
+ }
7641
+ return host;
7642
+ };
7643
+ concatUrl = ({
7644
+ host,
7645
+ port,
7646
+ protocol
7647
+ }) => `${protocol}://${host}:${port}`;
7648
+ LOCAL_LABEL = "Local: ";
7649
+ NETWORK_LABEL = "Network: ";
7650
+ getUrlLabel = (url2) => {
7651
+ try {
7652
+ const { host } = new URL(url2);
7653
+ return isLoopbackHost(host) ? LOCAL_LABEL : NETWORK_LABEL;
7654
+ } catch (err) {
7655
+ return NETWORK_LABEL;
7656
+ }
7657
+ };
7658
+ getAddressUrls = ({
7659
+ protocol = "http",
7660
+ port,
7661
+ host
7662
+ }) => {
7663
+ if (host && host !== DEFAULT_DEV_HOST) {
7664
+ return [
7665
+ {
7666
+ label: isLoopbackHost(host) ? LOCAL_LABEL : NETWORK_LABEL,
7667
+ url: concatUrl({
7668
+ port,
7669
+ host: getHostInUrl(host),
7670
+ protocol
7671
+ })
7672
+ }
7673
+ ];
7674
+ }
7675
+ const ipv4Interfaces = getIpv4Interfaces();
7676
+ const addressUrls = [];
7677
+ let hasLocalUrl = false;
7678
+ for (const detail of ipv4Interfaces) {
7679
+ if (isLoopbackHost(detail.address) || detail.internal) {
7680
+ if (hasLocalUrl) {
7681
+ continue;
7682
+ }
7683
+ addressUrls.push({
7684
+ label: LOCAL_LABEL,
7685
+ url: concatUrl({ host: "localhost", port, protocol })
7686
+ });
7687
+ hasLocalUrl = true;
7688
+ } else {
7689
+ addressUrls.push({
7690
+ label: NETWORK_LABEL,
7691
+ url: concatUrl({ host: detail.address, port, protocol })
7692
+ });
7693
+ }
7694
+ }
7695
+ return addressUrls;
7696
+ };
7697
+ COMPILATION_ID_REGEX = /[^a-zA-Z0-9_-]/g;
7698
+ getCompilationId = (compiler) => {
7699
+ const uniqueName = compiler.options.output.uniqueName ?? "";
7700
+ return `${compiler.name ?? ""}_${uniqueName.replace(COMPILATION_ID_REGEX, "_")}`;
7701
+ };
7702
+ }
7703
+ });
7704
+
7705
+ // src/server/middlewares.ts
7706
+ var import_node_path17, import_picocolors11, faviconFallbackMiddleware, getStatusCodeColor, getRequestLoggerMiddleware, notFoundMiddleware, isFileExists2, maybeHTMLRequest, postfixRE, getUrlPathname, getHtmlCompletionMiddleware, getBaseMiddleware, getHtmlFallbackMiddleware;
7707
+ var init_middlewares = __esm({
7708
+ "src/server/middlewares.ts"() {
7709
+ "use strict";
7710
+ import_node_path17 = __toESM(require("path"));
7711
+ import_picocolors11 = __toESM(require("../compiled/picocolors/index.js"));
7712
+ init_helpers();
7713
+ init_logger();
7714
+ init_helper();
7715
+ faviconFallbackMiddleware = (req, res, next) => {
7716
+ if (req.url === "/favicon.ico") {
7717
+ res.statusCode = 204;
7718
+ res.end();
7719
+ } else {
7720
+ next();
7721
+ }
7722
+ };
7723
+ getStatusCodeColor = (status) => {
7724
+ if (status >= 500) {
7725
+ return import_picocolors11.default.red;
7726
+ }
7727
+ if (status >= 400) {
7728
+ return import_picocolors11.default.yellow;
7729
+ }
7730
+ if (status >= 300) {
7731
+ return import_picocolors11.default.cyan;
7732
+ }
7733
+ if (status >= 200) {
7734
+ return import_picocolors11.default.green;
7735
+ }
7736
+ return (res) => res;
7737
+ };
7738
+ getRequestLoggerMiddleware = async () => {
7739
+ const { default: onFinished } = await import("../compiled/on-finished/index.js");
7740
+ return (req, res, next) => {
7741
+ const _startAt = process.hrtime();
7742
+ const logRequest = () => {
7743
+ const method = req.method;
7744
+ const url2 = req.originalUrl || req.url;
7745
+ const status = Number(res.statusCode);
7746
+ const statusColor = getStatusCodeColor(status);
7747
+ const endAt = process.hrtime();
7748
+ const totalTime = (endAt[0] - _startAt[0]) * 1e3 + (endAt[1] - _startAt[1]) * 1e-6;
7749
+ import_rslog.logger.debug(
7750
+ `${statusColor(status)} ${method} ${import_picocolors11.default.gray(url2)} ${import_picocolors11.default.gray(
7751
+ `${totalTime.toFixed(3)} ms`
7752
+ )}`
7753
+ );
7754
+ };
7755
+ onFinished(res, logRequest);
7756
+ next();
7757
+ };
7758
+ };
7759
+ notFoundMiddleware = (_req, res, _next) => {
7760
+ res.statusCode = 404;
7761
+ res.end();
7762
+ };
7763
+ isFileExists2 = async (filePath, outputFileSystem) => new Promise((resolve2) => {
7764
+ outputFileSystem.stat(filePath, (_error, stats) => {
7765
+ resolve2(stats?.isFile());
7766
+ });
7767
+ });
7768
+ maybeHTMLRequest = (req) => {
7769
+ if (
7770
+ // require headers and url
7771
+ !req.url || !req.headers || // only accept GET or HEAD
7772
+ req.method !== "GET" && req.method !== "HEAD"
7773
+ ) {
7774
+ return false;
7775
+ }
7776
+ const { accept } = req.headers;
7777
+ return typeof accept === "string" && (accept.includes("text/html") || accept.includes("*/*"));
7778
+ };
7779
+ postfixRE = /[?#].*$/;
7780
+ getUrlPathname = (url2) => {
7781
+ return url2.replace(postfixRE, "");
7782
+ };
7783
+ getHtmlCompletionMiddleware = ({ distPath, callback, outputFileSystem }) => {
7784
+ return async (req, res, next) => {
7785
+ if (!maybeHTMLRequest(req)) {
7786
+ return next();
7787
+ }
7788
+ const url2 = req.url;
7789
+ const pathname = getUrlPathname(url2);
7790
+ const rewrite = (newUrl) => {
7791
+ req.url = newUrl;
7792
+ return callback(req, res, (...args) => {
7793
+ next(...args);
7794
+ });
7795
+ };
7796
+ if (pathname.endsWith("/")) {
7797
+ const newUrl = `${pathname}index.html`;
7798
+ const filePath = import_node_path17.default.join(distPath, newUrl);
7799
+ if (await isFileExists2(filePath, outputFileSystem)) {
7800
+ return rewrite(newUrl);
7801
+ }
7802
+ } else if (!import_node_path17.default.extname(pathname)) {
7803
+ const newUrl = `${pathname}.html`;
7804
+ const filePath = import_node_path17.default.join(distPath, newUrl);
7805
+ if (await isFileExists2(filePath, outputFileSystem)) {
7806
+ return rewrite(newUrl);
7807
+ }
7808
+ }
7809
+ next();
7810
+ };
7811
+ };
7812
+ getBaseMiddleware = ({
7813
+ base
7814
+ }) => {
7815
+ return async (req, res, next) => {
7816
+ const url2 = req.url;
7817
+ const pathname = getUrlPathname(url2);
7818
+ if (pathname.startsWith(base)) {
7819
+ req.url = stripBase(url2, base);
7820
+ return next();
7821
+ }
7822
+ const redirectPath = addTrailingSlash(url2) !== base ? joinUrlSegments(base, url2) : base;
7823
+ if (pathname === "/" || pathname === "/index.html") {
7824
+ res.writeHead(302, {
7825
+ Location: redirectPath
7826
+ });
7827
+ res.end();
7828
+ return;
7829
+ }
7830
+ if (req.headers.accept?.includes("text/html")) {
7831
+ res.writeHead(404, {
7832
+ "Content-Type": "text/html"
7833
+ });
7834
+ res.end(
7835
+ `The server is configured with a base URL of ${base} - did you mean to visit <a href="${redirectPath}">${redirectPath}</a> instead?`
7836
+ );
7837
+ return;
7838
+ }
7839
+ res.writeHead(404, {
7840
+ "Content-Type": "text/plain"
7841
+ });
7842
+ res.end(
7843
+ `The server is configured with a base URL of ${base} - did you mean to visit ${redirectPath} instead?`
7844
+ );
7845
+ return;
7846
+ };
7847
+ };
7848
+ getHtmlFallbackMiddleware = ({ htmlFallback, distPath, callback, outputFileSystem }) => {
7849
+ return async (req, res, next) => {
7850
+ if (!maybeHTMLRequest(req) || "/favicon.ico" === req.url || htmlFallback !== "index") {
7851
+ return next();
7852
+ }
7853
+ const filePath = import_node_path17.default.join(distPath, "index.html");
7393
7854
  if (await isFileExists2(filePath, outputFileSystem)) {
7394
7855
  const newUrl = "/index.html";
7395
7856
  if (import_rslog.logger.level === "verbose") {
7396
7857
  import_rslog.logger.debug(
7397
- `${req.method} ${import_picocolors9.default.gray(
7398
- `${req.url} ${import_picocolors9.default.yellow("fallback")} to ${newUrl}`
7858
+ `${req.method} ${import_picocolors11.default.gray(
7859
+ `${req.url} ${import_picocolors11.default.yellow("fallback")} to ${newUrl}`
7399
7860
  )}`
7400
7861
  );
7401
7862
  }
@@ -7565,477 +8026,188 @@ var init_proxy = __esm({
7565
8026
  proxyMiddleware(req, res, next);
7566
8027
  }
7567
8028
  };
7568
- middlewares.push(middleware);
7569
- opts.ws && proxyMiddlewares.push(proxyMiddleware);
7570
- }
7571
- const handleUpgrade = (req, socket, head) => {
7572
- for (const middleware of proxyMiddlewares) {
7573
- if (typeof middleware.upgrade === "function") {
7574
- middleware.upgrade(req, socket, head);
7575
- }
7576
- }
7577
- };
7578
- return {
7579
- middlewares,
7580
- upgrade: handleUpgrade
7581
- };
7582
- };
7583
- }
7584
- });
7585
-
7586
- // src/server/getDevMiddlewares.ts
7587
- var import_node_path17, import_node_url2, applySetupMiddlewares, applyDefaultMiddlewares, getMiddlewares;
7588
- var init_getDevMiddlewares = __esm({
7589
- "src/server/getDevMiddlewares.ts"() {
7590
- "use strict";
7591
- import_node_path17 = require("path");
7592
- import_node_url2 = __toESM(require("url"));
7593
- init_config();
7594
- init_logger();
7595
- init_middlewares();
7596
- applySetupMiddlewares = (dev, environments, compileMiddlewareAPI) => {
7597
- const setupMiddlewares = dev.setupMiddlewares || [];
7598
- const serverOptions = {
7599
- sockWrite: (type, data) => compileMiddlewareAPI?.sockWrite(type, data),
7600
- environments
7601
- };
7602
- const before = [];
7603
- const after = [];
7604
- for (const handler of setupMiddlewares) {
7605
- handler(
7606
- {
7607
- unshift: (...handlers) => before.unshift(...handlers),
7608
- push: (...handlers) => after.push(...handlers)
7609
- },
7610
- serverOptions
7611
- );
7612
- }
7613
- return { before, after };
7614
- };
7615
- applyDefaultMiddlewares = async ({
7616
- middlewares,
7617
- server,
7618
- compileMiddlewareAPI,
7619
- output,
7620
- pwd,
7621
- outputFileSystem
7622
- }) => {
7623
- const upgradeEvents = [];
7624
- if (server.compress) {
7625
- const { gzipMiddleware: gzipMiddleware2 } = await Promise.resolve().then(() => (init_gzipMiddleware(), gzipMiddleware_exports));
7626
- middlewares.push(gzipMiddleware2());
7627
- }
7628
- middlewares.push((req, res, next) => {
7629
- res.setHeader("Access-Control-Allow-Origin", "*");
7630
- const path21 = req.url ? import_node_url2.default.parse(req.url).pathname : "";
7631
- if (path21?.includes("hot-update")) {
7632
- res.setHeader("Access-Control-Allow-Credentials", "false");
7633
- }
7634
- const confHeaders = server.headers;
7635
- if (confHeaders) {
7636
- for (const [key, value] of Object.entries(confHeaders)) {
7637
- res.setHeader(key, value);
7638
- }
7639
- }
7640
- next();
7641
- });
7642
- if (server.proxy) {
7643
- const { createProxyMiddleware: createProxyMiddleware2 } = await Promise.resolve().then(() => (init_proxy(), proxy_exports));
7644
- const { middlewares: proxyMiddlewares, upgrade } = await createProxyMiddleware2(server.proxy);
7645
- upgradeEvents.push(upgrade);
7646
- for (const middleware of proxyMiddlewares) {
7647
- middlewares.push(middleware);
7648
- }
7649
- }
7650
- const { default: launchEditorMiddleware } = await import("../compiled/launch-editor-middleware/index.js");
7651
- middlewares.push(["/__open-in-editor", launchEditorMiddleware()]);
7652
- if (compileMiddlewareAPI) {
7653
- middlewares.push(compileMiddlewareAPI.middleware);
7654
- upgradeEvents.push(
7655
- compileMiddlewareAPI.onUpgrade.bind(compileMiddlewareAPI)
7656
- );
7657
- middlewares.push((req, res, next) => {
7658
- if (req.url?.endsWith(".hot-update.json") && req.method !== "OPTIONS") {
7659
- res.statusCode = 404;
7660
- res.end();
7661
- } else {
7662
- next();
7663
- }
7664
- });
7665
- }
7666
- const distPath = (0, import_node_path17.isAbsolute)(output.distPath) ? output.distPath : (0, import_node_path17.join)(pwd, output.distPath);
7667
- if (compileMiddlewareAPI) {
7668
- middlewares.push(
7669
- getHtmlCompletionMiddleware({
7670
- distPath,
7671
- callback: compileMiddlewareAPI.middleware,
7672
- outputFileSystem
7673
- })
7674
- );
7675
- }
7676
- const publicDirs = normalizePublicDirs(server?.publicDir);
7677
- for (const publicDir of publicDirs) {
7678
- const { default: sirv } = await import("../compiled/sirv/index.js");
7679
- const { name } = publicDir;
7680
- const normalizedPath = (0, import_node_path17.isAbsolute)(name) ? name : (0, import_node_path17.join)(pwd, name);
7681
- const assetMiddleware = sirv(normalizedPath, {
7682
- etag: true,
7683
- dev: true
7684
- });
7685
- middlewares.push(assetMiddleware);
7686
- }
7687
- if (compileMiddlewareAPI) {
7688
- middlewares.push(
7689
- getHtmlFallbackMiddleware({
7690
- distPath,
7691
- callback: compileMiddlewareAPI.middleware,
7692
- htmlFallback: server.htmlFallback,
7693
- outputFileSystem
7694
- })
7695
- );
7696
- }
7697
- if (server.historyApiFallback) {
7698
- const { default: connectHistoryApiFallback } = await import("../compiled/connect-history-api-fallback/index.js");
7699
- const historyApiFallbackMiddleware = connectHistoryApiFallback(
7700
- server.historyApiFallback === true ? {} : server.historyApiFallback
7701
- );
7702
- middlewares.push(historyApiFallbackMiddleware);
7703
- compileMiddlewareAPI?.middleware && middlewares.push(compileMiddlewareAPI.middleware);
7704
- }
7705
- middlewares.push(faviconFallbackMiddleware);
7706
- middlewares.push((req, res, next) => {
7707
- if (req.method === "OPTIONS") {
7708
- res.statusCode = 204;
7709
- res.setHeader("Content-Length", "0");
7710
- res.end();
7711
- return;
7712
- }
7713
- next();
7714
- });
7715
- return {
7716
- onUpgrade: (...args) => {
7717
- for (const cb of upgradeEvents) {
7718
- cb(...args);
8029
+ middlewares.push(middleware);
8030
+ opts.ws && proxyMiddlewares.push(proxyMiddleware);
8031
+ }
8032
+ const handleUpgrade = (req, socket, head) => {
8033
+ for (const middleware of proxyMiddlewares) {
8034
+ if (typeof middleware.upgrade === "function") {
8035
+ middleware.upgrade(req, socket, head);
7719
8036
  }
7720
8037
  }
7721
8038
  };
7722
- };
7723
- getMiddlewares = async (options) => {
7724
- const middlewares = [];
7725
- const { environments, compileMiddlewareAPI } = options;
7726
- if (import_rslog.logger.level === "verbose") {
7727
- middlewares.push(await getRequestLoggerMiddleware());
7728
- }
7729
- const { before, after } = applySetupMiddlewares(
7730
- options.dev,
7731
- environments,
7732
- compileMiddlewareAPI
7733
- );
7734
- middlewares.push(...before);
7735
- const { onUpgrade } = await applyDefaultMiddlewares({
7736
- ...options,
7737
- middlewares
7738
- });
7739
- middlewares.push(...after);
7740
8039
  return {
7741
- close: async () => {
7742
- compileMiddlewareAPI?.close();
7743
- },
7744
- onUpgrade,
7745
- middlewares
8040
+ middlewares,
8041
+ upgrade: handleUpgrade
7746
8042
  };
7747
8043
  };
7748
8044
  }
7749
8045
  });
7750
8046
 
7751
- // src/server/helper.ts
7752
- function getURLMessages(urls, routes) {
7753
- if (routes.length === 1) {
7754
- return urls.map(
7755
- ({ label, url: url2 }) => ` ${`➜ ${label.padEnd(10)}`}${import_picocolors10.default.cyan(
7756
- normalizeUrl(`${url2}${routes[0].pathname}`)
7757
- )}
7758
- `
7759
- ).join("");
7760
- }
7761
- let message = "";
7762
- const maxNameLength = Math.max(...routes.map((r) => r.entryName.length));
7763
- urls.forEach(({ label, url: url2 }, index) => {
7764
- if (index > 0) {
7765
- message += "\n";
7766
- }
7767
- message += ` ${`➜ ${label}`}
7768
- `;
7769
- for (const r of routes) {
7770
- message += ` ${import_picocolors10.default.dim("-")} ${import_picocolors10.default.dim(
7771
- r.entryName.padEnd(maxNameLength + 4)
7772
- )}${import_picocolors10.default.cyan(normalizeUrl(`${url2}${r.pathname}`))}
7773
- `;
7774
- }
7775
- });
7776
- return message;
7777
- }
7778
- function printServerURLs({
7779
- urls: originalUrls,
7780
- port,
7781
- routes,
7782
- protocol,
7783
- printUrls
7784
- }) {
7785
- if (printUrls === false) {
7786
- return null;
7787
- }
7788
- let urls = originalUrls;
7789
- if (isFunction(printUrls)) {
7790
- const newUrls = printUrls({
7791
- urls: urls.map((item) => item.url),
7792
- port,
7793
- routes,
7794
- protocol
7795
- });
7796
- if (!newUrls) {
7797
- return null;
7798
- }
7799
- if (!Array.isArray(newUrls)) {
7800
- throw new Error(
7801
- `"server.printUrls" must return an array, but got ${typeof newUrls}.`
7802
- );
7803
- }
7804
- urls = newUrls.map((url2) => ({
7805
- url: url2,
7806
- label: getUrlLabel(url2)
7807
- }));
7808
- }
7809
- if (urls.length === 0 || routes.length === 0) {
7810
- return null;
7811
- }
7812
- const message = getURLMessages(urls, routes);
7813
- import_rslog.logger.log(message);
7814
- return message;
7815
- }
7816
- function getServerTerminator(server) {
7817
- let listened = false;
7818
- const pendingSockets = /* @__PURE__ */ new Set();
7819
- const onConnection = (socket) => {
7820
- pendingSockets.add(socket);
7821
- socket.on("close", () => {
7822
- pendingSockets.delete(socket);
7823
- });
7824
- };
7825
- server.on("connection", onConnection);
7826
- server.on("secureConnection", onConnection);
7827
- server.once("listening", () => {
7828
- listened = true;
7829
- });
7830
- return () => new Promise((resolve2, reject) => {
7831
- for (const socket of pendingSockets) {
7832
- socket.destroy();
7833
- }
7834
- if (listened) {
7835
- server.close((err) => err ? reject(err) : resolve2());
7836
- } else {
7837
- resolve2();
7838
- }
7839
- });
7840
- }
7841
- var import_node_net, import_node_os, import_node_path18, import_picocolors10, normalizeUrl, formatPrefix, getRoutes, formatRoutes, getPort, getServerConfig, getIpv4Interfaces, isLoopbackHost, getHostInUrl, concatUrl, LOCAL_LABEL, NETWORK_LABEL, getUrlLabel, getAddressUrls, COMPILATION_ID_REGEX, getCompilationId;
7842
- var init_helper = __esm({
7843
- "src/server/helper.ts"() {
8047
+ // src/server/getDevMiddlewares.ts
8048
+ var import_node_path18, import_node_url2, applySetupMiddlewares, applyDefaultMiddlewares, getMiddlewares;
8049
+ var init_getDevMiddlewares = __esm({
8050
+ "src/server/getDevMiddlewares.ts"() {
7844
8051
  "use strict";
7845
- import_node_net = __toESM(require("net"));
7846
- import_node_os = __toESM(require("os"));
7847
8052
  import_node_path18 = require("path");
7848
- import_picocolors10 = __toESM(require("../compiled/picocolors/index.js"));
7849
- init_constants();
7850
- init_helpers();
8053
+ import_node_url2 = __toESM(require("url"));
8054
+ init_config();
7851
8055
  init_logger();
7852
- normalizeUrl = (url2) => url2.replace(/([^:]\/)\/+/g, "$1");
7853
- formatPrefix = (input) => {
7854
- let prefix = input;
7855
- if (prefix?.startsWith("./")) {
7856
- prefix = prefix.replace("./", "");
7857
- }
7858
- if (!prefix) {
7859
- return "/";
8056
+ init_middlewares();
8057
+ applySetupMiddlewares = (dev, environments, compileMiddlewareAPI) => {
8058
+ const setupMiddlewares = dev.setupMiddlewares || [];
8059
+ const serverOptions = {
8060
+ sockWrite: (type, data) => compileMiddlewareAPI?.sockWrite(type, data),
8061
+ environments
8062
+ };
8063
+ const before = [];
8064
+ const after = [];
8065
+ for (const handler of setupMiddlewares) {
8066
+ handler(
8067
+ {
8068
+ unshift: (...handlers) => before.unshift(...handlers),
8069
+ push: (...handlers) => after.push(...handlers)
8070
+ },
8071
+ serverOptions
8072
+ );
7860
8073
  }
7861
- const hasLeadingSlash = prefix.startsWith("/");
7862
- const hasTailSlash = prefix.endsWith("/");
7863
- return `${hasLeadingSlash ? "" : "/"}${prefix}${hasTailSlash ? "" : "/"}`;
7864
- };
7865
- getRoutes = (context) => {
7866
- return Object.values(context.environments).reduce(
7867
- (prev, environmentContext) => {
7868
- const { distPath, config } = environmentContext;
7869
- const distPrefix = import_node_path18.posix.relative(context.distPath, distPath);
7870
- const routes = formatRoutes(
7871
- environmentContext.htmlPaths,
7872
- import_node_path18.posix.join(distPrefix, config.output.distPath.html),
7873
- config.html.outputStructure
7874
- );
7875
- return prev.concat(...routes);
7876
- },
7877
- []
7878
- );
7879
- };
7880
- formatRoutes = (entry, prefix, outputStructure) => {
7881
- const formattedPrefix = formatPrefix(prefix);
7882
- return Object.keys(entry).map((entryName) => {
7883
- const isIndex = entryName === "index" && outputStructure !== "nested";
7884
- const displayName = isIndex ? "" : entryName;
7885
- return {
7886
- entryName,
7887
- pathname: formattedPrefix + displayName
7888
- };
7889
- }).sort((a) => a.entryName === "index" ? -1 : 1);
8074
+ return { before, after };
7890
8075
  };
7891
- getPort = async ({
7892
- host,
7893
- port,
7894
- strictPort,
7895
- tryLimits = 20
8076
+ applyDefaultMiddlewares = async ({
8077
+ middlewares,
8078
+ server,
8079
+ compileMiddlewareAPI,
8080
+ output,
8081
+ pwd,
8082
+ outputFileSystem
7896
8083
  }) => {
7897
- if (typeof port === "string") {
7898
- port = Number.parseInt(port, 10);
7899
- }
7900
- if (strictPort) {
7901
- tryLimits = 1;
7902
- }
7903
- const original = port;
7904
- let found = false;
7905
- let attempts = 0;
7906
- while (!found && attempts <= tryLimits) {
7907
- try {
7908
- await new Promise((resolve2, reject) => {
7909
- const server = import_node_net.default.createServer();
7910
- server.unref();
7911
- server.on("error", reject);
7912
- server.listen({ port, host }, () => {
7913
- found = true;
7914
- server.close(resolve2);
7915
- });
7916
- });
7917
- } catch (e) {
7918
- if (e.code !== "EADDRINUSE") {
7919
- throw e;
7920
- }
7921
- port++;
7922
- attempts++;
7923
- }
7924
- }
7925
- if (port !== original) {
7926
- if (strictPort) {
7927
- throw new Error(
7928
- `Port "${original}" is occupied, please choose another one.`
7929
- );
7930
- }
8084
+ const upgradeEvents = [];
8085
+ if (server.compress) {
8086
+ const { gzipMiddleware: gzipMiddleware2 } = await Promise.resolve().then(() => (init_gzipMiddleware(), gzipMiddleware_exports));
8087
+ middlewares.push(gzipMiddleware2());
7931
8088
  }
7932
- return port;
7933
- };
7934
- getServerConfig = async ({
7935
- config
7936
- }) => {
7937
- const host = config.server.host || DEFAULT_DEV_HOST;
7938
- const originalPort = config.server.port || DEFAULT_PORT;
7939
- const port = await getPort({
7940
- host,
7941
- port: originalPort,
7942
- strictPort: config.server.strictPort || false
7943
- });
7944
- const https = Boolean(config.server.https) || false;
7945
- const portTip = port !== originalPort ? `Port ${originalPort} is in use, ${import_picocolors10.default.yellow(`using port ${port}.`)}` : void 0;
7946
- return {
7947
- port,
7948
- host,
7949
- https,
7950
- portTip
7951
- };
7952
- };
7953
- getIpv4Interfaces = () => {
7954
- const interfaces = import_node_os.default.networkInterfaces();
7955
- const ipv4Interfaces = /* @__PURE__ */ new Map();
7956
- for (const key of Object.keys(interfaces)) {
7957
- for (const detail of interfaces[key]) {
7958
- const familyV4Value = typeof detail.family === "string" ? "IPv4" : 4;
7959
- if (detail.family === familyV4Value && !ipv4Interfaces.has(detail.address)) {
7960
- ipv4Interfaces.set(detail.address, detail);
8089
+ middlewares.push((req, res, next) => {
8090
+ res.setHeader("Access-Control-Allow-Origin", "*");
8091
+ const path21 = req.url ? import_node_url2.default.parse(req.url).pathname : "";
8092
+ if (path21?.includes("hot-update")) {
8093
+ res.setHeader("Access-Control-Allow-Credentials", "false");
8094
+ }
8095
+ const confHeaders = server.headers;
8096
+ if (confHeaders) {
8097
+ for (const [key, value] of Object.entries(confHeaders)) {
8098
+ res.setHeader(key, value);
7961
8099
  }
7962
8100
  }
8101
+ next();
8102
+ });
8103
+ if (server.proxy) {
8104
+ const { createProxyMiddleware: createProxyMiddleware2 } = await Promise.resolve().then(() => (init_proxy(), proxy_exports));
8105
+ const { middlewares: proxyMiddlewares, upgrade } = await createProxyMiddleware2(server.proxy);
8106
+ upgradeEvents.push(upgrade);
8107
+ for (const middleware of proxyMiddlewares) {
8108
+ middlewares.push(middleware);
8109
+ }
7963
8110
  }
7964
- return Array.from(ipv4Interfaces.values());
7965
- };
7966
- isLoopbackHost = (host) => {
7967
- const loopbackHosts = [
7968
- "localhost",
7969
- "127.0.0.1",
7970
- "::1",
7971
- "0000:0000:0000:0000:0000:0000:0000:0001"
7972
- ];
7973
- return loopbackHosts.includes(host);
7974
- };
7975
- getHostInUrl = (host) => {
7976
- if (import_node_net.default.isIPv6(host)) {
7977
- return host === "::" ? "[::1]" : `[${host}]`;
7978
- }
7979
- return host;
7980
- };
7981
- concatUrl = ({
7982
- host,
7983
- port,
7984
- protocol
7985
- }) => `${protocol}://${host}:${port}`;
7986
- LOCAL_LABEL = "Local: ";
7987
- NETWORK_LABEL = "Network: ";
7988
- getUrlLabel = (url2) => {
7989
- try {
7990
- const { host } = new URL(url2);
7991
- return isLoopbackHost(host) ? LOCAL_LABEL : NETWORK_LABEL;
7992
- } catch (err) {
7993
- return NETWORK_LABEL;
8111
+ if (server.base && server.base !== "/") {
8112
+ middlewares.push(getBaseMiddleware({ base: server.base }));
7994
8113
  }
7995
- };
7996
- getAddressUrls = ({
7997
- protocol = "http",
7998
- port,
7999
- host
8000
- }) => {
8001
- if (host && host !== DEFAULT_DEV_HOST) {
8002
- return [
8003
- {
8004
- label: isLoopbackHost(host) ? LOCAL_LABEL : NETWORK_LABEL,
8005
- url: concatUrl({
8006
- port,
8007
- host: getHostInUrl(host),
8008
- protocol
8009
- })
8114
+ const { default: launchEditorMiddleware } = await import("../compiled/launch-editor-middleware/index.js");
8115
+ middlewares.push(["/__open-in-editor", launchEditorMiddleware()]);
8116
+ if (compileMiddlewareAPI) {
8117
+ middlewares.push(compileMiddlewareAPI.middleware);
8118
+ upgradeEvents.push(
8119
+ compileMiddlewareAPI.onUpgrade.bind(compileMiddlewareAPI)
8120
+ );
8121
+ middlewares.push((req, res, next) => {
8122
+ if (req.url?.endsWith(".hot-update.json") && req.method !== "OPTIONS") {
8123
+ res.statusCode = 404;
8124
+ res.end();
8125
+ } else {
8126
+ next();
8010
8127
  }
8011
- ];
8128
+ });
8012
8129
  }
8013
- const ipv4Interfaces = getIpv4Interfaces();
8014
- const addressUrls = [];
8015
- let hasLocalUrl = false;
8016
- for (const detail of ipv4Interfaces) {
8017
- if (isLoopbackHost(detail.address) || detail.internal) {
8018
- if (hasLocalUrl) {
8019
- continue;
8130
+ const distPath = (0, import_node_path18.isAbsolute)(output.distPath) ? output.distPath : (0, import_node_path18.join)(pwd, output.distPath);
8131
+ if (compileMiddlewareAPI) {
8132
+ middlewares.push(
8133
+ getHtmlCompletionMiddleware({
8134
+ distPath,
8135
+ callback: compileMiddlewareAPI.middleware,
8136
+ outputFileSystem
8137
+ })
8138
+ );
8139
+ }
8140
+ const publicDirs = normalizePublicDirs(server?.publicDir);
8141
+ for (const publicDir of publicDirs) {
8142
+ const { default: sirv } = await import("../compiled/sirv/index.js");
8143
+ const { name } = publicDir;
8144
+ const normalizedPath = (0, import_node_path18.isAbsolute)(name) ? name : (0, import_node_path18.join)(pwd, name);
8145
+ const assetMiddleware = sirv(normalizedPath, {
8146
+ etag: true,
8147
+ dev: true
8148
+ });
8149
+ middlewares.push(assetMiddleware);
8150
+ }
8151
+ if (compileMiddlewareAPI) {
8152
+ middlewares.push(
8153
+ getHtmlFallbackMiddleware({
8154
+ distPath,
8155
+ callback: compileMiddlewareAPI.middleware,
8156
+ htmlFallback: server.htmlFallback,
8157
+ outputFileSystem
8158
+ })
8159
+ );
8160
+ }
8161
+ if (server.historyApiFallback) {
8162
+ const { default: connectHistoryApiFallback } = await import("../compiled/connect-history-api-fallback/index.js");
8163
+ const historyApiFallbackMiddleware = connectHistoryApiFallback(
8164
+ server.historyApiFallback === true ? {} : server.historyApiFallback
8165
+ );
8166
+ middlewares.push(historyApiFallbackMiddleware);
8167
+ compileMiddlewareAPI?.middleware && middlewares.push(compileMiddlewareAPI.middleware);
8168
+ }
8169
+ middlewares.push(faviconFallbackMiddleware);
8170
+ middlewares.push((req, res, next) => {
8171
+ if (req.method === "OPTIONS") {
8172
+ res.statusCode = 204;
8173
+ res.setHeader("Content-Length", "0");
8174
+ res.end();
8175
+ return;
8176
+ }
8177
+ next();
8178
+ });
8179
+ return {
8180
+ onUpgrade: (...args) => {
8181
+ for (const cb of upgradeEvents) {
8182
+ cb(...args);
8020
8183
  }
8021
- addressUrls.push({
8022
- label: LOCAL_LABEL,
8023
- url: concatUrl({ host: "localhost", port, protocol })
8024
- });
8025
- hasLocalUrl = true;
8026
- } else {
8027
- addressUrls.push({
8028
- label: NETWORK_LABEL,
8029
- url: concatUrl({ host: detail.address, port, protocol })
8030
- });
8031
8184
  }
8032
- }
8033
- return addressUrls;
8185
+ };
8034
8186
  };
8035
- COMPILATION_ID_REGEX = /[^a-zA-Z0-9_-]/g;
8036
- getCompilationId = (compiler) => {
8037
- const uniqueName = compiler.options.output.uniqueName ?? "";
8038
- return `${compiler.name ?? ""}_${uniqueName.replace(COMPILATION_ID_REGEX, "_")}`;
8187
+ getMiddlewares = async (options) => {
8188
+ const middlewares = [];
8189
+ const { environments, compileMiddlewareAPI } = options;
8190
+ if (import_rslog.logger.level === "verbose") {
8191
+ middlewares.push(await getRequestLoggerMiddleware());
8192
+ }
8193
+ const { before, after } = applySetupMiddlewares(
8194
+ options.dev,
8195
+ environments,
8196
+ compileMiddlewareAPI
8197
+ );
8198
+ middlewares.push(...before);
8199
+ const { onUpgrade } = await applyDefaultMiddlewares({
8200
+ ...options,
8201
+ middlewares
8202
+ });
8203
+ middlewares.push(...after);
8204
+ return {
8205
+ close: async () => {
8206
+ compileMiddlewareAPI?.close();
8207
+ },
8208
+ onUpgrade,
8209
+ middlewares
8210
+ };
8039
8211
  };
8040
8212
  }
8041
8213
  });
@@ -8216,7 +8388,7 @@ async function setupWatchFiles(options) {
8216
8388
  if (!hmr && !liveReload || !compileMiddlewareAPI) {
8217
8389
  return;
8218
8390
  }
8219
- const devFilesWatcher = await watchDevFiles(dev, compileMiddlewareAPI);
8391
+ const closeDevFilesWatcher = await watchDevFiles(dev, compileMiddlewareAPI);
8220
8392
  const serverFilesWatcher = await watchServerFiles(
8221
8393
  server,
8222
8394
  compileMiddlewareAPI
@@ -8224,23 +8396,30 @@ async function setupWatchFiles(options) {
8224
8396
  return {
8225
8397
  async close() {
8226
8398
  await Promise.all([
8227
- devFilesWatcher?.close(),
8399
+ closeDevFilesWatcher?.(),
8228
8400
  serverFilesWatcher?.close()
8229
8401
  ]);
8230
8402
  }
8231
8403
  };
8232
8404
  }
8233
8405
  async function watchDevFiles(devConfig, compileMiddlewareAPI) {
8234
- const { watchFiles: watchFiles2 } = devConfig;
8235
- if (!watchFiles2) {
8406
+ const { watchFiles } = devConfig;
8407
+ if (!watchFiles) {
8236
8408
  return;
8237
8409
  }
8238
- const watchOptions = prepareWatchOptions(
8239
- watchFiles2.paths,
8240
- watchFiles2.options,
8241
- watchFiles2.type
8242
- );
8243
- return startWatchFiles(watchOptions, compileMiddlewareAPI);
8410
+ const watchers = [];
8411
+ for (const { paths, options, type } of castArray(watchFiles)) {
8412
+ const watchOptions = prepareWatchOptions(paths, options, type);
8413
+ const watcher = await startWatchFiles(watchOptions, compileMiddlewareAPI);
8414
+ if (watcher) {
8415
+ watchers.push(watcher);
8416
+ }
8417
+ }
8418
+ return async () => {
8419
+ for (const watcher of watchers) {
8420
+ await watcher.close();
8421
+ }
8422
+ };
8244
8423
  }
8245
8424
  function watchServerFiles(serverConfig, compileMiddlewareAPI) {
8246
8425
  const publicDirs = normalizePublicDirs(serverConfig.publicDir);
@@ -8276,6 +8455,7 @@ var init_watchFiles = __esm({
8276
8455
  "src/server/watchFiles.ts"() {
8277
8456
  "use strict";
8278
8457
  init_config();
8458
+ init_helpers();
8279
8459
  }
8280
8460
  });
8281
8461
 
@@ -8606,6 +8786,7 @@ var init_compilerDevMiddleware = __esm({
8606
8786
  "use strict";
8607
8787
  init_path();
8608
8788
  init_devMiddleware();
8789
+ init_helper();
8609
8790
  init_socketServer();
8610
8791
  noop = () => {
8611
8792
  };
@@ -8642,7 +8823,10 @@ var init_compilerDevMiddleware = __esm({
8642
8823
  });
8643
8824
  }
8644
8825
  setupDevMiddleware(devMiddleware, publicPaths) {
8645
- const { devConfig, serverConfig } = this;
8826
+ const {
8827
+ devConfig,
8828
+ serverConfig: { headers, base }
8829
+ } = this;
8646
8830
  const callbacks = {
8647
8831
  onInvalid: (compilationId) => {
8648
8832
  this.socketServer.sockWrite({
@@ -8656,7 +8840,7 @@ var init_compilerDevMiddleware = __esm({
8656
8840
  };
8657
8841
  const clientPaths = getClientPaths(devConfig);
8658
8842
  const middleware = devMiddleware({
8659
- headers: serverConfig.headers,
8843
+ headers,
8660
8844
  publicPath: "/",
8661
8845
  stats: false,
8662
8846
  callbacks,
@@ -8669,7 +8853,9 @@ var init_compilerDevMiddleware = __esm({
8669
8853
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests#weak_validation
8670
8854
  etag: "weak"
8671
8855
  });
8672
- const assetPrefixes = publicPaths.map(pathnameParse);
8856
+ const assetPrefixes = publicPaths.map(pathnameParse).map(
8857
+ (prefix) => base && base !== "/" ? stripBase(prefix, base) : prefix
8858
+ );
8673
8859
  const warp = async (req, res, next) => {
8674
8860
  const { url: url2 } = req;
8675
8861
  const assetPrefix = url2 && assetPrefixes.find((prefix) => url2.startsWith(prefix));
@@ -8751,22 +8937,47 @@ async function createDevServer(options, createCompiler2, config, {
8751
8937
  await options.context.hooks.onBeforeStartDevServer.call({
8752
8938
  environments: options.context.environments
8753
8939
  });
8754
- const printUrls = () => {
8755
- printServerURLs({
8756
- urls,
8940
+ const cliShortcutsEnabled = isCliShortcutsEnabled(devConfig);
8941
+ const printUrls = () => printServerURLs({
8942
+ urls,
8943
+ port,
8944
+ routes,
8945
+ protocol,
8946
+ printUrls: config.server.printUrls,
8947
+ trailingLineBreak: !cliShortcutsEnabled
8948
+ });
8949
+ const openPage = async () => {
8950
+ return open({
8951
+ https,
8757
8952
  port,
8758
8953
  routes,
8759
- protocol,
8760
- printUrls: config.server.printUrls
8954
+ config,
8955
+ clearCache: true
8761
8956
  });
8957
+ };
8958
+ const closeServer = async () => {
8959
+ await options.context.hooks.onCloseDevServer.call();
8960
+ await Promise.all([devMiddlewares.close(), fileWatcher?.close()]);
8961
+ };
8962
+ const beforeCreateCompiler = () => {
8963
+ printUrls();
8964
+ if (cliShortcutsEnabled) {
8965
+ setupCliShortcuts({
8966
+ openPage,
8967
+ closeServer,
8968
+ printUrls,
8969
+ restartServer: () => restartDevServer({ clear: false }),
8970
+ customShortcuts: typeof devConfig.cliShortcuts === "boolean" ? void 0 : devConfig.cliShortcuts.custom
8971
+ });
8972
+ }
8762
8973
  if (!getPortSilently && portTip) {
8763
8974
  import_rslog.logger.info(portTip);
8764
8975
  }
8765
8976
  };
8766
8977
  if (runCompile) {
8767
- options.context.hooks.onBeforeCreateCompiler.tap(printUrls);
8978
+ options.context.hooks.onBeforeCreateCompiler.tap(beforeCreateCompiler);
8768
8979
  } else {
8769
- printUrls();
8980
+ beforeCreateCompiler();
8770
8981
  }
8771
8982
  const compileMiddlewareAPI = runCompile ? await startCompile() : void 0;
8772
8983
  const fileWatcher = await setupWatchFiles({
@@ -8879,20 +9090,9 @@ async function createDevServer(options, createCompiler2, config, {
8879
9090
  connectWebSocket: ({ server }) => {
8880
9091
  server.on("upgrade", devMiddlewares.onUpgrade);
8881
9092
  },
8882
- close: async () => {
8883
- await options.context.hooks.onCloseDevServer.call();
8884
- await Promise.all([devMiddlewares.close(), fileWatcher?.close()]);
8885
- },
9093
+ close: closeServer,
8886
9094
  printUrls,
8887
- open: async () => {
8888
- return open({
8889
- https,
8890
- port,
8891
- routes,
8892
- config,
8893
- clearCache: true
8894
- });
8895
- }
9095
+ open: openPage
8896
9096
  };
8897
9097
  import_rslog.logger.debug("create dev server done");
8898
9098
  return devServerAPI;
@@ -8905,6 +9105,7 @@ var init_devServer = __esm({
8905
9105
  init_constants();
8906
9106
  init_helpers();
8907
9107
  init_logger();
9108
+ init_cliShortcuts();
8908
9109
  init_environment();
8909
9110
  init_getDevMiddlewares();
8910
9111
  init_helper();
@@ -9130,11 +9331,11 @@ var entry_exports = {};
9130
9331
  __export(entry_exports, {
9131
9332
  pluginEntry: () => pluginEntry
9132
9333
  });
9133
- var import_picocolors11, pluginEntry;
9334
+ var import_picocolors12, pluginEntry;
9134
9335
  var init_entry = __esm({
9135
9336
  "src/plugins/entry.ts"() {
9136
9337
  "use strict";
9137
- import_picocolors11 = __toESM(require("../compiled/picocolors/index.js"));
9338
+ import_picocolors12 = __toESM(require("../compiled/picocolors/index.js"));
9138
9339
  init_helpers();
9139
9340
  pluginEntry = () => ({
9140
9341
  name: "rsbuild:entry",
@@ -9163,9 +9364,9 @@ var init_entry = __esm({
9163
9364
  api.onBeforeCreateCompiler(({ bundlerConfigs }) => {
9164
9365
  if (bundlerConfigs.every((config) => !config.entry)) {
9165
9366
  throw new Error(
9166
- `Could not find any entry module, please make sure that ${import_picocolors11.default.cyan(
9367
+ `Could not find any entry module, please make sure that ${import_picocolors12.default.cyan(
9167
9368
  "src/index.(ts|js|tsx|jsx|mjs|cjs)"
9168
- )} exists, or customize entry through the ${import_picocolors11.default.cyan(
9369
+ )} exists, or customize entry through the ${import_picocolors12.default.cyan(
9169
9370
  "source.entry"
9170
9371
  )} configuration.`
9171
9372
  );
@@ -9742,7 +9943,7 @@ function getHeader(longestFileLength, longestLabelLength, options) {
9742
9943
  }
9743
9944
  return `${prev + curLabel} `;
9744
9945
  }, " ");
9745
- return import_picocolors12.default.bold(import_picocolors12.default.blue(headerRow));
9946
+ return import_picocolors13.default.bold(import_picocolors13.default.blue(headerRow));
9746
9947
  }
9747
9948
  async function printFileSizes(options, stats, rootPath) {
9748
9949
  const logs = [];
@@ -9815,7 +10016,7 @@ async function printFileSizes(options, stats, rootPath) {
9815
10016
  const rightPadding = " ".repeat(longestLabelLength - sizeLength);
9816
10017
  sizeLabel += rightPadding;
9817
10018
  }
9818
- let fileNameLabel = import_picocolors12.default.dim(asset.folder + import_node_path23.default.sep) + coloringAssetName(asset.name);
10019
+ let fileNameLabel = import_picocolors13.default.dim(asset.folder + import_node_path23.default.sep) + coloringAssetName(asset.name);
9819
10020
  if (fileNameLength < longestFileLength) {
9820
10021
  const rightPadding = " ".repeat(longestFileLength - fileNameLength);
9821
10022
  fileNameLabel += rightPadding;
@@ -9828,15 +10029,15 @@ async function printFileSizes(options, stats, rootPath) {
9828
10029
  }
9829
10030
  }
9830
10031
  if (options.total !== false) {
9831
- const totalSizeLabel = `${import_picocolors12.default.bold(
9832
- import_picocolors12.default.blue("Total size:")
10032
+ const totalSizeLabel = `${import_picocolors13.default.bold(
10033
+ import_picocolors13.default.blue("Total size:")
9833
10034
  )} ${calcFileSize(totalSize)}`;
9834
10035
  let log = `
9835
10036
  ${totalSizeLabel}
9836
10037
  `;
9837
10038
  if (options.compressed) {
9838
- const gzippedSizeLabel = `${import_picocolors12.default.bold(
9839
- import_picocolors12.default.blue("Gzipped size:")
10039
+ const gzippedSizeLabel = `${import_picocolors13.default.bold(
10040
+ import_picocolors13.default.blue("Gzipped size:")
9840
10041
  )} ${calcFileSize(totalGzipSize)}`;
9841
10042
  log += ` ${gzippedSizeLabel}
9842
10043
  `;
@@ -9845,7 +10046,7 @@ async function printFileSizes(options, stats, rootPath) {
9845
10046
  }
9846
10047
  return logs;
9847
10048
  }
9848
- var import_node_fs7, import_node_path23, import_node_util2, import_node_zlib2, import_picocolors12, gzip, filterAsset, getAssetColor, calcFileSize, coloringAssetName, pluginFileSize;
10049
+ var import_node_fs7, import_node_path23, import_node_util2, import_node_zlib2, import_picocolors13, gzip, filterAsset, getAssetColor, calcFileSize, coloringAssetName, pluginFileSize;
9849
10050
  var init_fileSize = __esm({
9850
10051
  "src/plugins/fileSize.ts"() {
9851
10052
  "use strict";
@@ -9853,19 +10054,19 @@ var init_fileSize = __esm({
9853
10054
  import_node_path23 = __toESM(require("path"));
9854
10055
  import_node_util2 = require("util");
9855
10056
  import_node_zlib2 = __toESM(require("zlib"));
9856
- import_picocolors12 = __toESM(require("../compiled/picocolors/index.js"));
10057
+ import_picocolors13 = __toESM(require("../compiled/picocolors/index.js"));
9857
10058
  init_constants();
9858
10059
  init_logger();
9859
10060
  gzip = (0, import_node_util2.promisify)(import_node_zlib2.default.gzip);
9860
10061
  filterAsset = (asset) => !/\.map$/.test(asset) && !/\.LICENSE\.txt$/.test(asset);
9861
10062
  getAssetColor = (size) => {
9862
10063
  if (size > 300 * 1e3) {
9863
- return import_picocolors12.default.red;
10064
+ return import_picocolors13.default.red;
9864
10065
  }
9865
10066
  if (size > 100 * 1e3) {
9866
- return import_picocolors12.default.yellow;
10067
+ return import_picocolors13.default.yellow;
9867
10068
  }
9868
- return import_picocolors12.default.green;
10069
+ return import_picocolors13.default.green;
9869
10070
  };
9870
10071
  calcFileSize = (len) => {
9871
10072
  const val = len / 1e3;
@@ -9873,15 +10074,15 @@ var init_fileSize = __esm({
9873
10074
  };
9874
10075
  coloringAssetName = (assetName) => {
9875
10076
  if (JS_REGEX.test(assetName)) {
9876
- return import_picocolors12.default.cyan(assetName);
10077
+ return import_picocolors13.default.cyan(assetName);
9877
10078
  }
9878
10079
  if (CSS_REGEX.test(assetName)) {
9879
- return import_picocolors12.default.yellow(assetName);
10080
+ return import_picocolors13.default.yellow(assetName);
9880
10081
  }
9881
10082
  if (HTML_REGEX.test(assetName)) {
9882
- return import_picocolors12.default.green(assetName);
10083
+ return import_picocolors13.default.green(assetName);
9883
10084
  }
9884
- return import_picocolors12.default.magenta(assetName);
10085
+ return import_picocolors13.default.magenta(assetName);
9885
10086
  };
9886
10087
  pluginFileSize = () => ({
9887
10088
  name: "rsbuild:file-size",
@@ -9911,7 +10112,7 @@ var init_fileSize = __esm({
9911
10112
  multiStats[index],
9912
10113
  api.context.rootPath
9913
10114
  );
9914
- const name = import_picocolors12.default.green(environment.name);
10115
+ const name = import_picocolors13.default.green(environment.name);
9915
10116
  import_rslog.logger.info(`Production file sizes for ${name}:
9916
10117
  `);
9917
10118
  for (const log of statsLog) {
@@ -9934,12 +10135,12 @@ __export(cleanOutput_exports, {
9934
10135
  dedupeCleanPaths: () => dedupeCleanPaths,
9935
10136
  pluginCleanOutput: () => pluginCleanOutput
9936
10137
  });
9937
- var import_node_path24, import_picocolors13, addTrailingSep, isStrictSubdir, dedupeCleanPaths, pluginCleanOutput;
10138
+ var import_node_path24, import_picocolors14, addTrailingSep, isStrictSubdir, dedupeCleanPaths, pluginCleanOutput;
9938
10139
  var init_cleanOutput = __esm({
9939
10140
  "src/plugins/cleanOutput.ts"() {
9940
10141
  "use strict";
9941
10142
  import_node_path24 = require("path");
9942
- import_picocolors13 = __toESM(require("../compiled/picocolors/index.js"));
10143
+ import_picocolors14 = __toESM(require("../compiled/picocolors/index.js"));
9943
10144
  init_constants();
9944
10145
  init_helpers();
9945
10146
  init_logger();
@@ -9982,10 +10183,10 @@ var init_cleanOutput = __esm({
9982
10183
  "The dist path is not a subdir of root path, Rsbuild will not empty it."
9983
10184
  );
9984
10185
  import_rslog.logger.warn(
9985
- `Please set ${import_picocolors13.default.yellow("`output.cleanDistPath`")} config manually.`
10186
+ `Please set ${import_picocolors14.default.yellow("`output.cleanDistPath`")} config manually.`
9986
10187
  );
9987
- import_rslog.logger.warn(`Current root path: ${import_picocolors13.default.dim(rootPath)}`);
9988
- import_rslog.logger.warn(`Current dist path: ${import_picocolors13.default.dim(distPath)}`);
10188
+ import_rslog.logger.warn(`Current root path: ${import_picocolors14.default.dim(rootPath)}`);
10189
+ import_rslog.logger.warn(`Current dist path: ${import_picocolors14.default.dim(distPath)}`);
9989
10190
  }
9990
10191
  }
9991
10192
  if (cleanDistPath) {
@@ -10372,7 +10573,7 @@ async function getTemplate(entryName, config, rootPath) {
10372
10573
  if (!existTemplatePath.has(absolutePath)) {
10373
10574
  if (!await isFileExists(absolutePath)) {
10374
10575
  throw new Error(
10375
- `Failed to resolve HTML template, please check if the file exists: ${import_picocolors14.default.cyan(
10576
+ `Failed to resolve HTML template, please check if the file exists: ${import_picocolors15.default.cyan(
10376
10577
  absolutePath
10377
10578
  )}`
10378
10579
  );
@@ -10458,13 +10659,13 @@ function getChunks(entryName, entryValue) {
10458
10659
  }
10459
10660
  return chunks;
10460
10661
  }
10461
- var import_node_fs8, import_node_path27, import_picocolors14, getDefaultTemplateContent, existTemplatePath, getTagConfig, pluginHtml;
10662
+ var import_node_fs8, import_node_path27, import_picocolors15, getDefaultTemplateContent, existTemplatePath, getTagConfig, pluginHtml;
10462
10663
  var init_html = __esm({
10463
10664
  "src/plugins/html.ts"() {
10464
10665
  "use strict";
10465
10666
  import_node_fs8 = __toESM(require("fs"));
10466
10667
  import_node_path27 = __toESM(require("path"));
10467
- import_picocolors14 = __toESM(require("../compiled/picocolors/index.js"));
10668
+ import_picocolors15 = __toESM(require("../compiled/picocolors/index.js"));
10468
10669
  init_dist2();
10469
10670
  init_helpers();
10470
10671
  getDefaultTemplateContent = (mountId) => `<!doctype html><html><head></head><body><div id="${mountId}"></div></body></html>`;
@@ -10881,13 +11082,16 @@ var init_define = __esm({
10881
11082
  setup(api) {
10882
11083
  api.modifyBundlerChain((chain, { CHAIN_ID: CHAIN_ID2, bundler, environment }) => {
10883
11084
  const { config } = environment;
11085
+ const baseUrl = JSON.stringify(config.server.base);
11086
+ const assetPrefix = JSON.stringify(getPublicPathFromChain(chain, false));
10884
11087
  const builtinVars = {
10885
11088
  "import.meta.env.MODE": JSON.stringify(config.mode),
10886
11089
  "import.meta.env.DEV": config.mode === "development",
10887
11090
  "import.meta.env.PROD": config.mode === "production",
10888
- "process.env.ASSET_PREFIX": JSON.stringify(
10889
- getPublicPathFromChain(chain, false)
10890
- )
11091
+ "import.meta.env.BASE_URL": baseUrl,
11092
+ "import.meta.env.ASSET_PREFIX": assetPrefix,
11093
+ "process.env.BASE_URL": baseUrl,
11094
+ "process.env.ASSET_PREFIX": assetPrefix
10891
11095
  };
10892
11096
  chain.plugin(CHAIN_ID2.PLUGIN.DEFINE).use(bundler.DefinePlugin, [
10893
11097
  { ...builtinVars, ...config.source.define }
@@ -11046,25 +11250,22 @@ __export(swc_exports, {
11046
11250
  });
11047
11251
  function applyScriptCondition({
11048
11252
  rule,
11049
- chain,
11253
+ isDev,
11050
11254
  config,
11051
11255
  context,
11052
- includes,
11053
- excludes
11256
+ rsbuildTarget
11054
11257
  }) {
11055
11258
  rule.include.add({
11056
11259
  and: [context.rootPath, { not: NODE_MODULES_REGEX }]
11057
11260
  });
11058
11261
  rule.include.add(/\.(?:ts|tsx|jsx|mts|cts)$/);
11059
- const target = castArray(chain.get("target"));
11060
- const legacyTarget = ["es5", "es6", "es2015", "es2016"];
11061
- if (legacyTarget.some((item) => target.includes(item))) {
11262
+ if (rsbuildTarget === "web" && isDev) {
11062
11263
  rule.include.add(/[\\/]@rsbuild[\\/]core[\\/]dist[\\/]/);
11063
11264
  }
11064
- for (const condition of [...includes, ...config.source.include || []]) {
11265
+ for (const condition of config.source.include || []) {
11065
11266
  rule.include.add(condition);
11066
11267
  }
11067
- for (const condition of [...excludes, ...config.source.exclude || []]) {
11268
+ for (const condition of config.source.exclude || []) {
11068
11269
  rule.exclude.add(condition);
11069
11270
  }
11070
11271
  }
@@ -11139,7 +11340,7 @@ var init_swc = __esm({
11139
11340
  setup(api) {
11140
11341
  api.modifyBundlerChain({
11141
11342
  order: "pre",
11142
- handler: async (chain, { CHAIN_ID: CHAIN_ID2, target, environment }) => {
11343
+ handler: async (chain, { CHAIN_ID: CHAIN_ID2, isDev, target, environment }) => {
11143
11344
  const { config, browserslist } = environment;
11144
11345
  const cacheRoot = import_node_path31.default.join(api.context.cachePath, ".swc");
11145
11346
  const rule = chain.module.rule(CHAIN_ID2.RULE.JS).test(SCRIPT_REGEX).type("javascript/auto");
@@ -11148,11 +11349,10 @@ var init_swc = __esm({
11148
11349
  });
11149
11350
  applyScriptCondition({
11150
11351
  rule,
11151
- chain,
11352
+ isDev,
11152
11353
  config,
11153
11354
  context: api.context,
11154
- includes: [],
11155
- excludes: []
11355
+ rsbuildTarget: target
11156
11356
  });
11157
11357
  if (api.context.bundlerType === "webpack") {
11158
11358
  return;
@@ -11665,11 +11865,11 @@ var rsdoctor_exports = {};
11665
11865
  __export(rsdoctor_exports, {
11666
11866
  pluginRsdoctor: () => pluginRsdoctor
11667
11867
  });
11668
- var import_picocolors15, pluginRsdoctor;
11868
+ var import_picocolors16, pluginRsdoctor;
11669
11869
  var init_rsdoctor = __esm({
11670
11870
  "src/plugins/rsdoctor.ts"() {
11671
11871
  "use strict";
11672
- import_picocolors15 = __toESM(require("../compiled/picocolors/index.js"));
11872
+ import_picocolors16 = __toESM(require("../compiled/picocolors/index.js"));
11673
11873
  init_logger();
11674
11874
  pluginRsdoctor = () => ({
11675
11875
  name: "rsbuild:rsdoctor",
@@ -11697,7 +11897,7 @@ var init_rsdoctor = __esm({
11697
11897
  });
11698
11898
  } catch (err) {
11699
11899
  import_rslog.logger.warn(
11700
- `\`process.env.RSDOCTOR\` enabled, please install ${import_picocolors15.default.bold(import_picocolors15.default.yellow(packageName))} package.`
11900
+ `\`process.env.RSDOCTOR\` enabled, please install ${import_picocolors16.default.bold(import_picocolors16.default.yellow(packageName))} package.`
11701
11901
  );
11702
11902
  return;
11703
11903
  }
@@ -11706,7 +11906,7 @@ var init_rsdoctor = __esm({
11706
11906
  module2 = await import(packagePath);
11707
11907
  } catch (err) {
11708
11908
  import_rslog.logger.error(
11709
- `\`process.env.RSDOCTOR\` enabled, but failed to load ${import_picocolors15.default.bold(import_picocolors15.default.yellow(packageName))} module.`
11909
+ `\`process.env.RSDOCTOR\` enabled, but failed to load ${import_picocolors16.default.bold(import_picocolors16.default.yellow(packageName))} module.`
11710
11910
  );
11711
11911
  return;
11712
11912
  }
@@ -11717,7 +11917,7 @@ var init_rsdoctor = __esm({
11717
11917
  config.plugins ||= [];
11718
11918
  config.plugins.push(new module2[pluginName]());
11719
11919
  }
11720
- import_rslog.logger.info(`${import_picocolors15.default.bold(import_picocolors15.default.yellow(packageName))} enabled.`);
11920
+ import_rslog.logger.info(`${import_picocolors16.default.bold(import_picocolors16.default.yellow(packageName))} enabled.`);
11721
11921
  });
11722
11922
  }
11723
11923
  });
@@ -12848,24 +13048,44 @@ async function startProdServer(context, config, { getPortSilently } = {}) {
12848
13048
  });
12849
13049
  const protocol = https ? "https" : "http";
12850
13050
  const urls = getAddressUrls({ protocol, port, host });
12851
- printServerURLs({
13051
+ const cliShortcutsEnabled = isCliShortcutsEnabled(config.dev);
13052
+ const closeServer = async () => {
13053
+ await Promise.all([server.close(), serverTerminator()]);
13054
+ };
13055
+ const printUrls = () => printServerURLs({
12852
13056
  urls,
12853
13057
  port,
12854
13058
  routes,
12855
13059
  protocol,
12856
- printUrls: serverConfig.printUrls
13060
+ printUrls: serverConfig.printUrls,
13061
+ trailingLineBreak: !cliShortcutsEnabled
12857
13062
  });
12858
- if (portTip && !getPortSilently) {
13063
+ const openPage = async () => {
13064
+ return open({
13065
+ https,
13066
+ port,
13067
+ routes,
13068
+ config,
13069
+ clearCache: true
13070
+ });
13071
+ };
13072
+ printUrls();
13073
+ if (cliShortcutsEnabled) {
13074
+ setupCliShortcuts({
13075
+ openPage,
13076
+ closeServer,
13077
+ printUrls,
13078
+ customShortcuts: typeof config.dev.cliShortcuts === "boolean" ? void 0 : config.dev.cliShortcuts.custom
13079
+ });
13080
+ }
13081
+ if (!getPortSilently && portTip) {
12859
13082
  import_rslog.logger.info(portTip);
12860
13083
  }
12861
- const onClose = async () => {
12862
- await Promise.all([server.close(), serverTerminator()]);
12863
- };
12864
13084
  resolve2({
12865
13085
  port,
12866
13086
  urls: urls.map((item) => item.url),
12867
13087
  server: {
12868
- close: onClose
13088
+ close: closeServer
12869
13089
  }
12870
13090
  });
12871
13091
  }
@@ -12878,9 +13098,11 @@ var init_prodServer = __esm({
12878
13098
  "use strict";
12879
13099
  init_path();
12880
13100
  init_logger();
13101
+ init_cliShortcuts();
12881
13102
  init_helper();
12882
13103
  init_httpServer();
12883
13104
  init_middlewares();
13105
+ init_open();
12884
13106
  RsbuildProdServer = class {
12885
13107
  constructor(options, middlewares) {
12886
13108
  __publicField(this, "app");
@@ -12895,7 +13117,7 @@ var init_prodServer = __esm({
12895
13117
  await this.applyDefaultMiddlewares();
12896
13118
  }
12897
13119
  async applyDefaultMiddlewares() {
12898
- const { headers, proxy, historyApiFallback, compress } = this.options.serverConfig;
13120
+ const { headers, proxy, historyApiFallback, compress, base } = this.options.serverConfig;
12899
13121
  if (import_rslog.logger.level === "verbose") {
12900
13122
  this.middlewares.use(await getRequestLoggerMiddleware());
12901
13123
  }
@@ -12924,6 +13146,9 @@ var init_prodServer = __esm({
12924
13146
  }
12925
13147
  this.app.on("upgrade", upgrade);
12926
13148
  }
13149
+ if (base && base !== "/") {
13150
+ this.middlewares.use(getBaseMiddleware({ base }));
13151
+ }
12927
13152
  this.applyStaticAssetMiddleware();
12928
13153
  if (historyApiFallback) {
12929
13154
  const { default: connectHistoryApiFallback } = await import("../compiled/connect-history-api-fallback/index.js");
@@ -13067,12 +13292,30 @@ async function createRsbuild(options = {}) {
13067
13292
  rsbuildOptions,
13068
13293
  setCssExtractPlugin
13069
13294
  });
13070
- const preview = async (options2) => {
13295
+ const preview = async (options2 = {}) => {
13071
13296
  if (!getNodeEnv()) {
13072
13297
  setNodeEnv("production");
13073
13298
  }
13074
- const { startProdServer: startProdServer2 } = await Promise.resolve().then(() => (init_prodServer(), prodServer_exports));
13075
13299
  const config = await initRsbuildConfig({ context, pluginManager });
13300
+ const { distPath } = context;
13301
+ const { checkDistDir = true } = options2;
13302
+ if (checkDistDir) {
13303
+ if (!(0, import_node_fs12.existsSync)(distPath)) {
13304
+ throw new Error(
13305
+ `The output directory ${import_picocolors17.default.yellow(
13306
+ distPath
13307
+ )} does not exist, please build the project before previewing.`
13308
+ );
13309
+ }
13310
+ if (isEmptyDir(distPath)) {
13311
+ throw new Error(
13312
+ `The output directory ${import_picocolors17.default.yellow(
13313
+ distPath
13314
+ )} is empty, please build the project before previewing.`
13315
+ );
13316
+ }
13317
+ }
13318
+ const { startProdServer: startProdServer2 } = await Promise.resolve().then(() => (init_prodServer(), prodServer_exports));
13076
13319
  return startProdServer2(context, config, options2);
13077
13320
  };
13078
13321
  const build2 = (...args) => {
@@ -13154,11 +13397,13 @@ async function createRsbuild(options = {}) {
13154
13397
  }
13155
13398
  return rsbuild;
13156
13399
  }
13157
- var import_types3, getRspackProvider;
13400
+ var import_node_fs12, import_types3, import_picocolors17, getRspackProvider;
13158
13401
  var init_createRsbuild = __esm({
13159
13402
  "src/createRsbuild.ts"() {
13160
13403
  "use strict";
13404
+ import_node_fs12 = require("fs");
13161
13405
  import_types3 = require("util/types");
13406
+ import_picocolors17 = __toESM(require("../compiled/picocolors/index.js"));
13162
13407
  init_createContext();
13163
13408
  init_helpers();
13164
13409
  init_initPlugins();
@@ -13200,13 +13445,20 @@ async function init({
13200
13445
  if (configFilePath) {
13201
13446
  files.push(configFilePath);
13202
13447
  }
13203
- const { watchFiles: watchFilesConfig } = config.dev || {};
13204
- if (watchFilesConfig?.type === "reload-server") {
13205
- files.push(...castArray(watchFilesConfig.paths));
13206
- watchFiles(files, watchFilesConfig.options);
13207
- } else {
13208
- watchFiles(files);
13448
+ if (config.dev?.watchFiles) {
13449
+ for (const watchFilesConfig of castArray(config.dev.watchFiles)) {
13450
+ if (watchFilesConfig.type === "reload-page") {
13451
+ continue;
13452
+ }
13453
+ const paths = castArray(watchFilesConfig.paths);
13454
+ if (watchFilesConfig.options) {
13455
+ watchFilesForRestart(paths, watchFilesConfig.options);
13456
+ } else {
13457
+ files.push(...paths);
13458
+ }
13459
+ }
13209
13460
  }
13461
+ watchFilesForRestart(files);
13210
13462
  }
13211
13463
  const { createRsbuild: createRsbuild2 } = await Promise.resolve().then(() => (init_createRsbuild(), createRsbuild_exports));
13212
13464
  config.source ||= {};
@@ -13232,6 +13484,10 @@ async function init({
13232
13484
  config.server ||= {};
13233
13485
  config.server.port = commonOpts.port;
13234
13486
  }
13487
+ if (config.dev?.cliShortcuts === void 0) {
13488
+ config.dev ||= {};
13489
+ config.dev.cliShortcuts = true;
13490
+ }
13235
13491
  return createRsbuild2({
13236
13492
  cwd: root,
13237
13493
  rsbuildConfig: config,
@@ -13267,7 +13523,7 @@ var init_init = __esm({
13267
13523
 
13268
13524
  // src/cli/commands.ts
13269
13525
  function runCli() {
13270
- program.name("rsbuild").usage("<command> [options]").version("1.0.9");
13526
+ program.name("rsbuild").usage("<command> [options]").version("1.0.11");
13271
13527
  const devCommand = program.command("dev");
13272
13528
  const buildCommand = program.command("build");
13273
13529
  const previewCommand = program.command("preview");
@@ -13301,24 +13557,6 @@ function runCli() {
13301
13557
  previewCommand.description("preview the production build locally").action(async (options) => {
13302
13558
  try {
13303
13559
  const rsbuild = await init({ cliOptions: options });
13304
- await rsbuild?.initConfigs();
13305
- if (rsbuild) {
13306
- const { distPath } = rsbuild.context;
13307
- if (!(0, import_node_fs12.existsSync)(distPath)) {
13308
- throw new Error(
13309
- `The output directory ${import_picocolors16.default.yellow(
13310
- distPath
13311
- )} does not exist, please build the project before previewing.`
13312
- );
13313
- }
13314
- if (isEmptyDir(distPath)) {
13315
- throw new Error(
13316
- `The output directory ${import_picocolors16.default.yellow(
13317
- distPath
13318
- )} is empty, please build the project before previewing.`
13319
- );
13320
- }
13321
- }
13322
13560
  await rsbuild?.preview();
13323
13561
  } catch (err) {
13324
13562
  import_rslog.logger.error("Failed to start preview server.");
@@ -13342,14 +13580,11 @@ function runCli() {
13342
13580
  });
13343
13581
  program.parse();
13344
13582
  }
13345
- var import_node_fs12, import_picocolors16, applyCommonOptions, applyServerOptions;
13583
+ var applyCommonOptions, applyServerOptions;
13346
13584
  var init_commands = __esm({
13347
13585
  "src/cli/commands.ts"() {
13348
13586
  "use strict";
13349
- import_node_fs12 = require("fs");
13350
13587
  init_esm();
13351
- import_picocolors16 = __toESM(require("../compiled/picocolors/index.js"));
13352
- init_helpers();
13353
13588
  init_logger();
13354
13589
  init_init();
13355
13590
  applyCommonOptions = (command) => {
@@ -13386,16 +13621,25 @@ function initNodeEnv() {
13386
13621
  }
13387
13622
  function prepareCli() {
13388
13623
  initNodeEnv();
13624
+ const { enableCompileCache } = import_node_module.default;
13625
+ if (enableCompileCache && !process.env.NODE_DISABLE_COMPILE_CACHE) {
13626
+ try {
13627
+ enableCompileCache();
13628
+ } catch {
13629
+ }
13630
+ }
13389
13631
  const { npm_execpath } = process.env;
13390
13632
  if (!npm_execpath || npm_execpath.includes("npx-cli.js") || npm_execpath.includes(".bun")) {
13391
13633
  console.log();
13392
13634
  }
13393
- import_rslog.logger.greet(` ${`Rsbuild v${"1.0.9"}`}
13635
+ import_rslog.logger.greet(` ${`Rsbuild v${"1.0.11"}`}
13394
13636
  `);
13395
13637
  }
13638
+ var import_node_module;
13396
13639
  var init_prepare = __esm({
13397
13640
  "src/cli/prepare.ts"() {
13398
13641
  "use strict";
13642
+ import_node_module = __toESM(require("module"));
13399
13643
  init_logger();
13400
13644
  }
13401
13645
  });
@@ -13474,7 +13718,7 @@ init_logger();
13474
13718
  init_mergeConfig();
13475
13719
  init_helpers();
13476
13720
  init_constants();
13477
- var version = "1.0.9";
13721
+ var version = "1.0.11";
13478
13722
  // Annotate the CommonJS export names for ESM import in node:
13479
13723
  0 && (module.exports = {
13480
13724
  PLUGIN_CSS_NAME,