Implementing a Monorepo with Lerna, Yarn Workspaces, and TypeScript for Automated NPM Package Publishing
By migrating the “全民 K 歌” base library to a monorepo using Lerna, Yarn workspaces, and TypeScript, the team unified dependency management, enabled topological builds, enforced master‑only versioning with conventional commits, and automated CI‑driven publishing—including beta canary releases—significantly speeding iteration and improving maintenance.
Lerna has become the preferred tool for building monorepo projects, but the official documentation lacks guidance for the final steps of monorepo construction. This article records the experience of migrating the “全民 K 歌” base library to a monorepo using Lerna, Yarn workspaces, TypeScript, and Orange CI.
Background
The original base library was mixed with business code, causing issues such as hidden code, lack of package classification, poor iteration speed, difficulty tracing changes, no version management, and missing documentation.
Code Management Options Comparison
1. Git Submodule / Subtree – easy to feed changes but high management cost with many submodules.
2. Multirepo – clear module division, each module has its own repo, but version control and dependency handling become manual.
3. Monorepo – unified code management, easier issue handling and changelog generation, but requires unified CI/build pipelines and larger repository size.
Monorepo was chosen as the optimal solution.
Implementation
1. Dependency Management
Using Yarn workspaces instead of npm link reduces conflicts and simplifies dependency resolution. Important commands:
lerna bootstrapYarn uses a single yarn.lock instead of multiple package-lock.json files.
Run yarn why <query> to understand why a package is installed.
Yarn workspaces are the underlying mechanism used by Lerna.
Root package.json must contain:
{
"name": "root",
"private": true,
"workspaces": ["packages/*"]
}2. Project Initialization
Initialize Lerna with independent versioning:
lerna init --independentCreate packages:
lerna create @tencent/pkg1
lerna create @tencent/pkg2Each package’s package.json includes name, version, main, and types fields.
Install TypeScript at the root:
yarn add typescript -W -DRoot tsconfig.json defines compiler options, path mapping, and includes all packages.
Package‑specific tsconfig.json extends the root config and sets outDir and include .
Resulting directory structure:
├── lerna.json
├── yarn.lock
├── package.json
├── packages
│ ├── pkg1
│ │ ├── package.json
│ │ ├── src/index.ts
│ │ └── tsconfig.json
│ └── pkg2
│ ├── package.json
│ ├── src/index.ts
│ └── tsconfig.json
└── tsconfig.json3. Build Process
Monorepo builds must respect inter‑package dependencies. Two approaches:
Use lerna run to execute scripts in topological order.
Leverage TypeScript Project References (TS 3.0+).
Typical lerna run workflow runs each package’s build script after its dependencies are built.
Project References require each package’s tsconfig.json to set composite: true and list dependent packages in references .
4. Versioning and Publishing
Key requirements:
Code review before publishing.
Publish only from the master branch.
CI should automatically build, bump versions, and generate changelogs.
Support temporary “beta” releases for testing.
Enforce branch restriction in lerna.json :
{
"packages": ["packages/*"],
"version": "independent",
"command": {
"version": {
"allowBranch": "master"
}
},
"useWorkspaces": true,
"npmClient": "yarn"
}CI scripts in package.json :
{
"scripts": {
"clean": "rm -rf ./lib && rm -rf tsconfig.build.tsbuildinfo",
"build": "yarn clean && tsc --build",
"prepublishOnly": "npm run build"
}
}Version bump follows Conventional Commits:
feat → minor bump.
fix → patch bump.
BREAKING CHANGE → major bump.
CI runs:
npx lerna version --conventional-graduate --yes
npx lerna publish from-package --legacy-auth $TNPM_USERPASSWORD_BASE64 --yesTemporary canary releases use:
lerna publish -y --canary --preid "beta.$(git rev-parse --short HEAD)" --pre-dist-tag=beta --legacy-auth xxxResult
The automated pipeline provides real‑time build notifications via WeChat, generates changelogs automatically, and has been adopted across multiple internal projects, improving iteration speed and maintenance order.
Tencent Music Tech Team
Public account of Tencent Music's development team, focusing on technology sharing and communication.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.