前言
学习vue-cli@3.0这个脚手架源码,希望达到以下目的:
- 了解vue-cli的原理与机制
- 学会编写命令行工具以及相关常用的npm包
- 学会如何发布npm
准备
将GitHub上的仓库fork一份,再clone下来
@vue/babel-preset-app
这是所有Vue CLI项目中使用的默认Babel预设。(你可以简单认为是一系列 babel 的plugin
组合)
- babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
这里的@vue/cli-plugin-babel/preset
入口就是@vue/babel-preset-app这个包。
入口index.js
// code snippet
module.exports = (context, options = {}) => {
return {
sourceType: "unambiguous", // 判断文件中是否出现了import/export,来决定采用的模块化标准
overrides: [
{
exclude: [/@babel[/|\\\\]runtime/, /core-js/],
presets,
plugins,
},
{
// there are some untranspiled code in @babel/runtime
// https://github.com/babel/babel/issues/9903
include: [/@babel[/|\\\\]runtime/],
presets: [[require("@babel/preset-env"), envOptions]],
},
],
};
};
主要看overrides
中第一个 option 对象。plugins
和presets
的执行顺序是plugins
优先,所以先从plugins
开始。
const plugins = [];
plugins.push([
require("./polyfillsPlugin"),
{ polyfills, entryFiles, useAbsolutePath: !!absoluteRuntime },
]);
// 测试环境这里直接忽略
if (process.env.VUE_CLI_BABEL_TRANSPILE_MODULES) {
envOptions.modules = "commonjs";
if (process.env.VUE_CLI_BABEL_TARGET_NODE) {
// necessary for dynamic import to work in tests
plugins.push(require("babel-plugin-dynamic-import-node"));
}
}
plugins.push(
require("@babel/plugin-syntax-dynamic-import"),
[
require("@babel/plugin-proposal-decorators"),
{
decoratorsBeforeExport,
legacy: decoratorsLegacy !== false,
},
],
[require("@babel/plugin-proposal-class-properties"), { loose }]
);
plugins.push([
require("@babel/plugin-transform-runtime"),
{
regenerator: useBuiltIns !== "usage",
// polyfills are injected by preset-env & polyfillsPlugin, so no need to add them again
corejs: false,
helpers: useBuiltIns === "usage",
useESModules: !process.env.VUE_CLI_BABEL_TRANSPILE_MODULES,
absoluteRuntime,
version,
},
]);
按照babel
插件执行顺序,第一个是polyfillsPlugin.js
.
// add polyfill imports to the first file encountered.
module.exports = (
{ types },
{ polyfills, entryFiles = [], useAbsolutePath }
) => {
return {
name: 'vue-cli-inject-polyfills',
visitor: {
Program (path, state) {
if (!entryFiles.includes(state.filename)) {
return
}
// imports are injected in reverse order
polyfills
.slice()
.reverse()
.forEach(p => {
createImport(path, p, useAbsolutePath)
})
}
}
}
}
@vue/cli-overlay
定制覆盖Client
在TODO列表中,还没实现
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。