从vuecli3学习webpack记录(四)vue是怎么进行默认配置的
从vuecli3学习webpack记录(四)vue是怎么进行默认配置的
在我们讲到从vuecli3学习webpack记录(一)vue-cli-serve机制
vue cli3中在commands文件夹里面的是调用api.registerCommand方法,在config文件夹里面的(teserOptions.js和html除外)是调用api.chainWebpack方法,该方法会将传得的参数(该参数是一个方法)push到this.service.webpackChainFns数组。
今天就展开看看里面具体是什么。
- this.service其实就是cli3里面的Service(node_modules/@vue/cli-service/lib/Service.js)的实例,通过api.registerCommand方法将对应的serve(就是npm run serve那个serve)等command加入到this.commands这个对象属性里面,通过api.chainWebpack方法将app、base等webpack配置加入到this.webpackChainFns这个数组属性里面。
- 上面的api其实是PluginApi(node_modules/@vue/cli-service/lib/PluginApi.js)的实例,
部分代码如下
// node_modules/@vue/cli-service/lib/PluginApi.js
constructor (id, service) {
this.id = id
this.service = service
}
registerCommand (name, opts, fn) {
if (typeof opts === 'function') {
fn = opts
opts = null
}
this.service.commands[name] = { fn, opts: opts || {}}
}
chainWebpack (fn) {
this.service.webpackChainFns.push(fn)
}
cli3帮我们配置的默认配置是怎么进去的呢? 在此之前,我们先看看这些配置长什么样吧,以node_modules/@vue/cli-service/lib/config/base.js为例 我们一般在webpack里面是这样配置它
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
}
]
}
而在cli3里面这样配置
module.exports = (api, options) => {
api.chainWebpack(webpackConfig => {
webpackConfig.module
.rule('vue')
.test(/\.vue$/)
.use('cache-loader')
.loader('cache-loader')
.options(vueLoaderCacheConfig)
.end()
.use('vue-loader')
.loader('vue-loader')
.options(Object.assign({
compilerOptions: {
preserveWhitespace: false
}
}, vueLoaderCacheConfig))
webpackConfig
.plugin('vue-loader')
.use(require('vue-loader/lib/plugin'))
webpackConfig.module
.rule('images')
.test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
.use('url-loader')
.loader('url-loader')
.options(genUrlLoaderOptions('img'))
})
}
可以看出webpack的配置可以以链式调用的方式添加,这样就可以以更加灵活的函数式添加配置了。
webpackConfig
是什么鬼,这就要再次回到Service.js了,看它是怎执行webpackChainFns
数组里面的函数了
const Config = require('webpack-chain')
resolveChainableWebpackConfig () {
const chainableConfig = new Config()
// apply chains
this.webpackChainFns.forEach(fn => fn(chainableConfig))
return chainableConfig
}
再看看webpack-chain
const ChainedMap = require('./ChainedMap');
const ChainedSet = require('./ChainedSet');
const Resolve = require('./Resolve');
const ResolveLoader = require('./ResolveLoader');
const Output = require('./Output');
const DevServer = require('./DevServer');
const Plugin = require('./Plugin');
const Module = require('./Module');
const Optimization = require('./Optimization');
const Performance = require('./Performance');
module.exports = class extends ChainedMap {
constructor() {
super();
this.devServer = new DevServer(this);
this.entryPoints = new ChainedMap(this);
this.module = new Module(this);
this.node = new ChainedMap(this);
this.optimization = new Optimization(this);
this.output = new Output(this);
this.performance = new Performance(this);
this.plugins = new ChainedMap(this);
this.resolve = new Resolve(this);
this.resolveLoader = new ResolveLoader(this);
this.extend([
'amd',
'bail',
'cache',
'context',
'devtool',
'externals',
'loader',
'mode',
'parallelism',
'profile',
'recordsInputPath',
'recordsPath',
'recordsOutputPath',
'stats',
'target',
'watch',
'watchOptions',
]);
}
toConfig() {
const entryPoints = this.entryPoints.entries() || {};
return this.clean(
Object.assign(this.entries() || {}, {
node: this.node.entries(),
output: this.output.entries(),
resolve: this.resolve.toConfig(),
resolveLoader: this.resolveLoader.toConfig(),
devServer: this.devServer.toConfig(),
module: this.module.toConfig(),
optimization: this.optimization.entries(),
plugins: this.plugins.values().map(plugin => plugin.toConfig()),
performance: this.performance.entries(),
entry: Object.keys(entryPoints).reduce(
(acc, key) =>
Object.assign(acc, { [key]: entryPoints[key].values() }),
{}
),
})
);
}
}
原来它针对webpack的配置里面的每一个大项都设置了不同的属性,并且分配以不同的方式实现。我们还可以看到里面有个toConfig
方法,它会将最终的配置返回为我们熟悉的对象形式 的wepback配置,毕竟webpack只认这种配置。
下面就以this.module
为例吧,因为看到它的链式调用里面有个end
方法,会让链式调用调回去,方便执行后续的use('vue-loader')
// node_modules/webpack-chain/src/Module.js
module.exports = class extends ChainedMap {
constructor(parent) {
super(parent);
this.rules = new ChainedMap(this);
this.defaultRules = new ChainedMap(this);
this.extend(['noParse']);
}
}
Module
继承ChainMap
,而ChainMap
又继承自Chainable
,我们要看的end
方法就是在这里
// node_modules/webpack-chain/src/Chainable.js
module.exports = class {
constructor(parent) {
this.parent = parent;
}
batch(handler) {
handler(this);
return this;
}
end() {
return this.parent;
}
};
- 分类:
- Web前端
相关文章
从vuecli3学习webpack记录(三)基类Tapable和Hook分析
在查看webpack(及插件)源码的过程中,我们会经常看到类似这样的代码 compiler.hooks.done.tap('vue-cli-service serve',( 阅读更多…
webpack笔记——hook执行时call的是什么
我们一般使用的插件都是Hook子类,比如SyncHook,没有复杂的重写基类Hook的compile方法 先看Hook基类 // node_module/tapable/Hook.js cla 阅读更多…
回顾下跨域解决方案http-proxy-middleware
我们在React(或Vue)项目本地开发过程中很容易由前端自己解决跨域问题,这里面就用到的是插件 http-proxy-middleware ,它并不是webpack独享的插件,而是一个通用插件,它 阅读更多…
webpack笔记——在html-webpack-plugin插件中提供给其它插件是使用的hooks
最近在这段时间刚好在温故下webpack源码,webpack5都出来了,4还不再学习下? 这次顺便学习下webpack的常用插件html-webpack-plugin。 发现这个插件里面还额外加入了 阅读更多…
怎么调试Webpack+React项目,报错basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")怎么办
今天在WebStorm上Windows上准备调试一个React项目,就出现了这样的报错。 Node Parameters里面写的是webpack-dev-server的执行文件 .\node_mod 阅读更多…
从vuecli3学习webpack记录(一)vue-cli-serve机制
最近看了看vuecli3,把自己的学习记录下来。 首先看入口 npm run dev 即是 vue-cli-service serve ,之所以能运行 vue-cli-service 命令,就是 阅读更多…