Make writing a habit together! This is my first day to participate in the “Gold Digging Day New Plan · April More text challenge”, click to see the details of the activity.
Influenced by some students (@dongdong acridine), I feel it is necessary to record some of the things I do, stomp pits or experience, maybe some people seem to be a running account, but there will always be some people feel a little useful, or you see the officer not hesitate to give advice, I feel helpful. I’m @Laffery, a new front end beginner on the road. If you find this article helpful, please give it a thumbs up and slide away.
background
Back to the point, recently when I was developing my own project, as the project got bigger and bigger, and I wanted to develop an additional library, the old project structure was no longer suitable.
For example, the original project structure is like this
# app├ ─ ─ lib │ ├ ─ ─ two packages pkg1 │ │ └ ─ ─ package. The json │ ├ ─ ─ pkg2 │ │ └ ─ ─ package. The json │ └ ─ ─ pkg3 │ └ ─ ─ package. The json └ ─ ─ package. The jsonCopy the code
My main pain point at the moment is this
-
Why do I need these packages in my project?
-
These packages are generic (to me) packages that I’ve accumulated over the course of development and that the project body app relies on
-
I wanted to develop them together in this project because there was a lot of reusable code
-
-
Imagine pkG1, PKG2, pkG3 and the dependencies of our main project app overlap. Anyone who has suffered from node_modules knows what this means
- Slow download
- Project volume too large
-
Each PKG has a variety of NPM scripts, mostly dev,build,test, Lint, etc. If you had a workflow that allowed all packages to be merged only after they were lint or test in the CI after each PR, you would be frustrated by the need to execute scripts in each package directory in turn.
What is a monorepo?
Simply put, you put multiple projects in the same repository, as opposed to Multirepo, where there is one repository for each project. Its core advantage is easy code reuse and versioning.
Here is not much to introduce, if there is no clear partner, you can search by yourself.
pnpm
As you all know, NPM is a package management tool for downloading NodeJS, which is certainly excellent, but can sometimes be slow to download.
Yarn, which I’ve been using recently, does a good job of addressing some of the download slowdowns, but that’s irrelevant to the topic of this article. Yarn can also do monorepo, but why do I use PNPM? Because I saw PNPM at my last company.)
Talk about the main character of this article, PNPM.
Save disk space and speed up installation
PNPM has a concept called workspace, which is to divide a warehouse into different workspaces. Generally, a package corresponds to a workspace.
PNPM install will download all workspace dependencies to node_modules/. PNPM, and then add those dependencies to the workspace dependencies via soft links.
Steal the official drawing
I believe you will realize that all dependencies only need to be downloaded once, so the download is not only fast, but also small disk size.
The original project was transformed by Monorepo
Let’s restructure the project
# app├ ─ ─ packages │ ├ ─ ─ two packages pkg1 │ │ ├ ─ ─ package. The json │ │ └ ─ ─ PNPM - lock. Yaml │ ├ ─ ─ pkg2 │ │ ├ ─ ─ package. The json │ │ └ ─ ─ ├─ ├─ ├─ ├─ download.txt, ├─ download.txt, download.txt, download.txt, download.txt, download.txt, download.txt, download.txt, download.txt, download.txt ├ ─ ─ package. Json ├ ─ ─ PNPM - lock. Yaml └ ─ ─ PNPM - workspace. YamlCopy the code
Don’t you feel a lot cleaner [wang Chai].
We configure workspace in pnpm-workshop. yaml so that PNPM knows which workspace there are.
# ./pnpm-workspace.yaml
packages:
# root directory
- "."
# all packages in subdirs of packages/
- "packages/**"
# exclude packages that are inside test/ directories
- ! "" **/test/**" # '! ' means exclude
Copy the code
Now execute PNPM install, and as mentioned above, all the workspace dependencies are downloaded at the same time.
Execute the scripts for each workspace
Now let’s go back to the scene mentioned at the beginning.
If you had a workflow that allowed all packages to be merged only after they were lint or test in the CI after each PR, you would be frustrated by the need to execute scripts in each package directory in turn.
Execute the app script in the root directory
Usually you’re going to execute the app package, and you might do something like this
cd packages/app
npm run xxx
Copy the code
Or if you’re a handy handy, write it like this in./package.json
// ./package.json
{
// ...
"scripts": {
"app:xxx": "cd packages/app && npm run xxx"
}
// ...
}
Copy the code
All you need to do is run app:dev in the root directory.
This is fine, but if you take the fancy and change the package directory name to webApp, you’ll have to painfully change all these instructions to CD Packages/webApp && NPM run XXX.
PNPM provides a –filter (-f) instruction that you can set to execute under a particular package.
Let’s assume that the package mentioned above is called by these names (package.json name).
- pkg1: @laffery/pkg1
- pkg2: @laffery/pkg2
- pkg3: @laffery/pkg3
- app: @laffery/app
Now you need to execute dev in your app
pnpm run --filter @laffery/app dev
Copy the code
We don’t change package names very often, so we can change directory names this way.
Of course, we are handy and can configure all common commands in the root directory.
// ./package.json
{
// ...
"scripts": {
"app:dev": "pnpm run --filter @laffery/app dev"."app:build": "pnpm run --filter @laffery/app build"."app:deploy": "pnpm run --filter @laffery/app deploy"
}
// ...
}
Copy the code
All of our commands can now be executed in the root directory.
Batch Command Execution
If you want to filter multiple workspaces, you can filter the workspace.
Now you want to lint or test all packages, you can do so
// ./package.json
{
// ...
"scripts": {
"lint": "pnpm run --filter=\"@laffery/*\" lint"."test": "pnpm run --filter=\"@laffery/*\" test"
}
// ...
}
Copy the code
Then in your lot/workflows/ci yaml easily write down under
# .github/workflows/ci.yaml
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install
run: npm i -g pnpm && pnpm i
- name: ESlint
run: pnpm lint
- name: Tests
run: pnpm t
Copy the code
And you’re done!
Of course, there are some other features, such as the Universal Publish NPM package, which you can check out on the website.
Reuse the same repository under the code
Assume that app relies on [email protected] and [email protected], both of which rely on [email protected]. The general approach is to use the version on NPM directly. However, if you want to use [email protected] directly, which is currently in development, without publishing to NPM, it is difficult.
You cannot import XXX from “.. /.. / pacakge/pkc3 / XXX.”
This is where workspace comes in handy, and you can write dependencies to PKG1 like this
// packages/pkg1/package.json
{
"dependencies": {
"@laffery/pkg3": "The workspace: 1.5.1",}}Copy the code
Workspace: * is recommended when setting dependencies, so that the dependency version is the latest version in the workspace and you don’t need to manually update the dependency version every time.
You can see the documentation on the official website for more details.
VSCode Workspace
As a bonus, if you’re a big VSCode fan like me, consider creating a new xxx.code-workspace file in your root directory
// xxx.code-workspace
{
"folders": [{"path": "packages/pkg1"."name": "Package 1"
},
// ...
{
"path": "packages/app"."name": "Web Application"]}},Copy the code
The editor will pop up the “Open Workspace” button. Click “Start meeting” for more information.
conclusion
This article introduces some of the lessons you can learn from building monorepo projects based on PNPM
- Save disk space and speed up installation
- Convenient unified management, execution of test, build, release and other commands
- Reuse code from other packages under the repository
This post is posted on my personal blog, click here.
I’m @Laffery, a new front end on the road. If you like my article or find it useful, please like it or follow it or forward it.