create-packkit 2.6.1 → 2.7.1
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/README.md +10 -3
- package/package.json +1 -1
- package/src/cli/args.js +1 -0
- package/src/cli/wizard.js +53 -16
- package/src/core/features/jsr.js +3 -3
- package/src/core/features/workflows.js +7 -7
- package/src/core/monorepo.js +3 -3
package/README.md
CHANGED
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
> A highly configurable scaffolder for modern **npm packages and CLIs** — pick your stack from a CLI **or** a web configurator, and get a ready-to-ship repo.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/create-packkit)
|
|
6
|
+
[](https://www.npmjs.com/package/create-packkit)
|
|
7
|
+
[](https://github.com/DanMat/create-packkit/actions/workflows/ci.yml)
|
|
8
|
+
[](https://packagephobia.com/result?p=create-packkit)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
<br/>
|
|
11
|
+
[](https://danmat.github.io/create-packkit/)
|
|
12
|
+
[](mcp)
|
|
13
|
+
[](https://danmat.github.io/create-packkit/llms.txt)
|
|
14
|
+
[](CONTRIBUTING.md)
|
|
8
15
|
|
|
9
16
|
Most scaffolders lock you into one stack, one language, and the terminal. Packkit lets you **choose** — TypeScript or JavaScript, library or CLI, ESM/CJS/dual, your bundler, test runner, linter, git hooks, release flow, GitHub Actions and more — and it works from a CLI **or** a browser page that downloads your project as a zip.
|
|
10
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-packkit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"description": "Highly configurable scaffolder for modern npm packages and CLIs — pick your stack (TS/JS, bundler, tests, linter, CI, releases) from a CLI or a web configurator.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/cli/args.js
CHANGED
package/src/cli/wizard.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import { OPTIONS } from '../core/options.js';
|
|
3
|
+
import { PRESETS, PRESET_INFO } from '../core/presets.js';
|
|
3
4
|
|
|
4
5
|
function bail(value) {
|
|
5
6
|
if (p.isCancel(value)) {
|
|
@@ -24,40 +25,76 @@ export async function runWizard(seed = {}) {
|
|
|
24
25
|
}),
|
|
25
26
|
);
|
|
26
27
|
|
|
28
|
+
// Fast path: pick a preset and skip the interrogation, or go Custom.
|
|
29
|
+
const start = bail(
|
|
30
|
+
await p.select({
|
|
31
|
+
message: 'Start from a preset, or customize everything?',
|
|
32
|
+
options: [
|
|
33
|
+
{ value: '__custom__', label: 'Custom', hint: 'answer all the questions' },
|
|
34
|
+
...Object.keys(PRESETS).map((k) => ({ value: k, label: k, hint: PRESET_INFO[k] })),
|
|
35
|
+
],
|
|
36
|
+
initialValue: 'ts-lib',
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
|
|
27
40
|
cfg.description = bail(await p.text({ message: 'Description', placeholder: '(optional)', defaultValue: '' }));
|
|
28
|
-
cfg.author = bail(await p.text({ message: 'Author', placeholder: '(optional)', defaultValue: seed.author || '' }));
|
|
29
41
|
|
|
42
|
+
// Preset chosen — merge it under the name/description they typed and we're done.
|
|
43
|
+
if (start !== '__custom__') return { ...PRESETS[start], ...cfg };
|
|
44
|
+
|
|
45
|
+
// ---- Custom: the full wizard ----
|
|
46
|
+
cfg.author = bail(await p.text({ message: 'Author', placeholder: '(optional)', defaultValue: seed.author || '' }));
|
|
30
47
|
cfg.language = bail(await p.select({ message: 'Language', options: asOptions('language'), initialValue: OPTIONS.language.default }));
|
|
48
|
+
cfg.framework = bail(await p.select({ message: 'Framework', options: asOptions('framework'), initialValue: OPTIONS.framework.default }));
|
|
31
49
|
cfg.target = bail(await p.multiselect({ message: 'What are you building?', options: asOptions('target'), initialValues: ['library'], required: true }));
|
|
32
|
-
|
|
50
|
+
if (!cfg.target.includes('app')) {
|
|
51
|
+
cfg.moduleFormat = bail(await p.select({ message: 'Module format', options: asOptions('moduleFormat'), initialValue: OPTIONS.moduleFormat.default }));
|
|
52
|
+
}
|
|
33
53
|
cfg.packageManager = bail(await p.select({ message: 'Package manager', options: asOptions('packageManager'), initialValue: OPTIONS.packageManager.default }));
|
|
34
54
|
cfg.bundler = bail(await p.select({ message: 'Build / bundler', options: asOptions('bundler'), initialValue: OPTIONS.bundler.default }));
|
|
35
|
-
if (cfg.bundler !== 'none') {
|
|
36
|
-
cfg.minify = bail(await p.confirm({ message: 'Minify the build output?', initialValue: false }));
|
|
37
|
-
}
|
|
38
|
-
cfg.test = bail(await p.select({ message: 'Test runner', options: asOptions('test'), initialValue: OPTIONS.test.default }));
|
|
39
55
|
if (cfg.target.includes('service')) {
|
|
40
56
|
cfg.serviceFramework = bail(await p.select({ message: 'Service framework', options: asOptions('serviceFramework'), initialValue: OPTIONS.serviceFramework.default }));
|
|
41
57
|
}
|
|
42
|
-
|
|
43
|
-
cfg.e2e = bail(await p.confirm({ message: 'Add Playwright end-to-end tests?', initialValue: false }));
|
|
44
|
-
}
|
|
58
|
+
cfg.test = bail(await p.select({ message: 'Test runner', options: asOptions('test'), initialValue: OPTIONS.test.default }));
|
|
45
59
|
cfg.lint = bail(await p.select({ message: 'Lint / format', options: asOptions('lint'), initialValue: OPTIONS.lint.default }));
|
|
46
60
|
cfg.gitHooks = bail(await p.select({ message: 'Git hooks', options: asOptions('gitHooks'), initialValue: OPTIONS.gitHooks.default }));
|
|
47
|
-
if (cfg.target.includes('service') || cfg.target.includes('cli')) {
|
|
48
|
-
cfg.env = bail(await p.confirm({ message: 'Type-safe env validation (Zod)?', initialValue: false }));
|
|
49
|
-
}
|
|
50
61
|
cfg.release = bail(await p.select({ message: 'Release / versioning', options: asOptions('release'), initialValue: OPTIONS.release.default }));
|
|
51
|
-
if (cfg.release === 'changesets') {
|
|
52
|
-
cfg.canary = bail(await p.confirm({ message: 'Add a canary/snapshot release workflow?', initialValue: false }));
|
|
53
|
-
}
|
|
54
62
|
cfg.workflows = bail(await p.multiselect({ message: 'GitHub Actions (space to toggle)', options: asOptions('workflows'), initialValues: OPTIONS.workflows.default, required: false }));
|
|
55
63
|
cfg.deps = bail(await p.select({ message: 'Dependency updates', options: asOptions('deps'), initialValue: OPTIONS.deps.default }));
|
|
56
64
|
cfg.license = bail(await p.select({ message: 'License', options: asOptions('license'), initialValue: OPTIONS.license.default }));
|
|
57
65
|
|
|
66
|
+
// One screen for all the applicable feature toggles, instead of a dozen
|
|
67
|
+
// yes/no prompts. Options are filtered to what the chosen targets support.
|
|
68
|
+
const isApp = cfg.target.includes('app');
|
|
69
|
+
const isService = cfg.target.includes('service');
|
|
70
|
+
const isCli = cfg.target.includes('cli');
|
|
71
|
+
const isLib = cfg.target.includes('library');
|
|
72
|
+
const componentLib = cfg.framework !== 'none' && isLib && !isApp;
|
|
73
|
+
const publishable = (isLib || isCli) && !isApp && !isService;
|
|
74
|
+
|
|
75
|
+
const featOpts = [];
|
|
76
|
+
const on = [];
|
|
77
|
+
const add = (value, label, def = false) => { featOpts.push({ value, label }); if (def) on.push(value); };
|
|
78
|
+
if (cfg.bundler !== 'none') add('minify', 'Minify the build output');
|
|
79
|
+
if (cfg.test !== 'none') add('coverage', 'Coverage reporting', true);
|
|
80
|
+
if (publishable) {
|
|
81
|
+
add('sourcemaps', 'Ship sourcemaps + source (debug into your code)', true);
|
|
82
|
+
add('pkgChecks', 'Package checks (publint + are-the-types-wrong)');
|
|
83
|
+
add('sizeLimit', 'Bundle-size budget (size-limit)');
|
|
84
|
+
}
|
|
85
|
+
if (componentLib) add('storybook', 'Storybook');
|
|
86
|
+
if (isApp) add('e2e', 'Playwright end-to-end tests');
|
|
87
|
+
if (isService || isCli) add('env', 'Type-safe env validation (Zod)');
|
|
88
|
+
if (cfg.release === 'changesets') add('canary', 'Canary / snapshot release workflow');
|
|
89
|
+
add('knip', 'Knip (find unused files / deps / exports)');
|
|
90
|
+
add('doctor', 'Env doctor (warn on Node / package-manager mismatch)');
|
|
91
|
+
|
|
92
|
+
const feats = bail(await p.multiselect({ message: 'Optional features (space to toggle, enter to accept)', options: featOpts, initialValues: on, required: false }));
|
|
93
|
+
for (const o of featOpts) cfg[o.value] = feats.includes(o.value);
|
|
94
|
+
|
|
58
95
|
const extras = bail(
|
|
59
96
|
await p.multiselect({
|
|
60
|
-
message: '
|
|
97
|
+
message: 'Repo extras (space to toggle)',
|
|
61
98
|
options: [
|
|
62
99
|
{ value: 'community', label: 'Community files (CONTRIBUTING, CoC, SECURITY, templates)' },
|
|
63
100
|
{ value: 'agents', label: 'AI agent instructions (AGENTS.md + CLAUDE.md)' },
|
package/src/core/features/jsr.js
CHANGED
|
@@ -28,10 +28,10 @@ export default {
|
|
|
28
28
|
' publish:',
|
|
29
29
|
' runs-on: ubuntu-latest',
|
|
30
30
|
' steps:',
|
|
31
|
-
' - uses: actions/checkout@
|
|
32
|
-
' - uses: actions/setup-node@
|
|
31
|
+
' - uses: actions/checkout@v7',
|
|
32
|
+
' - uses: actions/setup-node@v7',
|
|
33
33
|
" with:",
|
|
34
|
-
" node-version: '
|
|
34
|
+
" node-version: '24'",
|
|
35
35
|
' - run: npx jsr publish',
|
|
36
36
|
'',
|
|
37
37
|
].join('\n'),
|
|
@@ -17,13 +17,13 @@ function pmExec(cfg, cmd) {
|
|
|
17
17
|
return { npm: `npx ${cmd}`, pnpm: `pnpm exec ${cmd}`, yarn: `yarn ${cmd}`, bun: `bunx ${cmd}` }[cfg.packageManager];
|
|
18
18
|
}
|
|
19
19
|
function setupSteps(cfg) {
|
|
20
|
-
const steps = [' - uses: actions/checkout@
|
|
21
|
-
if (cfg.packageManager === 'pnpm') steps.push(' - uses: pnpm/action-setup@
|
|
20
|
+
const steps = [' - uses: actions/checkout@v7'];
|
|
21
|
+
if (cfg.packageManager === 'pnpm') steps.push(' - uses: pnpm/action-setup@v6');
|
|
22
22
|
if (cfg.packageManager === 'bun') {
|
|
23
23
|
steps.push(' - uses: oven-sh/setup-bun@v2');
|
|
24
24
|
} else {
|
|
25
25
|
steps.push(
|
|
26
|
-
' - uses: actions/setup-node@
|
|
26
|
+
' - uses: actions/setup-node@v7',
|
|
27
27
|
' with:',
|
|
28
28
|
` node-version: '${cfg.nodeVersion}'`,
|
|
29
29
|
` cache: '${cfg.packageManager === 'yarn' ? 'yarn' : cfg.packageManager === 'pnpm' ? 'pnpm' : 'npm'}'`,
|
|
@@ -83,7 +83,7 @@ function ciWorkflow(cfg, codecov) {
|
|
|
83
83
|
if (cfg.sizeLimit) jobs.push(` - run: ${pmRun(cfg, 'size')}`); // after build (measures dist)
|
|
84
84
|
if (cfg.pkgChecks) jobs.push(` - run: ${pmRun(cfg, 'check:pkg')}`); // after build (attw packs dist)
|
|
85
85
|
const cov = codecov
|
|
86
|
-
? '\n - uses: codecov/codecov-action@
|
|
86
|
+
? '\n - uses: codecov/codecov-action@v7\n with:\n token: ${{ secrets.CODECOV_TOKEN }}'
|
|
87
87
|
: '';
|
|
88
88
|
return [
|
|
89
89
|
'name: CI',
|
|
@@ -155,7 +155,7 @@ function pagesWorkflow(cfg) {
|
|
|
155
155
|
// Storybook projects deploy the built catalog; everything else serves ./docs.
|
|
156
156
|
const build = cfg.storybook
|
|
157
157
|
? [setupSteps(cfg), ` - run: ${pmRun(cfg, 'build-storybook')}`, ' - uses: actions/configure-pages@v5', ' - uses: actions/upload-pages-artifact@v3', ' with:', ' path: ./storybook-static']
|
|
158
|
-
: [' - uses: actions/checkout@
|
|
158
|
+
: [' - uses: actions/checkout@v7', ' - uses: actions/configure-pages@v5', ' - uses: actions/upload-pages-artifact@v3', ' with:', ' path: ./docs'];
|
|
159
159
|
return [
|
|
160
160
|
`name: Deploy ${cfg.storybook ? 'Storybook' : 'Pages'}`,
|
|
161
161
|
'on:',
|
|
@@ -197,7 +197,7 @@ function codeqlWorkflow() {
|
|
|
197
197
|
' permissions:',
|
|
198
198
|
' security-events: write',
|
|
199
199
|
' steps:',
|
|
200
|
-
' - uses: actions/checkout@
|
|
200
|
+
' - uses: actions/checkout@v7',
|
|
201
201
|
' - uses: github/codeql-action/init@v3',
|
|
202
202
|
' with:',
|
|
203
203
|
' languages: javascript-typescript',
|
|
@@ -220,7 +220,7 @@ function e2eWorkflow(cfg) {
|
|
|
220
220
|
setupSteps(cfg),
|
|
221
221
|
' - run: npx playwright install --with-deps chromium',
|
|
222
222
|
` - run: ${pmRun(cfg, 'test:e2e')}`,
|
|
223
|
-
' - uses: actions/upload-artifact@
|
|
223
|
+
' - uses: actions/upload-artifact@v7',
|
|
224
224
|
' if: ${{ !cancelled() }}',
|
|
225
225
|
' with:',
|
|
226
226
|
' name: playwright-report',
|
package/src/core/monorepo.js
CHANGED
|
@@ -180,10 +180,10 @@ function exampleTest(importLine, assertion) {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
function ciWorkflow(cfg, pm) {
|
|
183
|
-
const setup = [' - uses: actions/checkout@
|
|
184
|
-
if (pm === 'pnpm') setup.push(' - uses: pnpm/action-setup@
|
|
183
|
+
const setup = [' - uses: actions/checkout@v7'];
|
|
184
|
+
if (pm === 'pnpm') setup.push(' - uses: pnpm/action-setup@v6');
|
|
185
185
|
setup.push(
|
|
186
|
-
' - uses: actions/setup-node@
|
|
186
|
+
' - uses: actions/setup-node@v7',
|
|
187
187
|
' with:',
|
|
188
188
|
` node-version: '${cfg.nodeVersion}'`,
|
|
189
189
|
` cache: '${pm === 'yarn' ? 'yarn' : pm === 'pnpm' ? 'pnpm' : 'npm'}'`,
|