返回顶部
本页目录

pnpm+Monorepo+rollup

初始化项目

                            
  • pnpm init

根目录下package.json添加

                            
  • {
  • "packageManager": "pnpm@7.5.2",
  • "private": true,
  • "workspaces": [
  • "packages/*"
  • ]
  • }

创建子包

                            
  • mkdir packages packages/compiler-sfc packages/shared

使用npm init初始化子包

                            
  • npm init -w ./packages/compiler-sfc
  • npm init -w ./packages/shared

目录结构为:

                            
  • .
  • +-- node_modules
  • | `-- compiler-sfc -> ../packages/compiler-sfc
  • | `-- shared -> ../shared
  • +-- package-lock.json
  • +-- package.json
  • `-- packages
  • +-- compiler-sfc
  • | `-- package.json
  • +-- shared
  • | `-- package.json

添加依赖

  • 指定包的依赖

    pnpm 可以通过-F 来选择不同的子包。语法:

                                
    • pnpm -F 子包名 add 需要下载的包名

    例:compiler-sfc添加@babel/parser

                                
    • pnpm -F compiler-sfc add @babel/parser -D
  • 共用的依赖

    根目录下存在`pnpm-workspace.yaml`文件

    在执行pnpm add xx时,需要添加-w,例:

                                
    • pnpm add -w typescript -D
    • 添加typescript

                                  
      • pnpm add typescript -D

      生成tsconfig.json

                                  
      • npx tsc --init
    • 添加rollup相关依赖

                                  
      • pnpm add rollup execa rollup-plugin-typescript2 @rollup/plugin-node-resolve @rollup/plugin-json -D

运行

脚本文件

通过mkdir scripts创建scripts文件夹,并创建build.js

                            
  • +-- scripts
  • | `-- build.js -> pnpm build

build.js

                            
  • import { readdirSync, statSync } from 'fs'
  • import { execa } from 'execa'
  • // 获取打包目录
  • const dirs = readdirSync('packages').filter(dir => statSync(`packages/${dir}`).isDirectory())
  • // 对获取的目录进行打包
  • buildAll()
  • async function buildAll() {
  • await runParallel(build).then(() => {
  • console.log('ok')
  • }).catch(e => {
  • console.log(e);
  • })
  • }
  • async function runParallel(fn) {
  • let result = []
  • for (const dir of dirs) {
  • result.push(fn(dir))
  • }
  • return Promise.all(result)
  • }
  • async function build(target) {
  • // 并行打包
  • await execa(
  • 'rollup',
  • [
  • '-c', //执行rollup的配置
  • '--environment', //环境变量
  • `TARGET:${target}`
  • ],
  • { stdio: 'inherit' } // 输出子进程的日志
  • )
  • }

rollup.config.js

                            
  • import { createRequire } from 'module';
  • import { fileURLToPath } from 'url';
  • import { basename, resolve } from 'path';
  • import json from '@rollup/plugin-json'
  • import nodeResolve from '@rollup/plugin-node-resolve'
  • import ts from 'rollup-plugin-typescript2'
  • const require = createRequire(import.meta.url)
  • // 根目录
  • const __dirname = fileURLToPath(new URL('.', import.meta.url))
  • // 子包的根目录
  • // build.js 中定义的`TARGET:${target}` 就是 process.env.TARGET
  • const packageDir = resolve(__dirname, `packages/${process.env.TARGET}`)
  • // 每个包的package.json
  • const pkg = require(resolve(packageDir, `package.json`))
  • // 自定义的`buildOptions`
  • const packageOptions = pkg.buildOptions || {}
  • const name = basename(process.env.TARGET)
  • const outputConfigs = {
  • 'esm-bundler': {
  • file: resolve(packageDir, `dist/${name}.esm-bundler.js`),
  • format: `es`
  • },
  • 'esm-browser': {
  • file: resolve(packageDir, `dist/${name}.esm-browser.js`),
  • format: `es`
  • },
  • cjs: {
  • file: resolve(packageDir, `dist/${name}.cjs.js`),
  • format: `cjs`
  • },
  • }
  • // 导出配置
  • function createConfig(format, output) {
  • output.name = packageOptions.name
  • // true的时候 会同时生成 xx.map 的文件
  • output.sourcemap = false
  • return {
  • // 入口
  • input: resolve(packageDir, `src/index.ts`),
  • output,
  • plugins: [
  • json(),
  • ts({
  • tsconfig: resolve(__dirname, 'tsconfig.json'),
  • }),
  • nodeResolve()
  • ]
  • }
  • }
  • export default packageOptions.formats.map(format => createConfig(format, outputConfigs[format]))

执行build

                            
  • pnpm build

packages/shared/dist中:

                            
  • +-- dist
  • | `-- shared.cjs.js
  • | `-- shared.cjs.js.map
  • | `-- shared.esm-bundler.js
  • | `-- shared.esm-bundler.js.map

packages/compiler-sfc/dist中:

                            
  • +-- dist
  • | `-- compiler-sfc.cjs.js
  • | `-- compiler-sfc.cjs.js.map
  • | `-- compiler-sfc.esm-browser.js
  • | `-- compiler-sfc.esm-browser.js.map

Using workspaces

tsconfig.json

                            
  • {
  • "compilerOptions": {
  • // 修改
  • "target": "ES2016",
  • "module": "ES6",
  • "sourceMap": true,
  • "moduleResolution": "node",
  • // 添加
  • "baseUrl": ".",
  • "paths": {
  • "@vue/*": ["packages/*/src"]
  • }
  • }
  • }

packages/compiler-sfc引入packages/shared

packages/compiler-sfc/src/index.ts

                            
  • import { e } from '@vue/shared'
  • let a = 1
  • let x = e
  • console.log(e)
  • export {
  • a,
  • x
  • }

packages/shared/src/index.ts

                            
  • let e = 4
  • export {
  • e
  • }

执行pnpm build,查看compiler-sfc.cjs.js

                            
  • 'use strict';
  • let e = 4;
  • let a = 1;
  • let x = e;
  • console.log(e);
  • exports.a = a;
  • exports.x = x;

新增子包

当项目运行了一段时间了,各个子项目相互依赖也都建好。这时候需要新增一个项目,这个项目该如何跟之前项目快速建立依赖关系呢?

根目录下的package.json:

                            
  • "dependencies": {
  • "@vue/compiler-sfc": "workspace:*",
  • "@vue/shared": "workspace:*"
  • // 新增一条
  • "@vue/reactivity": "workspace:*",
  • }

可以参见:新解析协议workspace:

然后运行:

                            
  • pnpm install