An overview of
Monorepo (monolithic Repository) is a project architecture that, in simple terms, consists of multiple development projects (modules, packages) in a single repository. For front-end projects: VUE3, Element all adopt this architectural pattern. Next, focus on the following points to expand:
- Common forms of monorepo
- Advantages and disadvantages of Monorepo
- A simple implementation of Monorepo (rollup implementation). The code address
Common forms of monorepo
This is the source directory structure for Element (vue2 version) and VUe3. Both projects have packages directories. For Element each module is a component. Vue3 splits its modules into packages and each module is a project (you’ll find package.json files under each module).
Advantages and disadvantages of Monorepo
For the advantages and development history of Monorepo, you can refer to the advantages of Monorepo. To sum up:
- Separate modules for easy management (For Element, you only need to modify the Form directory under Packages)
- Clear structure (after the module is independent, the structure is naturally clear)
- The disadvantage is that the repository code volume may be relatively large (a repository contains multiple projects, more projects, the volume will naturally be large)
Simple implementation of Monorepo
Having covered some of the basics, it’s time to implement a MonorePO using the common packaging tools (Webpack, rollup) and feel the benefits. Implementing a MonorePO requires some attention:
- The package management tool must use YARN (for reasons described below)
- Dev and Build implementations
- Module to module communication
Project introduction
Next, let’s simulate Vue3. Use the rollup + ts. Build two modules: Reactive and shared. The directory structure is as follows
. ├ ─ ─ the README. Md ├ ─ ─ package. The json ├ ─ ─ scripts | ├ ─ ─ build. Js | └ ─ ─ dev. Js └ ─ ─ packges ├ ─ ─ reactivity │ └ ─ ─ the SRC | └ ─ ─ └── └─ package. 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
Packages configuration for the total project
{" private ":" true ", "name" : "monorepo - stu", "version" : "1.0.0", "main" : "index. Js", "license" : "MIT", "workspaces" : [ "packages/*" ] }Copy the code
Workspaces are configured for packages/*. When yarn install is used, yarn will soft connect all packages of the package to node_modules, so that modules communicate with each other. A common module is usually set up, with some public methods in the package and others in separate packages
Submodule Packages configuration
{" name ", "reactivity", and "version" : "1.0.0", "main" : "index. Js", "license" : "MIT", "buildOptions" : {// Expose the name of the global variable "name": "Reactivity", // Wrap type "formats": [" CJS ", "ESM-bundler ", "global"]}}Copy the code
BuildOptions is our custom packaging configuration, and name is the name of the exposed global variable. Formats are the packaging type:
- CJS == commonJS (Module.exports)
- esm-bundler ==> (import)
- Global ==> (iife immediately executes the function, exposing global variables)
Build.js package script implementation
Build.js reads modules under Packages, generates rollup execution commands, and packages (dependent on execa) all modules in parallel.
- Read Packages for all modules
- Iterate over the module and package in parallel
Const fs = require('fs') const path = require('path') Execa = require('execa') const execa = require('execa') Const targets = fs.readdirsync (path.resolve(process.cwd(), './packages').filter(f => fs.statsync (' packages/${f} ').isdirectory ()) Async function build (target) {// rollup-c -environment target :shared await execa('rollup', ['-c', '--environment' ,`TARGET:${target}`], {stdio: 'inherit'} function runParallel(targets, iteratorFn) { const res = [] for(const item of targets) { const p = iteratorFn(item) res.push(p) } return Promise.all(res) } runParallel(targets, build)Copy the code
Build. js executes the following command:
- rollup -c –environment TARGET:reactivity
- rollup -c –environment TARGET:shared
Dev.js package script implementation
// Must use version 5.1.1 or below, Execa = require('execa') // specific package name const target = 'reactivity' build(target) // Async function build (target) {// rhup-cW-environment target :shared compile execa('rollup', ['-cw', '--environment', 'TARGET:${TARGET}'], {stdio: 'inherit'}Copy the code
Dev.js is much more convenient than build.js. The command is changed from rollup -c –environment TARGET:shared to rollup -cw –environment TARGET:shared to enable continuous packing
rollup.config.js
The purpose of this file is to generate the corresponding rollup packaging configuration based on the environment variables of the command that we executed in the previous step.
Import ts from 'rollup-plugin-typescript2' import {nodeResolve} from '@rollup/plugin-node-resolve' // import {nodeResolve} from '@rollup/plugin-node-resolve' // Import path from 'path' // parse json, Package. json import json from '@rollup/plugin-json' // import serve from 'rollup-plugin-serve' const packagesDir Resolve (__dirname, 'packages') const packageDir = path.resolve(packagesDir, 'packages') Process.env.target) // // according to the packages benchmark directory, Path const resolve = (p) => path.resolve(packageDir, P) const PKG = require(resolve('package.json')) const name = path.basename(packageDir) Const outputConfig = {'esm-bundler': {file: resolve(' dist/${name}.esm-bundler.js'), format: 'es' // esm }, 'cjs': { file: resolve(`dist/${name}.cjs.js`), format: 'cjs' // commonjs }, 'global': { file: resolve(`dist/${name}.global.js`), format: }} // Get buildOptions in package, Const options = pkG.buildOptions function createConfig(format, Output) {output.name = options.name output.sourcemap = true // generate rollup configuration return {input: resolve('src/index.ts'), output, plugins: [ json(), ts({ tsconfig: Path.resolve (__dirname, 'tsconfig.json')}), nodeResolve({// resolve third-party extensions: ['.js', '.ts']}),]}} // Export default options. Formats. Map (format => createConfig(format, outputConfig[format]))Copy the code