读完 Vue 发布源码,小姐姐回答了 leader 的提问,并优化了项目发布流程~

大家好,我是若川。这是 源码共读 第三期活动,纪年小姐姐的第三次投稿。纪年小姐姐学习完优化了自己的项目发布流程,而且回答了leader对她的提问,来看看她的思考和实践。

第三期是 Vue 3.2 发布了,那尤雨溪是怎么发布 Vue.js 的?。不知不觉,源码共读已经进行了快一个月,有些小伙伴表示对面试和工作很有帮助,学完立马能用。如果你也感兴趣可以加我微信 ruochuan12参加。

1. 学习目标和资源准备

这一期阅读的是 Vue3 源码中的 script/release.js 代码,也就是 Vue.js 的发布流程。在上一期源码阅读中从 .github/contributing.md[1] 了解到 Vue.js 采用的是 monorepo 的方式进行代码的管理。

monorepo 是管理项目代码的一个方式,指在一个项目仓库 (repo) 中管理多个模块/包 (package),不同于常见的每个 package 都建一个 repo。

刚好我最近搭建组件库也是使用 monorepo 的方式去管理包。monorepo 有个缺点,因为每个包都维护着自己的 dependencies,那么在 install 的时候会导致 node_modules 的体积非常大。目前最常见的 monorepo 解决方案是使用 lerna 和 yarn 的 workspaces 特性去处理仓库的依赖,我搭建的组件库也是使用了 lerna 和 yarn。但 Vue3 的包管理没有使用 lerna,它是怎么管理依赖包的版本号呢?让我们跟着源码一探究竟。

Lerna[2] 是一个管理工具,用于管理包含多个软件包(package)的 JavaScript 项目,针对使用 git 和 npm 管理多软件包代码仓库的工作流程进行优化。

学习目标:

1)学习 release.js 源码,输出记录文档。

资源准备:

Vue3 源码地址:https://github.com/vuejs/vue-next

2. Yarn Workspace

// vue-next/package.json (多余的代码已省略)
{"private": true,"version": "3.2.2","workspaces": ["packages/*"],"scripts": {"release": "node scripts/release.js"}
}

Yarn 从 1.0 版开始支持 Workspace (工作区),Workspace 可以更好的统一管理有多个项目的仓库。

  • 管理依赖关系便捷:每个项目使用独立的 package.json 管理依赖,可以使用 yarn 命令一次性安装或者升级所有依赖,无需在每个目录下分别安装依赖

  • 降低磁盘空间占用:可以使多个项目共享同一个 node_modules 目录

3. release.js 文件解读

先手动跑一遍 yarn run release --dry,控制台会输出以下信息(多余信息已省略),从控制台日志看出来,发布 Vue.js 会经历以下几个步骤:

// 确认发布版本号
? Select release type ...
> patch (3.2.3)minor (3.3.0)major (4.0.0)custom
// 执行测试用例
Running tests...
// 更新依赖版本
Updating cross dependencies...
// 打包编译所有包
Building all packages...
// 生成 changelog
conventional-changelog -p angular -i CHANGELOG.md -s
// 提交代码
Committing changes...
// 发布包
Publishing packages...
// 推送代码到 GitHub
Pushing to GitHub...

初步了解发布流程后,来看看 release.js 源码做了什么,先看入口函数 main()

main 函数

代码太多就不贴代码了,记录一下思路和思考

  1. 确认要发布的版本:

    • 如果从命令行获取到了版本号,先验证版本号规范,再次确认版本号

    • 如果命令行没有输入版本号,会让用户选择一个版本发布

确认版本号使用了一个库叫 semver,它的作用是用于版本校验比较。

// 目的是获取命令行参数(也就是允许用户自定义输入版本号,比如 yarn release v3.5.0)
const args = require('minimist')(process.argv.slice(2))
let targetVersion = args._[0]
  1. 执行测试用例

const execa = require('execa')
const run = (bin, args, opts = {}) => execa(bin, args, { stdio: 'inherit', ...opts })
const bin = name => path.resolve(__dirname, '../node_modules/.bin/' + name)if (!skipTests && !isDryRun) {// bin("jest") 先获取 node_modules/.bin/jest 的目录,run 的本质就是执行命令行// 这行代码的意思就相当于在命令终端,项目根目录运行 ./node_modules/.bin/jest 命令。await run(bin('jest'), ['--clearCache'])await run('yarn', ['test', '--bail'])
} else {console.log(`(skipped)`)
}
  1. 更新依赖版本

// 1)获取 packages 目录下的所有包
const packages = fs.readdirSync(path.resolve(__dirname, '../packages')).filter(p => !p.endsWith('.ts') && !p.startsWith('.'))
// 1)获取包的根目录路径
const getPkgRoot = pkg => path.resolve(__dirname, '../packages/' + pkg)
// 2)更新根目录和 packages 目录下每个包的 package.json 的版本号
function updateVersions(version) {}
// 3)实现更新 package.json 版本号的,以及更新依赖包的版本号
function updatePackage(pkgRoot, version) {}
// 4)实现更新与 vue 相关依赖包的版本号
function updateDeps(pkg, depType, version) {}
  1. 打包编译所有包

这部分涉及另外一个文件 script/build.js,这个文件主要是将各个包打包在对应的目录下,比如打包一个依赖就运行一次yarn build,如果有多个包,就异步循环调用打包命令。核心代码如下:

/*** 迭代打包* @param {*} maxConcurrency 最大并发* @param {*} source 目录* @param {*} iteratorFn 构建函数(核心就是运行 build 命令)* @returns*/
async function runParallel(maxConcurrency, source, iteratorFn) {const ret = [];const executing = [];for (const item of source) {const p = Promise.resolve().then(() => iteratorFn(item, source));ret.push(p);if (maxConcurrency <= source.length) {const e = p.then(() => executing.splice(executing.indexOf(e), 1));executing.push(e);if (executing.length >= maxConcurrency) {await Promise.race(executing);}}}return Promise.all(ret);
}
  1. 生成 CHANGELOG 文件

主要运行的是这行命令:conventional-changelog -p angular -i CHANGELOG.md -s

  1. 提交代码

先执行 git diff 命令,检查文件是否有修改,如果有,执行 git add 和 git commit 命令

  1. 发布包

最后执行的命令是,yarn publish,发布新版本和打 Tag

  1. 推送到 GitHub

主要运行的命令:

    • 打 tag:git tag ${version}

    • 推送 tag:git push origin refs/tags/${version}

    • 提交代码到远程仓库:git push

至此,release 发布流程已经分析完了。

release 发布流程

4. 感想

回答一下开篇的问题,Vue 是如何管理版本号呢?阅读完源码我们会分现,在发版的时候会统一更新所有包的 package.json 的版本号。对比我在搭建组件库过程中使用的 lerna,其实 lerna 是把 release 这一套流程封装成了一个包,它里面处理发包的流程跟 Vue Release 流程基本是一致的。

这次的源码解读解答了我的一些疑惑。在我搭建组件库的过程中,我一开始了解到的是一个组件一个目录,单包推送到 npm 私库。这样做的缺点很明显,需要在每个目录安装一遍依赖,单独处理版本号。后来了解到了 yarn workspace,知道它可以处理依赖安装的问题,但版本号的处理还是没有解决方案。于是我去寻找业内比较流行的解决办法,发现大部分是使用了 lerna。

于是我向我的 TL 沟通询问,可否采用 yarn + lerna 的方式来搭建组件库。我记得特别清楚他反问我,问我 lerna 解决了什么问题,我支支吾吾回答了官网上的介绍,因为我当时对 lerna 的了解仅停留在官网以及它的常用命令,实际上我不知道它解决了什么问题。TL 见我答不上来,回复了我一句【如无必要,勿增实体】。

通过这次的源码阅读,我可以回答 TL 反问我的那个问题了,lerna 解决的是发包流程中版本号处理,自动生成 CHANGELOG 文件,提交代码,发布包,推送到仓库这几个问题,它把这几个流程封装成命令供用户使用。它不是搭建组件库非必要引入的工具,虽然引用了 lerna 会增加了新的复杂度,但在不了解发包流程的前期使用 lerna 可以使组件库开发者更专注于组件开发的工作上,而不需要过度关注如何发包。

5. 实践

经过一番思考,我认为引入 lerna 确实给系统增加了一些复杂度,因为它要求开发人员额外学习 lerna 的一些知识和命令,增加了学习成本以及系统复杂度。我觉得可以参考 Vue 的 release.js,写一个适用于项目的构建发版脚本用来发包,降低系统复杂度。

逻辑代码基本与 Vue3 的 release.js 和 build.js 一致,去掉了一些没必要的代码,比如单元测试和一些环境判断。还修改了一下 rollup.config.js 的配置,感觉用起来确实比 lerna 好用一些。最终效果如下:

img

参考资料

[1]

.github/contributing.md: https://github.com/vuejs/vue-next/blob/master/.github/contributing.md

[2]

Lerna: https://www.lernajs.cn/

最近组建了一个江西人的前端交流群,如果你是江西人可以加我微信 ruochuan12 私信 江西 拉你进群。


推荐阅读

我在阿里招前端,该怎么帮你(可进面试群)
我读源码的经历

初学者也能看懂的 Vue3 源码中那些实用的基础工具函数
老姚浅谈:怎么学JavaScript?

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》多篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,活跃在知乎@若川,掘金@若川。致力于分享前端开发经验,愿景:帮助5年内前端人走向前列。

识别方二维码加我微信、拉你进源码共读

今日话题

略。欢迎分享、收藏、点赞、在看我的公众号文章~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275518.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序背景图片的坑

本人是前端菜鸟一个&#xff0c;比小白还要白&#xff0c;这完全是自己的经验总结&#xff0c;并不是要给各位分享什么宝贵经验哈&#xff0c;各位大佬不喜勿喷&#xff0c;不然会打击到我的哈哈因为公司要求做几个小程序的页面&#xff0c;我不得不拾起丢弃了几个月的小程序开…

SimpleAdapter类使用方法

SimpleAdapter的构造函数是&#xff1a; public SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) 官方说明了其各个参数含义&#xff0c;我这里根据自己的理解解释下&#xff1a; 第一个context&…

小程序 富文本自适应屏幕_自适应文本:跨屏幕尺寸构建可读文本

小程序 富文本自适应屏幕Many of you may already know about responsive web design. Cited from Wikipedia, responsive web design (RWD) is an approach to web design that makes web pages render well on a variety of devices and windows or screen sizes. The respon…

Vue、React 之间如何实现代码移植?

大家好&#xff0c;我是若川。面对前端最火的两个框架&#xff0c;学 React 还是 Vue &#xff1f;这可能是每个前端人都曾纠结过的问题。不过&#xff0c;现在你不用纠结了——因为很多公司都是两个框架都有大量的应用&#xff0c;取决于不同团队的技术选型&#xff0c;特别是…

linux mariadb 乱码,配置mariadb远程访问权限,解决数据库乱码问题

配置mariadb远程访问权限&#xff1a;1)登录数据库:# mysql -uroot -p2)配置授权数据库用户远程访问权限&#xff0c;%表示所有远程IP&#xff0c;也可以指定IP。WITH GRANT OPTION表示mysql数据库的grant表中重新加载权限数据&#xff1a;GRANT ALL PRIVILEGES ON *.* TO 用户…

平面设计师和ui设计师_游戏设计师的平面设计

平面设计师和ui设计师Design is a very ancient practice, but graphic design really found its core principles post World War One. Games are also very ancient but video games are still finding their feet. I think graphic design has a few things to teach people…

从零开发一个命令行脚手架工具 等

大家好&#xff0c;我是若川。今天周末&#xff0c;话不多说&#xff0c;这一次花了几小时精心为大家挑选了20余篇好文&#xff0c;供大家阅读学习。本文阅读技巧&#xff0c;先粗看标题&#xff0c;感兴趣可以都关注一波&#xff0c;绝对不亏。前端宇宙小编就职于某大厂&#…

linux的HAL库函数,STM32 HAL库 IIC 协议库函数

/* 第1个参数为I2C操作句柄第2个参数为从机设备地址第3个参数为从机寄存器地址第4个参数为从机寄存器地址长度第5个参数为发送的数据的起始地址第6个参数为传输数据的大小第7个参数为操作超时时间 */HAL_I2C_Mem_Write(&hi2c2,salve_add,0,0,PA_BUFF,sizeof(PA_BUFF),0x10)…

pku acm 2140 Herd Sums http://acm.pku.edu.cn/JudgeOnline/problem?id=2140

2140代码短小精悍&#xff1a;#include<stdio.h> int main() { int cnt0,i; long s; scanf("%ld",&s); for(i1;(i1)*i/2<s;i)if((s-(i-1)*i/2)%i0)cnt; printf("%d\n",cnt); return 0; }转载于:https://www.cnblogs.com/Chinese-Coder-C…

java合成海报的工具类

2019独角兽企业重金招聘Python工程师标准>>> package io.renren.common.utils;import cn.hutool.core.lang.Console; import io.renren.modules.oss.cloud.OSSFactory;import javax.imageio.ImageIO; import javax.imageio.stream.ImageOutputStream; import java.a…

a说b说谎b说c说谎说d说_说谎的眼睛及其同伙

a说b说谎b说c说谎说d说The eye is a complex and temperamental organ. By the end of this article, designers will have a better understanding of how the eye works with the brain, how it deconstructs images that the brain stitches back up again, and how the two…

一名运营,自学一年前端,成功入职杭州某独角兽企业,他的面试经验和学习方法等分享...

大家好&#xff0c;我是若川。这是我的微信群里小伙伴年年 的投稿。他是19年毕业&#xff0c;之前做的是运营相关的工作&#xff0c;在我的交流群里非常活跃&#xff0c;自学一年前端&#xff0c;目前成功转行入职杭州一家独角兽企业。相信他的文章能带给大家一些启发和激励。0…

linux下svn relocate,如何进行svn relocate 操作

1。进入工作复本&#xff03;> cd ~/test2。查看仓库地址(URL)&#xff03;> svn info路径&#xff1a;.地址(URL)&#xff1a;http://192.168.28.1/repos/test档案库 UUID&#xff1a;a81f9bed-3506-0410-b369-e50476f75162修订版&#xff1a;44节点种类&#xff1a;目录…

教你怎么买虚拟空间(转)

虚拟空间是什么?经常听到站长们在群里问&#xff0c;哪里的虚拟空间好?哪里的虚拟空间性能好?哪里的虚拟空间便宜?虚拟空间是当今IDC行业的一个重要销售产品&#xff0c;虚拟空间也是中国站长们建设网站中最常应用的网站载体。各种数据说明&#xff0c;虚拟空间的好坏能影响…

React笔记-事件分发

事件分发 之前讲述了事件如何绑定在document上&#xff0c;那么具体事件触发的时候是如何分发到具体的监听者呢&#xff1f;我们接着上次注册的事件代理看。当我点击update counter按钮时&#xff0c;触发注册的click事件代理。 function dispatchInteractiveEvent(topLevelTyp…

百度指数可视化_可视化指数

百度指数可视化Abstract:– Analysis of the visual representations of exponentials.– Proposals to solve current visualization issues.– Call to discussion to come up with a better visual representation convention.抽象&#xff1a; –分析指数的视觉表示形式。…

qemu+linux+x86+64,kvm 内部错误:无法找到适合 x86_64 的模拟器

本文将为您描述kvm 内部错误&#xff1a;无法找到适合 x86_64 的模拟器,教程操作方法:0x00 问题安装完 KVM 之后&#xff0c;启动管理工具报错&#xff1a;内部错误&#xff1a;无法找到适合 x86_64 的模拟器于是查看 libvirtd 服务状态&#xff0c;查看到以下内容&#xff1a;…

阿里云谦大佬:时间精力有限的情况下如何高效学习前端?

大家好&#xff0c;我是若川。最近组织了源码共读活动1个月&#xff0c;200人&#xff0c;一起读了4周源码&#xff0c;欢迎加我微信 ruochuan12 进群参与。今天分享一篇阿里云谦大佬的文章。昨天在群里也有小伙伴说到&#xff1a;大佬们是需要什么学什么&#xff0c;新手一般是…

JQuery小记

访问dom元素 $代表整个dom tree $("#content") $("p") $("li .red") 字符串转换为json对象 $.parseJSON ajax $.ajax({type: "post",url: "GetUser.ashx",success: function (data) {var t "";var json $.pars…

React个人整理

React基础//ReactDOM.render(reactWhat,domWhere)在浏览器中渲染应用的一种途径 //React.DOM表示预定义好的HTML元素集合 //React.DOM.h1(attributes,children)表示一个预定义的React 组件 //h1()第一个参数接收一个对象&#xff0c;用于指定该组件的任何属性&#xff08;比如i…