@icebreakers/monorepo-templates 0.1.15 → 1.0.0

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.
Files changed (80) hide show
  1. package/README.md +12 -0
  2. package/assets/.changeset/config.json +7 -2
  3. package/assets/.github/workflows/ci.yml +8 -2
  4. package/assets/.github/workflows/release.yml +2 -2
  5. package/assets/.husky/commit-msg +1 -1
  6. package/assets/.husky/pre-commit +1 -1
  7. package/assets/.husky/pre-push +5 -0
  8. package/assets/.vscode/settings.json +1 -6
  9. package/assets/AGENTS.md +8 -7
  10. package/assets/commitlint.config.ts +2 -2
  11. package/assets/eslint.config.js +2 -6
  12. package/assets/lint-staged.config.js +3 -0
  13. package/assets/package.json +39 -28
  14. package/assets/repoctl.config.ts +68 -0
  15. package/assets/stylelint.config.js +2 -2
  16. package/assets/tooling/ensure-tooling-built.mjs +24 -0
  17. package/assets/tooling/load-tooling-module.mjs +71 -0
  18. package/assets/tsconfig.json +1 -49
  19. package/assets/turbo.json +17 -6
  20. package/assets/vitest.config.ts +2 -125
  21. package/assets-data.mjs +4 -2
  22. package/dist/index.d.mts +22 -1
  23. package/dist/index.mjs +114 -30
  24. package/package.json +12 -8
  25. package/template-data.mjs +48 -8
  26. package/templates/client/eslint.config.js +6 -4
  27. package/templates/client/package.json +22 -22
  28. package/templates/client/vite.config.ts +4 -3
  29. package/templates/client/wrangler.jsonc +1 -6
  30. package/templates/server/package.json +4 -4
  31. package/templates/server/src/app.ts +4 -4
  32. package/templates/server/tsconfig.json +1 -2
  33. package/templates/server/vitest.config.ts +6 -5
  34. package/templates/server/wrangler.jsonc +1 -6
  35. package/templates/tsdown/package.json +2 -1
  36. package/templates/tsdown/test-d/index.test-d.ts +5 -0
  37. package/templates/tsdown/tsconfig.json +1 -2
  38. package/templates/tsdown/vitest.config.ts +6 -5
  39. package/templates/vitepress/.vitepress/config.ts +34 -36
  40. package/templates/vitepress/getting-started.md +243 -0
  41. package/templates/vitepress/gitignore +2 -1
  42. package/templates/vitepress/index.md +144 -79
  43. package/templates/vitepress/monorepo/commands.md +281 -0
  44. package/templates/vitepress/monorepo/index.md +103 -34
  45. package/templates/vitepress/monorepo/manage.md +181 -80
  46. package/templates/vitepress/monorepo/publish.md +128 -57
  47. package/templates/vitepress/monorepo/templates.md +67 -0
  48. package/templates/vitepress/monorepo/troubleshooting.md +207 -0
  49. package/templates/vitepress/package.json +5 -5
  50. package/templates/vitepress/thinking.md +1 -1
  51. package/templates/vitepress/tools/husky.md +7 -2
  52. package/templates/vitepress/tools/lint-staged.md +15 -1
  53. package/templates/vitepress/why/examples/usage-cjs/index.js +2 -6
  54. package/templates/vitepress/why/examples/usage-cjs/package-lock.json +7 -13
  55. package/templates/vitepress/why/examples/usage-cjs/package.json +2 -2
  56. package/templates/vitepress/why/examples/usage-esm/index.js +2 -2
  57. package/templates/vitepress/why/examples/usage-esm/package-lock.json +7 -13
  58. package/templates/vitepress/why/examples/usage-esm/package.json +2 -2
  59. package/templates/vitepress/why/modern/bundlers.md +8 -46
  60. package/templates/vue-lib/eslint.config.js +6 -4
  61. package/templates/vue-lib/package.json +17 -12
  62. package/templates/vue-lib/test-d/index.test-d.ts +6 -0
  63. package/templates/vue-lib/tsconfig.test.json +1 -1
  64. package/templates/vue-lib/vitest.config.ts +8 -5
  65. package/assets/monorepo.config.ts +0 -22
  66. package/assets/nano-staged.js +0 -18
  67. package/templates/tsup/build.config.ts +0 -24
  68. package/templates/tsup/package.json +0 -49
  69. package/templates/tsup/src/index.ts +0 -12
  70. package/templates/tsup/test/index.test.ts +0 -18
  71. package/templates/tsup/tsconfig.json +0 -15
  72. package/templates/tsup/tsup.config.ts +0 -18
  73. package/templates/tsup/vitest.config.ts +0 -15
  74. package/templates/unbuild/build.config.ts +0 -24
  75. package/templates/unbuild/package.json +0 -49
  76. package/templates/unbuild/src/index.ts +0 -9
  77. package/templates/unbuild/src/utils.ts +0 -5
  78. package/templates/unbuild/test/index.test.ts +0 -18
  79. package/templates/unbuild/tsconfig.json +0 -15
  80. package/templates/unbuild/vitest.config.ts +0 -15
@@ -1,127 +1,4 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
- import { fileURLToPath } from 'node:url'
1
+ import { defineVitestConfig } from 'repoctl/tooling'
4
2
  import { defineConfig } from 'vitest/config'
5
- import YAML from 'yaml'
6
3
 
7
- const ROOT_DIR = path.dirname(fileURLToPath(new URL(import.meta.url)))
8
- const WORKSPACE_FILE = path.resolve(ROOT_DIR, 'pnpm-workspace.yaml')
9
- const CONFIG_FILENAMES = [
10
- 'vitest.config.ts',
11
- 'vitest.config.mts',
12
- 'vitest.config.cts',
13
- 'vitest.config.js',
14
- 'vitest.config.cjs',
15
- 'vitest.config.mjs',
16
- ] as const
17
- const WINDOWS_PATH_SEPARATOR_RE = /\\/g
18
- const RELATIVE_CURRENT_DIR_RE = /^\.\//
19
- const GLOB_TOKEN_RE = /[*?[{]/
20
- const TRAILING_SLASH_RE = /\/+$/
21
-
22
- function extractBaseDirFromGlob(pattern: string): string | null {
23
- if (!pattern) {
24
- return null
25
- }
26
-
27
- const normalized = pattern
28
- .replace(WINDOWS_PATH_SEPARATOR_RE, '/')
29
- .replace(RELATIVE_CURRENT_DIR_RE, '')
30
- const globIndex = normalized.search(GLOB_TOKEN_RE)
31
- const base = globIndex === -1
32
- ? normalized
33
- : normalized.slice(0, globIndex)
34
-
35
- const cleaned = base.replace(TRAILING_SLASH_RE, '')
36
- return cleaned || null
37
- }
38
-
39
- function loadProjectRootsFromWorkspace(): string[] {
40
- if (!fs.existsSync(WORKSPACE_FILE)) {
41
- return []
42
- }
43
-
44
- try {
45
- const workspaceContent = fs.readFileSync(WORKSPACE_FILE, 'utf8')
46
- const workspace = YAML.parse(workspaceContent) ?? {}
47
- const packages: unknown[] = Array.isArray(workspace.packages) ? workspace.packages : []
48
- const roots = packages
49
- .map(entry => typeof entry === 'string' ? entry.trim() : '')
50
- .filter(entry => entry && !entry.startsWith('!'))
51
- .map(extractBaseDirFromGlob)
52
- .filter((entry): entry is string => Boolean(entry))
53
-
54
- return roots.length ? [...new Set(roots)] : []
55
- }
56
- catch (error) {
57
- console.warn('[vitest] Failed to parse pnpm-workspace.yaml, no project roots will be used.', error)
58
- return []
59
- }
60
- }
61
-
62
- const PROJECT_ROOTS = loadProjectRootsFromWorkspace()
63
-
64
- if (!PROJECT_ROOTS.length) {
65
- console.warn('[vitest] No project roots detected. Check pnpm-workspace.yaml to define workspace packages.')
66
- }
67
-
68
- function findConfig(basePath: string): string | null {
69
- for (const filename of CONFIG_FILENAMES) {
70
- const candidate = path.join(basePath, filename)
71
- if (fs.existsSync(candidate)) {
72
- return candidate
73
- }
74
- }
75
- return null
76
- }
77
-
78
- function resolveProjects(): string[] {
79
- const projects: string[] = []
80
-
81
- for (const folder of PROJECT_ROOTS) {
82
- const rootPath = path.resolve(ROOT_DIR, folder)
83
- if (!fs.existsSync(rootPath)) {
84
- continue
85
- }
86
-
87
- const rootConfig = findConfig(rootPath)
88
- if (rootConfig) {
89
- projects.push(rootConfig)
90
- }
91
-
92
- const entries = fs.readdirSync(rootPath, { withFileTypes: true })
93
- for (const entry of entries) {
94
- if (!entry.isDirectory()) {
95
- continue
96
- }
97
-
98
- const projectDir = path.join(rootPath, entry.name)
99
- const configPath = findConfig(projectDir)
100
- if (configPath) {
101
- projects.push(configPath)
102
- }
103
- }
104
- }
105
-
106
- return projects
107
- }
108
-
109
- const projects = resolveProjects()
110
-
111
- export default defineConfig(() => {
112
- return {
113
- test: {
114
- projects,
115
- coverage: {
116
- enabled: true,
117
- skipFull: true,
118
- exclude: [
119
- '**/dist/**',
120
- ],
121
- },
122
- forceRerunTriggers: [
123
- '**/{vitest,vite}.config.*/**',
124
- ],
125
- },
126
- }
127
- })
4
+ export default defineConfig(async () => await defineVitestConfig())
package/assets-data.mjs CHANGED
@@ -8,13 +8,15 @@ const coreAssetTargets = [
8
8
  '.npmrc',
9
9
  'commitlint.config.ts',
10
10
  'eslint.config.js',
11
- 'nano-staged.js',
11
+ 'lint-staged.config.js',
12
12
  'stylelint.config.js',
13
- 'monorepo.config.ts',
13
+ 'repoctl.config.ts',
14
14
  'package.json',
15
15
  'AGENTS.md',
16
16
  // pnpm
17
17
  'pnpm-workspace.yaml',
18
+ 'scripts',
19
+ 'tooling',
18
20
  // base tsconfig
19
21
  'tsconfig.json',
20
22
  // turbo
package/dist/index.d.mts CHANGED
@@ -4,16 +4,25 @@ import select from "@inquirer/select";
4
4
  import { Command, program } from "commander";
5
5
 
6
6
  //#region src/types.d.ts
7
+ type TemplateCategory = 'app' | 'docs' | 'library' | 'service' | 'tool';
7
8
  interface TemplateChoice {
8
9
  key: string;
9
10
  label: string;
10
11
  source: string;
11
12
  target: string;
13
+ description?: string;
14
+ category?: TemplateCategory;
12
15
  }
13
16
  interface TemplateDefinition {
14
17
  source: string;
15
18
  target: string;
16
19
  }
20
+ interface GetTemplateChoicesOptions {
21
+ category?: TemplateCategory;
22
+ }
23
+ interface SuggestTemplateKeyOptions extends GetTemplateChoicesOptions {
24
+ keys?: readonly string[];
25
+ }
17
26
  //#endregion
18
27
  //#region src/paths.d.ts
19
28
  declare const packageDir: string;
@@ -74,6 +83,18 @@ declare function isGitignoreFile(name: string): boolean;
74
83
  declare function shouldSkipTemplatePath(rootDir: string, targetPath: string): boolean;
75
84
  declare function createTemplateCopyFilter(rootDir: string): (src: string) => boolean;
76
85
  //#endregion
86
+ //#region src/templates.d.ts
87
+ declare const templateCategories: readonly ["app", "docs", "library", "service", "tool"];
88
+ declare function isTemplateCategory(value: string): value is TemplateCategory;
89
+ declare function getTemplateChoices(options?: GetTemplateChoicesOptions): TemplateChoice[];
90
+ declare function getTemplateKeys(options?: GetTemplateChoicesOptions): string[];
91
+ declare function getTemplateChoice(key: string): TemplateChoice | undefined;
92
+ declare function isTemplateKey(key: string): boolean;
93
+ declare function getTemplateDefinition(key: string): TemplateDefinition | undefined;
94
+ declare function getTemplateSource(key: string): string | undefined;
95
+ declare function getTemplateTarget(key: string): string | undefined;
96
+ declare function suggestTemplateKey(key: string, options?: SuggestTemplateKeyOptions): string | undefined;
97
+ //#endregion
77
98
  //#region src/index.d.ts
78
99
  declare const templateChoices: TemplateChoice[];
79
100
  declare const assetTargets: string[];
@@ -82,4 +103,4 @@ declare const templateSourceMap: Record<string, string>;
82
103
  declare const templateTargetMap: Record<string, string>;
83
104
  declare const templateMap: Record<string, string>;
84
105
  //#endregion
85
- export { Command, type TemplateChoice, type TemplateDefinition, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, input, isGitignoreFile, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
106
+ export { Command, type GetTemplateChoicesOptions, type SuggestTemplateKeyOptions, type TemplateCategory, type TemplateChoice, type TemplateDefinition, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, getTemplateChoice, getTemplateChoices, getTemplateDefinition, getTemplateKeys, getTemplateSource, getTemplateTarget, input, isGitignoreFile, isTemplateCategory, isTemplateKey, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, suggestTemplateKey, templateCategories, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
package/dist/index.mjs CHANGED
@@ -18,12 +18,14 @@ const coreAssetTargets = [
18
18
  ".npmrc",
19
19
  "commitlint.config.ts",
20
20
  "eslint.config.js",
21
- "nano-staged.js",
21
+ "lint-staged.config.js",
22
22
  "stylelint.config.js",
23
- "monorepo.config.ts",
23
+ "repoctl.config.ts",
24
24
  "package.json",
25
25
  "AGENTS.md",
26
26
  "pnpm-workspace.yaml",
27
+ "scripts",
28
+ "tooling",
27
29
  "tsconfig.json",
28
30
  "turbo.json",
29
31
  "vitest.config.ts",
@@ -44,64 +46,64 @@ function getAssetTargets$1(core = false) {
44
46
  return core ? [...coreAssetTargets] : [...assetTargets$1];
45
47
  }
46
48
  //#endregion
49
+ //#region src/paths.ts
50
+ const packageDir = path$1.resolve(fileURLToPath(new URL("../", import.meta.url)));
51
+ const templatesDir = path$1.join(packageDir, "templates");
52
+ const assetsDir = path$1.join(packageDir, "assets");
53
+ const skeletonDir = assetsDir;
54
+ //#endregion
47
55
  //#region template-data.mjs
48
56
  const templateChoices$1 = [
49
- {
50
- key: "unbuild",
51
- label: "unbuild 打包",
52
- source: "unbuild",
53
- target: "packages/unbuild"
54
- },
55
- {
56
- key: "tsup",
57
- label: "tsup 打包",
58
- source: "tsup",
59
- target: "packages/tsup"
60
- },
61
57
  {
62
58
  key: "tsdown",
63
59
  label: "tsdown 打包",
64
60
  source: "tsdown",
65
- target: "packages/tsdown"
61
+ target: "packages/tsdown",
62
+ category: "library",
63
+ description: "使用 tsdown 构建的 TypeScript 库包"
66
64
  },
67
65
  {
68
66
  key: "vue-lib",
69
67
  label: "vue 组件",
70
68
  source: "vue-lib",
71
- target: "packages/vue-lib"
69
+ target: "packages/vue-lib",
70
+ category: "library",
71
+ description: "Vue 3 组件库模板,适合沉淀可复用 UI"
72
72
  },
73
73
  {
74
74
  key: "vue-hono",
75
75
  label: "vue hono 全栈",
76
76
  source: "client",
77
- target: "apps/client"
77
+ target: "apps/client",
78
+ category: "app",
79
+ description: "Vue 3 + Hono 的前后端一体应用模板"
78
80
  },
79
81
  {
80
82
  key: "hono-server",
81
83
  label: "hono 模板",
82
84
  source: "server",
83
- target: "apps/server"
85
+ target: "apps/server",
86
+ category: "service",
87
+ description: "Hono API 服务模板"
84
88
  },
85
89
  {
86
90
  key: "vitepress",
87
91
  label: "vitepress 文档",
88
92
  source: "vitepress",
89
- target: "apps/website"
93
+ target: "apps/website",
94
+ category: "docs",
95
+ description: "VitePress 文档站模板"
90
96
  },
91
97
  {
92
98
  key: "cli",
93
99
  label: "cli 模板",
94
100
  source: "cli",
95
- target: "apps/cli"
101
+ target: "apps/cli",
102
+ category: "tool",
103
+ description: "TypeScript 命令行工具模板"
96
104
  }
97
105
  ];
98
106
  //#endregion
99
- //#region src/paths.ts
100
- const packageDir = path$1.resolve(fileURLToPath(new URL("../", import.meta.url)));
101
- const templatesDir = path$1.join(packageDir, "templates");
102
- const assetsDir = path$1.join(packageDir, "assets");
103
- const skeletonDir = assetsDir;
104
- //#endregion
105
107
  //#region src/utils/gitignore.ts
106
108
  const publishBasename = "gitignore";
107
109
  const workspaceBasename = ".gitignore";
@@ -156,6 +158,7 @@ function shouldSkipTemplatePath(rootDir, targetPath) {
156
158
  const basename = path.basename(targetPath);
157
159
  if (skipFiles.has(basename)) return true;
158
160
  if (basename.endsWith(".tsbuildinfo")) return true;
161
+ if (/\.timestamp-\d+-[a-z0-9]+\.mjs$/i.test(basename)) return true;
159
162
  const relative = path.relative(rootDir, targetPath);
160
163
  if (!relative || relative.startsWith("..")) return false;
161
164
  const segments = relative.split(path.sep);
@@ -223,8 +226,11 @@ async function copyEntry(from, to, overwriteExisting, filter) {
223
226
  }
224
227
  }
225
228
  async function copyAssets(repoRoot, overwriteExisting) {
229
+ const monorepoAssetRoot = path$1.resolve(repoRoot, "packages/monorepo/assets");
226
230
  for (const target of assetTargets$1) {
227
- const from = path$1.join(repoRoot, target);
231
+ const packageAsset = path$1.join(monorepoAssetRoot, toPublishGitignorePath(target));
232
+ const repoAsset = path$1.join(repoRoot, target);
233
+ const from = await pathExists$1(packageAsset) ? packageAsset : repoAsset;
228
234
  if (!await pathExists$1(from)) continue;
229
235
  const to = path$1.join(assetsDir, toPublishGitignorePath(target));
230
236
  const stats = await fs.stat(from);
@@ -277,7 +283,7 @@ async function isPrepared() {
277
283
  const checks = [
278
284
  path.join(assetsDir, "AGENTS.md"),
279
285
  path.join(assetsDir, "LICENSE"),
280
- path.join(templatesDir, "unbuild")
286
+ path.join(templatesDir, "tsdown")
281
287
  ];
282
288
  return (await Promise.all(checks.map(pathExists))).every(Boolean);
283
289
  }
@@ -399,6 +405,84 @@ async function scaffoldWorkspace(options) {
399
405
  }
400
406
  }
401
407
  //#endregion
408
+ //#region src/templates.ts
409
+ const templateCategories = [
410
+ "app",
411
+ "docs",
412
+ "library",
413
+ "service",
414
+ "tool"
415
+ ];
416
+ const choices = templateChoices$1;
417
+ const categorySet = new Set(templateCategories);
418
+ function cloneTemplateChoice(choice) {
419
+ return { ...choice };
420
+ }
421
+ function isTemplateCategory(value) {
422
+ return categorySet.has(value);
423
+ }
424
+ function getTemplateChoices(options = {}) {
425
+ const { category } = options;
426
+ return (category ? choices.filter((choice) => choice.category === category) : choices).map(cloneTemplateChoice);
427
+ }
428
+ function getTemplateKeys(options = {}) {
429
+ return getTemplateChoices(options).map((choice) => choice.key);
430
+ }
431
+ function getTemplateChoice(key) {
432
+ const choice = choices.find((item) => item.key === key);
433
+ return choice ? cloneTemplateChoice(choice) : void 0;
434
+ }
435
+ function isTemplateKey(key) {
436
+ return choices.some((choice) => choice.key === key);
437
+ }
438
+ function getTemplateDefinition(key) {
439
+ const choice = getTemplateChoice(key);
440
+ if (!choice) return;
441
+ return {
442
+ source: choice.source,
443
+ target: choice.target
444
+ };
445
+ }
446
+ function getTemplateSource(key) {
447
+ return getTemplateChoice(key)?.source;
448
+ }
449
+ function getTemplateTarget(key) {
450
+ return getTemplateChoice(key)?.target;
451
+ }
452
+ function getEditDistance(left, right) {
453
+ const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
454
+ for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
455
+ const current = [leftIndex];
456
+ for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {
457
+ const substitutionCost = left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1;
458
+ current[rightIndex] = Math.min((current[rightIndex - 1] ?? 0) + 1, (previous[rightIndex] ?? 0) + 1, (previous[rightIndex - 1] ?? 0) + substitutionCost);
459
+ }
460
+ previous.splice(0, previous.length, ...current);
461
+ }
462
+ return previous[right.length] ?? 0;
463
+ }
464
+ function getTemplateSuggestionThreshold(value) {
465
+ if (value.length <= 4) return 1;
466
+ if (value.length <= 8) return 2;
467
+ return 3;
468
+ }
469
+ function suggestTemplateKey(key, options = {}) {
470
+ const normalizedKey = key.trim().toLowerCase();
471
+ if (!normalizedKey) return;
472
+ const keys = options.keys ? [...options.keys] : getTemplateKeys(options);
473
+ const prefixMatch = keys.find((candidate) => {
474
+ const normalizedCandidate = candidate.toLowerCase();
475
+ return normalizedCandidate.startsWith(normalizedKey) || normalizedKey.startsWith(normalizedCandidate);
476
+ });
477
+ if (prefixMatch) return prefixMatch;
478
+ const [best] = keys.map((candidate) => ({
479
+ key: candidate,
480
+ distance: getEditDistance(normalizedKey, candidate.toLowerCase())
481
+ })).sort((left, right) => left.distance - right.distance || left.key.localeCompare(right.key));
482
+ if (!best || best.distance > getTemplateSuggestionThreshold(normalizedKey)) return;
483
+ return best.key;
484
+ }
485
+ //#endregion
402
486
  //#region src/utils/command.ts
403
487
  async function runCommand(command, args, options = {}) {
404
488
  const result = await exec(command, args, {
@@ -419,11 +503,11 @@ async function execaCommand(command, options = {}) {
419
503
  }
420
504
  //#endregion
421
505
  //#region src/index.ts
422
- const templateChoices = templateChoices$1;
506
+ const templateChoices = getTemplateChoices();
423
507
  const assetTargets = assetTargets$1;
424
508
  const getAssetTargets = getAssetTargets$1;
425
509
  const templateSourceMap = Object.fromEntries(templateChoices.map((item) => [item.key, item.source]));
426
510
  const templateTargetMap = Object.fromEntries(templateChoices.map((item) => [item.key, item.target]));
427
511
  const templateMap = templateSourceMap;
428
512
  //#endregion
429
- export { Command, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, input, isGitignoreFile, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
513
+ export { Command, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, getTemplateChoice, getTemplateChoices, getTemplateDefinition, getTemplateKeys, getTemplateSource, getTemplateTarget, input, isGitignoreFile, isTemplateCategory, isTemplateKey, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, suggestTemplateKey, templateCategories, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@icebreakers/monorepo-templates",
3
3
  "type": "module",
4
- "version": "0.1.15",
4
+ "version": "1.0.0",
5
5
  "description": "Template assets for icebreaker monorepo scaffolding",
6
6
  "author": "ice breaker <hi@sonofmagic.top>",
7
7
  "license": "MIT",
@@ -21,14 +21,17 @@
21
21
  "sideEffects": false,
22
22
  "exports": {
23
23
  ".": {
24
- "types": "./dist/index.d.ts",
25
- "import": "./dist/index.mjs",
24
+ "types": "./dist/index.d.mts",
25
+ "import": {
26
+ "types": "./dist/index.d.mts",
27
+ "default": "./dist/index.mjs"
28
+ },
26
29
  "default": "./dist/index.mjs"
27
30
  },
28
31
  "./package.json": "./package.json"
29
32
  },
30
33
  "main": "./dist/index.mjs",
31
- "types": "./dist/index.d.ts",
34
+ "types": "./dist/index.d.mts",
32
35
  "files": [
33
36
  "assets",
34
37
  "assets-data.mjs",
@@ -40,9 +43,9 @@
40
43
  "node": ">=18.0.0"
41
44
  },
42
45
  "dependencies": {
43
- "@inquirer/checkbox": "^5.1.0",
44
- "@inquirer/input": "^5.0.8",
45
- "@inquirer/select": "^5.1.0",
46
+ "@inquirer/checkbox": "^5.1.4",
47
+ "@inquirer/input": "^5.0.12",
48
+ "@inquirer/select": "^5.1.4",
46
49
  "commander": "^14.0.3",
47
50
  "nanoexec": "^1.1.0"
48
51
  },
@@ -52,7 +55,8 @@
52
55
  "scripts": {
53
56
  "dev": "tsdown --watch --sourcemap",
54
57
  "build": "tsdown",
55
- "typecheck": "tsc -p tsconfig.json",
58
+ "typecheck": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json",
59
+ "tsd": "pnpm build && tsd --files test-d/**/*.test-d.ts",
56
60
  "sync:assets": "pnpm run build && node scripts/sync-assets.mjs",
57
61
  "lint": "eslint ."
58
62
  }
package/template-data.mjs CHANGED
@@ -1,10 +1,50 @@
1
1
  export const templateChoices = [
2
- { key: 'unbuild', label: 'unbuild 打包', source: 'unbuild', target: 'packages/unbuild' },
3
- { key: 'tsup', label: 'tsup 打包', source: 'tsup', target: 'packages/tsup' },
4
- { key: 'tsdown', label: 'tsdown 打包', source: 'tsdown', target: 'packages/tsdown' },
5
- { key: 'vue-lib', label: 'vue 组件', source: 'vue-lib', target: 'packages/vue-lib' },
6
- { key: 'vue-hono', label: 'vue hono 全栈', source: 'client', target: 'apps/client' },
7
- { key: 'hono-server', label: 'hono 模板', source: 'server', target: 'apps/server' },
8
- { key: 'vitepress', label: 'vitepress 文档', source: 'vitepress', target: 'apps/website' },
9
- { key: 'cli', label: 'cli 模板', source: 'cli', target: 'apps/cli' },
2
+ {
3
+ key: 'tsdown',
4
+ label: 'tsdown 打包',
5
+ source: 'tsdown',
6
+ target: 'packages/tsdown',
7
+ category: 'library',
8
+ description: '使用 tsdown 构建的 TypeScript 库包',
9
+ },
10
+ {
11
+ key: 'vue-lib',
12
+ label: 'vue 组件',
13
+ source: 'vue-lib',
14
+ target: 'packages/vue-lib',
15
+ category: 'library',
16
+ description: 'Vue 3 组件库模板,适合沉淀可复用 UI',
17
+ },
18
+ {
19
+ key: 'vue-hono',
20
+ label: 'vue hono 全栈',
21
+ source: 'client',
22
+ target: 'apps/client',
23
+ category: 'app',
24
+ description: 'Vue 3 + Hono 的前后端一体应用模板',
25
+ },
26
+ {
27
+ key: 'hono-server',
28
+ label: 'hono 模板',
29
+ source: 'server',
30
+ target: 'apps/server',
31
+ category: 'service',
32
+ description: 'Hono API 服务模板',
33
+ },
34
+ {
35
+ key: 'vitepress',
36
+ label: 'vitepress 文档',
37
+ source: 'vitepress',
38
+ target: 'apps/website',
39
+ category: 'docs',
40
+ description: 'VitePress 文档站模板',
41
+ },
42
+ {
43
+ key: 'cli',
44
+ label: 'cli 模板',
45
+ source: 'cli',
46
+ target: 'apps/cli',
47
+ category: 'tool',
48
+ description: 'TypeScript 命令行工具模板',
49
+ },
10
50
  ]
@@ -1,10 +1,12 @@
1
1
  import { fileURLToPath } from 'node:url'
2
- import { icebreaker } from '@icebreakers/eslint-config'
2
+ import { loadRepoctlToolingModule } from '../../tooling/load-tooling-module.mjs'
3
+
4
+ const { defineEslintConfig } = await loadRepoctlToolingModule()
3
5
 
4
6
  const tailwindEntryPoint = fileURLToPath(new URL('./src/style.css', import.meta.url))
5
7
 
6
- export default icebreaker(
7
- {
8
+ export default await defineEslintConfig({
9
+ options: {
8
10
  vue: true,
9
11
  typescript: true,
10
12
  tailwindcss: {
@@ -12,4 +14,4 @@ export default icebreaker(
12
14
  },
13
15
  ignores: ['**/fixtures/**'],
14
16
  },
15
- )
17
+ })
@@ -15,38 +15,38 @@
15
15
  "typecheck": "vue-tsc -b"
16
16
  },
17
17
  "dependencies": {
18
- "@faker-js/faker": "^10.3.0",
19
- "@tanstack/vue-query": "^5.92.9",
20
- "@tanstack/vue-query-devtools": "^6.1.5",
18
+ "@faker-js/faker": "^10.4.0",
19
+ "@tanstack/vue-query": "^5.100.8",
20
+ "@tanstack/vue-query-devtools": "^6.1.27",
21
21
  "@tanstack/vue-table": "^8.21.3",
22
- "@tanstack/vue-virtual": "^3.13.22",
23
- "@trpc/client": "^11.12.1",
22
+ "@tanstack/vue-virtual": "^3.13.24",
23
+ "@trpc/client": "^11.17.0",
24
24
  "clsx": "^2.1.1",
25
25
  "pinia": "^3.0.4",
26
26
  "tailwind-merge": "^3.5.0",
27
27
  "tailwind-variants": "^3.2.2",
28
- "vue": "^3.5.30",
29
- "vue-i18n": "^11.3.0",
30
- "vue-router": "^5.0.3"
28
+ "vue": "^3.5.33",
29
+ "vue-i18n": "^11.4.0",
30
+ "vue-router": "^5.0.6"
31
31
  },
32
32
  "devDependencies": {
33
- "@cloudflare/vite-plugin": "^1.28.0",
34
- "@hono/node-server": "^1.19.11",
33
+ "@cloudflare/vite-plugin": "^1.35.0",
34
+ "@hono/node-server": "^2.0.1",
35
35
  "@hono/trpc-server": "^0.4.2",
36
- "@tailwindcss/vite": "^4.2.1",
37
- "@trpc/server": "^11.12.1",
38
- "@vitejs/plugin-vue": "^6.0.5",
36
+ "@tailwindcss/vite": "^4.2.4",
37
+ "@trpc/server": "^11.17.0",
38
+ "@vitejs/plugin-vue": "^6.0.6",
39
39
  "@vitejs/plugin-vue-jsx": "^5.1.5",
40
- "@vue/tsconfig": "^0.9.0",
40
+ "@vue/tsconfig": "^0.9.1",
41
41
  "consola": "^3.4.2",
42
- "hono": "^4.12.8",
43
- "tailwindcss": "^4.2.1",
44
- "typescript": "~5.9.3",
45
- "vite": "^8.0.0",
46
- "vite-plugin-vue-devtools": "^8.1.0",
42
+ "hono": "^4.12.16",
43
+ "tailwindcss": "^4.2.4",
44
+ "typescript": "~6.0.3",
45
+ "vite": "^8.0.10",
46
+ "vite-plugin-vue-devtools": "^8.1.1",
47
47
  "vite-tsconfig-paths": "^6.1.1",
48
- "vue-tsc": "3.2.5",
49
- "wrangler": "^4.73.0",
50
- "zod": "^4.3.6"
48
+ "vue-tsc": "3.2.7",
49
+ "wrangler": "^4.87.0",
50
+ "zod": "^4.4.2"
51
51
  }
52
52
  }
@@ -8,7 +8,7 @@ import VueDevTools from 'vite-plugin-vue-devtools'
8
8
  import VueRouter from 'vue-router/vite'
9
9
 
10
10
  // https://vite.dev/config/
11
- export default defineConfig({
11
+ export default defineConfig(({ command }) => ({
12
12
  build: {
13
13
  target: 'baseline-widely-available',
14
14
  },
@@ -22,12 +22,13 @@ export default defineConfig({
22
22
  VueRouter(
23
23
  {
24
24
  dts: path.resolve(import.meta.dirname, 'src/route-map.d.ts'),
25
+ watch: command === 'serve',
25
26
  },
26
27
  ),
27
28
  Vue(),
28
29
  VueJsx(),
29
30
  Tailwindcss(),
30
31
  cloudflare(),
31
- VueDevTools(),
32
+ command === 'serve' ? VueDevTools() : null,
32
33
  ],
33
- })
34
+ }))
@@ -12,12 +12,7 @@
12
12
  "dev": {
13
13
  "port": 8787
14
14
  },
15
- "routes": [
16
- {
17
- "custom_domain": true,
18
- "pattern": "client.monorepo.icebreaker.top"
19
- }
20
- ],
15
+ // Add "routes" here when you bind a real custom domain.
21
16
  "observability": {
22
17
  "enabled": true
23
18
  }