fix(create-wcb): add tsconfig.json for tsc
This commit is contained in:
parent
751067d367
commit
2adc4e8d43
5 changed files with 102 additions and 3 deletions
|
|
@ -16,10 +16,11 @@ This file provides guidance to AI coding agents when working with code in this r
|
|||
- `pnpm build` — `tsc` emits `.d.ts` types, then `copy:source` uses esbuild to minify/bundle `src/*.js` + `src/utils/*` into `dist/` as ESM. **`dist/` is what gets published; `src/` is shipped as the readable source.**
|
||||
- `pnpm size-limit` — enforces the per-file byte budgets declared in `package.json` `size-limit` (each `dist/` file has its own, e.g. `WebComponent.js` ≤ 2.05 KB, `html.js` ≤ 0.6 KB, each util ≤ 0.5–0.8 KB). Keep additions tiny; this gate is a core project value. `size-change-log.md` is the running record of how each change moved the base-class bundle and why; its latest row's min+brotli figure is the single source of truth for the base-class size, so `docs/src/content/docs/guides/library-size.md` must be updated in lockstep whenever a new row lands.
|
||||
- `pnpm test:types` — builds, then type-checks the TS type tests (`test/types/typed-props.test-d.ts`) and the `demo/examples/typed-props/` example. `this.props` is typed by passing the props shape as a class type argument: `class X extends WebComponent<typeof props>`.
|
||||
- `pnpm test:template` — scaffolds `create/template/` into a temp directory with the real scaffolder, links this repo in as `web-component-base`, and type-checks it with the template's own `tsconfig.json` (`scripts/check-template.js`). It resolves through the root `exports` map, so it catches a template that can't resolve the package — the failure mode that leaves every `this.props` access an error while `vite build` still exits 0.
|
||||
- `pnpm docs` — run the Astro docs site (`docs/` workspace) locally.
|
||||
- `pnpm demo` — run the Vite examples showcase (`demo/` workspace) locally; `pnpm demo:build` builds it.
|
||||
- `pnpm -F storybook dev` — run the Storybook testing ground (`storybook/`) locally; `pnpm -F storybook build` builds it. Both run `cem analyze` first to regenerate `custom-elements.json`. The CEM config imports the plugin from the **published subpath** (`web-component-base/cem-plugin` → `dist/`), so run `pnpm build` at the root first.
|
||||
- `pnpm test:e2e` — run the browser e2e specs (`test/e2e/`) via Vitest browser mode (Playwright). Defaults to Chromium; `pnpm test:e2e:firefox` / `:webkit` / `:all` target the other engines (the `E2E_BROWSERS` env var, comma-separated, selects instances). `pnpm test:all` runs unit + types + e2e across all engines.
|
||||
- `pnpm test:e2e` — run the browser e2e specs (`test/e2e/`) via Vitest browser mode (Playwright). Defaults to Chromium; `pnpm test:e2e:firefox` / `:webkit` / `:all` target the other engines (the `E2E_BROWSERS` env var, comma-separated, selects instances). `pnpm test:all` runs unit + types + template + e2e across all engines.
|
||||
- `pnpm create wcb` (the `create/` workspace package) scaffolds a new component project from `create/template/`. `create/` is a separate publishable package, not part of the `web-component-base` bundle.
|
||||
|
||||
pnpm is mandatory (a `preinstall` `only-allow pnpm` guard enforces it). This is a pnpm workspace with three sub-packages: `docs/` (Astro docs site), `demo/` (Vite examples showcase, which consumes the root `web-component-base` package as a `workspace:*` dependency), and `storybook/` (Storybook testing ground — it writes no components of its own, it builds stories over the `demo/examples/` components so the CEM plugin is exercised against real ones). The runnable example sources live in `demo/examples/` and import the package by name (`web-component-base`), not via relative `src/` paths.
|
||||
|
|
@ -56,7 +57,7 @@ Any change to observable behavior ships as one unit — code alone is an incompl
|
|||
3. **Documentation** — the guide under `docs/src/content/docs/guides/` that doubles as the behavioral spec. For a breaking change, also update the `README.md` banner with the migration consumers have to perform.
|
||||
4. **Size budget** — `pnpm size-limit` stays green. If an addition genuinely needs more headroom, raise the budget in `package.json` deliberately and say so in the change description; never let it drift silently. Whenever the change moves the base-class bundle, record it as a new row in `size-change-log.md` **and** update the headline size in `docs/src/content/docs/guides/library-size.md` to match that row's new min+brotli figure — the two must never disagree.
|
||||
|
||||
Verify with `pnpm test:all` (unit + types + e2e across all engines) before calling the change done.
|
||||
Verify with `pnpm test:all` (unit + types + template + e2e across all engines) before calling the change done.
|
||||
|
||||
## Testing notes
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ describe('create-wcb', () => {
|
|||
'src/my-button.ts',
|
||||
'custom-elements-manifest.config.mjs',
|
||||
'vite-lib.config.ts',
|
||||
'tsconfig.json',
|
||||
'pnpm-workspace.yaml',
|
||||
'README.md',
|
||||
])
|
||||
|
|
|
|||
21
create/template/tsconfig.json
Normal file
21
create/template/tsconfig.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// TypeScript config for the component source. `npm run build:lib` runs
|
||||
// vite-plugin-dts against this to emit `.d.ts` files next to the bundles.
|
||||
//
|
||||
// `moduleResolution: "bundler"` is the load-bearing line. Without it tsc falls
|
||||
// back to classic resolution, never looks in node_modules, and the
|
||||
// `web-component-base` import fails — which in turn makes every `this.props`
|
||||
// access an error, because the base class it resolves to is an error type.
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
@ -43,7 +43,8 @@
|
|||
"test:e2e:webkit": "E2E_BROWSERS=webkit vitest --run --config vitest.e2e.config.mjs",
|
||||
"test:e2e:all": "vitest --run --config vitest.e2e.config.mjs",
|
||||
"test:types": "pnpm run build && tsc -p test/types/tsconfig.json && tsc -p demo/examples/typed-props/tsconfig.json",
|
||||
"test:all": "pnpm test && pnpm test:types && pnpm test:e2e:all",
|
||||
"test:template": "pnpm run build && node ./scripts/check-template.js",
|
||||
"test:all": "pnpm test && pnpm test:types && pnpm test:template && pnpm test:e2e:all",
|
||||
"demo": "pnpm -F demo dev",
|
||||
"demo:build": "pnpm -F demo build",
|
||||
"docs": "pnpm -F docs start",
|
||||
|
|
|
|||
75
scripts/check-template.js
Normal file
75
scripts/check-template.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @license MIT <https://opensource.org/licenses/MIT>
|
||||
*
|
||||
* Type-checks the `create/` scaffold the way a user gets it: runs the real
|
||||
* scaffolder into a temp directory, links this repo in as
|
||||
* `web-component-base`, and runs `tsc` with the template's own
|
||||
* `tsconfig.json`.
|
||||
*
|
||||
* The link resolves through the root `package.json` `exports` map, so this
|
||||
* exercises the same module resolution a scaffolded project does — which is
|
||||
* what catches a template that ships no `tsconfig.json`, or one whose
|
||||
* `moduleResolution` can't read an `exports` map. Both leave the
|
||||
* `web-component-base` import unresolvable and every `this.props` access an
|
||||
* error, while `vite build` still exits 0.
|
||||
*
|
||||
* Run via `pnpm test:template` (part of `pnpm test:all`). Needs `dist/` built.
|
||||
*/
|
||||
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const repoRoot = fileURLToPath(new URL('..', import.meta.url))
|
||||
const scaffolder = path.join(repoRoot, 'create', 'index.js')
|
||||
const tsc = path.join(repoRoot, 'node_modules', '.bin', 'tsc')
|
||||
const PROJECT = 'template-check'
|
||||
|
||||
if (!fs.existsSync(path.join(repoRoot, 'dist', 'index.d.ts'))) {
|
||||
console.error('check-template: dist/index.d.ts missing — run `pnpm build`')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'wcb-template-'))
|
||||
const root = path.join(workDir, PROJECT)
|
||||
|
||||
try {
|
||||
execFileSync(process.execPath, [scaffolder, PROJECT], {
|
||||
cwd: workDir,
|
||||
stdio: 'pipe',
|
||||
})
|
||||
|
||||
// Stand in for `npm install` of the peer dependency: the scaffold resolves
|
||||
// `web-component-base` to this repo, exports map and all.
|
||||
fs.mkdirSync(path.join(root, 'node_modules'), { recursive: true })
|
||||
fs.symlinkSync(
|
||||
repoRoot,
|
||||
path.join(root, 'node_modules', 'web-component-base'),
|
||||
'dir'
|
||||
)
|
||||
|
||||
// The template emits declarations during `build:lib`; here we only want the
|
||||
// diagnostics, and `emitDeclarationOnly` may not be combined with `noEmit`.
|
||||
execFileSync(
|
||||
tsc,
|
||||
['-p', 'tsconfig.json', '--emitDeclarationOnly', 'false', '--noEmit'],
|
||||
{
|
||||
cwd: root,
|
||||
stdio: 'inherit',
|
||||
}
|
||||
)
|
||||
|
||||
console.log('check-template: scaffold type-checks clean')
|
||||
} catch {
|
||||
console.error(
|
||||
`\ncheck-template: the scaffolded template does not type-check.\n` +
|
||||
`A user running \`npm create wcb@latest\` sees these errors on their\n` +
|
||||
`first \`npm run build:lib\`. Check create/template/tsconfig.json.`
|
||||
)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
fs.rmSync(workDir, { recursive: true, force: true })
|
||||
}
|
||||
Loading…
Reference in a new issue