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(),// 先解析tsts({  // ts插件tsconfig : path.resolve(__dirname,'tsconfig.json')}),// 再解析第三方nodeResolve()  // 解析第三方模块]}
}
// rollup 最终需要导出配置
export default options.formats.map(item=>{// 调用打包方法// 这块如果没有写在一行  需要加returnreturn  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"]}

Vue3源码分析之打包原理相关推荐

  1. vue3源码分析——实现slots

    引言 <<往期回顾>> vue3源码分析--rollup打包monorepo vue3源码分析--实现组件的挂载流程 vue3源码分析--实现props,emit,事件处理等 ...

  2. 手撸spring源码分析IOC实现原理

    手撸spring源码分析IOC实现原理 文章出处:https://github.com/fuzhengwei/small-spring 根据小付哥的手撸spring核心源码一步步学习出来的结果收货总结 ...

  3. cocos源码分析--SpriteBatchNode绘图原理(转--侵删)

    cocos源码分析–SpriteBatchNode绘图原理 https://www.cnblogs.com/xiaonanxia/p/9199737.html

  4. vue3源码分析——看看complier是怎么来解析的

    引言 <<往期回顾>> vue3源码分析--手写diff算法 vue3源码分析--实现组件更新 vue3源码分析--解密nextTick的实现 想知道vue3-complier ...

  5. Dubbo 源码分析 - 自适应拓展原理

    1.原理 我在上一篇文章中分析了 Dubbo 的 SPI 机制,Dubbo SPI 是 Dubbo 框架的核心.Dubbo 中的很多拓展都是通过 SPI 机制进行加载的,比如 Protocol.Clu ...

  6. [Vue源码分析]自定义事件原理及事件总线的实现

    最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: 我们都知道Vue中父组件可以通过 props 向下传数据给子组件:子组件可以通过向$emit触发一个事件,在父组件中执行回调函数,从而实 ...

  7. [Vue源码分析] v-model实现原理

    最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: 我们都知道使用v-model可以实现数据的双向绑定,及实现数据的变化驱动dom的更新,dom的更新影响数据的变化.那么v-model是怎 ...

  8. vue3源码分析--真的有必要掌握框架的细枝末节吗?

    古人云:工欲善其事必先利其器,磨刀不误砍柴工.但是砍柴的人需要知道怎么制作刀吗? 注意:本文先分析要不要学源码,然后分析要不要掌握源码的每一个细枝末节(深究技术)!!! 为什么要学源码 为了面试被迫学 ...

  9. Springmvc源码分析、底层原理

    1.Springmvc是如何找到Controller的? 首先在请求过来时,会先进入DispatcherServlet进行请求分发,执行DispatcherServlet类中的doDispatch() ...

最新文章

  1. Line上半年扭亏为盈 用户及营收遇瓶颈
  2. Android之自定义view引用xml,Android自定义View在XML中映射错误
  3. C++笔记(2017/2/9)
  4. 【数论】YY的GCD(P2257)
  5. ELK入门01—Elasticsearch安装
  6. [转]Oracle销售人员普遍腐败?
  7. LVS负载均衡群集-NAT
  8. ghost 开发主题
  9. Python春节特训营03:打倒拦路虎,学会键盘打字
  10. android timepicker分割线颜色,Android TimePicker 的使用
  11. 51单片机入门(第二讲)
  12. linux开启443端口
  13. 二叉树no与n2关系数学证明
  14. CAN发送和接收数据(回环测试,ok)
  15. NR PRACH(五) type1 RA(4-step)基本过程
  16. 性能测试的实施及总结(二)
  17. BOSE QC35 蓝牙卡顿,断断续续问题
  18. [bootstrap]如何使用modal
  19. Invoke 和 BeginInvoke 的真正涵义
  20. 领域驱动设计 -- 领域驱动建模与面向对象建模的差异(一)

热门文章

  1. idea打开maven项目时,部分jar包报红问题
  2. 下颌骨锥形束计算机断层扫描的英文缩写,山东地区人下颌后牙C形根管的锥形束CT研究...
  3. L1-044 稳赢(15分) java
  4. sp_depends
  5. 基于Python的小游戏
  6. 前端js+canvas实现雷达扫描效果
  7. 木瓜移动:从KOL到内容营销,出海品牌如何争夺流量新战场
  8. 二进制代码保护和混淆
  9. 049_jQuery 操作标签
  10. PS中“曲线”【ctrl+M】的作用【加强对曲线的使用】