1. 前言
大家好,我是若川。最近组织了源码共读活动。每周读 200 行左右的源码。很多第一次读源码的小伙伴都感觉很有收获,感兴趣可以加我微信
ruochuan12
,拉你进群学习。
写相对很难的源码,耗费了自己的时间和精力,也没收获多少阅读点赞,其实是一件挺受打击的事情。从阅读量和读者受益方面来看,不能促进作者持续输出文章。
所以转变思路,写一些相对通俗易懂的文章。其实源码也不是想象的那么难,至少有很多看得懂。比如工具函数。本文通过学习Vue3
源码中的工具函数模块的源码,学习源码为自己所用。歌德曾说:读一本好书,就是在和高尚的人谈话。同理可得:读源码,也算是和作者的一种学习交流的方式。
阅读本文,你将学到:
1. 如何学习 JavaScript 基础知识,会推荐很多学习资料
2. 如何学习调试 vue 3 源码
3. 如何学习源码中优秀代码和思想,投入到自己的项目中
4. Vue 3 源码 shared 模块中的几十个实用工具函数
5. 我的一些经验分享
shared
模块中57个
工具函数,本次阅读其中的30余个
。
2. 环境准备
2.1 读开源项目 贡献指南
打开 vue-next[1], 开源项目一般都能在 README.md
或者 .github/contributing.md[2] 找到贡献指南。
而贡献指南写了很多关于参与项目开发的信息。比如怎么跑起来,项目目录结构是怎样的。怎么投入开发,需要哪些知识储备等。
我们可以在 项目目录结构[3] 描述中,找到shared
模块。
shared
: Internal utilities shared across multiple packages (especially environment-agnostic utils used by both runtime and compiler packages).
README.md
和 contributing.md
一般都是英文的。可能会难倒一部分人。其实看不懂,完全可以可以借助划词翻译,整页翻译和百度翻译等翻译工具。再把英文加入后续学习计划。
本文就是讲shared
模块,对应的文件路径是:`vue-next/packages/shared/src/index.ts`[4]
也可以用github1s
访问,速度更快。github1s packages/shared/src/index.ts[5]
2.2 按照项目指南 打包构建代码
为了降低文章难度,我按照贡献指南中方法打包把ts
转成了js
。如果你需要打包,也可以参考下文打包构建。
你需要确保 Node.js[6] 版本是 10+
, 而且 yarn
的版本是 1.x
Yarn 1.x[7]。
你安装的 Node.js
版本很可能是低于 10
。最简单的办法就是去官网重新安装。也可以使用 nvm
等管理Node.js
版本。
node -v
# v14.16.0
# 全局安装 yarn
# 克隆项目
git clone https://github.com/vuejs/vue-next.git
cd vue-next
# 或者克隆我的项目
git clone https://github.com/lxchuan12/vue-next-analysis.git
cd vue-next-analysis
npm install --global yarn
yarn # install the dependencies of the project
yarn build
可以得到 vue-next/packages/shared/dist/shared.esm-bundler.js
,文件也就是纯js
文件。也接下就是解释其中的一些方法。
当然,前面可能比较啰嗦。我可以直接讲
3. 工具函数
。但通过我上文的介绍,即使是初学者,都能看懂一些开源项目源码,也许就会有一定的成就感。另外,面试问到被类似的问题或者笔试题时,你说看Vue3
源码学到的,面试官绝对对你刮目相看。
2.3 如何生成 sourcemap 调试 vue-next 源码
熟悉我的读者知道,我是经常强调生成sourcemap
调试看源码,所以顺便提一下如何配置生成sourcemap
,如何调试。这部分可以简单略过,动手操作时再仔细看。
其实贡献指南[8]里描述了。
Build with Source Maps Use the
--sourcemap
or-s
flag to build with source maps. Note this will make the build much slower.
所以在 vue-next/package.json
追加 "dev:sourcemap": "node scripts/dev.js --sourcemap"
,yarn dev:sourcemap
执行,即可生成sourcemap
,或者直接 build
。
// package.json
{
"version": "3.2.1",
"scripts": {
"dev:sourcemap": "node scripts/dev.js --sourcemap"
}
}
会在控制台输出类似vue-next/packages/vue/src/index.ts → packages/vue/dist/vue.global.js
的信息。
其中packages/vue/dist/vue.global.js.map
就是sourcemap
文件了。
我们在 Vue3官网找个例子,在 vue-next/examples/index.html
。其内容引入packages/vue/dist/vue.global.js
。
// vue-next/examples/index.html
<script src="../../packages/vue/dist/vue.global.js"></script>
<script>
const Counter = {
data() {
return {
counter: 0
}
}
}
Vue.createApp(Counter).mount('#counter')
</script>
然后我们新建一个终端窗口,yarn serve
,在浏览器中打开http://localhost:5000/examples/
,如下图所示,按F11
等进入函数,就可以愉快的调试源码了。
3. 工具函数
本文主要按照源码 `vue-next/packages/shared/src/index.ts`[9] 的顺序来写。也省去了一些从外部导入的方法。
我们也可以通过ts
文件,查看使用函数的位置。同时在VSCode
运行调试JS代码,我们比较推荐韩老师写的code runner
插件。
3.1 babelParserDefaultPlugins babel 解析默认插件
/**
* List of @babel/parser plugins that are used for template expression
* transforms and SFC script transforms. By default we enable proposals slated
* for ES2020. This will need to be updated as the spec moves forward.
* Full list at https://babeljs.io/docs/en/next/babel-parser#plugins
*/
const babelParserDefaultPlugins = [
'bigInt',
'optionalChaining',
'nullishCoalescingOperator'
];
这里就是几个默认插件。感兴趣看英文注释查看。
3.2 EMPTY_OBJ 空对象
const EMPTY_OBJ = (process.env.NODE_ENV !== 'production')
? Object.freeze({})
: {};
// 例子:
// Object.freeze 是 冻结对象
// 冻结的对象最外层无法修改。
const EMPTY_OBJ_1 = Object.freeze({});
EMPTY_OBJ_1.name = '若川';
console.log(EMPTY_OBJ_1.name); // undefined
const EMPTY_OBJ_2 = Object.freeze({ props: { mp: '若川视野' } });
EMPTY_OBJ_2.props.name = '若川';
EMPTY_OBJ_2.props2 = 'props2';
console.log(EMPTY_OBJ_2.props.name); // '若川'
console.log(EMPTY_OBJ_2.props2); // undefined
console.log(EMPTY_OBJ_2);
/**
*
* {
* props: {
mp: "若川视野",
name: "若川"
}
* }
* */
process.env.NODE_ENV
是 node
项目中的一个环境变量,一般定义为:development
和production
。根据环境写代码。比如开发环境,有报错等信息,生产环境则不需要这些报错警告。