@4399ywkf/core 5.0.18 → 5.0.20

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/cli/index.js CHANGED
@@ -1,20 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/index.ts
4
- import { Command } from "commander";
5
- import chalk4 from "chalk";
6
4
  import { createRequire as createRequire4 } from "module";
7
- import { fileURLToPath as fileURLToPath3 } from "url";
8
5
  import { dirname as dirname3, join as join7 } from "path";
6
+ import { fileURLToPath as fileURLToPath3 } from "url";
7
+ import chalk4 from "chalk";
8
+ import { Command } from "commander";
9
9
 
10
- // src/cli/dev.ts
10
+ // src/cli/build.ts
11
11
  import { rspack as rspack3 } from "@rspack/core";
12
- import { RspackDevServer } from "@rspack/dev-server";
13
12
  import chalk2 from "chalk";
14
13
 
15
14
  // src/config/loader.ts
16
15
  import { existsSync } from "fs";
17
- import { resolve, extname } from "path";
16
+ import { extname, resolve } from "path";
18
17
  import { pathToFileURL } from "url";
19
18
  import deepmerge from "deepmerge";
20
19
 
@@ -78,12 +77,7 @@ var defaultConfig = {
78
77
  };
79
78
 
80
79
  // src/config/loader.ts
81
- var CONFIG_FILES = [
82
- "ywkf.config.ts",
83
- "ywkf.config.mts",
84
- "ywkf.config.js",
85
- "ywkf.config.mjs"
86
- ];
80
+ var CONFIG_FILES = ["ywkf.config.ts", "ywkf.config.mts", "ywkf.config.js", "ywkf.config.mjs"];
87
81
  function findConfigFile(cwd) {
88
82
  for (const file of CONFIG_FILES) {
89
83
  const configPath = resolve(cwd, file);
@@ -121,9 +115,7 @@ function mergeConfig(userConfig, baseConfig = defaultConfig) {
121
115
  async function resolveConfig(cwd) {
122
116
  const configPath = findConfigFile(cwd);
123
117
  if (!configPath) {
124
- console.warn(
125
- "\u26A0\uFE0F \u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6 (ywkf.config.ts)\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E"
126
- );
118
+ console.warn("\u26A0\uFE0F \u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6 (ywkf.config.ts)\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E");
127
119
  return {
128
120
  config: defaultConfig,
129
121
  configPath: null
@@ -145,36 +137,257 @@ function createPathResolver(cwd) {
145
137
  };
146
138
  }
147
139
 
140
+ // src/plugin/manager.ts
141
+ function createLogger(pluginName) {
142
+ const prefix = `[${pluginName}]`;
143
+ const verbose = !!process.env.DEBUG;
144
+ return {
145
+ info: (msg) => {
146
+ if (verbose) console.log(`${prefix} ${msg}`);
147
+ },
148
+ warn: (msg) => console.warn(`${prefix} ${msg}`),
149
+ error: (msg) => console.error(`${prefix} ${msg}`),
150
+ debug: (msg) => {
151
+ if (verbose) console.debug(`${prefix} ${msg}`);
152
+ }
153
+ };
154
+ }
155
+ async function resolvePlugin(pluginConfig, _cwd) {
156
+ let plugin;
157
+ let options = {};
158
+ if (typeof pluginConfig === "string") {
159
+ const module = await import(pluginConfig);
160
+ plugin = module.default || module;
161
+ } else if (Array.isArray(pluginConfig)) {
162
+ const [pluginOrName, pluginOptions] = pluginConfig;
163
+ options = pluginOptions;
164
+ if (typeof pluginOrName === "string") {
165
+ const module = await import(pluginOrName);
166
+ plugin = module.default || module;
167
+ } else {
168
+ plugin = pluginOrName;
169
+ }
170
+ } else {
171
+ plugin = pluginConfig;
172
+ }
173
+ if (typeof plugin === "function") {
174
+ plugin = plugin(options);
175
+ }
176
+ return { plugin, options };
177
+ }
178
+ var PluginManager = class {
179
+ plugins = /* @__PURE__ */ new Map();
180
+ context;
181
+ constructor(config, cwd, isDev) {
182
+ this.context = {
183
+ cwd,
184
+ isDev,
185
+ isProd: !isDev,
186
+ config,
187
+ logger: createLogger("PluginManager")
188
+ };
189
+ }
190
+ /**
191
+ * 加载并初始化所有插件
192
+ */
193
+ async loadPlugins(pluginConfigs) {
194
+ for (const pluginConfig of pluginConfigs) {
195
+ try {
196
+ const { plugin } = await resolvePlugin(pluginConfig, this.context.cwd);
197
+ if (this.plugins.has(plugin.name)) {
198
+ this.context.logger.warn(`\u63D2\u4EF6 ${plugin.name} \u5DF2\u52A0\u8F7D\uFF0C\u8DF3\u8FC7\u91CD\u590D\u52A0\u8F7D`);
199
+ continue;
200
+ }
201
+ const pluginContext = {
202
+ ...this.context,
203
+ logger: createLogger(plugin.name)
204
+ };
205
+ const hooks = await plugin.setup(pluginContext);
206
+ this.plugins.set(plugin.name, { plugin, hooks });
207
+ this.context.logger.info(`\u5DF2\u52A0\u8F7D\u63D2\u4EF6: ${plugin.name}`);
208
+ } catch (error) {
209
+ this.context.logger.error(`\u52A0\u8F7D\u63D2\u4EF6\u5931\u8D25: ${String(pluginConfig)} - ${error}`);
210
+ }
211
+ }
212
+ }
213
+ /**
214
+ * 执行 modifyRspackConfig 钩子
215
+ */
216
+ async applyRspackConfigHooks(config) {
217
+ let result = config;
218
+ for (const [name, { hooks }] of this.plugins) {
219
+ if (hooks.modifyRspackConfig) {
220
+ try {
221
+ const modified = await hooks.modifyRspackConfig(result, this.context);
222
+ if (modified) {
223
+ result = modified;
224
+ }
225
+ } catch (error) {
226
+ this.context.logger.error(`\u63D2\u4EF6 ${name} modifyRspackConfig \u6267\u884C\u5931\u8D25: ${error}`);
227
+ }
228
+ }
229
+ }
230
+ return result;
231
+ }
232
+ /**
233
+ * 执行 modifyRoutes 钩子
234
+ */
235
+ async applyRoutesHooks(routes) {
236
+ let result = routes;
237
+ for (const [name, { hooks }] of this.plugins) {
238
+ if (hooks.modifyRoutes) {
239
+ try {
240
+ const modified = await hooks.modifyRoutes(result, this.context);
241
+ if (modified) {
242
+ result = modified;
243
+ }
244
+ } catch (error) {
245
+ this.context.logger.error(`\u63D2\u4EF6 ${name} modifyRoutes \u6267\u884C\u5931\u8D25: ${error}`);
246
+ }
247
+ }
248
+ }
249
+ return result;
250
+ }
251
+ /**
252
+ * 执行 modifyAppConfig 钩子
253
+ */
254
+ applyAppConfigHooks(appConfig) {
255
+ let result = appConfig;
256
+ for (const [name, { hooks }] of this.plugins) {
257
+ if (hooks.modifyAppConfig) {
258
+ try {
259
+ const modified = hooks.modifyAppConfig(result, this.context);
260
+ if (modified) {
261
+ result = modified;
262
+ }
263
+ } catch (error) {
264
+ this.context.logger.error(`\u63D2\u4EF6 ${name} modifyAppConfig \u6267\u884C\u5931\u8D25: ${error}`);
265
+ }
266
+ }
267
+ }
268
+ return result;
269
+ }
270
+ /**
271
+ * 收集所有插件的 Provider
272
+ */
273
+ collectProviders() {
274
+ const providers = [];
275
+ for (const [name, { hooks }] of this.plugins) {
276
+ if (hooks.addProvider) {
277
+ try {
278
+ const result = hooks.addProvider(this.context);
279
+ if (Array.isArray(result)) {
280
+ providers.push(...result);
281
+ } else if (result) {
282
+ providers.push(result);
283
+ }
284
+ } catch (error) {
285
+ this.context.logger.error(`\u63D2\u4EF6 ${name} addProvider \u6267\u884C\u5931\u8D25: ${error}`);
286
+ }
287
+ }
288
+ }
289
+ return providers;
290
+ }
291
+ /**
292
+ * 执行 beforeBuild 钩子
293
+ */
294
+ async runBeforeBuild() {
295
+ for (const [name, { hooks }] of this.plugins) {
296
+ if (hooks.beforeBuild) {
297
+ try {
298
+ await hooks.beforeBuild(this.context);
299
+ } catch (error) {
300
+ this.context.logger.error(`\u63D2\u4EF6 ${name} beforeBuild \u6267\u884C\u5931\u8D25: ${error}`);
301
+ }
302
+ }
303
+ }
304
+ }
305
+ /**
306
+ * 执行 afterBuild 钩子
307
+ */
308
+ async runAfterBuild(stats) {
309
+ for (const [name, { hooks }] of this.plugins) {
310
+ if (hooks.afterBuild) {
311
+ try {
312
+ await hooks.afterBuild(this.context, stats);
313
+ } catch (error) {
314
+ this.context.logger.error(`\u63D2\u4EF6 ${name} afterBuild \u6267\u884C\u5931\u8D25: ${error}`);
315
+ }
316
+ }
317
+ }
318
+ }
319
+ /**
320
+ * 执行 beforeDevServer 钩子
321
+ */
322
+ async runBeforeDevServer() {
323
+ for (const [name, { hooks }] of this.plugins) {
324
+ if (hooks.beforeDevServer) {
325
+ try {
326
+ await hooks.beforeDevServer(this.context);
327
+ } catch (error) {
328
+ this.context.logger.error(`\u63D2\u4EF6 ${name} beforeDevServer \u6267\u884C\u5931\u8D25: ${error}`);
329
+ }
330
+ }
331
+ }
332
+ }
333
+ /**
334
+ * 执行 afterDevServer 钩子
335
+ */
336
+ async runAfterDevServer(server) {
337
+ for (const [name, { hooks }] of this.plugins) {
338
+ if (hooks.afterDevServer) {
339
+ try {
340
+ await hooks.afterDevServer(this.context, server);
341
+ } catch (error) {
342
+ this.context.logger.error(`\u63D2\u4EF6 ${name} afterDevServer \u6267\u884C\u5931\u8D25: ${error}`);
343
+ }
344
+ }
345
+ }
346
+ }
347
+ /**
348
+ * 获取所有已加载的插件名称
349
+ */
350
+ getPluginNames() {
351
+ return Array.from(this.plugins.keys());
352
+ }
353
+ /**
354
+ * 获取所有已加载的插件
355
+ */
356
+ getPlugins() {
357
+ return Array.from(this.plugins.values()).map((p) => p.plugin);
358
+ }
359
+ /**
360
+ * 获取所有已加载的插件钩子
361
+ */
362
+ getPluginHooks() {
363
+ return Array.from(this.plugins.values()).map((p) => p.hooks);
364
+ }
365
+ };
366
+
148
367
  // src/rspack/index.ts
149
368
  import { RsdoctorRspackPlugin } from "@rsdoctor/rspack-plugin";
150
369
 
151
370
  // src/rspack/dev.ts
371
+ import { createRequire as createRequire2 } from "module";
152
372
  import ReactRefreshPlugin from "@rspack/plugin-react-refresh";
153
373
  import { merge } from "webpack-merge";
154
- import { createRequire as createRequire2 } from "module";
155
374
 
156
375
  // src/rspack/base.ts
157
- import { rspack } from "@rspack/core";
158
376
  import { createRequire } from "module";
159
- import { fileURLToPath } from "url";
160
377
  import { dirname, join as join5 } from "path";
378
+ import { fileURLToPath } from "url";
379
+ import { rspack } from "@rspack/core";
161
380
 
162
381
  // src/generator/plugin.ts
163
- import { watch, existsSync as existsSync5 } from "fs";
382
+ import { existsSync as existsSync5, watch } from "fs";
164
383
  import { join as join4 } from "path";
165
384
 
166
385
  // src/generator/generator.ts
167
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync2 } from "fs";
386
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
168
387
  import { join as join3 } from "path";
169
388
 
170
389
  // src/router/generator.ts
171
- import {
172
- existsSync as existsSync2,
173
- readdirSync,
174
- statSync,
175
- mkdirSync,
176
- writeFileSync
177
- } from "fs";
390
+ import { existsSync as existsSync2, mkdirSync, readdirSync, statSync, writeFileSync } from "fs";
178
391
  import { join, relative } from "path";
179
392
  function winPath(path) {
180
393
  const isExtendedLengthPath = /^\\\\\?\\/.test(path);
@@ -234,9 +447,7 @@ var ConventionalRouteGenerator = class {
234
447
  const subDirPath = join(dir, subDir);
235
448
  if (subDir.startsWith("__")) {
236
449
  const pathlessRoutes = this.scanDirectory(subDirPath, routePath);
237
- const pathlessLayout = readdirSync(subDirPath).find(
238
- (e) => CONVENTION_FILES.layout.test(e)
239
- );
450
+ const pathlessLayout = readdirSync(subDirPath).find((e) => CONVENTION_FILES.layout.test(e));
240
451
  if (pathlessLayout) {
241
452
  const pathlessChildren = this.scanDirectory(subDirPath, routePath);
242
453
  const pathlessLayoutRel = winPath(
@@ -248,9 +459,7 @@ var ConventionalRouteGenerator = class {
248
459
  layoutFile: pathlessLayoutRel,
249
460
  isLayout: true,
250
461
  pathless: true,
251
- children: pathlessChildren.filter(
252
- (r) => r.layoutFile !== pathlessLayoutRel
253
- )
462
+ children: pathlessChildren.filter((r) => r.layoutFile !== pathlessLayoutRel)
254
463
  });
255
464
  } else {
256
465
  childRoutes.push(...pathlessRoutes);
@@ -268,7 +477,7 @@ var ConventionalRouteGenerator = class {
268
477
  layoutChildren.push({
269
478
  path: routePath,
270
479
  file: relPath(pageFile),
271
- name: routeName + "Index",
480
+ name: `${routeName}Index`,
272
481
  index: true
273
482
  });
274
483
  }
@@ -276,7 +485,7 @@ var ConventionalRouteGenerator = class {
276
485
  layoutChildren.push({
277
486
  path: "*",
278
487
  file: relPath(catchAllFile),
279
- name: routeName + "CatchAll"
488
+ name: `${routeName}CatchAll`
280
489
  });
281
490
  }
282
491
  layoutChildren.push(...childRoutes);
@@ -305,7 +514,7 @@ var ConventionalRouteGenerator = class {
305
514
  result.push({
306
515
  path: "*",
307
516
  file: relPath(catchAllFile),
308
- name: routeName + "CatchAll"
517
+ name: `${routeName}CatchAll`
309
518
  });
310
519
  }
311
520
  result.push(...childRoutes);
@@ -340,15 +549,13 @@ var ConventionalRouteGenerator = class {
340
549
  * 生成有效的 JS 标识符名称
341
550
  */
342
551
  generateRouteName(path) {
343
- const name = path.split("/").filter(Boolean).map(
344
- (s) => s.replace(/^:/, "Param").replace(/\?$/, "Optional").replace(/^\*$/, "CatchAll")
345
- ).map((s) => {
552
+ const name = path.split("/").filter(Boolean).map((s) => s.replace(/^:/, "Param").replace(/\?$/, "Optional").replace(/^\*$/, "CatchAll")).map((s) => {
346
553
  const cleaned = s.replace(/[^a-zA-Z0-9]/g, "");
347
554
  if (!cleaned) return "";
348
555
  return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
349
556
  }).join("");
350
557
  if (!name || /^\d/.test(name)) {
351
- return "Page" + (name || "Root");
558
+ return `Page${name || "Root"}`;
352
559
  }
353
560
  return name;
354
561
  }
@@ -367,8 +574,12 @@ import { createBrowserRouter, type RouteObject } from "react-router";
367
574
 
368
575
  // \u61D2\u52A0\u8F7D\u9875\u9762\u7EC4\u4EF6
369
576
  ${lazyImports.join("\n")}
370
- ${errorImports.length > 0 ? "\n// \u9519\u8BEF\u8FB9\u754C\u7EC4\u4EF6\n" + errorImports.join("\n") : ""}
371
- ${loadingImports.length > 0 ? "\n// \u52A0\u8F7D\u72B6\u6001\u7EC4\u4EF6\n" + loadingImports.join("\n") : ""}
577
+ ${errorImports.length > 0 ? `
578
+ // \u9519\u8BEF\u8FB9\u754C\u7EC4\u4EF6
579
+ ${errorImports.join("\n")}` : ""}
580
+ ${loadingImports.length > 0 ? `
581
+ // \u52A0\u8F7D\u72B6\u6001\u7EC4\u4EF6
582
+ ${loadingImports.join("\n")}` : ""}
372
583
 
373
584
  // \u9ED8\u8BA4\u52A0\u8F7D\u72B6\u6001
374
585
  const DefaultLoading = () => <div style={{ padding: 24, textAlign: "center" }}>\u52A0\u8F7D\u4E2D...</div>;
@@ -407,23 +618,17 @@ export default routes;
407
618
  const toImportPath = (f) => f.replace(/\.(tsx?|jsx?)$/, "");
408
619
  if (route.isLayout && route.layoutFile) {
409
620
  lazyImports.push(
410
- `const ${name}Layout = lazy(() => import("@/pages/${toImportPath(
411
- route.layoutFile
412
- )}"));`
621
+ `const ${name}Layout = lazy(() => import("@/pages/${toImportPath(route.layoutFile)}"));`
413
622
  );
414
623
  }
415
624
  if (route.file) {
416
625
  lazyImports.push(
417
- `const ${name}Page = lazy(() => import("@/pages/${toImportPath(
418
- route.file
419
- )}"));`
626
+ `const ${name}Page = lazy(() => import("@/pages/${toImportPath(route.file)}"));`
420
627
  );
421
628
  }
422
629
  if (route.errorFile) {
423
630
  errorImports.push(
424
- `const ${name}Error = lazy(() => import("@/pages/${toImportPath(
425
- route.errorFile
426
- )}"));`
631
+ `const ${name}Error = lazy(() => import("@/pages/${toImportPath(route.errorFile)}"));`
427
632
  );
428
633
  }
429
634
  if (route.loadingFile) {
@@ -434,12 +639,7 @@ export default routes;
434
639
  );
435
640
  }
436
641
  if (route.children) {
437
- this.collectImports(
438
- route.children,
439
- lazyImports,
440
- errorImports,
441
- loadingImports
442
- );
642
+ this.collectImports(route.children, lazyImports, errorImports, loadingImports);
443
643
  }
444
644
  }
445
645
  }
@@ -465,9 +665,7 @@ export default routes;
465
665
  }
466
666
  if (route.isLayout && route.layoutFile) {
467
667
  const loadingProp = route.loadingFile ? ` Loading={${name}Loading}` : "";
468
- parts.push(
469
- `element: <LazyRoute Component={${name}Layout}${loadingProp} />`
470
- );
668
+ parts.push(`element: <LazyRoute Component={${name}Layout}${loadingProp} />`);
471
669
  } else if (route.file) {
472
670
  parts.push(`element: <LazyRoute Component={${name}Page} />`);
473
671
  }
@@ -476,9 +674,7 @@ export default routes;
476
674
  }
477
675
  if (route.children && route.children.length > 0) {
478
676
  const childParent = route.pathless ? parentPath : route.path;
479
- parts.push(
480
- `children: ${this.emitRouteArray(route.children, childParent)}`
481
- );
677
+ parts.push(`children: ${this.emitRouteArray(route.children, childParent)}`);
482
678
  }
483
679
  return `{
484
680
  ${parts.join(",\n ")}
@@ -498,53 +694,13 @@ export default routes;
498
694
  }
499
695
  };
500
696
 
501
- // src/generator/templates/entry.ts
502
- function generateEntry(config, injections = {}) {
697
+ // src/generator/templates/bootstrap.ts
698
+ function generateBootstrap(config, injections = {}) {
699
+ const { appName, router } = config;
700
+ const routerImport = router.conventional ? `import { createRouter } from "./routes";` : `import { createRouter } from "@/routes";`;
503
701
  const imports = [
504
- `import "@/index.css";`,
505
- `import { runApp } from "./bootstrap";`,
506
- ...injections.imports || []
507
- ];
508
- const topLevel = injections.topLevel || [];
509
- const exports = injections.exports || [];
510
- const hasPluginExports = exports.length > 0;
511
- const hasAsyncTopLevel = topLevel.some((line) => line.includes("await "));
512
- let startupBody;
513
- if (hasPluginExports) {
514
- startupBody = [
515
- ...topLevel,
516
- ...exports,
517
- ``,
518
- `if (shouldRunIndependently !== false) {`,
519
- ` runApp();`,
520
- `}`
521
- ].join("\n");
522
- } else if (hasAsyncTopLevel) {
523
- startupBody = [
524
- `(async () => {`,
525
- ...topLevel.map((l) => ` ${l}`),
526
- ` await runApp();`,
527
- `})();`
528
- ].join("\n");
529
- } else {
530
- startupBody = topLevel.length > 0 ? [...topLevel, `runApp();`].join("\n") : `runApp();`;
531
- }
532
- return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
533
- // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
534
-
535
- ${imports.join("\n")}
536
-
537
- ${startupBody}
538
- `;
539
- }
540
-
541
- // src/generator/templates/bootstrap.ts
542
- function generateBootstrap(config, injections = {}) {
543
- const { appName, router } = config;
544
- const routerImport = router.conventional ? `import { createRouter } from "./routes";` : `import { createRouter } from "@/routes";`;
545
- const imports = [
546
- `import { bootstrap, type AppConfig } from "@4399ywkf/core/runtime";`,
547
- routerImport,
702
+ `import { bootstrap, type AppConfig } from "@4399ywkf/core/runtime";`,
703
+ routerImport,
548
704
  ...injections.imports || []
549
705
  ];
550
706
  const topLevel = injections.topLevel || [];
@@ -626,8 +782,50 @@ export async function runApp(): Promise<void> {
626
782
  const userConfig = await getUserConfig();
627
783
  await bootstrap(createAppConfig(userConfig));
628
784
  }
629
- ${topLevel.length > 0 ? "\n" + topLevel.join("\n") : ""}
630
- ${exports.length > 0 ? "\n" + exports.join("\n") : ""}
785
+ ${topLevel.length > 0 ? `
786
+ ${topLevel.join("\n")}` : ""}
787
+ ${exports.length > 0 ? `
788
+ ${exports.join("\n")}` : ""}
789
+ `;
790
+ }
791
+
792
+ // src/generator/templates/entry.ts
793
+ function generateEntry(_config, injections = {}) {
794
+ const imports = [
795
+ `import "@/index.css";`,
796
+ `import { runApp } from "./bootstrap";`,
797
+ ...injections.imports || []
798
+ ];
799
+ const topLevel = injections.topLevel || [];
800
+ const exports = injections.exports || [];
801
+ const hasPluginExports = exports.length > 0;
802
+ const hasAsyncTopLevel = topLevel.some((line) => line.includes("await "));
803
+ let startupBody;
804
+ if (hasPluginExports) {
805
+ startupBody = [
806
+ ...topLevel,
807
+ ...exports,
808
+ ``,
809
+ `if (shouldRunIndependently !== false) {`,
810
+ ` runApp();`,
811
+ `}`
812
+ ].join("\n");
813
+ } else if (hasAsyncTopLevel) {
814
+ startupBody = [
815
+ `(async () => {`,
816
+ ...topLevel.map((l) => ` ${l}`),
817
+ ` await runApp();`,
818
+ `})();`
819
+ ].join("\n");
820
+ } else {
821
+ startupBody = topLevel.length > 0 ? [...topLevel, `runApp();`].join("\n") : `runApp();`;
822
+ }
823
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
824
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
825
+
826
+ ${imports.join("\n")}
827
+
828
+ ${startupBody}
631
829
  `;
632
830
  }
633
831
 
@@ -791,17 +989,14 @@ var YwkfGenerator = class {
791
989
  const { outputDir, config } = this.context;
792
990
  const configPath = join3(outputDir, "config.json");
793
991
  const serializableConfig = JSON.parse(
794
- JSON.stringify(config, (key, value) => {
992
+ JSON.stringify(config, (_key, value) => {
795
993
  if (typeof value === "function") {
796
994
  return "[Function]";
797
995
  }
798
996
  return value;
799
997
  })
800
998
  );
801
- this.writeFileIfChanged(
802
- configPath,
803
- JSON.stringify(serializableConfig, null, 2)
804
- );
999
+ this.writeFileIfChanged(configPath, JSON.stringify(serializableConfig, null, 2));
805
1000
  }
806
1001
  /**
807
1002
  * 生成约定式路由
@@ -905,16 +1100,10 @@ var YwkfGenerator = class {
905
1100
  generateTypes() {
906
1101
  const { outputDir, config, cwd } = this.context;
907
1102
  const envTypesContent = generateEnvTypes(cwd, config);
908
- this.writeFileIfChanged(
909
- join3(outputDir, "types", "env.d.ts"),
910
- envTypesContent
911
- );
1103
+ this.writeFileIfChanged(join3(outputDir, "types", "env.d.ts"), envTypesContent);
912
1104
  if (config.router.conventional) {
913
1105
  const routeTypesContent = generateRouteTypes();
914
- this.writeFileIfChanged(
915
- join3(outputDir, "types", "routes.d.ts"),
916
- routeTypesContent
917
- );
1106
+ this.writeFileIfChanged(join3(outputDir, "types", "routes.d.ts"), routeTypesContent);
918
1107
  }
919
1108
  }
920
1109
  /**
@@ -1049,7 +1238,7 @@ var YwkfGeneratorPlugin = class {
1049
1238
  }
1050
1239
  apply(compiler) {
1051
1240
  const pluginName = "YwkfGeneratorPlugin";
1052
- compiler.hooks.beforeCompile.tapAsync(pluginName, async (params, callback) => {
1241
+ compiler.hooks.beforeCompile.tapAsync(pluginName, async (_params, callback) => {
1053
1242
  try {
1054
1243
  await this.initialize();
1055
1244
  if (!this.hasGenerated && this.generator) {
@@ -1077,24 +1266,20 @@ var YwkfGeneratorPlugin = class {
1077
1266
  }
1078
1267
  this.isWatching = true;
1079
1268
  let debounceTimer = null;
1080
- const watcher = watch(
1081
- pagesDir,
1082
- { recursive: true },
1083
- (eventType, filename) => {
1084
- if (!filename?.match(/\.(tsx?|jsx?)$/)) {
1085
- return;
1086
- }
1087
- if (debounceTimer) {
1088
- clearTimeout(debounceTimer);
1089
- }
1090
- debounceTimer = setTimeout(async () => {
1091
- if (process.env.DEBUG) console.log(`[ywkf] \u68C0\u6D4B\u5230\u9875\u9762\u53D8\u5316: ${filename}`);
1092
- if (this.generator) {
1093
- await this.generator.generate();
1094
- }
1095
- }, 500);
1269
+ const watcher = watch(pagesDir, { recursive: true }, (_eventType, filename) => {
1270
+ if (!filename?.match(/\.(tsx?|jsx?)$/)) {
1271
+ return;
1096
1272
  }
1097
- );
1273
+ if (debounceTimer) {
1274
+ clearTimeout(debounceTimer);
1275
+ }
1276
+ debounceTimer = setTimeout(async () => {
1277
+ if (process.env.DEBUG) console.log(`[ywkf] \u68C0\u6D4B\u5230\u9875\u9762\u53D8\u5316: ${filename}`);
1278
+ if (this.generator) {
1279
+ await this.generator.generate();
1280
+ }
1281
+ }, 500);
1282
+ });
1098
1283
  process.on("exit", () => {
1099
1284
  watcher.close();
1100
1285
  });
@@ -1125,8 +1310,10 @@ var YwkfGeneratorPlugin = class {
1125
1310
  this.resetState();
1126
1311
  await this.initialize();
1127
1312
  await this.regenerate();
1128
- console.log(` [ywkf] .ywkf \u76EE\u5F55\u5DF2\u91CD\u65B0\u751F\u6210\u3002\u90E8\u5206\u914D\u7F6E\u53D8\u66F4\uFF08\u5982\u7AEF\u53E3\u3001\u4EE3\u7406\uFF09\u9700\u91CD\u542F dev server \u751F\u6548\u3002
1129
- `);
1313
+ console.log(
1314
+ ` [ywkf] .ywkf \u76EE\u5F55\u5DF2\u91CD\u65B0\u751F\u6210\u3002\u90E8\u5206\u914D\u7F6E\u53D8\u66F4\uFF08\u5982\u7AEF\u53E3\u3001\u4EE3\u7406\uFF09\u9700\u91CD\u542F dev server \u751F\u6548\u3002
1315
+ `
1316
+ );
1130
1317
  } catch (error) {
1131
1318
  console.error(` [ywkf] \u914D\u7F6E\u91CD\u8F7D\u5931\u8D25:`, error);
1132
1319
  }
@@ -1145,15 +1332,7 @@ var coreNodeModules = join5(__dirname, "../../node_modules");
1145
1332
  function createBaseConfig(config, cwd, options = {}) {
1146
1333
  const isDev = options.isDev ?? process.env.NODE_ENV !== "production";
1147
1334
  const { resolveApp } = createPathResolver(cwd);
1148
- const {
1149
- appName,
1150
- appCName,
1151
- output,
1152
- html,
1153
- alias: userAlias,
1154
- microFrontend,
1155
- router
1156
- } = config;
1335
+ const { appName, appCName, output, html, alias: userAlias, microFrontend, router } = config;
1157
1336
  const ywkfOutputDir = resolveApp(".ywkf");
1158
1337
  const defaultAlias = {
1159
1338
  "@": resolveApp("src"),
@@ -1329,7 +1508,7 @@ function createBaseConfig(config, cwd, options = {}) {
1329
1508
  }
1330
1509
 
1331
1510
  // src/rspack/dev.ts
1332
- var require3 = createRequire2(import.meta.url);
1511
+ var _require = createRequire2(import.meta.url);
1333
1512
  function convertProxyToArray(proxy) {
1334
1513
  if (!proxy || Object.keys(proxy).length === 0) {
1335
1514
  return void 0;
@@ -1360,10 +1539,7 @@ function createDevConfig(config, cwd) {
1360
1539
  // Less - antd
1361
1540
  {
1362
1541
  test: /\.less$/,
1363
- include: [
1364
- /[\\/]node_modules[\\/].*antd/,
1365
- /[\\/]node_modules[\\/]@4399ywkf[\\/]design/
1366
- ],
1542
+ include: [/[\\/]node_modules[\\/].*antd/, /[\\/]node_modules[\\/]@4399ywkf[\\/]design/],
1367
1543
  use: [
1368
1544
  { loader: "style-loader" },
1369
1545
  {
@@ -1536,9 +1712,7 @@ function createDevConfig(config, cwd) {
1536
1712
  clean: false
1537
1713
  },
1538
1714
  stats: "errors-only",
1539
- plugins: [
1540
- new ReactRefreshPlugin()
1541
- ],
1715
+ plugins: [new ReactRefreshPlugin()],
1542
1716
  devServer: {
1543
1717
  host: dev2.host,
1544
1718
  port: dev2.port,
@@ -1569,10 +1743,7 @@ function createProdConfig(config, cwd) {
1569
1743
  // Less - antd
1570
1744
  {
1571
1745
  test: /\.less$/,
1572
- include: [
1573
- /[\\/]node_modules[\\/].*antd/,
1574
- /[\\/]node_modules[\\/]@4399ywkf[\\/]design/
1575
- ],
1746
+ include: [/[\\/]node_modules[\\/].*antd/, /[\\/]node_modules[\\/]@4399ywkf[\\/]design/],
1576
1747
  use: [
1577
1748
  { loader: rspack2.CssExtractRspackPlugin.loader },
1578
1749
  {
@@ -1788,10 +1959,7 @@ function createRspackConfig(config, cwd, options = {}) {
1788
1959
  const isDev = options.isDev ?? process.env.NODE_ENV !== "production";
1789
1960
  let rspackConfig = isDev ? createDevConfig(config, cwd) : createProdConfig(config, cwd);
1790
1961
  if (config.performance.rsdoctor) {
1791
- rspackConfig.plugins = [
1792
- ...rspackConfig.plugins || [],
1793
- new RsdoctorRspackPlugin({})
1794
- ];
1962
+ rspackConfig.plugins = [...rspackConfig.plugins || [], new RsdoctorRspackPlugin({})];
1795
1963
  }
1796
1964
  if (config.tools.rspack) {
1797
1965
  const userConfig = config.tools.rspack(rspackConfig, {
@@ -1823,10 +1991,7 @@ function preloadEnv(cwd, mode, nodeEnv) {
1823
1991
  break;
1824
1992
  }
1825
1993
  }
1826
- const modeEnvPaths = [
1827
- resolve2(cwd, `config/env/.env.${mode}`),
1828
- resolve2(cwd, `.env.${mode}`)
1829
- ];
1994
+ const modeEnvPaths = [resolve2(cwd, `config/env/.env.${mode}`), resolve2(cwd, `.env.${mode}`)];
1830
1995
  for (const envPath of modeEnvPaths) {
1831
1996
  if (existsSync6(envPath)) {
1832
1997
  const envContent = readFileSync3(envPath, "utf-8");
@@ -1864,379 +2029,101 @@ function loadEnv(config, cwd, mode, nodeEnv) {
1864
2029
  process.env.APP_PORT = process.env.APP_PORT || String(config.dev.port);
1865
2030
  }
1866
2031
 
1867
- // src/plugin/manager.ts
1868
- function createLogger(pluginName) {
1869
- const prefix = `[${pluginName}]`;
1870
- const verbose = !!process.env.DEBUG;
1871
- return {
1872
- info: (msg) => {
1873
- if (verbose) console.log(`${prefix} ${msg}`);
1874
- },
1875
- warn: (msg) => console.warn(`${prefix} ${msg}`),
1876
- error: (msg) => console.error(`${prefix} ${msg}`),
1877
- debug: (msg) => {
1878
- if (verbose) console.debug(`${prefix} ${msg}`);
1879
- }
1880
- };
2032
+ // src/cli/printer.ts
2033
+ import { createRequire as createRequire3 } from "module";
2034
+ import os from "os";
2035
+ import { dirname as dirname2, join as join6 } from "path";
2036
+ import { fileURLToPath as fileURLToPath2 } from "url";
2037
+ import chalk from "chalk";
2038
+ var __filename = fileURLToPath2(import.meta.url);
2039
+ var __dirname2 = dirname2(__filename);
2040
+ var require3 = createRequire3(import.meta.url);
2041
+ var _version = null;
2042
+ function getFrameworkVersion() {
2043
+ if (_version) return _version;
2044
+ try {
2045
+ const pkgPath = join6(__dirname2, "../../package.json");
2046
+ const pkg = require3(pkgPath);
2047
+ _version = pkg.version || "0.0.0";
2048
+ } catch {
2049
+ _version = "0.0.0";
2050
+ }
2051
+ return _version;
1881
2052
  }
1882
- async function resolvePlugin(pluginConfig, cwd) {
1883
- let plugin;
1884
- let options = {};
1885
- if (typeof pluginConfig === "string") {
1886
- const module = await import(pluginConfig);
1887
- plugin = module.default || module;
1888
- } else if (Array.isArray(pluginConfig)) {
1889
- const [pluginOrName, pluginOptions] = pluginConfig;
1890
- options = pluginOptions;
1891
- if (typeof pluginOrName === "string") {
1892
- const module = await import(pluginOrName);
1893
- plugin = module.default || module;
1894
- } else {
1895
- plugin = pluginOrName;
2053
+ function getNetworkAddress(port) {
2054
+ const interfaces = os.networkInterfaces();
2055
+ for (const entries of Object.values(interfaces)) {
2056
+ if (!entries) continue;
2057
+ for (const entry of entries) {
2058
+ if (entry.family === "IPv4" && !entry.internal) {
2059
+ return `http://${entry.address}:${port}/`;
2060
+ }
1896
2061
  }
1897
- } else {
1898
- plugin = pluginConfig;
1899
- }
1900
- if (typeof plugin === "function") {
1901
- plugin = plugin(options);
1902
2062
  }
1903
- return { plugin, options };
2063
+ return null;
1904
2064
  }
1905
- var PluginManager = class {
1906
- plugins = /* @__PURE__ */ new Map();
1907
- context;
1908
- constructor(config, cwd, isDev) {
1909
- this.context = {
1910
- cwd,
1911
- isDev,
1912
- isProd: !isDev,
1913
- config,
1914
- logger: createLogger("PluginManager")
1915
- };
2065
+ var BAR_WIDTH = 30;
2066
+ function renderBar(percent) {
2067
+ const filled = Math.round(BAR_WIDTH * percent);
2068
+ const empty = BAR_WIDTH - filled;
2069
+ const bar = chalk.green("\u2501".repeat(filled)) + chalk.gray("\u2501".repeat(empty));
2070
+ return bar;
2071
+ }
2072
+ var DevPrinter = class {
2073
+ constructor(_host, port, pluginNames, isBuild = false) {
2074
+ this._host = _host;
2075
+ this.port = port;
2076
+ this.pluginNames = pluginNames;
2077
+ this.isBuild = isBuild;
1916
2078
  }
2079
+ startTime = 0;
2080
+ lastProgressLine = "";
2081
+ firstCompileDone = false;
1917
2082
  /**
1918
- * 加载并初始化所有插件
2083
+ * 打印框架 banner
1919
2084
  */
1920
- async loadPlugins(pluginConfigs) {
1921
- for (const pluginConfig of pluginConfigs) {
1922
- try {
1923
- const { plugin } = await resolvePlugin(pluginConfig, this.context.cwd);
1924
- if (this.plugins.has(plugin.name)) {
1925
- this.context.logger.warn(`\u63D2\u4EF6 ${plugin.name} \u5DF2\u52A0\u8F7D\uFF0C\u8DF3\u8FC7\u91CD\u590D\u52A0\u8F7D`);
1926
- continue;
1927
- }
1928
- const pluginContext = {
1929
- ...this.context,
1930
- logger: createLogger(plugin.name)
1931
- };
1932
- const hooks = await plugin.setup(pluginContext);
1933
- this.plugins.set(plugin.name, { plugin, hooks });
1934
- this.context.logger.info(`\u5DF2\u52A0\u8F7D\u63D2\u4EF6: ${plugin.name}`);
1935
- } catch (error) {
1936
- this.context.logger.error(
1937
- `\u52A0\u8F7D\u63D2\u4EF6\u5931\u8D25: ${String(pluginConfig)} - ${error}`
1938
- );
1939
- }
1940
- }
2085
+ printBanner() {
2086
+ const version2 = getFrameworkVersion();
2087
+ console.log();
2088
+ console.log(` ${chalk.bold.cyan("@4399ywkf/core")} ${chalk.green(`Framework v${version2}`)}`);
2089
+ console.log();
1941
2090
  }
1942
2091
  /**
1943
- * 执行 modifyRspackConfig 钩子
2092
+ * 打印 "start build started..."
1944
2093
  */
1945
- async applyRspackConfigHooks(config) {
1946
- let result = config;
1947
- for (const [name, { hooks }] of this.plugins) {
1948
- if (hooks.modifyRspackConfig) {
1949
- try {
1950
- const modified = await hooks.modifyRspackConfig(result, this.context);
1951
- if (modified) {
1952
- result = modified;
1953
- }
1954
- } catch (error) {
1955
- this.context.logger.error(
1956
- `\u63D2\u4EF6 ${name} modifyRspackConfig \u6267\u884C\u5931\u8D25: ${error}`
1957
- );
1958
- }
1959
- }
1960
- }
1961
- return result;
2094
+ printBuildStart() {
2095
+ this.startTime = Date.now();
2096
+ this.compileDone = false;
2097
+ const label = chalk.gray("start");
2098
+ console.log(` ${label} build started...`);
1962
2099
  }
1963
2100
  /**
1964
- * 执行 modifyRoutes 钩子
2101
+ * 更新编译进度条(原地覆写同一行)
1965
2102
  */
1966
- async applyRoutesHooks(routes) {
1967
- let result = routes;
1968
- for (const [name, { hooks }] of this.plugins) {
1969
- if (hooks.modifyRoutes) {
1970
- try {
1971
- const modified = await hooks.modifyRoutes(result, this.context);
1972
- if (modified) {
1973
- result = modified;
1974
- }
1975
- } catch (error) {
1976
- this.context.logger.error(
1977
- `\u63D2\u4EF6 ${name} modifyRoutes \u6267\u884C\u5931\u8D25: ${error}`
1978
- );
1979
- }
2103
+ updateProgress(percent, message) {
2104
+ const pct = Math.min(Math.round(percent * 100), 100);
2105
+ const bar = renderBar(percent);
2106
+ const status = message || "compiling";
2107
+ const line = ` ${chalk.yellow("\u25CF")} client ${bar} ${chalk.bold(`(${pct}%)`)} ${chalk.gray(status)}`;
2108
+ if (process.stdout.isTTY) {
2109
+ if (this.lastProgressLine) {
2110
+ process.stdout.write("\x1B[1A\x1B[2K");
1980
2111
  }
2112
+ process.stdout.write(`${line}
2113
+ `);
2114
+ } else if (!this.firstCompileDone && pct === 100) {
2115
+ console.log(line);
1981
2116
  }
1982
- return result;
2117
+ this.lastProgressLine = line;
1983
2118
  }
1984
2119
  /**
1985
- * 执行 modifyAppConfig 钩子
1986
- */
1987
- applyAppConfigHooks(appConfig) {
1988
- let result = appConfig;
1989
- for (const [name, { hooks }] of this.plugins) {
1990
- if (hooks.modifyAppConfig) {
1991
- try {
1992
- const modified = hooks.modifyAppConfig(result, this.context);
1993
- if (modified) {
1994
- result = modified;
1995
- }
1996
- } catch (error) {
1997
- this.context.logger.error(
1998
- `\u63D2\u4EF6 ${name} modifyAppConfig \u6267\u884C\u5931\u8D25: ${error}`
1999
- );
2000
- }
2001
- }
2002
- }
2003
- return result;
2004
- }
2005
- /**
2006
- * 收集所有插件的 Provider
2007
- */
2008
- collectProviders() {
2009
- const providers = [];
2010
- for (const [name, { hooks }] of this.plugins) {
2011
- if (hooks.addProvider) {
2012
- try {
2013
- const result = hooks.addProvider(this.context);
2014
- if (Array.isArray(result)) {
2015
- providers.push(...result);
2016
- } else if (result) {
2017
- providers.push(result);
2018
- }
2019
- } catch (error) {
2020
- this.context.logger.error(
2021
- `\u63D2\u4EF6 ${name} addProvider \u6267\u884C\u5931\u8D25: ${error}`
2022
- );
2023
- }
2024
- }
2025
- }
2026
- return providers;
2027
- }
2028
- /**
2029
- * 执行 beforeBuild 钩子
2030
- */
2031
- async runBeforeBuild() {
2032
- for (const [name, { hooks }] of this.plugins) {
2033
- if (hooks.beforeBuild) {
2034
- try {
2035
- await hooks.beforeBuild(this.context);
2036
- } catch (error) {
2037
- this.context.logger.error(
2038
- `\u63D2\u4EF6 ${name} beforeBuild \u6267\u884C\u5931\u8D25: ${error}`
2039
- );
2040
- }
2041
- }
2042
- }
2043
- }
2044
- /**
2045
- * 执行 afterBuild 钩子
2046
- */
2047
- async runAfterBuild(stats) {
2048
- for (const [name, { hooks }] of this.plugins) {
2049
- if (hooks.afterBuild) {
2050
- try {
2051
- await hooks.afterBuild(this.context, stats);
2052
- } catch (error) {
2053
- this.context.logger.error(
2054
- `\u63D2\u4EF6 ${name} afterBuild \u6267\u884C\u5931\u8D25: ${error}`
2055
- );
2056
- }
2057
- }
2058
- }
2059
- }
2060
- /**
2061
- * 执行 beforeDevServer 钩子
2062
- */
2063
- async runBeforeDevServer() {
2064
- for (const [name, { hooks }] of this.plugins) {
2065
- if (hooks.beforeDevServer) {
2066
- try {
2067
- await hooks.beforeDevServer(this.context);
2068
- } catch (error) {
2069
- this.context.logger.error(
2070
- `\u63D2\u4EF6 ${name} beforeDevServer \u6267\u884C\u5931\u8D25: ${error}`
2071
- );
2072
- }
2073
- }
2074
- }
2075
- }
2076
- /**
2077
- * 执行 afterDevServer 钩子
2078
- */
2079
- async runAfterDevServer(server) {
2080
- for (const [name, { hooks }] of this.plugins) {
2081
- if (hooks.afterDevServer) {
2082
- try {
2083
- await hooks.afterDevServer(this.context, server);
2084
- } catch (error) {
2085
- this.context.logger.error(
2086
- `\u63D2\u4EF6 ${name} afterDevServer \u6267\u884C\u5931\u8D25: ${error}`
2087
- );
2088
- }
2089
- }
2090
- }
2091
- }
2092
- /**
2093
- * 获取所有已加载的插件名称
2094
- */
2095
- getPluginNames() {
2096
- return Array.from(this.plugins.keys());
2097
- }
2098
- /**
2099
- * 获取所有已加载的插件
2100
- */
2101
- getPlugins() {
2102
- return Array.from(this.plugins.values()).map((p) => p.plugin);
2103
- }
2104
- /**
2105
- * 获取所有已加载的插件钩子
2106
- */
2107
- getPluginHooks() {
2108
- return Array.from(this.plugins.values()).map((p) => p.hooks);
2109
- }
2110
- };
2111
-
2112
- // src/cli/port.ts
2113
- import net from "net";
2114
- function isPortAvailable(port, host) {
2115
- return new Promise((resolve3) => {
2116
- const server = net.createServer();
2117
- server.once("error", (err) => {
2118
- if (err.code === "EADDRINUSE") {
2119
- resolve3(false);
2120
- } else {
2121
- resolve3(false);
2122
- }
2123
- });
2124
- server.once("listening", () => {
2125
- server.close(() => resolve3(true));
2126
- });
2127
- server.listen(port, host);
2128
- });
2129
- }
2130
- async function getAvailablePort(preferredPort, host) {
2131
- const MAX_ATTEMPTS = 20;
2132
- for (let i = 0; i < MAX_ATTEMPTS; i++) {
2133
- const port = preferredPort + i;
2134
- const available = await isPortAvailable(port, host);
2135
- if (available) return port;
2136
- }
2137
- throw new Error(
2138
- `No available port found in range ${preferredPort}-${preferredPort + MAX_ATTEMPTS - 1}`
2139
- );
2140
- }
2141
-
2142
- // src/cli/printer.ts
2143
- import chalk from "chalk";
2144
- import os from "os";
2145
- import { createRequire as createRequire3 } from "module";
2146
- import { fileURLToPath as fileURLToPath2 } from "url";
2147
- import { dirname as dirname2, join as join6 } from "path";
2148
- var __filename = fileURLToPath2(import.meta.url);
2149
- var __dirname2 = dirname2(__filename);
2150
- var require4 = createRequire3(import.meta.url);
2151
- var _version = null;
2152
- function getFrameworkVersion() {
2153
- if (_version) return _version;
2154
- try {
2155
- const pkgPath = join6(__dirname2, "../../package.json");
2156
- const pkg = require4(pkgPath);
2157
- _version = pkg.version || "0.0.0";
2158
- } catch {
2159
- _version = "0.0.0";
2160
- }
2161
- return _version;
2162
- }
2163
- function getNetworkAddress(port) {
2164
- const interfaces = os.networkInterfaces();
2165
- for (const entries of Object.values(interfaces)) {
2166
- if (!entries) continue;
2167
- for (const entry of entries) {
2168
- if (entry.family === "IPv4" && !entry.internal) {
2169
- return `http://${entry.address}:${port}/`;
2170
- }
2171
- }
2172
- }
2173
- return null;
2174
- }
2175
- var BAR_WIDTH = 30;
2176
- function renderBar(percent) {
2177
- const filled = Math.round(BAR_WIDTH * percent);
2178
- const empty = BAR_WIDTH - filled;
2179
- const bar = chalk.green("\u2501".repeat(filled)) + chalk.gray("\u2501".repeat(empty));
2180
- return bar;
2181
- }
2182
- var DevPrinter = class {
2183
- constructor(host, port, pluginNames, isBuild = false) {
2184
- this.host = host;
2185
- this.port = port;
2186
- this.pluginNames = pluginNames;
2187
- this.isBuild = isBuild;
2188
- }
2189
- startTime = 0;
2190
- lastProgressLine = "";
2191
- firstCompileDone = false;
2192
- /**
2193
- * 打印框架 banner
2194
- */
2195
- printBanner() {
2196
- const version2 = getFrameworkVersion();
2197
- console.log();
2198
- console.log(
2199
- ` ${chalk.bold.cyan("@4399ywkf/core")} ${chalk.green(`Framework v${version2}`)}`
2200
- );
2201
- console.log();
2202
- }
2203
- /**
2204
- * 打印 "start build started..."
2205
- */
2206
- printBuildStart() {
2207
- this.startTime = Date.now();
2208
- this.compileDone = false;
2209
- const label = chalk.gray("start");
2210
- console.log(` ${label} build started...`);
2211
- }
2212
- /**
2213
- * 更新编译进度条(原地覆写同一行)
2214
- */
2215
- updateProgress(percent, message) {
2216
- const pct = Math.min(Math.round(percent * 100), 100);
2217
- const bar = renderBar(percent);
2218
- const status = message || "compiling";
2219
- const line = ` ${chalk.yellow("\u25CF")} client ${bar} ${chalk.bold(`(${pct}%)`)} ${chalk.gray(status)}`;
2220
- if (process.stdout.isTTY) {
2221
- if (this.lastProgressLine) {
2222
- process.stdout.write("\x1B[1A\x1B[2K");
2223
- }
2224
- process.stdout.write(line + "\n");
2225
- } else if (!this.firstCompileDone && pct === 100) {
2226
- console.log(line);
2227
- }
2228
- this.lastProgressLine = line;
2229
- }
2230
- /**
2231
- * 编译完成
2120
+ * 编译完成
2232
2121
  */
2233
2122
  printBuildDone(hasErrors = false) {
2234
2123
  if (this.firstCompileDone) {
2235
2124
  if (!hasErrors) {
2236
2125
  const elapsed2 = ((Date.now() - this.startTime) / 1e3).toFixed(2);
2237
- console.log(
2238
- ` ${chalk.green("hmr")} update in ${chalk.bold(`${elapsed2} s`)}`
2239
- );
2126
+ console.log(` ${chalk.green("hmr")} update in ${chalk.bold(`${elapsed2} s`)}`);
2240
2127
  }
2241
2128
  return;
2242
2129
  }
@@ -2285,9 +2172,7 @@ var DevPrinter = class {
2285
2172
  }
2286
2173
  console.log();
2287
2174
  this.printPluginList();
2288
- console.log(
2289
- ` ${chalk.bold(">")} press ${chalk.bold("h + enter")} to show shortcuts`
2290
- );
2175
+ console.log(` ${chalk.bold(">")} press ${chalk.bold("h + enter")} to show shortcuts`);
2291
2176
  console.log();
2292
2177
  }
2293
2178
  /**
@@ -2342,103 +2227,7 @@ function registerShortcuts(printer, opts) {
2342
2227
  process.stdin.resume();
2343
2228
  }
2344
2229
 
2345
- // src/cli/dev.ts
2346
- async function dev(options = {}) {
2347
- const cwd = options.cwd || process.cwd();
2348
- const mode = options.mode || "development";
2349
- try {
2350
- preloadEnv(cwd, mode, "development");
2351
- const { config } = await resolveConfig(cwd);
2352
- loadEnv(config, cwd, mode, "development");
2353
- const pluginManager = new PluginManager(config, cwd, true);
2354
- if (config.plugins && config.plugins.length > 0) {
2355
- await pluginManager.loadPlugins(config.plugins);
2356
- }
2357
- await pluginManager.runBeforeDevServer();
2358
- let rspackConfig = createRspackConfig(config, cwd, { isDev: true });
2359
- rspackConfig = await pluginManager.applyRspackConfigHooks(rspackConfig);
2360
- const host = config.dev.host || "localhost";
2361
- const preferredPort = config.dev.port || 3e3;
2362
- const port = await getAvailablePort(preferredPort, host);
2363
- const pluginNames = pluginManager.getPluginNames();
2364
- if (port !== preferredPort) {
2365
- console.log(
2366
- chalk2.yellow(` Port ${preferredPort} is in use, using ${port} instead.
2367
- `)
2368
- );
2369
- }
2370
- const printer = new DevPrinter(host, port, pluginNames);
2371
- printer.printBanner();
2372
- printer.printBuildStart();
2373
- printer.updateProgress(0, "preparing");
2374
- rspackConfig.plugins = rspackConfig.plugins || [];
2375
- rspackConfig.plugins.push(
2376
- new rspack3.ProgressPlugin(createProgressHandler(printer))
2377
- );
2378
- rspackConfig.stats = "none";
2379
- rspackConfig.infrastructureLogging = { level: "none" };
2380
- if (rspackConfig.devServer) {
2381
- const ds = rspackConfig.devServer;
2382
- const existingClient = ds.client ?? {};
2383
- ds.client = {
2384
- ...existingClient,
2385
- logging: "warn",
2386
- overlay: false,
2387
- progress: false
2388
- };
2389
- }
2390
- const compiler = rspack3(rspackConfig);
2391
- compiler.hooks.done.tap("ywkf-dev-printer", (stats) => {
2392
- const hasErrors = stats.hasErrors();
2393
- if (hasErrors) {
2394
- const info = stats.toJson({ errors: true });
2395
- console.log();
2396
- console.log(chalk2.red(" Compile error:"));
2397
- for (const err of info.errors || []) {
2398
- console.log(chalk2.red(` ${err.message}`));
2399
- }
2400
- console.log();
2401
- }
2402
- printer.printBuildDone(hasErrors);
2403
- });
2404
- compiler.hooks.invalid.tap("ywkf-dev-printer", () => {
2405
- printer.markRebuildStart();
2406
- printer.updateProgress(0, "rebuilding");
2407
- });
2408
- const devServerOptions = {
2409
- ...rspackConfig.devServer || {},
2410
- host,
2411
- port
2412
- };
2413
- const server = new RspackDevServer(devServerOptions, compiler);
2414
- await server.start();
2415
- await pluginManager.runAfterDevServer({ host, port });
2416
- registerShortcuts(printer, {
2417
- port,
2418
- onQuit: async () => {
2419
- console.log(chalk2.gray("\n Shutting down...\n"));
2420
- await server.stop();
2421
- process.exit(0);
2422
- }
2423
- });
2424
- const signals = ["SIGINT", "SIGTERM"];
2425
- for (const signal of signals) {
2426
- process.on(signal, async () => {
2427
- await server.stop();
2428
- process.exit(0);
2429
- });
2430
- }
2431
- } catch (error) {
2432
- console.error();
2433
- console.error(chalk2.red(" \u2716 Dev server failed to start"));
2434
- console.error(error);
2435
- process.exit(1);
2436
- }
2437
- }
2438
-
2439
2230
  // src/cli/build.ts
2440
- import { rspack as rspack4 } from "@rspack/core";
2441
- import chalk3 from "chalk";
2442
2231
  function formatSize(bytes) {
2443
2232
  if (bytes < 1024) return `${bytes} B`;
2444
2233
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
@@ -2451,30 +2240,28 @@ function printBuildResult(stats) {
2451
2240
  warnings: true
2452
2241
  });
2453
2242
  if (info.errors && info.errors.length > 0) {
2454
- console.log(chalk3.red("\n Compile errors:"));
2243
+ console.log(chalk2.red("\n Compile errors:"));
2455
2244
  for (const error of info.errors) {
2456
- console.log(chalk3.red(` ${error.message}`));
2245
+ console.log(chalk2.red(` ${error.message}`));
2457
2246
  }
2458
2247
  return;
2459
2248
  }
2460
2249
  if (info.warnings && info.warnings.length > 0) {
2461
- console.log(chalk3.yellow("\n Warnings:"));
2250
+ console.log(chalk2.yellow("\n Warnings:"));
2462
2251
  for (const warning of info.warnings) {
2463
- console.log(chalk3.yellow(` ${warning.message}`));
2252
+ console.log(chalk2.yellow(` ${warning.message}`));
2464
2253
  }
2465
2254
  }
2466
- console.log(chalk3.bold("\n Build output:"));
2255
+ console.log(chalk2.bold("\n Build output:"));
2467
2256
  console.log();
2468
2257
  const assets = info.assets || [];
2469
2258
  const sortedAssets = assets.filter((asset) => !asset.name.endsWith(".map")).sort((a, b) => b.size - a.size);
2470
2259
  for (const asset of sortedAssets.slice(0, 15)) {
2471
- const sizeColor = asset.size > 500 * 1024 ? chalk3.yellow : chalk3.green;
2472
- console.log(
2473
- ` ${chalk3.dim(asset.name.padEnd(50))} ${sizeColor(formatSize(asset.size))}`
2474
- );
2260
+ const sizeColor = asset.size > 500 * 1024 ? chalk2.yellow : chalk2.green;
2261
+ console.log(` ${chalk2.dim(asset.name.padEnd(50))} ${sizeColor(formatSize(asset.size))}`);
2475
2262
  }
2476
2263
  if (sortedAssets.length > 15) {
2477
- console.log(chalk3.dim(` ... and ${sortedAssets.length - 15} more files`));
2264
+ console.log(chalk2.dim(` ... and ${sortedAssets.length - 15} more files`));
2478
2265
  }
2479
2266
  console.log();
2480
2267
  }
@@ -2498,12 +2285,10 @@ async function build(options = {}) {
2498
2285
  printer.printBuildStart();
2499
2286
  printer.updateProgress(0, "preparing");
2500
2287
  rspackConfig.plugins = rspackConfig.plugins || [];
2501
- rspackConfig.plugins.push(
2502
- new rspack4.ProgressPlugin(createProgressHandler(printer))
2503
- );
2288
+ rspackConfig.plugins.push(new rspack3.ProgressPlugin(createProgressHandler(printer)));
2504
2289
  rspackConfig.stats = "none";
2505
2290
  rspackConfig.infrastructureLogging = { level: "none" };
2506
- const compiler = rspack4(rspackConfig);
2291
+ const compiler = rspack3(rspackConfig);
2507
2292
  const stats = await new Promise((resolve3, reject) => {
2508
2293
  compiler.run((err, stats2) => {
2509
2294
  if (err) {
@@ -2537,7 +2322,132 @@ async function build(options = {}) {
2537
2322
  printBuildResult(stats);
2538
2323
  } catch (error) {
2539
2324
  console.error();
2540
- console.error(chalk3.red(" \u2716 Build failed"));
2325
+ console.error(chalk2.red(" \u2716 Build failed"));
2326
+ console.error(error);
2327
+ process.exit(1);
2328
+ }
2329
+ }
2330
+
2331
+ // src/cli/dev.ts
2332
+ import { rspack as rspack4 } from "@rspack/core";
2333
+ import { RspackDevServer } from "@rspack/dev-server";
2334
+ import chalk3 from "chalk";
2335
+
2336
+ // src/cli/port.ts
2337
+ import net from "net";
2338
+ function isPortAvailable(port, host) {
2339
+ return new Promise((resolve3) => {
2340
+ const server = net.createServer();
2341
+ server.once("error", (err) => {
2342
+ if (err.code === "EADDRINUSE") {
2343
+ resolve3(false);
2344
+ } else {
2345
+ resolve3(false);
2346
+ }
2347
+ });
2348
+ server.once("listening", () => {
2349
+ server.close(() => resolve3(true));
2350
+ });
2351
+ server.listen(port, host);
2352
+ });
2353
+ }
2354
+ async function getAvailablePort(preferredPort, host) {
2355
+ const MAX_ATTEMPTS = 20;
2356
+ for (let i = 0; i < MAX_ATTEMPTS; i++) {
2357
+ const port = preferredPort + i;
2358
+ const available = await isPortAvailable(port, host);
2359
+ if (available) return port;
2360
+ }
2361
+ throw new Error(
2362
+ `No available port found in range ${preferredPort}-${preferredPort + MAX_ATTEMPTS - 1}`
2363
+ );
2364
+ }
2365
+
2366
+ // src/cli/dev.ts
2367
+ async function dev(options = {}) {
2368
+ const cwd = options.cwd || process.cwd();
2369
+ const mode = options.mode || "development";
2370
+ try {
2371
+ preloadEnv(cwd, mode, "development");
2372
+ const { config } = await resolveConfig(cwd);
2373
+ loadEnv(config, cwd, mode, "development");
2374
+ const pluginManager = new PluginManager(config, cwd, true);
2375
+ if (config.plugins && config.plugins.length > 0) {
2376
+ await pluginManager.loadPlugins(config.plugins);
2377
+ }
2378
+ await pluginManager.runBeforeDevServer();
2379
+ let rspackConfig = createRspackConfig(config, cwd, { isDev: true });
2380
+ rspackConfig = await pluginManager.applyRspackConfigHooks(rspackConfig);
2381
+ const host = config.dev.host || "localhost";
2382
+ const preferredPort = config.dev.port || 3e3;
2383
+ const port = await getAvailablePort(preferredPort, host);
2384
+ const pluginNames = pluginManager.getPluginNames();
2385
+ if (port !== preferredPort) {
2386
+ console.log(chalk3.yellow(` Port ${preferredPort} is in use, using ${port} instead.
2387
+ `));
2388
+ }
2389
+ const printer = new DevPrinter(host, port, pluginNames);
2390
+ printer.printBanner();
2391
+ printer.printBuildStart();
2392
+ printer.updateProgress(0, "preparing");
2393
+ rspackConfig.plugins = rspackConfig.plugins || [];
2394
+ rspackConfig.plugins.push(new rspack4.ProgressPlugin(createProgressHandler(printer)));
2395
+ rspackConfig.stats = "none";
2396
+ rspackConfig.infrastructureLogging = { level: "none" };
2397
+ if (rspackConfig.devServer) {
2398
+ const ds = rspackConfig.devServer;
2399
+ const existingClient = ds.client ?? {};
2400
+ ds.client = {
2401
+ ...existingClient,
2402
+ logging: "warn",
2403
+ overlay: false,
2404
+ progress: false
2405
+ };
2406
+ }
2407
+ const compiler = rspack4(rspackConfig);
2408
+ compiler.hooks.done.tap("ywkf-dev-printer", (stats) => {
2409
+ const hasErrors = stats.hasErrors();
2410
+ if (hasErrors) {
2411
+ const info = stats.toJson({ errors: true });
2412
+ console.log();
2413
+ console.log(chalk3.red(" Compile error:"));
2414
+ for (const err of info.errors || []) {
2415
+ console.log(chalk3.red(` ${err.message}`));
2416
+ }
2417
+ console.log();
2418
+ }
2419
+ printer.printBuildDone(hasErrors);
2420
+ });
2421
+ compiler.hooks.invalid.tap("ywkf-dev-printer", () => {
2422
+ printer.markRebuildStart();
2423
+ printer.updateProgress(0, "rebuilding");
2424
+ });
2425
+ const devServerOptions = {
2426
+ ...rspackConfig.devServer || {},
2427
+ host,
2428
+ port
2429
+ };
2430
+ const server = new RspackDevServer(devServerOptions, compiler);
2431
+ await server.start();
2432
+ await pluginManager.runAfterDevServer({ host, port });
2433
+ registerShortcuts(printer, {
2434
+ port,
2435
+ onQuit: async () => {
2436
+ console.log(chalk3.gray("\n Shutting down...\n"));
2437
+ await server.stop();
2438
+ process.exit(0);
2439
+ }
2440
+ });
2441
+ const signals = ["SIGINT", "SIGTERM"];
2442
+ for (const signal of signals) {
2443
+ process.on(signal, async () => {
2444
+ await server.stop();
2445
+ process.exit(0);
2446
+ });
2447
+ }
2448
+ } catch (error) {
2449
+ console.error();
2450
+ console.error(chalk3.red(" \u2716 Dev server failed to start"));
2541
2451
  console.error(error);
2542
2452
  process.exit(1);
2543
2453
  }
@@ -2546,10 +2456,10 @@ async function build(options = {}) {
2546
2456
  // src/cli/index.ts
2547
2457
  var __filename2 = fileURLToPath3(import.meta.url);
2548
2458
  var __dirname3 = dirname3(__filename2);
2549
- var require5 = createRequire4(import.meta.url);
2459
+ var require4 = createRequire4(import.meta.url);
2550
2460
  var version = "0.0.0";
2551
2461
  try {
2552
- const pkg = require5(join7(__dirname3, "../../package.json"));
2462
+ const pkg = require4(join7(__dirname3, "../../package.json"));
2553
2463
  version = pkg.version;
2554
2464
  } catch {
2555
2465
  }