create-packkit 2.0.3 → 2.1.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.
- package/package.json +1 -1
- package/src/cli/args.js +2 -0
- package/src/cli/index.js +2 -1
- package/src/cli/wizard.js +3 -0
- package/src/core/features/e2e.js +47 -0
- package/src/core/features/gitfiles.js +5 -0
- package/src/core/features/index.js +2 -0
- package/src/core/features/test.js +3 -0
- package/src/core/features/workflows.js +25 -0
- package/src/core/options.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-packkit",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
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
|
@@ -48,6 +48,7 @@ export function parseCliArgs(argv) {
|
|
|
48
48
|
minify: { type: 'boolean' },
|
|
49
49
|
monorepo: { type: 'boolean' },
|
|
50
50
|
storybook: { type: 'boolean' },
|
|
51
|
+
e2e: { type: 'boolean' },
|
|
51
52
|
'pkg-checks': { type: 'boolean' },
|
|
52
53
|
knip: { type: 'boolean' },
|
|
53
54
|
jsr: { type: 'boolean' },
|
|
@@ -74,6 +75,7 @@ export function parseCliArgs(argv) {
|
|
|
74
75
|
if (values.minify) overrides.minify = true;
|
|
75
76
|
if (values.monorepo) overrides.monorepo = true;
|
|
76
77
|
if (values.storybook) overrides.storybook = true;
|
|
78
|
+
if (values.e2e) overrides.e2e = true;
|
|
77
79
|
if (values['pkg-checks']) overrides.pkgChecks = true;
|
|
78
80
|
if (values.knip) overrides.knip = true;
|
|
79
81
|
if (values.jsr) overrides.jsr = true;
|
package/src/cli/index.js
CHANGED
|
@@ -40,7 +40,8 @@ Options:
|
|
|
40
40
|
--language <ts|js> --module <esm|cjs|dual> --framework <none|react|vue|svelte>
|
|
41
41
|
--target <library|cli|service|app> (repeatable) --storybook
|
|
42
42
|
--bundler <tsup|tsdown|unbuild|rollup|none> --minify
|
|
43
|
-
--test <vitest|jest|node|none>
|
|
43
|
+
--test <vitest|jest|node|none> --e2e (Playwright, for apps)
|
|
44
|
+
--lint <eslint-prettier|biome|oxlint|none>
|
|
44
45
|
--hooks <simple-git-hooks|husky|lefthook|none> --release <changesets|release-it|np|none>
|
|
45
46
|
--workflows <ci|npm-publish|pages|codeql|codecov|stale> (repeatable)
|
|
46
47
|
--deps <renovate|dependabot|none> --license <MIT|Apache-2.0|ISC|none>
|
package/src/cli/wizard.js
CHANGED
|
@@ -36,6 +36,9 @@ export async function runWizard(seed = {}) {
|
|
|
36
36
|
cfg.minify = bail(await p.confirm({ message: 'Minify the build output?', initialValue: false }));
|
|
37
37
|
}
|
|
38
38
|
cfg.test = bail(await p.select({ message: 'Test runner', options: asOptions('test'), initialValue: OPTIONS.test.default }));
|
|
39
|
+
if (cfg.target.includes('app')) {
|
|
40
|
+
cfg.e2e = bail(await p.confirm({ message: 'Add Playwright end-to-end tests?', initialValue: false }));
|
|
41
|
+
}
|
|
39
42
|
cfg.lint = bail(await p.select({ message: 'Lint / format', options: asOptions('lint'), initialValue: OPTIONS.lint.default }));
|
|
40
43
|
cfg.gitHooks = bail(await p.select({ message: 'Git hooks', options: asOptions('gitHooks'), initialValue: OPTIONS.gitHooks.default }));
|
|
41
44
|
cfg.release = bail(await p.select({ message: 'Release / versioning', options: asOptions('release'), initialValue: OPTIONS.release.default }));
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Playwright end-to-end tests for app targets: a config that boots the Vite
|
|
2
|
+
// dev server, one smoke spec, the scripts and the dev dependency. The CI job
|
|
3
|
+
// lives in workflows.js, which owns all workflow YAML.
|
|
4
|
+
|
|
5
|
+
const DEV_URL = 'http://localhost:5173'; // Vite's default dev port
|
|
6
|
+
|
|
7
|
+
const runDev = (cfg) => (cfg.packageManager === 'npm' ? 'npm run dev' : `${cfg.packageManager} dev`);
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
id: 'e2e',
|
|
11
|
+
active: (cfg) => cfg.e2e && cfg.hasApp,
|
|
12
|
+
apply(cfg) {
|
|
13
|
+
const ext = cfg.ext; // 'ts' | 'js' — config/specs never need JSX
|
|
14
|
+
const files = {};
|
|
15
|
+
const pkg = { scripts: {}, devDependencies: { '@playwright/test': '^1.50.0' } };
|
|
16
|
+
|
|
17
|
+
files[`playwright.config.${ext}`] = [
|
|
18
|
+
`import { defineConfig, devices } from '@playwright/test';`,
|
|
19
|
+
``,
|
|
20
|
+
`export default defineConfig({`,
|
|
21
|
+
`\ttestDir: './e2e',`,
|
|
22
|
+
`\tuse: { baseURL: '${DEV_URL}', trace: 'on-first-retry' },`,
|
|
23
|
+
`\t// Playwright starts the app for you and waits for it to be ready.`,
|
|
24
|
+
`\twebServer: {`,
|
|
25
|
+
`\t\tcommand: '${runDev(cfg)}',`,
|
|
26
|
+
`\t\turl: '${DEV_URL}',`,
|
|
27
|
+
`\t\treuseExistingServer: !process.env.CI,`,
|
|
28
|
+
`\t},`,
|
|
29
|
+
`\tprojects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],`,
|
|
30
|
+
`});`,
|
|
31
|
+
``,
|
|
32
|
+
].join('\n');
|
|
33
|
+
|
|
34
|
+
files[`e2e/app.spec.${ext}`] = [
|
|
35
|
+
`import { test, expect } from '@playwright/test';`,
|
|
36
|
+
``,
|
|
37
|
+
`test('renders the app', async ({ page }) => {`,
|
|
38
|
+
`\tawait page.goto('/');`,
|
|
39
|
+
`\tawait expect(page.getByRole('heading', { name: /Hello from/ })).toBeVisible();`,
|
|
40
|
+
`});`,
|
|
41
|
+
``,
|
|
42
|
+
].join('\n');
|
|
43
|
+
|
|
44
|
+
pkg.scripts['test:e2e'] = 'playwright test';
|
|
45
|
+
return { files, pkg };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -8,6 +8,7 @@ import frameworks from './frameworks.js';
|
|
|
8
8
|
import vite from './vite.js';
|
|
9
9
|
import service from './service.js';
|
|
10
10
|
import test from './test.js';
|
|
11
|
+
import e2e from './e2e.js';
|
|
11
12
|
import lint from './lint.js';
|
|
12
13
|
import githooks from './githooks.js';
|
|
13
14
|
import release from './release.js';
|
|
@@ -29,6 +30,7 @@ export default [
|
|
|
29
30
|
vite,
|
|
30
31
|
service,
|
|
31
32
|
test,
|
|
33
|
+
e2e,
|
|
32
34
|
lint,
|
|
33
35
|
githooks,
|
|
34
36
|
release,
|
|
@@ -26,6 +26,9 @@ export default {
|
|
|
26
26
|
`export default defineConfig({`,
|
|
27
27
|
fw ? `\tplugins: [${fw.call}],` : null,
|
|
28
28
|
`\ttest: {`,
|
|
29
|
+
// Keep Vitest to unit tests under src/ so it never tries to run the
|
|
30
|
+
// Playwright specs in e2e/ (they share the *.spec.ts glob).
|
|
31
|
+
cfg.e2e ? `\t\tinclude: ['src/**/*.{test,spec}.{js,jsx,ts,tsx}'],` : null,
|
|
29
32
|
cfg.hasFramework ? `\t\tenvironment: 'jsdom',` : null,
|
|
30
33
|
cfg.hasFramework ? `\t\tglobals: true,` : null,
|
|
31
34
|
cfg.coverage ? `\t\tcoverage: { provider: 'v8', reporter: ['text', 'lcov'] },` : null,
|
|
@@ -41,6 +41,7 @@ export default {
|
|
|
41
41
|
if (wf.includes('pages')) files['.github/workflows/pages.yml'] = pagesWorkflow(cfg);
|
|
42
42
|
if (wf.includes('codeql')) files['.github/workflows/codeql.yml'] = codeqlWorkflow();
|
|
43
43
|
if (wf.includes('stale')) files['.github/workflows/stale.yml'] = staleWorkflow();
|
|
44
|
+
if (cfg.e2e && cfg.hasApp && wf.includes('ci')) files['.github/workflows/e2e.yml'] = e2eWorkflow(cfg);
|
|
44
45
|
|
|
45
46
|
if (cfg.deps === 'renovate') {
|
|
46
47
|
files['.github/renovate.json'] = toJson({
|
|
@@ -199,6 +200,30 @@ function codeqlWorkflow() {
|
|
|
199
200
|
].join('\n');
|
|
200
201
|
}
|
|
201
202
|
|
|
203
|
+
function e2eWorkflow(cfg) {
|
|
204
|
+
return [
|
|
205
|
+
'name: E2E',
|
|
206
|
+
'on:',
|
|
207
|
+
' push:',
|
|
208
|
+
' branches: [main]',
|
|
209
|
+
' pull_request:',
|
|
210
|
+
'jobs:',
|
|
211
|
+
' e2e:',
|
|
212
|
+
' runs-on: ubuntu-latest',
|
|
213
|
+
' steps:',
|
|
214
|
+
setupSteps(cfg),
|
|
215
|
+
' - run: npx playwright install --with-deps chromium',
|
|
216
|
+
` - run: ${pmRun(cfg, 'test:e2e')}`,
|
|
217
|
+
' - uses: actions/upload-artifact@v4',
|
|
218
|
+
' if: ${{ !cancelled() }}',
|
|
219
|
+
' with:',
|
|
220
|
+
' name: playwright-report',
|
|
221
|
+
' path: playwright-report/',
|
|
222
|
+
' retention-days: 7',
|
|
223
|
+
'',
|
|
224
|
+
].join('\n');
|
|
225
|
+
}
|
|
226
|
+
|
|
202
227
|
function staleWorkflow() {
|
|
203
228
|
return [
|
|
204
229
|
'name: Stale',
|
package/src/core/options.js
CHANGED
|
@@ -96,6 +96,7 @@ export const OPTIONS = {
|
|
|
96
96
|
},
|
|
97
97
|
coverage: { group: 'quality', type: 'boolean', label: 'Coverage reporting', default: true },
|
|
98
98
|
storybook: { group: 'quality', type: 'boolean', label: 'Storybook (component libraries)', default: false },
|
|
99
|
+
e2e: { group: 'quality', type: 'boolean', label: 'Playwright end-to-end tests (apps)', default: false },
|
|
99
100
|
pkgChecks: { group: 'quality', type: 'boolean', label: 'Package checks (publint + are-the-types-wrong)', default: false },
|
|
100
101
|
knip: { group: 'quality', type: 'boolean', label: 'Knip (unused files / deps / exports)', default: false },
|
|
101
102
|
|
|
@@ -245,6 +246,9 @@ export function normalizeConfig(input = {}) {
|
|
|
245
246
|
// Storybook only applies to component libraries.
|
|
246
247
|
if (!cfg.hasFramework || cfg.hasApp || !cfg.hasLibrary) cfg.storybook = false;
|
|
247
248
|
|
|
249
|
+
// Playwright E2E only applies to app targets.
|
|
250
|
+
if (!cfg.hasApp) cfg.e2e = false;
|
|
251
|
+
|
|
248
252
|
// A monorepo is its own generation path (see buildMonorepo); it has a build.
|
|
249
253
|
if (cfg.monorepo) cfg.hasBuild = true;
|
|
250
254
|
|