Build monorepo

Implementation of ES6 syntax, TS, project specific compilation, as much as possible to restore vue3 to the building of multiple modules.

Yarn Installation project dependency

Vue3 uses Menorepo. Currently, only YARN supports vuE3

yarn init -y
yarn add typescript rollup rollup-plugin-typescript2 @rollup/plugin-node-resolve @rollup/plugin-json execa -D
# execa: Package multiple projects at the same time. It is a child of Node
# P.S. -- ignore-workspace-root-check install the root module instead of the submodules
Copy the code
Rely on
typescript Support the typescript
rollup Packaging tools
rollup-plugin-typescript2 Bridge between Rollup and TS
@rollup/plugin-node-resolve Parse a third-party Node module
@rollup/plugin-json Support for importing JSON
execa Start a subprocess to facilitate command execution

The directory structure

├ ─ ─ package. Json# Configure the run command├ ─ ─ packages# n '│ ├ ─ ─ reactivity# Responsive systems│ │ ├ ─ ─ dist │ │ ├ ─ ─ package. The json │ │ └ ─ ─ the SRC │ ├ ─ ─ the runtime - core# platform-independent runtime core│ │ └ ─ ─ dist │ ├ ─ ─ the runtime - dom │ │ └ ─ ─ dist │ └ ─ ─ Shared │ ├ ─ ─ dist │ ├ ─ ─ package. The json │ └ ─ ─ the SRC ├ ─ ─ a rollup. Config. Js# rollup configuration file├ ─ ─ scriptsPackage command│ ├─ ├─ ├─ ├─ ├.txtCopy the code

The rootpackage.json

Purpose: Maintains multiple packages in the Packages /* directory

  • private:true: indicates a private package
  • Specify workspace:workspace:["packages/*"], all packages are managed under the Packages directory
  • performyarn installWhen will bepackages/*Generate soft links to node_modules, so that any current module can import other modules, that is, multiple packages can reference each other
  • A package can depend on another package:Yarn workspace @vue/reactivity add @vue/[email protected]
{+"private": true,
+  "workspaces": [+"packages/*"+],"name": "crx-vue3-core-code"."version": "1.0.0"."main": "index.js"."license": "MIT"."devDependencies": {
    "@rollup/plugin-json": "^ 4.1.0." "."@rollup/plugin-node-resolve": "^ 13.0.0"."execa": "^ 5.1.1." "."rollup": "^ 2.52.3"."rollup-plugin-typescript2": "^ 0.30.0"."typescript": "^ 4.3.4." "}}Copy the code

The childpackage.json

Each submodule needs to follow a certain mechanism:

packages/reactivity/package.json

"name": "@vue/reactivity"."main": "index.js".// node commonjs
"module": "dist/reactivity.esm-bundle.js".// import '@vue/reactivity' --> dist/reactivity.esm-bundle.js
"buildOptions": {"name":"VueReactivity". The VueReactivity variable can be used after introduction
  // Configure the current module to support Node, ES6, and global modules
  "formats": ["cjs"."esm-bundler"."global"]}Copy the code

packages/reactivity/package.json

{
  "name": "@vue/shared"."version": "1.0.0"."description": ""."main": "index.js"."module": "dist/shared.esm-bundle.js"."buildOptions": {"name":"VueShared"."formats": ["cjs"."esm-bundler"]},"scripts": {},
  "keywords": []."author": ""."license": "ISC"
}
Copy the code

Compile scripts, rollup, TS configuration

package.json

  "scripts": {
    "dev": "node scripts/dev.js"."build": "node scripts/build.js"
  }
Copy the code
  • dev.jsPackage only for specific purposes: pass the target environment variable to rollup, generate the rollup configuration, and ignore files based on the type of package that follows
  • build.jspackagingpackageAll packages in the directory

scripts/build.js

const fs = require("fs");
const execa = require("execa"); // Enable child packaging, and finally use rollup for packaging

// Filter files under packages directory, keep folders
const targets = fs.readdirSync("packages").filter((f) = > {
  if(! fs.statSync(`packages/${f}`).isDirectory()) {
    return false;
  }
  return true;
});

// Package the targets sequentially and in parallel
async function build(target) {
  // rollup -c --environment TARGET:shated
  await execa("rollup"["-c"."--environment".`TARGET:${target}`] and {stdio: "inherit"});// The information packed by the child is shared with the parent
}

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

scripts/dev.js

const execa = require("execa");
const target = "reactivity";
build(target);
async function build(target) {
  await execa("rollup"["-cw"."--environment".`TARGET:${target}`] and {stdio: "inherit"}); }Copy the code

rollup.config.js

import path from "path";
import json from "@rollup/plugin-json";
import resolvePlugin from "@rollup/plugin-node-resolve";
import ts from "rollup-plugin-typescript2";

// 1. Obtain pakcage.json from the corresponding module according to the target attribute in the environment variable
const packagesDir = path.resolve(__dirname, "packages");
const packageDir = path.resolve(packagesDir, process.env.TARGET); // packageDir finds a package to pack/the base directory to pack
const resolve = (p) = > path.resolve(packageDir, p);
const pkg = require(resolve("package.json"));
const name = path.basename(packageDir); // Take the filename or process.env.target

// For the mapping table of the packaging type, format the content to be packaged according to the provided formats
const outputConfig = {
  // Custom
  "esm-bundler": {
    file: resolve(`dist/${name}.esm-bundler.js`),
    format: "es",},cjs: {
    file: resolve(`dist/${name}.cjs.js`),
    format: "cjs",},global: {
    file: resolve(`dist/${name}.global.js`),
    format: "iife".// Execute the function immediately}};const options = pkg.buildOptions;

// Generate the rollup configuration
function createConfig(format, output) {
  output.name = options.name;
  output.sourcemap = true; / / generated sourcemap

  return {
    input: resolve(`src/index.ts`),
    output,
    plugins: [
      json(),
      ts({
        / / ts plug-in
        tsconfig: path.resolve(__dirname, "tsconfig.json"),
      }),
      resolvePlugin(), // Parse third-party module plug-ins]}; }// rollup ultimately requires the outgoing configuration
export default options.formats.map((format) = >
  createConfig(format, outputConfig[format])
);

Copy the code

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNEXT"."module": "ESNEXT"."strict": false."esModuleInterop": true."skipLibCheck": true."forceConsistentCasingInFileNames": true."moduleResolution": "node"."baseUrl": "."."paths": {
      "@vue/*": ["packages/*/src"]}}}Copy the code

github