写在前面
最近新部门的 React 项目要做多环境部署,参考了一下之前部门做的 Vue 项目,顺便把 vue-cli-service 的源码看了一下。看源码的时候还去看了下 Vue 源码,感觉挺有意思的,打算好好研究下,这里持续更新本人的心得体会~
vue-cli-service多环境
首先在 package.json
里面 script
下面添加如下内容:
"scripts": {
"serve": "vue-cli-service serve",
"serve:staging": "vue-cli-service serve --mode staging",
"serve:prod": "vue-cli-service serve --mode production",
"lint": "vue-cli-service lint",
"format": "vue-cli-service lint --formatter",
"inspect": "vue-cli-service inspect",
"build": "vue-cli-service build",
"build:staging": "vue-cli-service build --mode staging",
"build:prod": "vue-cli-service build --mode production"
},
vue-cli-service
源码在 node_modules/@vue/cli-service/bin/vue-cli-service.js 目录下
vue-cli-service.js
在第 14 行加载了 ../lib/Service.js
模块,这个模块在 151 行加载了 serve.js
模块
serve.js
在 node_modules/@vue/cli-service/lib/commands/serve.js 目录下
// serve.js 第 50 行
// 检测环境,只在开发环境引入热更新插件
// webpack配置链式语法可以看一下
// configs that only matters for dev server
api.chainWebpack(webpackConfig => {
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
webpackConfig
.devtool('cheap-module-eval-source-map')
webpackConfig
.plugin('hmr')
.use(require('webpack/lib/HotModuleReplacementPlugin'))
// https://github.com/webpack/webpack/issues/6642
// https://github.com/vuejs/vue-cli/issues/3539
webpackConfig
.output
.globalObject(`(typeof self !== 'undefined' ? self : this)`)
if (!process.env.VUE_CLI_TEST && options.devServer.progress !== false) {
webpackConfig
.plugin('progress')
.use(require('webpack/lib/ProgressPlugin'))
}
}
})
vue-cli和creat-react-app打开浏览器的插件
Vue 中 openBrowser
的插件在 node_modules/@vue/cli-shared-utils 目录下。打开 index.js
可以看到如下内容:
这边引入了 openBrowser.js
文件,这个文件在 lib
目录下,打开可以看到如下内容:
这个插件跟 React 里面的 openBrowser.js
是一样的,React相关代码如下:
Vue 检测数组变化
我们知道 Vue 2.x 版本的响应式机制是通过 Object.defineProperty
实现的,这种方式不能够检测数组长度的变化,只能将数组整个替换掉才会触发 setter
。但是在实际开发中,调用数组的非变异方法(push,pop,shift,unshift,splice,sort,reverse),也能触发视图更新,这是因为 Vue 对这些方法进行了封装。
源码在 node_modules/vue/src/core/observer/array.js
import { def } from '../util/index'
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()
return result
})
})
其中 def()
的作用就是重新定义对象属性的value值,代码在 util/lang.js
/**
* Define a property.
*/
export function def (obj: Object, key: string, val: any, enumerable?: boolean) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
})
}
def(arrayMethods,method,function(){})
这个函数可以看作 arrayMethods[method] = function mutator(){}
。具体可以看下面的例子:
const push = Array.prototype.push;
Array.prototype.push = function mutator (...arg){
const result = push.apply(this,arg);
doSomething();
return result
}
function doSomething(){
console.log('do something');
}
首先第一步就是保存了原生的数组方法,先求出实际的值
注意:为触发视图更新,应该将数组整个替换/调用变异方法,或者使用非变异方法。直接用下标修改数组或者用 length 修改是无法被检测到的。
$nextTick原理
Vue 核心源码都在 node_modules/vue/src/core 目录下
这个目录下还包括 vdom ,observer ,global-api 的实现,都可以看一下
$nextTick 的源码在 node_modules/vue/src/core/util/next-tick.js 目录下
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。