The concepts of Menorepo will not be covered in this article. For why PNPM is used as a package manager instead of NPM or YARN, see PNPM: State-of-the-art Package Manager
Let’s build menorepo with PNPM and see if PNPM can do it.
Project initialization
Install PNPM and create the project
NPX PNPM add -g PNPM // install PNPM mkdir menorepo CD menorepo NPM init -yCopy the code
Create the workspace
Create a new pnpm-workshop. yaml file in the project root directory to create the workspace. This is the core step to create and manage the MenorePO
Packages: # all packages in the packages subdirectory - 'packages/**' # not in the test folder package - '! **/test/**'Copy the code
Our future projects will be built under the Packages directory.
Create a subproject
Create two new subprojects under package, core and utils,
TSC --init // create tscconfig.json touch index.ts // create index.tsCopy the code
The directory structure is as follows:
. ├ ─ ─ package. Json ├ ─ ─ packages │ ├ ─ ─ the core │ │ ├ ─ ─ but ts │ │ ├ ─ ─ package. The json │ └ ─ ─ tsconfig. Json │ └ ─ ─ utils │ ├ ─ ─ ├─ ├─ ├─ pnpm-workshop.txt TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXTCopy the code
Change the names of the two packages to core and utils, respectively
/ / packages/core {" name ":" the core ", "version" : "1.0.0", "description" : ""," main ":" index. Ts "and" author ":" ", "license" : "MIT", "dependencies" : {}} / / packages/utils {" name ":" utils ", "version" : "1.0.0", "description" : ""," main ": "index.ts", "author": "", "license": "MIT", "dependencies": {}}Copy the code
All subsequent operations use the name field to distinguish between subitems, so the value of this field must be unique and non-repeatable.
Install dependencies
Declare a function that prints logs in utils and reference it in the Core project
/ / packages/core {" name ":" the core ", "version" : "1.0.0", "description" : ""," main ":" index. Ts "and" author ":" ", "license" : "MIT", "dependencies" : {}} / / packages/utils {" name ":" utils ", "version" : "1.0.0", "description" : ""," main ": "index.ts", "author": "", "license": "MIT", "dependencies": {} }Copy the code
Subprojects depend on installation
PNPM add npmlog --filter utils // --filter specifies which subproject to applyCopy the code
You can specify a specific subproject by using –filter whenever you install dependencies for subprojects separately
–filter can take multiple project names, separated by Spaces
Globally dependent installation
// Install the node declaration file, -w means install in the global workspace, so that all packages can share this file PNPM add @types/node -wdCopy the code
-wd is short for -w -d, which means installed in devDependencies
Link local library files
PNPM add utils --filter coreCopy the code
You’ll see the new dependencies in the package.json file of core
/ / packages/core/package. Json "dependencies" : {" utils ":" the workspace: ^ 1.0.0 "}Copy the code
Utils is referenced in core
// core/index.ts import { log } from 'utils' const core = () => { log.info('test', 'Hello world! ') } core() export default coreCopy the code
Run ts-node index.ts in the core directory to view the result
Configuring Startup Commands
Add the start command to the subproject
Modify core/package.json to add start command
// packages/core/package.json
"scripts": {
"start": "ts-node index.ts",
},
Copy the code
Ts-node and typescript are installed globally on my computer, so you can use the ts-node command directly. You can do this if you don’t have it installed locally, or if you want to install dependencies in your current project
PNPM add ts-node typescript -wd // modify the startup command "scripts": {"start": "node_modules/ts-node/dist/bin.js index.ts", },Copy the code
Switch to the Packages/Core directory and run NPM run start to see the printed results
Add a startup command to the root directory
If you want to run core projects in the root directory, modify package.json in the root directory
// package.json
"scripts": {
"dev:core": "pnpm start --filter \"core\"",
},
Copy the code
Switch to the root directory and run dev:core to see the printed result
Add the bin shortcut command
If we also want to run core projects in other subproject directories using our own custom commands, we need to add the bin command, modify the core/package.json file, and add demo-cli custom commands
/ / packages/core/package. Json "name" : "the core", "version" : "1.0.0", "description" : ""," main ":" index. Ts "and" bin ": { "demo-cli": "bin/index.ts" }, "scripts": { "start": "node_modules/ts-node/dist/bin.js index.ts", },Copy the code
Add the bin folder in the core directory and create an index.ts file in the folder
#! /usr/bin/env ts-node import core from '.. /index' core()Copy the code
Since we are currently executing ts files directly, we need to set the bin executable environment to TS-Node instead of Node
The core project directory structure is as follows
. ├ ─ ─ bin │ └ ─ ─ but ts ├ ─ ─ but ts ├ ─ ─ node_modules ├ ─ ─ package. The json └ ─ ─ tsconfig. JsonCopy the code
Link library file
Switch to core and execute
PNPM link -g // Link the core library globallyCopy the code
At this point, we execute in another directory, such as utils
demo-cli
Copy the code
It also prints the results correctly
Cancel link
If you want to unlink, go to which demo-cli to see the file path of the link command
which demo-cli
Copy the code
\
Go to the corresponding bin directory to delete the demo-cli file.
Here, in fact, we can be happy to use TS to write and develop their own libraries, and local multiple libraries can also reference each other, convenient joint test; Different libraries can also share the same dependencies, avoiding the hassle of having to install them repeatedly.
packaging
If we finally want to publish our library to NPM for others to download, we also need to package ts files into JS files. Here we use rollup to do this. Let’s take core as an example.
Install dependencies
pnpm add tslib @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript rollup-plugin-clear -WD
Copy the code
Rollup has been installed globally on my computer. If not, please install it yourself
Configure a rollup
Create the rollup.config.js file in the core directory with the following contents
import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; import typescript from "@rollup/plugin-typescript"; import clear from 'rollup-plugin-clear' import pkg from "./package.json"; export default [ // browser-friendly UMD build { input: "index.ts", output: { name: "@js/core", file: pkg.browser, format: "umd", }, plugins: [ clear({ targets: ['dist'], watch: true, }), resolve(), commonjs(), typescript({ tsconfig: "./tsconfig.json" }), ], }, // CommonJS (for Node) and ES module (for bundlers) build. // (We could have three entries in the configuration array // instead of two, but it's quicker to generate multiple // builds from a single configuration where possible, using // an array for the `output` option, where we can specify // `file` and `format` for each target) { input: "index.ts", output: [ { file: pkg.main, format: "cjs", exports: "auto" }, { file: pkg.module, format: "es" }, ], plugins: [typescript({ tsconfig: "./tsconfig.json" })], }, ];Copy the code
Modify the core/tsconfig.json file
"outDir": "dist",
"module": "esnext",
Copy the code
Modify the core/package.json file
"main": "dist/index.js",
"module": "dist/index.esm.js",
"browser": "dist/index.umd.js",
"files": [
"dist"
],
"bin": {
"demo-cli": "bin/index.js"
},
"scripts": {
"start": "node_modules/ts-node/dist/bin.js index.ts",
"build": "rollup -c",
"test": "echo \"Error: no test specified\" && exit 1"
},
Copy the code
Core /bin/index.ts to core/bin/index.js and modify the contents inside
#! /usr/bin/env node require('.. /dist')()Copy the code
Quick transformation of utils project with JS-CLI
This is the end of the Core project. In order to reduce the amount of work you need to do in the Utils project, you can download the Rollup-typescript template directly through the JS-CLI scaffolding I developed
// Install scaffolding npx@js -cli/core // switch to utils directory js-cli init // select template project -> rollup-typescript templateCopy the code
Reinstall dependencies
pnpm add @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript rollup-plugin-clear tslib -WD
pnpm add npmlog --filter utils
pnpm add @types/npmlog --filter utils -D
Copy the code
Copy the previous code into the utils/ SRC /index.ts file
import log from 'npmlog'
log.level = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : 'info'
log.heading = 'js-cli'
log.addLevel('success', 2000, {fg: 'green', bold: true})
export { log }
Copy the code
Run the package command
npm run build
Copy the code
Switch to the core directory and run the package command
npm run build
Copy the code
To link
pnpm link -g
Copy the code
View the results
Both projects are now packaged and ready to run successfully.
release
Since core project depends on utils project, I choose to publish utils project first and change version in package.json file (the specific version is up to you).
Switch to the Packages /utils directory and execute the publish command
// packages/utilsnpm loginnpm publish
Copy the code
After publishing utils, since we referenced utils in core via workspace, we need to manually change the dependency to the corresponding online version of utils before publishing core project:
"Dependencies" : {" utils ":" the workspace: ^ 1.0.0 "}, into a "dependencies" : {" utils ":" ^ 1.0.0 "},Copy the code
And then release core
conclusion
Here, we found that the PNPM basic can meet the needs of our daily development, but at the time of release, PNPM would be a little helpless, we need to manually upgrade dependent version, update package, when the number of library management is little also, once the project, the need to manage the library more, still rely on manual to a a contract, Is obviously a hard thing to accept; In addition, we at the time of packaging, also need to switch to the corresponding directory alone package, of course, we can put all the components in root directory of the packaged commands are added, but it’s still not enough flexible, such as we just changed one of the library, so we only need to rely on other programs the library package line, Instead of everything being packaged.
In view of the above problems we encountered in the development process, the author found that Rush can solve the above problems well through research. The specific solutions will be introduced in the next article.
Js – CLI scaffolding source code