@4399ywkf/cli 2.0.20 → 2.0.22

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.js CHANGED
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var utils = require('@umijs/utils');
4
+ var boxen = require('boxen');
5
+ var figlet = require('figlet');
4
6
  var fs = require('fs');
5
7
  var path = require('path');
6
- var figlet = require('figlet');
7
- var boxen = require('boxen');
8
8
 
9
9
  var ERegistry = /* @__PURE__ */ ((ERegistry2) => {
10
10
  ERegistry2["npm"] = "https://registry.npmjs.com/";
@@ -17,9 +17,7 @@ const cloneGitTemplate = async (opts) => {
17
17
  const { template, dest, gitUrl = "https://ywgit.gz4399.com/ywkf/" /* git */ } = opts;
18
18
  const absoluteDest = path.resolve(dest);
19
19
  const tempDir = `${absoluteDest}_temp`;
20
- utils.logger.info(
21
- `Init a new project with template ${utils.chalk.blue(template)} from git ...`
22
- );
20
+ utils.logger.info(`Init a new project with template ${utils.chalk.blue(template)} from git ...`);
23
21
  const repoUrl = `${gitUrl}${template}.git`;
24
22
  try {
25
23
  if (utils.fsExtra.existsSync(absoluteDest)) {
@@ -46,7 +44,7 @@ const cloneGitTemplate = async (opts) => {
46
44
  if (utils.fsExtra.existsSync(tempDir)) {
47
45
  try {
48
46
  utils.fsExtra.removeSync(tempDir);
49
- } catch (cleanupError) {
47
+ } catch (_cleanupError) {
50
48
  utils.logger.warn(`Failed to cleanup temporary directory: ${tempDir}`);
51
49
  }
52
50
  }
@@ -75,22 +73,20 @@ const DEFAULT_DATA = {
75
73
  withHusky: false,
76
74
  extraNpmrc: "",
77
75
  appTemplate: "app" /* app */,
78
- microRole: "none" /* none */
76
+ microRole: "none" /* none */,
77
+ enableBiome: true
79
78
  };
80
- var index = async ({
81
- cwd,
82
- args,
83
- defaultData = DEFAULT_DATA
84
- }) => {
79
+ var index = async ({ cwd, args, defaultData = DEFAULT_DATA }) => {
85
80
  let [name] = args._;
86
81
  let npmClient = "pnpm" /* pnpm */;
87
82
  let registry = ERegistry.npm;
88
83
  let gitTemplate;
89
84
  let appTemplate = (defaultData == null ? void 0 : defaultData.appTemplate) || "app" /* app */;
90
85
  let microRole = (defaultData == null ? void 0 : defaultData.microRole) || "none" /* none */;
86
+ let enableBiome = (defaultData == null ? void 0 : defaultData.enableBiome) ?? true;
91
87
  const { username, email } = await utils.getGitInfo();
92
88
  const author = email && username ? `${username} <${email}>` : "";
93
- let pluginName = `${name || "demo"}`;
89
+ const pluginName = `${name || "demo"}`;
94
90
  let target = name ? path.join(cwd, name) : cwd;
95
91
  const { isCancel, text, select, intro, outro, confirm, note } = utils.clackPrompts;
96
92
  const exitPrompt = () => {
@@ -105,7 +101,7 @@ var index = async ({
105
101
  if (!value.length) {
106
102
  return "\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0";
107
103
  }
108
- if (value != "." && utils.fsExtra.existsSync(path.join(cwd, value))) {
104
+ if (value !== "." && utils.fsExtra.existsSync(path.join(cwd, value))) {
109
105
  return `\u76EE\u5F55 ${value} \u5DF2\u5B58\u5728`;
110
106
  }
111
107
  }
@@ -172,6 +168,16 @@ var index = async ({
172
168
  exitPrompt();
173
169
  }
174
170
  };
171
+ const selectBiome = async () => {
172
+ const useBiome = await confirm({
173
+ message: "\u662F\u5426\u542F\u7528 Biome \u4EE3\u7801\u89C4\u8303\u68C0\u67E5\uFF1F\uFF08Lint / Format / Import Sorting\uFF09",
174
+ initialValue: true
175
+ });
176
+ if (isCancel(useBiome)) {
177
+ exitPrompt();
178
+ }
179
+ enableBiome = !!useBiome;
180
+ };
175
181
  const selectGitInit = async () => {
176
182
  const initGitAnswer = await confirm({
177
183
  message: "\u662F\u5426\u521D\u59CB\u5316 Git \u4ED3\u5E93\uFF1F",
@@ -203,9 +209,7 @@ var index = async ({
203
209
  });
204
210
  console.log(utils.chalk.hex("#19BDD2")(banner));
205
211
  console.log("");
206
- console.log(
207
- utils.chalk.hex("#19BDD2")(" \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501")
208
- );
212
+ console.log(utils.chalk.hex("#19BDD2")(" \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
209
213
  console.log("");
210
214
  console.log(
211
215
  utils.chalk.bold.white(" \u{1F680} \u6B22\u8FCE\u4F7F\u7528 ") + utils.chalk.hex("#19BDD2").bold("\u8FD0\u7EF4\u6280\u672F\u4E2D\u5FC3\u5F00\u53D1\u90E8") + utils.chalk.bold.white(" \u9879\u76EE\u811A\u624B\u67B6\u5DE5\u5177")
@@ -217,9 +221,7 @@ var index = async ({
217
221
  console.log("");
218
222
  console.log(utils.chalk.yellow(" \u8BA9\u6211\u4EEC\u4E00\u8D77\u521B\u5EFA\u4E00\u4E2A\u65B0\u9879\u76EE\u5427\uFF01"));
219
223
  console.log("");
220
- console.log(
221
- utils.chalk.hex("#19BDD2")(" \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501")
222
- );
224
+ console.log(utils.chalk.hex("#19BDD2")(" \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
223
225
  console.log("");
224
226
  intro(utils.chalk.hex("#19BDD2").bold("\u5F00\u59CB\u521B\u5EFA"));
225
227
  await setName();
@@ -239,6 +241,7 @@ var index = async ({
239
241
  if (isCancel(registry)) {
240
242
  exitPrompt();
241
243
  }
244
+ await selectBiome();
242
245
  await selectMicroFrontend();
243
246
  await selectGitInit();
244
247
  outro(utils.chalk.green(`\u2728 \u4E00\u5207\u5C31\u7EEA, \u5F00\u59CB\u521B\u5EFA\u9879\u76EE...`));
@@ -262,7 +265,7 @@ var index = async ({
262
265
  });
263
266
  break;
264
267
  // TODO: init template from git
265
- case useGitTemplate:
268
+ case useGitTemplate: {
266
269
  intro(utils.chalk.bgHex("#19BDD2")(" create-ywkf "));
267
270
  await setName();
268
271
  if (isCancel(name)) {
@@ -298,6 +301,7 @@ Git\u6A21\u677F: ${gitTemplate}
298
301
  dest: target
299
302
  });
300
303
  break;
304
+ }
301
305
  default:
302
306
  if (!useDefaultData) {
303
307
  await internalTemplatePrompts();
@@ -339,7 +343,8 @@ Git\u6A21\u677F: ${gitTemplate}
339
343
  microRole,
340
344
  enableMicro: microRole !== "none" /* none */,
341
345
  isMasterApp: microRole === "master" /* master */,
342
- isSubApp: microRole === "sub" /* sub */
346
+ isSubApp: microRole === "sub" /* sub */,
347
+ enableBiome
343
348
  }
344
349
  });
345
350
  await generator.run();
@@ -349,6 +354,10 @@ Git\u6A21\u677F: ${gitTemplate}
349
354
  if (microRole !== "none" /* none */) {
350
355
  await injectMicroFrontendPages(target, microRole);
351
356
  }
357
+ await injectVscodeConfig(target, enableBiome);
358
+ if (enableBiome) {
359
+ await injectBiomeConfig(target);
360
+ }
352
361
  }
353
362
  const context = {
354
363
  target,
@@ -378,9 +387,7 @@ Git\u6A21\u677F: ${gitTemplate}
378
387
  utils.logger.info(`Skip install deps`);
379
388
  if (isPnpm8) {
380
389
  utils.logger.warn(
381
- utils.chalk.yellow(
382
- `You current using pnpm v8, it will install minimal version of dependencies`
383
- )
390
+ utils.chalk.yellow(`You current using pnpm v8, it will install minimal version of dependencies`)
384
391
  );
385
392
  utils.logger.warn(
386
393
  utils.chalk.green(
@@ -391,20 +398,21 @@ Git\u6A21\u677F: ${gitTemplate}
391
398
  );
392
399
  }
393
400
  }
394
- printSuccess({ name, target, npmClient, microRole });
401
+ printSuccess({ name, target, npmClient, microRole, enableBiome });
395
402
  };
396
403
  function printSuccess(opts) {
397
- const { name, target, npmClient, microRole } = opts;
404
+ const { name, target, npmClient, microRole, enableBiome } = opts;
398
405
  const { outro } = utils.clackPrompts;
399
406
  const microLabel = microRole === "master" ? "\u4E3B\u5E94\u7528\uFF08\u57FA\u5EA7\uFF09" : microRole === "sub" ? "\u5B50\u5E94\u7528" : "\u672A\u542F\u7528";
407
+ const biomeLabel = enableBiome ? "\u5DF2\u542F\u7528" : "\u672A\u542F\u7528";
400
408
  console.log("");
401
409
  console.log(
402
410
  boxen(
403
- utils.chalk.green.bold("\u{1F389} \u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF01\n\n") + utils.chalk.white("\u{1F4E6} \u9879\u76EE\u4FE1\u606F\n") + utils.chalk.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n") + utils.chalk.cyan("\u540D\u79F0: ") + utils.chalk.white(name) + "\n" + utils.chalk.cyan("\u8DEF\u5F84: ") + utils.chalk.white(target) + "\n" + utils.chalk.cyan("\u5305\u7BA1\u7406\u5668: ") + utils.chalk.white(npmClient) + "\n" + utils.chalk.cyan("\u5FAE\u524D\u7AEF: ") + utils.chalk.white(microLabel) + "\n\n" + utils.chalk.white("\u{1F680} \u5FEB\u901F\u5F00\u59CB\n") + utils.chalk.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n") + utils.chalk.white("1. \u8FDB\u5165\u9879\u76EE\u76EE\u5F55\n") + utils.chalk.cyan(` cd ${name}
411
+ utils.chalk.green.bold("\u{1F389} \u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF01\n\n") + utils.chalk.white("\u{1F4E6} \u9879\u76EE\u4FE1\u606F\n") + utils.chalk.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n") + utils.chalk.cyan("\u540D\u79F0: ") + utils.chalk.white(name) + "\n" + utils.chalk.cyan("\u8DEF\u5F84: ") + utils.chalk.white(target) + "\n" + utils.chalk.cyan("\u5305\u7BA1\u7406\u5668: ") + utils.chalk.white(npmClient) + "\n" + utils.chalk.cyan("\u4EE3\u7801\u89C4\u8303: ") + utils.chalk.white(`Biome ${biomeLabel}`) + "\n" + utils.chalk.cyan("\u5FAE\u524D\u7AEF: ") + utils.chalk.white(microLabel) + "\n\n" + utils.chalk.white("\u{1F680} \u5FEB\u901F\u5F00\u59CB\n") + utils.chalk.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n") + utils.chalk.white("1. \u8FDB\u5165\u9879\u76EE\u76EE\u5F55\n") + utils.chalk.cyan(` cd ${name}
404
412
 
405
413
  `) + utils.chalk.white("2. \u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668\n") + utils.chalk.cyan(` ${npmClient} run dev
406
414
 
407
- `) + utils.chalk.white("3. \u6784\u5EFA\u751F\u4EA7\u7248\u672C\n") + utils.chalk.cyan(` ${npmClient} run build`),
415
+ `) + utils.chalk.white("3. \u6784\u5EFA\u751F\u4EA7\u7248\u672C\n") + utils.chalk.cyan(` ${npmClient} run build`) + (enableBiome ? "\n\n" + utils.chalk.white("4. \u4EE3\u7801\u68C0\u67E5 & \u683C\u5F0F\u5316\n") + utils.chalk.cyan(` ${npmClient} run lint:fix`) : ""),
408
416
  {
409
417
  padding: 1,
410
418
  margin: 1,
@@ -423,10 +431,7 @@ async function detectMonorepoRoot(opts) {
423
431
  return null;
424
432
  }
425
433
  const rootDir = path.dirname(rootPkg);
426
- if (utils.tryPaths([
427
- path.join(rootDir, "lerna.json"),
428
- path.join(rootDir, "pnpm-workspace.yaml")
429
- ])) {
434
+ if (utils.tryPaths([path.join(rootDir, "lerna.json"), path.join(rootDir, "pnpm-workspace.yaml")])) {
430
435
  return rootDir;
431
436
  }
432
437
  return null;
@@ -456,6 +461,125 @@ async function removeHusky(opts) {
456
461
  await utils.fsExtra.remove(dir);
457
462
  }
458
463
  }
464
+ async function injectBiomeConfig(target) {
465
+ const biomeConfig = {
466
+ $schema: "https://biomejs.dev/schemas/2.3.2/schema.json",
467
+ vcs: {
468
+ enabled: true,
469
+ defaultBranch: "main",
470
+ clientKind: "git",
471
+ useIgnoreFile: true
472
+ },
473
+ formatter: {
474
+ enabled: true,
475
+ indentStyle: "space"
476
+ },
477
+ css: {
478
+ formatter: {
479
+ quoteStyle: "single"
480
+ }
481
+ },
482
+ javascript: {
483
+ formatter: {
484
+ quoteStyle: "double",
485
+ arrowParentheses: "always",
486
+ jsxQuoteStyle: "double",
487
+ lineWidth: 100
488
+ }
489
+ },
490
+ linter: {
491
+ enabled: true,
492
+ rules: {
493
+ recommended: true,
494
+ style: {
495
+ useNodejsImportProtocol: "off",
496
+ noNonNullAssertion: "off",
497
+ noUnusedTemplateLiteral: "off",
498
+ noUselessElse: "off",
499
+ useNumberNamespace: "off"
500
+ },
501
+ suspicious: {
502
+ noExplicitAny: "off",
503
+ noConfusingVoidType: "off",
504
+ noImplicitAnyLet: "off",
505
+ noAssignInExpressions: "off",
506
+ noPrototypeBuiltins: "off"
507
+ },
508
+ complexity: {
509
+ noForEach: "off",
510
+ noBannedTypes: "off",
511
+ useArrowFunction: "off"
512
+ },
513
+ correctness: {
514
+ useExhaustiveDependencies: "off"
515
+ },
516
+ a11y: {
517
+ useAltText: "off",
518
+ useKeyWithClickEvents: "off",
519
+ useButtonType: "off",
520
+ noSvgWithoutTitle: "off"
521
+ },
522
+ performance: {
523
+ noDelete: "off"
524
+ },
525
+ security: {
526
+ noDangerouslySetInnerHtml: "off"
527
+ }
528
+ }
529
+ },
530
+ assist: {
531
+ actions: {
532
+ source: {
533
+ organizeImports: "on"
534
+ }
535
+ }
536
+ },
537
+ files: {
538
+ ignoreUnknown: true,
539
+ includes: [
540
+ "**",
541
+ "!**/.vscode/**/*",
542
+ "!**/node_modules/**/*",
543
+ "!**/dist/**/*",
544
+ "!**/.ywkf/**/*"
545
+ ]
546
+ }
547
+ };
548
+ const filePath = path.join(target, "biome.json");
549
+ await writeFile(filePath, `${JSON.stringify(biomeConfig, null, 2)}
550
+ `);
551
+ }
552
+ async function injectVscodeConfig(target, enableBiome) {
553
+ const vscodeDir = path.join(target, ".vscode");
554
+ await utils.fsExtra.ensureDir(vscodeDir);
555
+ const settings = {
556
+ "editor.formatOnSave": true
557
+ };
558
+ const extensions = {
559
+ recommendations: []
560
+ };
561
+ if (enableBiome) {
562
+ Object.assign(settings, {
563
+ "editor.defaultFormatter": "biomejs.biome",
564
+ "editor.codeActionsOnSave": {
565
+ "quickfix.biome": "explicit",
566
+ "source.organizeImports.biome": "explicit"
567
+ },
568
+ "[javascript]": { "editor.defaultFormatter": "biomejs.biome" },
569
+ "[typescript]": { "editor.defaultFormatter": "biomejs.biome" },
570
+ "[javascriptreact]": { "editor.defaultFormatter": "biomejs.biome" },
571
+ "[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" },
572
+ "[json]": { "editor.defaultFormatter": "biomejs.biome" },
573
+ "[css]": { "editor.defaultFormatter": "biomejs.biome" },
574
+ "biome.lsp.bin": "./node_modules/@biomejs/biome/bin/biome"
575
+ });
576
+ extensions.recommendations.push("biomejs.biome");
577
+ }
578
+ await writeFile(path.join(vscodeDir, "settings.json"), `${JSON.stringify(settings, null, 2)}
579
+ `);
580
+ await writeFile(path.join(vscodeDir, "extensions.json"), `${JSON.stringify(extensions, null, 2)}
581
+ `);
582
+ }
459
583
  async function installAndUpdateWithPnpm(cwd) {
460
584
  await utils.execa.execa("pnpm", ["up", "-L"], { cwd, stdio: "inherit" });
461
585
  }
@@ -479,37 +603,16 @@ async function writeFile(filePath, content) {
479
603
  await utils.fsExtra.ensureDir(path.dirname(filePath));
480
604
  await utils.fsExtra.writeFile(filePath, content, "utf-8");
481
605
  }
482
- async function injectMasterAppPages(pagesDir, appName) {
483
- await writeFile(
484
- path.join(pagesDir, "layout.tsx"),
485
- MASTER_LAYOUT
486
- );
487
- await writeFile(
488
- path.join(pagesDir, "micro/page.tsx"),
489
- MASTER_MICRO_PAGE
490
- );
491
- await writeFile(
492
- path.join(pagesDir, "micro/layout.tsx"),
493
- MASTER_MICRO_LAYOUT
494
- );
495
- await writeFile(
496
- path.join(pagesDir, "micro/$.tsx"),
497
- MASTER_MICRO_CATCHALL
498
- );
499
- await writeFile(
500
- path.join(pagesDir, "page.tsx"),
501
- MASTER_HOME_PAGE
502
- );
606
+ async function injectMasterAppPages(pagesDir, _appName) {
607
+ await writeFile(path.join(pagesDir, "layout.tsx"), MASTER_LAYOUT);
608
+ await writeFile(path.join(pagesDir, "micro/page.tsx"), MASTER_MICRO_PAGE);
609
+ await writeFile(path.join(pagesDir, "micro/layout.tsx"), MASTER_MICRO_LAYOUT);
610
+ await writeFile(path.join(pagesDir, "micro/$.tsx"), MASTER_MICRO_CATCHALL);
611
+ await writeFile(path.join(pagesDir, "page.tsx"), MASTER_HOME_PAGE);
503
612
  }
504
- async function injectSubAppPages(pagesDir, appName) {
505
- await writeFile(
506
- path.join(pagesDir, "layout.tsx"),
507
- SUB_LAYOUT
508
- );
509
- await writeFile(
510
- path.join(pagesDir, "page.tsx"),
511
- SUB_HOME_PAGE
512
- );
613
+ async function injectSubAppPages(pagesDir, _appName) {
614
+ await writeFile(path.join(pagesDir, "layout.tsx"), SUB_LAYOUT);
615
+ await writeFile(path.join(pagesDir, "page.tsx"), SUB_HOME_PAGE);
513
616
  }
514
617
  const MASTER_LAYOUT = `import { Outlet, Link, useLocation } from "react-router";
515
618
  import { Layout, Menu } from "antd";
@@ -5,8 +5,9 @@
5
5
  "scripts": {
6
6
  "dev": "ywkf dev",
7
7
  "build": "ywkf build",
8
- "build:analyze": "ywkf build --analyze",
9
- "lint": "biome check"
8
+ "build:analyze": "ywkf build --analyze"{{#enableBiome}},
9
+ "lint": "biome check",
10
+ "lint:fix": "biome check --write"{{/enableBiome}}
10
11
  },
11
12
  "engines": {
12
13
  "node": ">=20.0.0",
@@ -29,7 +30,9 @@
29
30
  "zustand": "^5.0.5"
30
31
  },
31
32
  "devDependencies": {
32
- "@biomejs/biome": "2.3.2",
33
+ {{#enableBiome}}
34
+ "@biomejs/biome": "^2.3.2",
35
+ {{/enableBiome}}
33
36
  "@tailwindcss/postcss": "^4.1.8",
34
37
  "@types/node": "^22.9.0",
35
38
  "@types/react": "^19.1.6",
@@ -1,6 +1,6 @@
1
1
  module.exports = {
2
2
  plugins: {
3
- '@tailwindcss/postcss': {},
3
+ "@tailwindcss/postcss": {},
4
4
  autoprefixer: {},
5
5
  },
6
6
  };
@@ -6,8 +6,9 @@
6
6
  }
7
7
 
8
8
  body {
9
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
10
- "Helvetica Neue", Arial, sans-serif;
9
+ font-family:
10
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
11
+ Arial, sans-serif;
11
12
  -webkit-font-smoothing: antialiased;
12
13
  -moz-osx-font-smoothing: grayscale;
13
14
  background: #fafafa;
@@ -20,7 +21,7 @@ a:hover {
20
21
 
21
22
  /* Card hover effect */
22
23
  a[style*="border-radius: 12px"]:hover {
23
- border-color: #3b82f6 !important;
24
+ border-color: #3b82f6;
24
25
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.1);
25
26
  transform: translateY(-2px);
26
27
  }
@@ -1,5 +1,5 @@
1
- import { Outlet, Link, useLocation } from "react-router";
2
1
  import { Card, Menu } from "antd";
2
+ import { Link, Outlet, useLocation } from "react-router";
3
3
 
4
4
  const SUB_NAV = [
5
5
  { key: "/dashboard", label: <Link to="/dashboard">概览</Link> },
@@ -1,4 +1,4 @@
1
- import { Typography, Card, Row, Col, Statistic } from "antd";
1
+ import { Card, Col, Row, Statistic, Typography } from "antd";
2
2
 
3
3
  const { Paragraph } = Typography;
4
4
 
@@ -6,8 +6,8 @@ export default function DashboardPage() {
6
6
  return (
7
7
  <div>
8
8
  <Paragraph>
9
- 这是 <code>/dashboard</code> 的默认页面(<code>page.tsx</code>),
10
- <code>layout.tsx</code> 配合实现嵌套布局。
9
+ 这是 <code>/dashboard</code> 的默认页面(<code>page.tsx</code>), 与{" "}
10
+ <code>layout.tsx</code> 配合实现嵌套布局。
11
11
  </Paragraph>
12
12
  <Row gutter={16}>
13
13
  <Col span={8}>
@@ -1,5 +1,5 @@
1
1
  import { Button, Result } from "antd";
2
- import { useRouteError, useNavigate } from "react-router";
2
+ import { useNavigate, useRouteError } from "react-router";
3
3
 
4
4
  export default function RootError() {
5
5
  const error = useRouteError() as Error;
@@ -1,4 +1,4 @@
1
- import { Outlet, Link, useLocation } from "react-router";
1
+ import { Link, Outlet, useLocation } from "react-router";
2
2
 
3
3
  const NAV_ITEMS = [
4
4
  { key: "/", label: "首页" },
@@ -17,10 +17,7 @@ export default function RootLayout() {
17
17
  </Link>
18
18
  <nav style={styles.nav}>
19
19
  {NAV_ITEMS.map((item) => {
20
- const active =
21
- item.key === "/"
22
- ? pathname === "/"
23
- : pathname.startsWith(item.key);
20
+ const active = item.key === "/" ? pathname === "/" : pathname.startsWith(item.key);
24
21
  return (
25
22
  <Link
26
23
  key={item.key}
@@ -41,9 +38,7 @@ export default function RootLayout() {
41
38
  <Outlet />
42
39
  </main>
43
40
 
44
- <footer style={styles.footer}>
45
- YWKF Framework ©{new Date().getFullYear()}
46
- </footer>
41
+ <footer style={styles.footer}>YWKF Framework ©{new Date().getFullYear()}</footer>
47
42
  </div>
48
43
  );
49
44
  }
@@ -2,7 +2,9 @@ import { Spin } from "antd";
2
2
 
3
3
  export default function RootLoading() {
4
4
  return (
5
- <div style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "60vh" }}>
5
+ <div
6
+ style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "60vh" }}
7
+ >
6
8
  <Spin size="large" tip="加载中..." />
7
9
  </div>
8
10
  );
@@ -36,8 +36,7 @@ export default function WelcomePage() {
36
36
  <span style={styles.brand}>YWKF Framework</span>
37
37
  </h1>
38
38
  <p style={styles.hint}>
39
- 开始编辑{" "}
40
- <code style={styles.code}>src/pages/page.tsx</code>
39
+ 开始编辑 <code style={styles.code}>src/pages/page.tsx</code>
41
40
  </p>
42
41
  </div>
43
42
  </div>
@@ -1,5 +1,5 @@
1
- import { Typography, Descriptions, Button } from "antd";
2
- import { useParams, useNavigate } from "react-router";
1
+ import { Button, Descriptions, Typography } from "antd";
2
+ import { useNavigate, useParams } from "react-router";
3
3
 
4
4
  const { Title } = Typography;
5
5
 
@@ -16,8 +16,7 @@ export default function UserDetailPage() {
16
16
  <code>/user/[id]/page.tsx</code> → <code>/user/:id</code>
17
17
  </Descriptions.Item>
18
18
  <Descriptions.Item label="说明">
19
- 目录名 <code>[id]</code> 会被解析为动态路由参数,
20
- 使用 <code>useParams()</code> 获取值。
19
+ 目录名 <code>[id]</code> 会被解析为动态路由参数, 使用 <code>useParams()</code> 获取值。
21
20
  </Descriptions.Item>
22
21
  </Descriptions>
23
22
  <div style={{ marginTop: 16 }}>
@@ -1,4 +1,4 @@
1
- import { Typography, Table, Button } from "antd";
1
+ import { Button, Table, Typography } from "antd";
2
2
  import { Link } from "react-router";
3
3
 
4
4
  const { Title } = Typography;
@@ -26,12 +26,7 @@ export default function UserListPage() {
26
26
  return (
27
27
  <div style={{ maxWidth: 720, margin: "0 auto" }}>
28
28
  <Title level={2}>用户列表</Title>
29
- <Table
30
- dataSource={MOCK_USERS}
31
- columns={columns}
32
- rowKey="id"
33
- pagination={false}
34
- />
29
+ <Table dataSource={MOCK_USERS} columns={columns} rowKey="id" pagination={false} />
35
30
  <div style={{ marginTop: 16 }}>
36
31
  <Button type="link">
37
32
  <Link to="/user/42">直接访问 /user/42(动态路由)</Link>
@@ -1,4 +1,4 @@
1
- export { useAppStore, getAppStoreState } from "./store";
2
- export type { AppStore } from "./store";
3
- export { initialState } from "./initialState";
4
1
  export type { AppStoreState } from "./initialState";
2
+ export { initialState } from "./initialState";
3
+ export type { AppStore } from "./store";
4
+ export { getAppStoreState, useAppStore } from "./store";
@@ -1,7 +1,4 @@
1
- import {
2
- type CounterState,
3
- initialCounterState,
4
- } from "./slices/counter/initialState";
1
+ import { type CounterState, initialCounterState } from "./slices/counter/initialState";
5
2
 
6
3
  export type AppStoreState = CounterState;
7
4
 
@@ -15,7 +15,7 @@ export const createCounterSlice: StateCreator<
15
15
  [["zustand/devtools", never]],
16
16
  [],
17
17
  CounterAction
18
- > = (set, get) => ({
18
+ > = (set, _get) => ({
19
19
  increment: () => set((s) => ({ count: s.count + 1 })),
20
20
  decrement: () => set((s) => ({ count: s.count - 1 })),
21
21
  reset: () => set({ count: 0, error: null }),
@@ -6,16 +6,11 @@ import type { StateCreator } from "zustand/vanilla";
6
6
  import { createDevtools } from "../middleware/createDevtools";
7
7
  import { type AppStoreState, initialState } from "./initialState";
8
8
 
9
- import {
10
- type CounterAction,
11
- createCounterSlice,
12
- } from "./slices/counter/actions";
9
+ import { type CounterAction, createCounterSlice } from "./slices/counter/actions";
13
10
 
14
11
  export type AppStore = AppStoreState & CounterAction;
15
12
 
16
- const createStore: StateCreator<AppStore, [["zustand/devtools", never]]> = (
17
- ...parameters
18
- ) => ({
13
+ const createStore: StateCreator<AppStore, [["zustand/devtools", never]]> = (...parameters) => ({
19
14
  ...initialState,
20
15
  ...createCounterSlice(...parameters),
21
16
  });
@@ -1,2 +1,2 @@
1
- export { useAppStore, getAppStoreState } from "./app";
2
1
  export type { AppStore, AppStoreState } from "./app";
2
+ export { getAppStoreState, useAppStore } from "./app";
@@ -19,14 +19,6 @@
19
19
  "@ywkf/store": ["./.ywkf/store.ts"]
20
20
  }
21
21
  },
22
- "include": [
23
- "src/**/*",
24
- "store/**/*",
25
- ".ywkf/**/*",
26
- "ywkf.config.ts"
27
- ],
28
- "exclude": [
29
- "node_modules",
30
- "dist"
31
- ]
22
+ "include": ["src/**/*", "store/**/*", ".ywkf/**/*", "ywkf.config.ts"],
23
+ "exclude": ["node_modules", "dist"]
32
24
  }
@@ -1,5 +1,5 @@
1
1
  import { defineConfig } from "@4399ywkf/core/config";
2
- import { tailwindPlugin, reactQueryPlugin, zustandPlugin, themePlugin{{#enableMicro}}, garfishPlugin{{/enableMicro}} } from "@4399ywkf/core";
2
+ import { tailwindPlugin, reactQueryPlugin, zustandPlugin, themePlugin{{#enableBiome}}, biomePlugin{{/enableBiome}}{{#enableMicro}}, garfishPlugin{{/enableMicro}} } from "@4399ywkf/core";
3
3
 
4
4
  export default defineConfig({
5
5
  appName: process.env.APP_NAME || "{{{ name }}}",
@@ -58,6 +58,9 @@ export default defineConfig({
58
58
  }),
59
59
  zustandPlugin(),
60
60
  tailwindPlugin(),
61
+ {{#enableBiome}}
62
+ biomePlugin(),
63
+ {{/enableBiome}}
61
64
  {{#isSubApp}}
62
65
 
63
66
  // 微前端 · 子应用模式
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4399ywkf/cli",
3
- "version": "2.0.20",
3
+ "version": "2.0.22",
4
4
  "description": "运维开发部脚手架",
5
5
  "main": "dist/index.js",
6
6
  "bin": {