diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 0000000000..ef9039ea38 --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,19 @@ +{ + "name": "ran", + "interface": { + "displayName": "ran" + }, + "plugins": [ + { + "name": "ran", + "source": { + "source": "local", + "path": "./plugins/ran" + }, + "policy": { + "installation": "AVAILABLE" + }, + "category": "Productivity" + } + ] +} diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 51e761afe3..e57a6afdb9 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -4,23 +4,15 @@ "name": "chaxus", "url": "https://github.com/chaxus/ran" }, - "description": "Skills for the ran monorepo libraries — ranui (web components) and ranuts (utilities) — so AI can read and use them without spelunking the source. Install whichever you use.", + "description": "Product design methods and version-aware ranui and ranuts skills in one plugin.", "metadata": { "pluginRoot": "./plugins" }, "plugins": [ { - "name": "ranui", - "source": "./plugins/ranui", - "description": "Build, review and polish ranui UI: task-to-rule lookup, public contracts and browser acceptance.", - "author": { - "name": "chaxus" - } - }, - { - "name": "ranuts", - "source": "./plugins/ranuts", - "description": "ranuts utility library: import map (utils/node/visual/vnode), ranuts/utils inventory, conventions.", + "name": "ran", + "source": "./plugins/ran", + "description": "Product design methods and version-aware ranui and ranuts skills in one plugin.", "author": { "name": "chaxus" } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ec38a59d8..1ea52a2fd9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,11 @@ on: paths: - "packages/**" - "bin/**" + - "tsconfig.tooling.json" + - "plugins/**" + - "design/**" + - ".agents/plugins/**" + - ".claude-plugin/**" - "package.json" - "pnpm-lock.yaml" - "pnpm-workspace.yaml" @@ -17,6 +22,11 @@ on: paths: - "packages/**" - "bin/**" + - "tsconfig.tooling.json" + - "plugins/**" + - "design/**" + - ".agents/plugins/**" + - ".claude-plugin/**" - "package.json" - "pnpm-lock.yaml" - "pnpm-workspace.yaml" @@ -61,6 +71,9 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Type-check repository tooling + run: pnpm typecheck:tooling + - name: Verify repository scripts run: pnpm run verify:scripts @@ -146,7 +159,7 @@ jobs: pnpm release:prepare pnpm verify:release - # `pnpm run test` reaches ranui through `run-checks.mjs`, which runs the package's + # `pnpm run test` reaches ranui through `run-checks.ts`, which runs the package's # own `test` script. That script runs `vitest run`; the coverage gate used to be a # separate step that ran `vitest run --coverage` afterwards, executing the same # suite a second time to produce one report. Asking for coverage up front makes the diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 8c29d1d61b..83e541729f 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -6,6 +6,9 @@ on: paths: - "packages/docs/**" - "packages/ranui/**" + - "plugins/ran/**" + - "design/**" + - ".agents/plugins/**" - "packages/ranuts/**" - "packages/ranview/**" - "packages/im/**" @@ -18,6 +21,9 @@ on: paths: - "packages/docs/**" - "packages/ranui/**" + - "plugins/ran/**" + - "design/**" + - ".agents/plugins/**" - "packages/ranuts/**" - "packages/ranview/**" - "packages/im/**" @@ -73,6 +79,10 @@ jobs: - name: Build ranuts run: pnpm --filter ranuts run build + - name: Verify agent-evaluation browser oracles (no model calls) + if: matrix.browser == 'chromium' + run: pnpm verify:agent-evals + - name: Build ranui run: pnpm --filter ranui run build @@ -120,7 +130,7 @@ jobs: # The launcher installs/builds the three required workspaces inside the same # digest-pinned renderer used for local baseline updates. Missing PNGs fail. - name: Compare reviewed screenshot baselines - run: node packages/ranui/bin/visual.mjs check + run: node packages/ranui/bin/visual.ts check - name: Upload visual differences and environment if: always() uses: actions/upload-artifact@v7 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fe98cc1011..8803e4beea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -67,7 +67,8 @@ jobs: pnpm verify:links pnpm -F docs check:langs pnpm verify:design - node bin/run-checks.mjs tsc + pnpm typecheck:tooling + node bin/run-checks.ts tsc - name: Test libraries and applications run: pnpm test @@ -119,7 +120,7 @@ jobs: path: .release/ - name: Publish verified tarballs using npm trusted publishing - run: node bin/release.mjs publish --tag "$RELEASE_TAG" --confirm + run: node bin/release.ts publish --tag "$RELEASE_TAG" --confirm - name: Preserve partial or complete publication results if: always() diff --git a/.prettierignore b/.prettierignore index 9ee76bf63d..0c68930e08 100644 --- a/.prettierignore +++ b/.prettierignore @@ -43,3 +43,13 @@ packages/ranui/docs/style-tokens-public.md # The next-generation docs build's output, written alongside VitePress's during the # migration so the two can be compared. Generated, never edited. packages/docs/dist + +# Agent reference bytes are generated from formatted canonical design sources and hash-bound. +plugins/ran/skills/design/references/ + +# Captured evidence JSON is an immutable measurement record. Some manifests hash +# neighboring JSON byte-for-byte; formatting those records would invalidate provenance. +packages/*/test/evidence/**/*.json + +# Preserve raw Playwright failure snapshots, including the original whitespace. +packages/*/test/evidence/**/error-context.md diff --git a/AGENTS.md b/AGENTS.md index c6298ec04e..b1f2dfd24c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,12 +2,16 @@ Start with the owner of the change; do not load every reference or introduce a second standard. +For product positioning and website ownership, start with [PRODUCT.md](PRODUCT.md). +`packages/docs` owns ran.chaxus.com; `packages/ranpress` owns its build mechanism. + | Work | Read first | | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| Visual hierarchy, composition, tokens and craft | [ranui design standard](packages/ranui/docs/DESIGN.md) | -| Input, focus, drafts, feedback and recovery | [interaction standard](packages/ranui/docs/INTERACTION.md) | -| Optional batch/queue, settings, account/data or revision workflow | [workflow patterns](packages/ranui/docs/WORKFLOW_PATTERNS.md), only when relevant | -| Unsure which reference owns a decision | Short [interface index](packages/ranui/docs/INTERFACE_GUIDE.md) | +| Visual hierarchy, composition, tokens and craft | [portable design methods](design/DESIGN.md), then [ranui implementation adapter](packages/ranui/docs/adapters/DESIGN.md) | +| Browser proof, evidence freshness and acceptance status | [acceptance contract](design/ACCEPTANCE.md) | +| Input, focus, drafts, feedback and recovery | [interaction standard](design/INTERACTION.md) | +| Optional batch/queue, settings, account/data or revision workflow | [workflow patterns](design/WORKFLOW_PATTERNS.md), only when relevant | +| Unsure which reference owns a decision | Short [interface index](design/INTERFACE_GUIDE.md) | | Component state, events, lifecycle or SSR | [engineering standard](packages/ranui/docs/CODING.md), then [implementation reference](packages/ranui/CLAUDE.md) | | Exact attributes, events, slots, parts or theme variables | Generated [component API](packages/ranui/docs/COMPONENTS.md) and [public tokens](packages/ranui/docs/style-tokens-public.md); verify against source | | Public documentation or localized prose | [documentation site reference](packages/docs/CLAUDE.md) | @@ -17,6 +21,11 @@ Start with the owner of the change; do not load every reference or introduce a s do not create a parallel palette or copy one application's dimensions into library defaults. The index routes decisions; workflow recipes describe host responsibilities, not extra ranui APIs. +Avoid unnecessary secondary labels and descriptions. Let the layout do the explaining. +Keep copy that adds a decision, constraint or consequence; preserve accessible names, field labels, +units, errors and risk disclosures. [DESIGN's wording rules](design/DESIGN.md#words-are-part-of-the-interface) +own this principle; do not remove useful guidance merely to make a screenshot quieter. + For visual changes, use the [UI task lookup](packages/ranui/docs/INTERFACE_GUIDE.md#ui-task-lookup) to find exact owner sections and an evidence brief. Read only applicable owner sections; reuse existing controls and local token mappings. Stop when @@ -35,3 +44,8 @@ The local scope below does not weaken the complete repository CI gates: Public ranui guidance has English and Chinese entry points under `packages/docs/src/ranui/` and `packages/docs/cn/src/ranui/`. Link to canonical owners instead of duplicating long rules. + +Shared methods are edited in `design/`; ranui-specific guidance in `packages/ranui/docs/adapters/`. +Run `pnpm sync:design` and `pnpm sync:agent-plugin` after changing them. Generated npm guides +and bundled plugin references are checked distributions, not additional rule owners. +The unified `plugins/ran` entry has three skills; read only the one relevant to the task. diff --git a/PRODUCT.md b/PRODUCT.md index 42684b9348..98598b6c25 100644 --- a/PRODUCT.md +++ b/PRODUCT.md @@ -1,33 +1,31 @@ -# Product +# ran -## Register +ran provides design methods, UI components and TypeScript utilities for developers and agents building web products. -brand +## Three pillars -## Users +| Pillar | Responsibility | Delivery | +| ---------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------- | +| Ran Design | Product composition, coherent visual language, interaction, motion and evidence-based acceptance | Portable skills, agent plugin and public guidance | +| ranui | Accessible custom elements, themes and explicit component behavior | Independently installable npm package | +| ranuts | Typed utilities with explicit runtime boundaries | Independently installable npm package | -Frontend engineers, UI library maintainers, and technical learners evaluating Web Components for real applications. They arrive with a developer mindset: they want to see whether ranui is native, themeable, inspectable, and usable across frameworks before reading full API documentation. +Ran Design must also work in products that do not use ranui. The ranui adapter connects general methods to the installed library's actual tokens and APIs. ranuts remains useful without a UI dependency. -## Product Purpose +`@alixex/ranview` remains an independently published DOM/reactivity foundation. ranpress is private build infrastructure for the website. These implementation roles do not require additional top-level product pillars. -ranui is an experimental Web Components UI library. The demo should introduce the library, prove that the components are real custom elements, and make theme packs, import paths, styling hooks, and representative components easy to inspect in one page. +## Website -## Brand Personality +**https://ran.chaxus.com** is the product website, documentation and live-example destination. Its existing application owner is `packages/docs`; its build mechanism is `packages/ranpress`. Keep one navigation, search and locale system for the three pillars. The personal `chaxus.com` application is retired from this repository; domain and hosting administration are separate. -Precise, experimental, and tool-minded. The interface should feel like a component workbench for engineers, not a generic SaaS landing page or a decorative gallery. +The website should help a visitor understand the product, try a real interaction, choose a library or agent workflow, and reach accurate instructions. Use composed examples with realistic content and complete states. Let the same example connect design rationale, implementation and verification. -## Anti-references +## Ownership and quality -Avoid purple-gradient SaaS templates, oversized hero metrics, vague marketing claims, stock illustrations, and demo pages that look like raw component test fixtures. Avoid hiding the actual components behind screenshots or decorative mockups. +General methodology belongs to a neutral `design/` owner as it is extracted. Package source owns APIs and tokens. Skills route to the applicable references; public pages explain and demonstrate them. Generated distributions may include copies, but those copies must identify their source and cannot become separately edited standards. -## Design Principles +A library consumer should not need the plugin, and a plugin user should not need to install ranui to use general design guidance. Package and plugin releases are independent; library-specific guidance must identify its applicable version. -- Show real components first. -- Treat theme switching as the signature interaction. -- Keep developer next steps visible: install, import, inspect, style. -- Make the page dense enough for scanning without feeling like an API dump. -- Preserve ranui's experimental honesty while making the library feel intentional. +A polished result combines coherent proportions and typography with complete behavior, readable content and purposeful motion. Claims about visuals require current rendered evidence; claims about transitions require continuous recordings. Automated checks, agent review and human acceptance are distinct. -## Accessibility & Inclusion - -Target WCAG AA contrast for page chrome and documentation content. Respect reduced motion, keep touch targets at least 44px on coarse pointers, avoid hover-only functionality, and ensure anchors land below sticky navigation. +The accepted direction and staged implementation are recorded in the [architecture plan](docs/superpowers/plans/2026-10-23-ran-product-architecture.md). The [ranui demo brief](packages/ranui/demo/PRODUCT.md) applies only to its component workbench. diff --git a/README.md b/README.md index fe461278dd..341d5050c2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@
UI components and TypeScript tools for web applications.
+Design methods, UI components and TypeScript tools for web products.
English · 中文 · 日本語 · Español · Português · 한국어 · Deutsch · فارسی
@@ -49,28 +49,47 @@ Components use custom elements and standard browser events, so no React or Vue r ## Use with an agent -The [ranui skill](./plugins/ranui/skills/ranui/SKILL.md) guides UI implementation, visual -review and browser acceptance. It reads the host's installed ranui references on demand; -it does not install the library or add tools, hooks or external services. +The unified **ran** plugin contains [design](./plugins/ran/skills/design/SKILL.md), +[ranui](./plugins/ran/skills/ranui/SKILL.md) and [ranuts](./plugins/ran/skills/ranuts/SKILL.md) +skills. Design guidance works with the host's existing stack, including projects without ranui. +Library skills read the host's installed package version and public contracts. The plugin bundles +its design references; it needs no MCP server, account or hook. -**Claude Code plugin** — add this repository's marketplace, then install ranui: +For this checkout, register the local marketplace with `codex plugin marketplace add .` +or `claude plugin marketplace add .`, then install `ran@ran`. The remote instructions below +apply once the unified plugin is available on the repository's default branch. + +**Claude Code plugin** — add this repository's marketplace, then install ran: ```sh claude plugin marketplace add chaxus/ran -claude plugin install ranui@ran +claude plugin install ran@ran ``` -Invoke `/ranui:ranui` in a new session. The same marketplace also offers `ranuts` for utility work. +In a new session, use `/ran:design`, `/ran:ranui` or `/ran:ranuts` for the relevant task. + +**Codex plugin** — register the repository marketplace and install the same skill: + +```sh +codex plugin marketplace add chaxus/ran +codex plugin add ran@ran +``` -**Codex skill** — after cloning this repository, copy `plugins/ranui/skills/ranui/` into -your host project's `.agents/skills/ranui/`. Start a new task and invoke `$ranui`. -This uses the same skill body; the `.claude-plugin` manifest is the Claude installation route. -See [Codex skill discovery](https://learn.chatgpt.com/docs/build-skills#where-codex-loads-local-skills). +Start a new task and invoke `$design`, `$ranui` or `$ranuts`. For a local checkout, use `codex plugin marketplace add .` +from the repository root. The portable [plugin manifest](./plugins/ran/plugin.json) and +[Codex marketplace](./.agents/plugins/marketplace.json) follow the +[official packaging format](https://developers.openai.com/plugins/build/plugins). +Both installation routes load the same three skill bodies and bundled design references. Example task: “Use ranui to polish this settings pane: keep related text together, align control labels, and verify actual screenshots in light/dark at narrow/wide widths.” -The [UI task lookup](./packages/ranui/docs/INTERFACE_GUIDE.md#ui-task-lookup) maps these -requests to canonical rules and an evidence brief. Source contributors start with [AGENTS.md](./AGENTS.md). +The [UI task lookup](./packages/ranui/docs/INTERFACE_GUIDE.md#ui-task-lookup) routes to one owner: +[design](./packages/ranui/docs/DESIGN.md), [interaction](./packages/ranui/docs/INTERACTION.md), +[public API](./packages/ranui/docs/COMPONENTS.md), or [evidence and decisions](./packages/ranui/docs/ACCEPTANCE.md). +The plugin starts with a short task contract, preserves the host's product decisions and requires +actual rendered evidence for UI claims. Automated checks, agent inspection and human acceptance +remain distinct. [Six opt-in live scenarios](./plugins/ran/evals/README.md) test the guidance's +behavior separately from its token/API checks. Source contributors start with [AGENTS.md](./AGENTS.md). ## Work on the repository diff --git a/README.zh-CN.md b/README.zh-CN.md index 09c06f1fe7..c950aa71ab 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -49,27 +49,42 @@ document.body.append(button); ## 与 agent 一起使用 -[ranui skill](./plugins/ranui/skills/ranui/SKILL.md) 用于界面实现、视觉审查和浏览器验收。 -它按需读取宿主项目已安装的 ranui 规范,不会安装组件库,也不包含工具、hooks 或外部服务。 +统一的 **ran 插件**包含 [design](./plugins/ran/skills/design/SKILL.md)、 +[ranui](./plugins/ran/skills/ranui/SKILL.md) 和 [ranuts](./plugins/ran/skills/ranuts/SKILL.md) +三个 skill。设计方法适用于现有技术栈,无需安装 ranui;库相关指引读取宿主实际安装版本的公开契约。 +插件自带设计参考文件,无需 MCP 服务、账号或 hook。 + +测试当前分支时,在仓库根目录运行 `codex plugin marketplace add .` 或 +`claude plugin marketplace add .`,再安装 `ran@ran`。下面的远程安装方式在统一插件进入默认分支后适用。 **Claude Code 插件**:添加本仓库的 marketplace,再安装 ranui: ```sh claude plugin marketplace add chaxus/ran -claude plugin install ranui@ran +claude plugin install ran@ran ``` -新会话中使用 `/ranui:ranui`。同一 marketplace 也提供用于工具函数任务的 `ranuts`。 +新会话中按任务使用 `/ran:design`、`/ran:ranui` 或 `/ran:ranuts`。 + +**Codex 插件**:注册仓库的 marketplace,安装同一份 skill: -**Codex skill**:克隆本仓库后,将 `plugins/ranui/skills/ranui/` 复制到宿主项目的 -`.agents/skills/ranui/`,新建任务后使用 `$ranui`。两者使用同一份 skill 正文; -`.claude-plugin` 清单用于 Claude 的插件安装。 -参见 [Codex skill 发现规则](https://learn.chatgpt.com/docs/build-skills#where-codex-loads-local-skills)。 +```sh +codex plugin marketplace add chaxus/ran +codex plugin add ran@ran +``` -使用示例:“按 ranui 规范优化这个设置侧栏,收拢相关文案、对齐控件文字, -并用明暗主题、窄宽屏的实际截图验收。” -[UI 任务索引](./packages/ranui/docs/INTERFACE_GUIDE.md#ui-task-lookup) 将这些问题直接对应到 -权威规则和验收简表。修改 ran 源码时先读 [AGENTS.md](./AGENTS.md)。 +新任务中使用 `$design`、`$ranui` 或 `$ranuts`。本地检出仓库时,在仓库根目录执行 `codex plugin marketplace add .`。 +[插件清单](./plugins/ran/plugin.json)和 [Codex marketplace](./.agents/plugins/marketplace.json) +遵循[官方打包格式](https://developers.openai.com/plugins/build/plugins)。 +两种安装入口使用同一份 skill 正文,不需要 MCP 服务、额外账号或 hook。 + +使用示例:“用 ranui 优化这个设置侧栏,保留任务和交互,用相关主题、宽度的实际截图验证。” +[UI 任务索引](./packages/ranui/docs/INTERFACE_GUIDE.md#ui-task-lookup)按任务进入唯一规则来源: +[设计](./packages/ranui/docs/DESIGN.md)、[交互](./packages/ranui/docs/INTERACTION.md)、 +[公开 API](./packages/ranui/docs/COMPONENTS.md)和[证据与验收](./packages/ranui/docs/ACCEPTANCE.md)。 +插件先明确简短的任务契约,再保留宿主产品已有决策,并用实际渲染证据支撑界面结论。 +自动检查、agent 视觉审查和用户验收分别记录;[六个可选 agent 场景](./plugins/ran/evals/README.md) +验证指引的实际执行效果,不用 token/API 检查冒充行为验证。源码贡献者先读 [AGENTS.md](./AGENTS.md)。 ## 参与开发 diff --git a/bin/README.md b/bin/README.md new file mode 100644 index 0000000000..94e999a9ff --- /dev/null +++ b/bin/README.md @@ -0,0 +1,20 @@ +# Repository tooling + +Repository-owned scripts are TypeScript ES modules executed directly by the supported +Node.js 24+ runtime. Use explicit `.ts` relative imports and erasable TypeScript syntax; +no loader, emitted copy, path alias or second script runner is required. + +- `pnpm typecheck:tooling` checks strict NodeNext types without emitting files. +- `pnpm verify:scripts` runs isolated cleanup, declarations, licensing, size and release tests. +- `pnpm verify:agent-evals` checks the evaluation harness, including browser negative controls. + +Node strips types when running these scripts; it does **not** check them. Keep the separate +type-check gate in CI. Narrow JSON and caught errors at the boundary before acting on paths, +package metadata or release receipts. `tooling-json.ts` owns the shared small validators. + +Published library output remains JavaScript ESM with declarations. Temporary `.mjs` consumer +fixtures intentionally verify those JavaScript exports without a TypeScript runtime. Vendored +third-party skills and recorded historical evidence retain their original source files. + +Browser evaluation files run serially to avoid competing Vite/browser cold starts. Each file +retains its asynchronous interaction cases, original timeouts, negative controls and zero retries. diff --git a/bin/build-site.sh b/bin/build-site.sh deleted file mode 100755 index bc8c94ba11..0000000000 --- a/bin/build-site.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# Build chaxus.com (packages/site). POSIX sh — see packages/docs/bin/build.sh for why. -# -# This is the Cloudflare Pages build command for the personal site, and it mirrors -# bin/build.sh (which builds the documentation site). The site imports ranui's built -# output, so ranui — and ranuts underneath it — have to exist first. -set -eu -npx pnpm -F ranuts build -pnpm -F ranui build -pnpm -F site build diff --git a/bin/build.sh b/bin/build.sh index 8c67e5aa65..d37ffb6c33 100644 --- a/bin/build.sh +++ b/bin/build.sh @@ -4,8 +4,3 @@ pnpm -F ranuts build pnpm -F @alixex/ranview build pnpm -F ranui build pnpm -F docs build -# The site is a deployable artifact too. Its build ends in verify.ts, which fails on a -# dead link, a canonical naming another page, or a page missing from the sitemap — all -# things Cloudflare Pages would otherwise accept and publish. Building it here means CI -# finds that before the deploy does. -pnpm -F site build diff --git a/bin/clean.sh b/bin/clean.sh index c5a6fab2e9..5f17f3607d 100644 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -1,4 +1,4 @@ #!/bin/sh set -eu -exec node "$(dirname "$0")/clean.mjs" +exec node "$(dirname "$0")/clean.ts" diff --git a/bin/clean.mjs b/bin/clean.ts similarity index 88% rename from bin/clean.mjs rename to bin/clean.ts index 50048985d1..65900dcf33 100644 --- a/bin/clean.mjs +++ b/bin/clean.ts @@ -1,10 +1,11 @@ +import { object, hasErrorCode } from './tooling-json.ts'; import { lstatSync, readFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; // Resolve from this script so running the shell wrapper elsewhere is safe. const root = fileURLToPath(new URL('../', import.meta.url)); -const manifest = JSON.parse(readFileSync(join(root, 'packages/manifest.json'), 'utf8')); +const manifest = object(JSON.parse(readFileSync(join(root, 'packages/manifest.json'), 'utf8'))); if (!manifest.packages || typeof manifest.packages !== 'object' || Array.isArray(manifest.packages)) { throw new Error('Invalid packages manifest: expected a packages object'); } @@ -32,7 +33,7 @@ for (const owner of owners) { break; } } catch (error) { - if (error.code !== 'ENOENT') throw error; + if (!hasErrorCode(error, 'ENOENT')) throw error; safe = false; break; } diff --git a/bin/component-bundle-size.mjs b/bin/component-bundle-size.ts similarity index 68% rename from bin/component-bundle-size.mjs rename to bin/component-bundle-size.ts index a516be7f13..9dd34c6b5f 100644 --- a/bin/component-bundle-size.mjs +++ b/bin/component-bundle-size.ts @@ -1,3 +1,23 @@ +import type { build as viteBuild } from 'vite'; +export interface ConsumerChunk { + type: 'chunk'; + fileName: string; + code: string; + imports: string[]; + isEntry?: boolean; + name?: string; + dynamicImports?: string[]; +} +export interface ConsumerAsset { + type: 'asset'; + fileName: string; + source: string | Uint8Array; +} +export interface BundleSize { + bytes: number; + gzipBytes: number; + chunks?: number; +} /** Measure browser consumers of packed packages with Vite's normal tree shaking. */ import assert from 'node:assert/strict'; import { createRequire } from 'node:module'; @@ -13,12 +33,12 @@ export const componentBundleBudgets = { player: { bytes: 300_000, gzipBytes: 80_000 }, }; -export function initialJavaScriptSize(output, entryName = 'consumer') { +export function initialJavaScriptSize(output: readonly (ConsumerChunk | ConsumerAsset)[], entryName = 'consumer') { const chunks = new Map(output.filter((item) => item.type === 'chunk').map((chunk) => [chunk.fileName, chunk])); const entry = [...chunks.values()].find((chunk) => chunk.isEntry && chunk.name === entryName); assert.ok(entry, `Missing consumer entry: ${entryName}`); - const visited = new Set(); - function visit(fileName) { + const visited = new Set