Vue3源码分析之打包原理

Vue3源码分析之打包原理

如果之前你已经看过我的《Vue3源码分析之入门》,那么你可以直接阅读此篇文章

Vue3源码分析之入门

一、配置环境

1. 全局安装yarn

Monorepo 管理项目中多个包是依赖yarn的

$ npm install yarn -g

2. 初始化项目

新建文件夹,如:mycore,进入新建的文件夹,并运行如下命令,进行项目初始化,生成package.json文件

$ yarn init -y

在这里插入图片描述

3. 配置项目的package.json

{
  "private":true,  // 因为是一个项目管理多个包,所以将项目设置为私有的
  "workspaces":[
    "packages/*"  // 指定工作目录: 指定该项目下的所有的包都放在 packages下的文件夹
  ],  
  "name": "myCore",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT"
}

4. 在根目录中新建包管理文件夹packages,并新建子文件夹包reactivity和share文件夹

  • 重复步骤2,初始化reactivity和share包
  • 新建src/index.ts 入口文件
    在这里插入图片描述
  • 配置reactivity和share包的package.json
{
   // 表示vue里面的包   就可以如此使用该包  import reactivity from '@vue/reactivity'
  "name": "@vue/reactivity",  
  "version": "1.0.0",
  "license": "MIT",
  // node  commonJS引入的入口
  "main": "index.js",  
  // ES6 或者webpack引入的入口  会默认查找module
  "module": "dist/reactivity.esm-bundler.js",
  // 自定义打包配置
  "buildOptions" : {
    // 打包后的名称
    "name" : "VueReactivity",
    // 表示:当前模块/包  可以构建成CommonJS、ES6、全局  模块
    "formats" : [
      "cjs", // commonJS
      "esm-bundler",
      "global"     // shared包里面,是不需要声明可以构建全局的
    ]
  }
}

5. 安装依赖包

安装依赖一定要使用yarn

yarn add typescript rollup rollup-plugin-typescript2 @rollup/plugin-node-resolve @rollup/plugin-json execa 

此时会报如下错误

在这里插入图片描述

表示 需要添加声明:声明当前依赖包是给根目录的package.json安装的

yarn add typescript rollup rollup-plugin-typescript2 @rollup/plugin-node-resolve @rollup/plugin-json execa --ignore-workspace-root-check

6. 在根目录下package.json,配置打包脚本

  • 新建scripts文件夹,并新建dev.js,build.js
    在这里插入图片描述
  • 在根目录下package.json,配置打包脚本
{
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  // 使用脚本配置打包命令
  "scripts": {
    "dev" : "node scripts/dev.js",   // 使用node执行当前项目下的scripts的dev.js
    "build" : "node scripts/build.js"
  },
  "name": "mysore",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "@rollup/plugin-json": "^4.1.0",
    "@rollup/plugin-node-resolve": "^13.3.0",
    "execa": "^6.1.0",
    "rollup": "^2.72.0",
    "rollup-plugin-typescript2": "^0.31.2",
    "typescript": "^4.6.4"
  }
}

二、build.js

这个文件的作用是:把packages目录下的所有包 都进行打包 ,具体配置如下

1.build.js配置

// 把packages目录下的所有包  进行打包

// 1、获取packages目录下的所有包
const fs = require('fs');
const execa = require('execa')   // 开启子进程,使用rollup进行打包
// 同步读取packages目录下的内容
// 返回一个数组,默认会读取packages下的所有文件夹和文件
// 这里过滤掉文件
const targets = fs.readdirSync('packages').filter(f=>{
    // 返回目录
    return fs.statSync(`packages/${f}`).isDirectory()
})

// 2、对所获取的包目录,进行并行依次打包

// 打包的构建方式
// 打包是异步的
async function build(target) {
    // 参数一:执行的打包命令
    // 参数二:执行的打包参数
        // '-c'  表示采用某个配置文件
        // --environment 声明采用环境变量
        // `TARGET:${target}`  传的具体环境变量   可以在rollup.config.js文件中通过process.env.TARGET访问到环境变量target
    // 参数三: 子进程打包的信息共享给父进程
     await execa(
        'rollup',
        ['-c','--environment',`TARGET:${target}`],
        {stdio:'inherit'}
    )
}

// 轮循目录,依次打包
function runParallel(targets,iteratorFn) {
    let res = [];
    for(const item of targets) {
        // 打包每一个目录包
        // const p = await iteratorFn(item)   注意:这里不能加await  否则会变成同步打包,而不是并行打包
        const p = iteratorFn(item)  // 并行打包
        res.push(p)
    }
    return Promise.all(res)
}

// 调用
runParallel(targets,build)

3. 运行bug解决

此时,使用yarn run build 进行打包会出现以下错误:
在这里插入图片描述

解决如下

  • 在根package.json中添加type为module的配置
{
  ...
  "type": "module",
   ...
}
  • 更改包的导入方式
import fs from 'fs';
import {execa} from 'execa'
...

三、rollup配置

在根目录下,创建rollup.config.js,并进行如下配置

// rollup配置
import path from 'path'
import json from '@rollup/plugin-json';
import nodeResolve from '@rollup/plugin-node-resolve';
import ts from 'rollup-plugin-typescript2'
// 根据环境变量中的TARGET属性,获取对应模块的package.json
// 获取包的绝对路径
const packagesDir = path.resolve(__dirname,'packages');

// 获取要打包的目录
// console.log(process.env.TARGET,'cc')
const packageDir = path.resolve(packagesDir,process.env.TARGET)

// 针对某个模块 拼接路径
const resolve = (p) => path.resolve(packageDir,p)

// 获取当前被打包的package.json
const pkg = require(resolve('package.json'));

// 获取文件名
const name = path.basename(packageDir)
// 对打包类型 做映射表 ,根据提供的formats,格式化需要打包的内容
// 自定义配置
const outputConfig = {
    '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'  // 立即执行函数
    },
}

// 获取包的package.json 的 自定义选项buildOptions
const options = pkg.buildOptions;

// 打包
function createConfig(formatItem,outputItem) {
    // 给outputConfig 每一项添加参数
    outputItem.name = options.name;
    outputItem.sourcemap = true;  // 生成sourcemap

    // 生成rollup配置
    return {
        input : resolve('src/index.ts'), // 入口
        output : outputItem,  // 出口
        plugins : [
            json(),
            // 先解析ts
            ts({  // ts插件
                tsconfig : path.resolve(__dirname,'tsconfig.json')
            }),
            // 再解析第三方
            nodeResolve()  // 解析第三方模块
        ]
    }
}
// rollup 最终需要导出配置
export default options.formats.map(item=>{
    // 调用打包方法
    // 这块如果没有写在一行  需要加return
    return  createConfig(item,outputConfig[item])
})

四、配置tsconfig.json

初始化ts配置文件 npx tsc --init

将打包和模块配置成ESNEXT

"target": "ESNEXT",  // 打包
"module": "ESNEXT",  // 模块

五、使用yarn run build打包

打包成功后的截图如下:

在这里插入图片描述

六、dev.js

// 只针对某个具体的包进行打包
// 把packages目录下的所有包  进行打包
// 1、获取packages目录下的所有包
import fs from 'fs';
import {execa} from 'execa'   // 开启子进程,使用rollup进行打包
const target = 'reactivity'
// 2、对所获取的包目录,进行并行依次打包
// 打包的构建方式
// 打包是异步的
async function build(target) {
    // 参数一:执行的打包命令
    // 参数二:执行的打包参数
        // '-cw'  监听文件变化  
        // --environment 声明采用环境变量
        // `TARGET:${target}`  传的具体环境变量   可以在rollup.config.js文件中通过process.env.TARGET访问到环境变量target
    // 参数三: 子进程打包的信息共享给父进程
     await execa(
        'rollup',
        ['-cw','--environment',`TARGET:${target}`],
        {stdio:'inherit'}
    )
}
build(target)

七、packages目录下子包的互相引入

比如在reactivity中引入shared

import { share } from "@vue/share"

此时会报错,需要我们在tsconfig.json中,进行如下配置

"moduleResolution":"Node",
 "baseUrl": ".",
 "paths": {
   "@vue/*": [
     "packages/*/src"
   ]
 }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

原谅我很悲

不要打赏哦,加个好友一起学习呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值