A unified guide for the matrix runner that scaffolds, typechecks, builds, and runs unit tests across permutations (React Vite, React Webpack, Angular), UIs, languages, stores, and date libs — all inside a clean sandbox/ directory. It is designed to run consistently across Windows, macOS, and Linux, with no reliance on bash‑only features. 🧪⚙️📦
TL;DR 👉⚡️🧭
- Quick matrix:
npm run verify:matrix:quick- Full matrix:
npm run verify:matrix:full- Fast & parallel:
PF_CONCURRENCY=6 PF_FAST=fw-lang-first npm run verify:matrix:full- Watch one app:
npm run verify:watch -- my-app --framework react-vite --ts --ui mui --store none --test-unit vitest --test-e2e noneNote: The current
scripts/verify-once.jsdoes not (yet) run E2E. E2E remains a roadmap item below. 🗺️⏭️🧷
- Polyfront Scaffold — Verification Guide (Aligned to
scripts/verify-once.js) 🚀✨🧩- Table of Contents 📚🧭🧱
- Prerequisites 🧰🧵🔧
- Install / Setup 🏗️📦🔩
- Core Concepts 🧠🗂️🔁
- Fast Execution Toolkit 🏎️⚡️🧰
- Commands 🧾🧭
▶️ - Matrices (exact, as in code) 🧮🧰🔬
- Ordering 🗂️🔢🧭
- Languages 🗣️📦🧪
- Sandbox Policy 🏝️📁🧹
- Tool Detection (builder/tester) 🧰🔎📦
- Speed & Scalability 🚀📈🧵
- Troubleshooting 🧰🧯🔧
- CI Examples 🧪🛠️📦
- Environment Variables 🧾⚙️🧬
- Roadmap: E2E Phase 🧭🧪🧱
- File Map 🗺️📁🧭
- Ready to go 🎯🚀🧩
- Node.js 18+ (20+ recommended; CI covers Node 20 & 22)
- npm (pnpm/yarn also fine)
- Windows (PowerShell/CMD/Git Bash), macOS, or Linux
For speed and fewer prompts, install common dev tools at the repo root. ⚡️🏎️📦
npm i -D vite vitest webpack webpack-cli jest @angular/cli typescript jsdom
npm i -D cross-env execa kleur fs-extra chokidar oraWhy: the runner resolves binaries in this order: app → repo root → npx. Root installs avoid slow interactive prompts. 🚦🧭⚡️
{
"scripts": {
"verify:matrix:quick": "cross-env PF_MATRIX=quick node scripts/verify-once.js",
"verify:matrix:full": "cross-env PF_MATRIX=full node scripts/verify-once.js",
"verify:watch": "node scripts/watch-verify.js",
"clean:sandbox": "node -e \"require('fs').rmSync('sandbox',{recursive:true,force:true})\""
}
}If
cross-envisn’t installed, set env vars inline (examples below). 🧭🪄🔧
- Sandbox: All apps are generated under
sandbox/. - Job name:
app-<fw>-<lang>-<ui>-<store>-<unit>-<e2e>-<date>(e.g.app-react-vite-ts-mui-none-vitest-none-date-fns). - Pipeline (per app)
- Scaffold (your CLI in
bin/index.js) - Install is intentionally skipped unless
**node_modules**already exist - Typecheck (
tsc -b --noEmit) — non‑fatal (warn & continue) - Build (Vite/Webpack/Angular auto-detected)
- Unit tests (Vitest
--environment=jsdomor Jest--ci)
- Scaffold (your CLI in
- Watch mode: Continuously regenerates one app while you iterate. 🔁🧩🧪
Recommended project layout (React): 🗺️📁🏗️
src/
api/ assets/ components/ context/ features/ hooks/ i18n/
layout/ pages/ routes/ services/ store/ styles/ tests/ utils/
Env files scaffolded: 🧾🔐🧩
.env.development
.env.test
.env.production
.env.example
- Parallelism:
PF_CONCURRENCY=<n>(default = CPU cores − 1) - Fast mode:
PF_FAST=fw-lang-first→ only the first job per (framework,language) runs full build + unit; others typecheck only - Skip steps:
PF_SKIP_TSC=1,PF_SKIP_TESTS=1 - Build caches (put in templates):
- Webpack:
{ cache: { type: 'filesystem', cacheDirectory: '.webpack-cache' } } - Vite:
cacheDir: '.vite-cache'
- Webpack:
- Lean builds: Vite
minify: 'esbuild', sourcemap: false; Webpackdevtool: false,optimization.minimize: false
# Quick matrix
npm run verify:matrix:quick
# Full matrix
npm run verify:matrix:full
# Watch one app
npm run verify:watch -- \
my-app --framework react-vite --ts --ui mui --store none \
--test-unit vitest --test-e2e none --i18n --axiosSingle‑language runs: 🎛️🧪🧭
# TypeScript only
npm run verify:matrix:full:ts
# JavaScript only (Angular remains TS)
npm run verify:matrix:full:jsCleanup sandbox: 🧹📁✅
npm run clean:sandbox- Bash/zsh/Git Bash
PF_CONCURRENCY=6 PF_FAST=fw-lang-first npm run verify:matrix:full
- PowerShell
$env:PF_CONCURRENCY="6"; $env:PF_FAST="fw-lang-first"; npm run verify:matrix:full
- CMD
set PF_CONCURRENCY=6 && set PF_FAST=fw-lang-first && npm run verify:matrix:full
- React Vite — TS/JS × UIs: mui, bootstrap, tailwind, antd;
unit: vitest,date: date-fns,e2e: none - React Webpack — TS/JS × UIs: bootstrap, tailwind, antd;
unit: vitest,date: date-fns,e2e: none - React Webpack — one extra combo: bootstrap with
unit: jest,date: moment,e2e: none - Angular — TS only, material,
unit: none,e2e: none
Note: Some additional Vite/Jest or Chakra entries are commented out in code and therefore not part of the Quick set. 📝🔍🧷
- React Webpack × UIs:
mui, bootstrap, tailwind, antd, chakra→unit: jest,date: moment - React Webpack × Stores:
none, redux, mobx, react-query(UIchakra,unit: jest,date: moment) - React Webpack × Dates:
moment, dayjs, date-fns(UIchakra,unit: jest) - React Vite × UIs:
mui, chakra, tailwind(TS/JS) →unit: vitest,date: date-fns - Angular × UIs:
material, bootstrap, tailwind, primeng(TS only)
React variants expand across TS and JS per
PF_LANGS. Angular remains TS‑only. 🧬🔁📌
- Frameworks (default):
react-vite,react-webpack,angular→PF_ORDER - UIs (default):
mui,bootstrap,tailwind,antd,chakra→PF_UI_ORDER
Jobs are grouped by UI order within a framework for deterministic output. 🧱🧷🧭
PF_LANGS="ts,js"by default- React: TS + JS (restricted by
PF_LANGS) - Angular: TS only (enforced in code)
Examples: 🧩🧪📝
PF_LANGS=ts npm run verify:matrix:full
PF_LANGS=js npm run verify:matrix:full # Angular still TS- Always writes to
sandbox/ - If target exists and non‑empty →
PF_ON_EXISTS:rename(default): rename to*-bak-YYYY-MM-DD_HH-MM-SSoverwrite: delete & recreateskip: leave as‑is, do not regenerate
The runner auto‑detects tooling from app **node_modules** first, then falls back to repo root, then npx. 🧭🧱🧩
- Builder detection (order): Vite → Webpack → Angular (presence of
angular.jsonor@angular/cli) - Tester detection (precedence):
package.jsonscripts: iftestmentionsjestorvitest, that runner is chosendevDependencies/dependencieshints- Binary presence in node_modules or root
Special case: If a job is React Vite but the detector yields Webpack, the build step is skipped (to avoid mismatched runs in atypical templates). 🧯🚫🧭
PF_CONCURRENCY=<n>to parallelizePF_FAST=fw-lang-firstto run only one full job per (framework,language); others typecheck-only- Skip knobs:
PF_SKIP_TSC,PF_SKIP_TESTS - Tool resolution: app → root → npx (preinstall root devDeps to avoid prompts)
cross-env: command not found→ install or set envs inline- Webpack wants
webpack-cli→npm i -D webpack webpack-cliat repo root - Vite package not found →
npm i -D vite; ensure validvite.config.* - Vitest
document is not defined→ installjsdom; don’t forceenvironment: 'node' - Angular
--no-interactivewarning → remove deprecated flags in template - TS default import errors → in template
tsconfig.json:{ "compilerOptions": { "esModuleInterop": true, "allowSyntheticDefaultImports": true } } - Folder exists & nothing happens → check
PF_ON_EXISTS; useoverwriteor runnpm run clean:sandbox - Preflight logs (helpful on Windows PATH issues) are printed before the install‑skip note 🧭🪪🧾
name: Verify Scaffold Matrix
on:
push:
branches: [ main ]
pull_request:
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm i -D vite vitest webpack webpack-cli jest @angular/cli typescript jsdom
- name: Full matrix (parallel + fast)
env:
PF_MATRIX: full
PF_CONCURRENCY: '6'
PF_FAST: fw-lang-first
PF_ORDER: react-vite,react-webpack,angular
PF_UI_ORDER: mui,bootstrap,tailwind,antd,chakra
PF_LANGS: ts,js
PF_ON_EXISTS: rename
run: node scripts/verify-once.jstrigger:
- main
pool: { vmImage: 'ubuntu-latest' }
steps:
- task: NodeTool@0
inputs: { versionSpec: '22.x' }
- script: npm ci
- script: |
npm i -D vite vitest webpack webpack-cli jest @angular/cli typescript jsdom
cross-env PF_MATRIX=quick node scripts/verify-once.js| Variable | Default | Purpose |
|---|---|---|
PF_MATRIX |
quick |
Matrix preset (quick/full). |
PF_LANGS |
ts,js |
Languages for React (Angular is TS‑only). |
PF_ORDER |
react-vite,react-webpack,angular |
Framework execution order. |
PF_UI_ORDER |
mui,bootstrap,tailwind,antd,chakra |
UI order within a framework. |
PF_CONCURRENCY |
CPU cores − 1 | Parallel job count. |
PF_FAST |
off |
fw-lang-first = only first job per (framework,language) runs full build+tests. |
PF_SKIP_TSC |
'' |
1 to skip typechecking. |
PF_SKIP_TESTS |
'' |
1 to skip unit tests. |
PF_ON_EXISTS |
rename |
rename / overwrite / skip. |
PF_CLI |
bin/index.js |
Path to your scaffold CLI. |
PF_APP_NAME |
app-under-test |
Name used by verify:watch. |
CI |
1 |
CI-friendly output. |
NG_CLI_ANALYTICS |
false |
Disable Angular analytics. |
ADBLOCK |
1 |
Avoid ad-dependent downloads. |
BROWSERSLIST_DISABLE_CACHE |
1 |
Reduce cache variability. |
NODE_ENV |
development |
Default unless templates override. |
npm_config_production |
false |
Keep devDeps if you install. |
E2E execution (Playwright/Cypress) is not implemented in the current verify-once.js. When added, the doc will include: 🛠️🧪🚀
- E2E runner selection (
PF_E2E_RUNNER), port pool (PF_E2E_PORT_RANGE), readiness timeout (PF_E2E_READY_MS) - Server spin‑up/teardown and artifact upload guidance
- Optional
PF_SKIP_E2E
If you’d like, I can generate a code patch that adds minimal Playwright/Cypress support with the above toggles. 🧩📦🛠️
scripts/verify-once.js— matrix runner (ordering, concurrency, fast mode, skips, on‑exists, builder/tester detection)scripts/watch-verify.js— single‑app watch pipelinebin/index.js— your scaffold CLIsandbox/— generated appsdocs/— place this asdocs/end-to-end/verification-guide.mdif desired
# Quick smoke
npm run verify:matrix:quick
# Full coverage, fast & parallel
PF_CONCURRENCY=6 PF_FAST=fw-lang-first npm run verify:matrix:full
# Strict overwrite of existing sandbox apps
PF_ON_EXISTS=overwrite npm run verify:matrix:full
# Watch one app while iterating
npm run verify:watch -- my-new-app --framework react-vite --ts --ui mui --store none --test-unit vitest --test-e2e none --i18n --axios