pnpm 搭建Monorepo模式管理项目

596 阅读2分钟

搭建Monorepo项目

pnpm workspace实现项目搭建,pnpm是快速、节省磁盘空间的包管理器。主要采用符号链接的方式管理模块

全局安装pnpm

// 全局安装pnpm
npm install pnpm -g
// 初始化配置文件
pnpm init -y(已无效,执行npm init -y)

根目录下创建packages文件夹

根目录下创建pnpm-workspace.yaml

内容中的packages对应刚创建的文件夹名字,代表所有的包都在此文件夹packages下。 内容:

packages:
- 'packages/*'

全局安装vue

执行pnpm install vue -w

-w的意思是:workspace-root(工作目录的根路径下) 根目录下会生成node_modules

安装.png

根目录下创建.npmrc文件

第三方依赖一也有依赖,要是项目中使用了,第三方的依赖,要是哪天第三方卸载了,那就找不到了,称之为“幽灵依赖” 所以:羞耻提升,暴露到外层中,即是在node_modules下,而非在.pnpm文件夹中。 内容:

shamefully-hoist = true

安装typescript、minimist、esbuild

pnpm install typescript minimist esbuild -w -D

packages文件夹下创建reactivity跟shared文件夹

packages_reactivity_shared.png

初始化reactivity项目的package.json

初始化reactivity.png

初始化reactivity_package.json.png

添加buildOptions配置

  "buildOptions": {
    "name": "VueReactivity",
    "formats": [
      "global",
      "cjs",
      "esm-bundler"
    ]
  },

添加配置buildOptions.png

同理,shared项目

shared中不需要配置buildOptions.formats: global,因为几乎不会使用script标签来引入该项目,并且使用其中的某个子功能方法的情况。 image.png

1shared配置.png

reactivity跟shared项目下创建src目录,并创建index.ts

2创建文件.png

3.png 试验,manage路径下执行

pnpm uninstall vue

把manage中的node_modules删除,执行完删除vue的指令后,vscode其实还是看得到vue的东西还在node_modules中,这是因为缓存,vscode点击刷新一下文件就看不到vue相关了

4.png 所以需要将reactivity跟shared关联起来。

初始化ts配置文件ts.config.json

执行:

 tsc --init

ts.config.json 内容:

{
  "compilerOptions": {
   "outDir":"dist", // 输出的目录
   "sourceMap": true, //采用sourcemap 
   "target": "es2016", // 目标语法
   "module": "esnext", // 模块格式
   "moduleResolution": "node", // 模块解析
   "strict": false, // 严格模式
   "resolveJsonModule": true, // 解析json模块
   "esModuleInterop": true,// 允许通过es6语法引入commonjs模块
   "jsx":"preserve",// jsx不转义
   "lib":["esnext","dom"],// 支持的类库esnext及dom
   "baseUrl": ".",// 当前是以该路径进行查找
   "paths":{
     "@vue/*":["packages/*/src"], // 即以@vue开头的都去该路径下查找,是个数组
   }
  }
}

创建scripts/dev.js

const args = require("minimist")(process.argv.slice(2)); // node scripts/dev.js reactivity -f global
const { build } = require("esbuild");
// node 中的内置模块
const { resolve } = require("path");
// minist 用来解析命令参数
const target = args._[0] || "reactivity";
const format = args.f || "global";
// 开发环境只打包某一个
const pkg = require(resolve(__dirname, `../packages/${target}/package.json`));
// iife 立即执行函数(function(){})()
// cjs node中的模块 module.exports
// esm 浏览器中的esModule模块 import
const outpuFormat = format.startsWith("global")
  ? "iife"
  : format === "cjs"
  ? "cjs"
  : "esm";
//
const outfile = resolve(
  __dirname,
  `../packages/${target}/dist/${target}.${format}.js`
);
build({
    entryPoints:[resolve(__dirname,`../packages/${target}/src/index.ts`)],
    outfile,
    bundle:true,
    sourcemap:true,
    format:outpuFormat,
    globalName:pkg.buildOptions?.name,
    platform:format==='cjs'?'node':'browser',
    watch:{
        onRebuild(error){
            if(!error){
                console.log(`rebuild~~~`)
            }
        }
    }
}).then(() => {
    console.log('watching~~~')
})