This repository explains how to create monorepos project using npm and TypeScript.
- Tools
- Directory Structure
- Workspaces
- Dependencies across packages
- Resolve dependencies as TypeScript projects
- How to execute scripts for each package ?
- License
- npm cli(v7 or later)
- TypeScript
Put each package under the packages
directory.
.
├── node_modules/
├── README.md
├── package-lock.json
├── package.json
├── packages
│ ├── x-cli
│ │ ├── lib
│ │ │ ├── cli.d.ts
│ │ │ ├── cli.js
│ │ │ ├── cli.js.map
│ │ │ ├── main.d.ts
│ │ │ ├── main.js
│ │ │ └── main.js.map
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── cli.ts
│ │ │ └── main.ts
│ │ └── tsconfig.json
│ └── x-core
│ ├── lib
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ └── index.js.map
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
├── tsconfig.build.json
└── tsconfig.json
Using npm workspaces feature, configure the following files:
Open package.json
and append the workspaces
key.
/* package.json */
{
"name": "npm-ts-workspaces-example",
"private": true,
...
"workspaces": ["packages/*"]
}
Exec npm install
. After successful running, all dependencies included from each package are downloaded under the repository root node_modules
directory.
In this example, the x-cli
package depends on another package, x-core
. So to execute (or test) x-cli
, x-core
packages should be installed.
But in development the x-core
package is not published so you can't install it.
For example, packages/x-cli/src/main.spec.ts
is a test code for main.ts
, which depends on packages/x-core/src/index.ts
.
/* packages/x-cli/src/main.ts.*/
import { awesomeFn } from "@quramy/x-core";
export async function main() {
// dependencies across child packages
const out = await awesomeFn();
return out;
}
So we need to link x-core
package from x-cli
to execute the x-cli
's test.
Workspaces feature of npm also solves this problem. npm i
creates sim-links of each package into the top-level node_modules
dir.
As mentioned above, npm cli resolves dependencies across packages. It's enough for "runtime". However considering TypeScript sources, in other words "static", it's not.
We need to tell "x-cli package depends on x-core" to TypeScript compiler. TypeScript provides much useful feature to do this, "Project References".
First, you add composite: true
to project-root tsconfig.json to use project references feature.
/* tsconfig.json */
{
"compilerOptions": {
...
"composite": true
}
}
Second, configure each package's tsconfig and configure dependencies across packages.
/* packages/x-cli/tsconfig.json */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib"
},
"references": [{ "path": "../x-core" }]
}
And create a project which depends on all packages:
/* tsconfig.build.json */
{
"files": [],
"references": [{ "path": "packages/x-core" }, { "path": "packages/x-cli" }]
}
Let's exec npx tsc --build tsconfig.build.json
. The .ts files included in all packages are build at once!
We can use --workspaces
option.
# Excecute npm test in all workspaces
$ npm test --workspaces
# Bump up packages in all workspaces
$ npm version --workspaces patch
# Publish packages in all workspaces
$ npm publish --workspaces
The MIT License (MIT)