@composy/builder

现代 TypeScript 与前端库构建工具,支持零配置分析、多引擎打包、样式产物整理与 package.json 自动回写
Install
npm install @composy/builder
Latest Version:0.1.0
License:MIT
Last Updated:Oct 12, 2026
Links: npm
Maintainer: swimly

@composy/builder

English README

@composy/builder 是一个面向 TypeScript 库、组件库、工具库与 CLI 包的构建工具。它提供零配置分析、可扩展配置系统、多打包引擎适配、构建后样式补链、package.json 自动回写和产物自检能力,适合在 monorepo 中统一维护发布链。

核心能力

  • 零配置分析:自动识别项目入口、框架类型、推荐 external、UMD globals 与输出布局。
  • 多引擎适配:默认使用 rolldown,并内置 rollup、esbuild、swc、vite、rspack、turbopack 适配器。
  • 多框架策略:支持 TypeScript、React、Vue 2/3、Svelte、Solid、Preact、Lit、Angular、Qwik、Astro、Remix、Nuxt 3 与混合框架场景。
  • 样式产物整理:构建后可为 es/lib 写入编译 CSS,为 esm 保留样式源码,并为 dist 聚合样式文件。
  • 包元数据维护:根据真实输出目录更新 exports、files、样式导出与主入口字段。
  • 产物自检:对入口文件、声明文件、UMD 文件与聚合样式做轻量校验,提前暴露发布面漂移。
  • 项目诊断:通过 ldesign-builder doctor 检查配置、入口、package.json 发布面和可选产物布局。
  • CLI 与编程式 API 并存:既可直接使用 ldesign-builder,也可通过 LibraryBuilder、ConfigManager 等 API 集成到自定义脚本中。

安装

pnpm add -D @composy/builder

快速开始

1. 零配置构建

当项目结构符合常见库目录约定时,可以直接运行:

pnpm exec ldesign-builder build

在交互式终端中,build 会先询问本次是否升级包版本。选择升级后,可用上下键从 Patch、Minor、Major、Alpha、Beta、RC 和自定义精确版本中选择;每个选项都会显示 当前版本 → 目标版本 与适用场景。目标包版本会在构建前写入,只有完整构建成功后,builder 才会在检测到的 pnpm/npm/yarn/bun workspace 中同步所有消费方的 dependencies、devDependencies、peerDependencies、optionalDependencies 和 pnpm catalog 引用,并刷新 lockfile。构建或同步失败时会回滚本次版本事务。

CI、管道和其他非 TTY 环境不会等待输入,默认保持版本不变;请显式指定方案:

# 自动化发布构建
pnpm exec ldesign-builder build --version-bump minor

# 指定精确版本
pnpm exec ldesign-builder build --version-bump 2.0.0-rc.0

# 明确跳过询问;也可使用 --version-bump none
pnpm exec ldesign-builder build --no-version-prompt

# 特殊流程中保留消费方声明或 lockfile
pnpm exec ldesign-builder build --version-bump patch --no-workspace-update
pnpm exec ldesign-builder build --version-bump patch --no-lockfile-update

build --watch 不会开启一次性版本事务;如需升级,请先完成一次普通 build,再启动 watch。build --dry-run --version-bump minor 只展示版本计划,不写文件。

如果你想先确认最终解析到的配置和构建计划,而不真正写出产物,可以使用:

pnpm exec ldesign-builder build --print-config --dry-run

如果要复用预设,可在配置文件之后、CLI 显式覆盖之前应用构建预设:

pnpm exec ldesign-builder build --profile ci --dry-run

builder 会优先尝试自动分析:

  • src/index.ts 等常见源码入口
  • package.json 中的包名、依赖、peerDependencies
  • 当前项目的框架特征与输出需求

版本规划、workspace 检测与依赖同步

build 的版本事务分成“规划、构建、提交”三个阶段:

  1. 规划阶段在初始化 builder 前读取当前包的 package.json,确认当前版本并计算目标版本。
  2. 构建阶段先把目标版本写入当前包,使构建产物和包元数据使用同一个版本;随后执行普通构建、DTS、报告、体积限制和资源清理。
  3. 提交阶段只在上述步骤全部成功后更新 workspace 消费方、catalog 和 lockfile。任何阶段失败都会恢复当前包版本;workspace 同步失败还会恢复已修改的 manifest、pnpm-workspace.yaml 和 lockfile 快照。

只要本次事务确实升级了版本,提交阶段还会在当前包目录生成或更新 CHANGELOG.md。日志会记录构建工具、版本前后值、workspace 消费方的每个依赖字段变更、catalog/lockfile 状态,并结合 Git 提交按类型、作者、提交哈希、Breaking Changes 和统计信息生成详细条目。Git 历史不可用时会降级写入完整的版本事务摘要;日志及其降级摘要都无法写入时会和版本事务一起回滚。未升级版本、--dry-run 和 --watch 不会生成日志。

交互式版本选择

在真实 TTY 中,执行 ldesign-builder build 会先询问是否升级版本。选择“升级”后,使用上/下方向键移动,按 Enter 确认。菜单会同时展示当前版本、目标版本和使用场景:

方案 版本规则 适用场景
Patch x.y.Z 向后兼容的问题修复
Minor x.Y.0 向后兼容的新功能
Major X.0.0 包含破坏性变更
Alpha x.y.z-alpha.N 早期预览,API 仍可能变化
Beta x.y.z-beta.N 功能基本完整,继续收集兼容性反馈
RC x.y.z-rc.N 发布候选版本,只接受发布阻断修复
自定义 任意高于当前版本的合法 SemVer 需要精确指定版本或预发布标识

Alpha、Beta 和 RC 会根据当前版本自动计算下一序号;自定义版本必须是合法 SemVer,且严格高于当前版本。选择“不升级”时只执行构建,不修改版本或 workspace 依赖。

CI、脚本和非 TTY 环境

非 TTY、CI 或 TERM=dumb 环境不会等待键盘输入,默认保持当前版本。自动化流程应显式提供版本方案:

# 语义化升级
pnpm exec ldesign-builder build --version-bump patch
pnpm exec ldesign-builder build --version-bump minor
pnpm exec ldesign-builder build --version-bump major
pnpm exec ldesign-builder build --version-bump alpha
pnpm exec ldesign-builder build --version-bump beta
pnpm exec ldesign-builder build --version-bump rc

# 精确版本(包括预发布版本)
pnpm exec ldesign-builder build --version-bump 2.0.0-rc.0

# 明确不升级版本
pnpm exec ldesign-builder build --version-bump none
pnpm exec ldesign-builder build --no-version-prompt

--version-bump 也可以通过环境变量 LDESIGN_BUILDER_VERSION_BUMP 提供,适合统一的发布脚本。命令行参数优先于环境变量。

workspace 检测规则

builder 会从当前包目录向上查找 workspace 根目录,支持:

  • pnpm-workspace.yaml 的 packages 配置;
  • 根 package.json 的 workspaces 数组或 { "packages": [...] } 配置;
  • pnpm、npm、Yarn 和 Bun 的常见 lockfile。

包管理器的判断优先使用 workspace 根 package.json 中的 packageManager 声明,例如 "packageManager": "pnpm@10.0.0";没有明确声明时,才根据现有 lockfile 推断。这样可以避免目录中同时存在多个 lockfile 时选错包管理器。

如果当前包不属于任何 workspace,builder 只处理当前包版本,不会修改父目录或其他项目。如果属于 workspace,构建成功后会查找所有名称依赖当前包的其他 package,并更新以下字段:

位于 git submodule 中的包也会继续向上检查;只有上级 workspace 的 packages pattern 实际包含当前包时,才会把它当作该 workspace 的成员并同步消费方。未被 pattern 包含的独立子模块仍按非 workspace 包处理。

  • dependencies;
  • devDependencies;
  • peerDependencies;
  • optionalDependencies。

更新时会尽量保留原有依赖意图,例如 ^1.2.3 变为 ^1.3.0、~1.2.3 变为 ~1.3.0、workspace:^1.2.3 变为 workspace:^1.3.0。file:、link: 和未解析的特殊协议不会被强行改写。

对于 catalog: 依赖,consumer 的 catalog: 声明保持不变,builder 会更新 pnpm-workspace.yaml 中对应的 catalog 或命名 catalog 版本。只要 manifest 或 catalog 发生变化,并且检测到 lockfile,builder 就会调用对应包管理器刷新 lockfile。

workspace 同步控制

# 升级当前包并同步所有 workspace 消费方
pnpm exec ldesign-builder build --version-bump minor

# 只升级当前包,不修改其他 package.json 或 catalog
pnpm exec ldesign-builder build --version-bump minor --no-workspace-update

# 更新 manifest/catalog,但不执行 pnpm/npm/yarn/bun lockfile 刷新
pnpm exec ldesign-builder build --version-bump minor --no-lockfile-update

--no-workspace-update 和 --no-lockfile-update 只影响提交阶段,不会跳过构建,也不会阻止当前包版本在构建前写入。构建或同步失败时,builder 会优先恢复文件,避免出现“当前包已经升级但消费方没有同步”的半完成状态。

dry-run 与 watch

--dry-run 只解析配置并显示版本规划,不写入 package.json、workspace manifest、catalog 或 lockfile:

pnpm exec ldesign-builder build --version-bump minor --dry-run --print-config

build --watch 是长驻监听模式,不会启动一次性版本事务,也不会在每次文件变化时重复升级版本。需要升级版本时,先完成一次普通 build,确认构建和 workspace 同步成功后,再启动 watch:

pnpm exec ldesign-builder build --version-bump minor
pnpm exec ldesign-builder build --watch

2. 使用配置文件

创建 builder.config.ts:

import { defineConfig } from '@composy/builder'

export default defineConfig({
  bundler: 'rolldown',
  libraryType: 'react',
  input: 'src/index.ts',
  output: {
    es: {
      dir: 'es',
    },
    esm: {
      dir: 'esm',
      preserveLessSource: true,
    },
    cjs: {
      dir: 'lib',
    },
    umd: {
      dir: 'dist',
      name: 'DemoLibrary',
    },
  },
  packageUpdate: {
    enabled: true,
  },
  postBuildValidation: {
    enabled: true,
  },
})

然后执行:

pnpm exec ldesign-builder build --config builder.config.ts

输出目录语义

当前包围绕以下四类目录组织产物:

  • es/:编译后的主 ESM 产物,默认也是 module 与类型入口的首选目录。
  • esm/:保留结构或保留样式源码的辅助 ESM 目录,适合 less 等场景。
  • lib/:CJS 产物目录。
  • dist/:UMD 产物目录,同时可放置聚合样式文件。

如果你使用 legacy 形式:

output: {
  dir: 'dist',
  format: ['esm', 'cjs'],
}

它会被视为“单目录多格式输出”。如果希望对不同格式分别配置 dir、input、dts、preserveLessSource 等能力,应改用 output.es / output.esm / output.cjs / output.umd 分支配置。

当 UMD 包还需要发布独立 Worker 等浏览器资产时,在同一个 output.umd 中配置 entries;每个 entry 会使用同一套 builder/Rolldown 配置生成常规和压缩版本:

output: {
  umd: {
    input: 'src/index.ts',
    fileName: 'index.js',
    name: 'DemoLibrary',
    entries: [
      {
        input: 'src/workers/demo.worker.ts',
        fileName: 'demo.worker.js',
        name: 'DemoWorker',
      },
    ],
  },
}

CLI

每次 ldesign-builder 命令都会在当前项目创建完整执行日志:

.ldesign/.logs/builder/<ISO 时间>-<pid>.log

日志会记录命令、构建输出、错误堆栈、退出码和耗时;常见敏感命令参数会自动脱敏,日志写入失败不会影响原构建流程。

常用命令如下:

  • ldesign-builder build:执行构建。
  • ldesign-builder build --profile ci:应用构建预设后执行构建。
  • ldesign-builder build --print-config:打印最终合并后的配置。
  • ldesign-builder build --dry-run:只预览构建计划,不执行打包。
  • ldesign-builder watch --profile development:使用指定预设监听并增量构建。
  • ldesign-builder doctor --json:输出可脚本消费的项目诊断结果。
  • ldesign-builder doctor --strict --artifacts:在发布前严格检查 package 入口、exports 与构建产物。
  • ldesign-builder doctor --fail-on-warnings --report reports/builder-doctor.json:将 warning 也视为失败,并写入 JSON 诊断报告。
  • ldesign-builder analyze:输出构建分析信息。
  • ldesign-builder init:生成或初始化配置。
  • ldesign-builder examples:批量执行示例项目构建。
  • ldesign-builder typecheck:执行类型检查辅助流程。
  • ldesign-builder size:查看体积信息。
  • ldesign-builder visualize:输出可视化相关分析。

查看完整命令帮助:

doctor --json 与 doctor --report 会输出 metadata.layouts.configOutputDirs、 metadata.layouts.packageOutputDirs 和 metadata.layouts.effectiveOutputDirs,用于在 CI 中区分 builder 配置输出、package.json 推断输出和合并后的有效发布目录。

pnpm exec ldesign-builder --help

build 版本与 workspace 参数速查

参数 作用 默认行为
--version-bump <方案或版本> 非交互指定 patch、minor、major、alpha、beta、rc、none 或完整 SemVer TTY 中询问;非 TTY 保持当前版本
--no-version-prompt 跳过版本询问 保持当前版本
--no-workspace-update 不更新 workspace 消费方和 catalog 构建成功后自动同步
--no-lockfile-update 不刷新 pnpm/npm/yarn/bun lockfile 有 manifest/catalog 变化时自动刷新
--dry-run 只显示配置和版本计划,不写文件或执行打包 仅预览
--watch 进入长驻监听模式 跳过一次性版本事务

推荐的发布构建顺序是:先执行一次带 --version-bump 的普通构建,确认 workspace 同步和 lockfile 更新成功,再执行 build --watch 或其他后续开发命令。若发布流程由外部版本工具管理,可使用 --version-bump none 或 --no-version-prompt 明确关闭 builder 的版本写入。

编程式 API

最常用的公开 API 包括:

  • LibraryBuilder
  • ConfigManager
  • StrategyManager
  • PluginManager
  • PostBuildValidator
  • defineConfig
  • autoConfig
  • presets
  • ProjectAnalyzer

示例:

import { LibraryBuilder } from '@composy/builder'

const builder = new LibraryBuilder({
  config: {
    input: 'src/index.ts',
    output: {
      es: { dir: 'es' },
      cjs: { dir: 'lib' },
    },
  },
})

await builder.build()

缓存依赖失效

使用 BuildCacheManager.setWithDependencies() 写入构建缓存时,依赖路径会同时保存到缓存条目的 metadata.dependencies,并在内存中建立依赖追踪。后续调用 get(key) 不需要再次传入依赖列表;只要任一依赖文件的 mtime 晚于缓存创建时间,缓存就会被判定为失效并删除。该依赖元数据会随 .cache 文件持久化,因此进程重启后仍然有效。

await cache.setWithDependencies('bundle:src/index.ts', result, ['src/index.ts', 'src/shared.ts'])

// 依赖发生变化时返回 null,并清理对应缓存
const cached = await cache.get('bundle:src/index.ts')

如果调用方只在单次读取时拥有依赖列表,也可以继续使用 get(key, dependencies) 覆盖条目内记录的依赖集合。

样式处理与产物校验

构建完成后,builder 会按配置执行两类补链逻辑:

  1. 样式补链

    • 编译 less/scss/sass 到目标目录
    • 为组件库生成 style/index.js、style/css.js
    • 在 dist/ 中生成聚合 CSS
  2. 产物自检

    • 检查入口 JS/CJS 是否存在
    • 检查声明文件是否落盘
    • 检查 UMD 产物与聚合样式
    • 解析输出 JS,快速发现语法层面的坏包

默认情况下,自检失败会以 warning 形式反馈;需要阻断构建时,再显式开启 postBuildValidation.failOnError。

开发脚本

当前仓库脚本与发布链已经统一到 @composy/pack:

pnpm run build
pnpm run build:types
pnpm run type-check
pnpm run lint:check
pnpm run format:check

其中:

  • build 会使用 @composy/pack 编译 src/**/*.ts 对应的源码文件,输出 esm、cjs 与 d.ts
  • build:types 会通过 tsc -p tsconfig.build.json 单独补齐声明文件
  • lint:check 当前聚焦 src/**/*.ts、.ldesign 下的 JS/TS 配置与脚本,以及根转发配置

权威工程配置集中在 .ldesign/:pack.config.mjs 是 @composy/pack 构建入口, eslint.config.js 和 tsconfig*.json 是 ESLint/TypeScript 配置。保留的 .ldesign/tsup.config.mjs 只转发到 pack 配置;根目录同名 TypeScript/ESLint 文件以及 tsconfig.build.json、 tsconfig.dts.json 是为工具自动发现和现存脚本保留的薄 shim。

文档

更细分的使用说明仍保留在 docs/:

当前包维护约定

  • 构建配置统一走 .ldesign/pack.config.mjs
  • 发布产物统一输出到 dist/
  • 质量校验以 type-check、lint:check、build 为准
  • 会话结束前应更新 AGENTS.md,记录背景、发现、进度与待办

License

MIT

通过 @composy/cli 统一接入

  • 接入类型:bin
  • 统一命令:ldesign builder
  • 命令别名:ldesign-builder
  • 包内原生 bin:ldesign-builder

当前包通过独立 bin 接入,统一命令会转发到包自身 CLI。

pnpm add -D @composy/cli
ldesign builder --help
ldesign tools run builder --help

2026-10 构建可靠性与低内存优化

本次源码级增强的修复清单、并发控制、缓存失效策略、独立 smoke 校验和验证限制参见 Builder 强化审计报告。

Worker 线程池与构建监听的正确性说明

  • WorkerPool 默认按需创建线程,最多使用 8 个可用 CPU 并行度(可用 maxWorkers 自定义);minWorkers 默认 0,idleTimeout 可在空闲时回收额外线程。terminate() 会拒绝进行中和排队任务。enablePriority 默认开启,优先级高的任务先运行,同级按入队顺序执行。
  • 统一适配器不再使用仅凭时间戳命中的第二层 BuildResult 缓存,以免源码变化后返回旧结果;由底层打包器管理其经过文件校验的缓存。明确指定 cache:false 时会传递给具体打包器。
  • 不再隐式更改用户传入的 treeshake.moduleSideEffects、output.compact 或 output.sourcemap。不同引擎依各自约定执行多格式输出,SWC 使用顺序构建。
  • 可以运行 npm run test:smoke:builder:round6 检查这轮独立行为回归。这不是完整工作区的编译或真实 Rollup/Rolldown 集成测试。

第七轮构建适配器校验(2026-10-10)

新增 esbuild Sass/SCSS/Less 预处理、SWC 输出路径隔离与有界并发、动态 glob 监听。独立回归:npm run test:smoke:builder:round7。详细修改、限制和完整工程依赖请参阅 docs/DEEP_SOURCE_AUDIT_ROUND_7.md。

Related Packages

@composy/launcher

Zero-config frontend launcher built on Vite with dev, build, preview, config, en...

0
pledgepack

A Rust+Zig bundler with incremental computation, JS plugins, and Rollup-quality...

6,158 9
denji

A CLI tool to manage your SVG icons

1,815 6
@arclux/prism

Auto-generate framework wrappers (React, Vue, Svelte, Angular, Solid, Preact) an...

6,845 1
@wu-framework/cli

Native Zig dev server + CLI for wu-framework microfrontends. One binary, one por...

4,625

Version History

Version Released License
0.1.0 MIT
0.0.1 MIT