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(),// 先解析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源码分析之打包原理相关推荐
- vue3源码分析——实现slots
引言 <<往期回顾>> vue3源码分析--rollup打包monorepo vue3源码分析--实现组件的挂载流程 vue3源码分析--实现props,emit,事件处理等 ...
- 手撸spring源码分析IOC实现原理
手撸spring源码分析IOC实现原理 文章出处:https://github.com/fuzhengwei/small-spring 根据小付哥的手撸spring核心源码一步步学习出来的结果收货总结 ...
- cocos源码分析--SpriteBatchNode绘图原理(转--侵删)
cocos源码分析–SpriteBatchNode绘图原理 https://www.cnblogs.com/xiaonanxia/p/9199737.html
- vue3源码分析——看看complier是怎么来解析的
引言 <<往期回顾>> vue3源码分析--手写diff算法 vue3源码分析--实现组件更新 vue3源码分析--解密nextTick的实现 想知道vue3-complier ...
- Dubbo 源码分析 - 自适应拓展原理
1.原理 我在上一篇文章中分析了 Dubbo 的 SPI 机制,Dubbo SPI 是 Dubbo 框架的核心.Dubbo 中的很多拓展都是通过 SPI 机制进行加载的,比如 Protocol.Clu ...
- [Vue源码分析]自定义事件原理及事件总线的实现
最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: 我们都知道Vue中父组件可以通过 props 向下传数据给子组件:子组件可以通过向$emit触发一个事件,在父组件中执行回调函数,从而实 ...
- [Vue源码分析] v-model实现原理
最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: 我们都知道使用v-model可以实现数据的双向绑定,及实现数据的变化驱动dom的更新,dom的更新影响数据的变化.那么v-model是怎 ...
- vue3源码分析--真的有必要掌握框架的细枝末节吗?
古人云:工欲善其事必先利其器,磨刀不误砍柴工.但是砍柴的人需要知道怎么制作刀吗? 注意:本文先分析要不要学源码,然后分析要不要掌握源码的每一个细枝末节(深究技术)!!! 为什么要学源码 为了面试被迫学 ...
- Springmvc源码分析、底层原理
1.Springmvc是如何找到Controller的? 首先在请求过来时,会先进入DispatcherServlet进行请求分发,执行DispatcherServlet类中的doDispatch() ...
最新文章
- Line上半年扭亏为盈 用户及营收遇瓶颈
- Android之自定义view引用xml,Android自定义View在XML中映射错误
- C++笔记(2017/2/9)
- 【数论】YY的GCD(P2257)
- ELK入门01—Elasticsearch安装
- [转]Oracle销售人员普遍腐败?
- LVS负载均衡群集-NAT
- ghost 开发主题
- Python春节特训营03:打倒拦路虎,学会键盘打字
- android timepicker分割线颜色,Android TimePicker 的使用
- 51单片机入门(第二讲)
- linux开启443端口
- 二叉树no与n2关系数学证明
- CAN发送和接收数据(回环测试,ok)
- NR PRACH(五) type1 RA(4-step)基本过程
- 性能测试的实施及总结(二)
- BOSE QC35 蓝牙卡顿,断断续续问题
- [bootstrap]如何使用modal
- Invoke 和 BeginInvoke 的真正涵义
- 领域驱动设计 -- 领域驱动建模与面向对象建模的差异(一)