cli vue webpack 实战_webpack-chain源码 vue-cli3.0配置webpack

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-23 01:06   47   0

获取源码

git clone https://github.com/neutrinojs/webpack-chain.git

知识准备

需要先预习 下列方法

ES6 Set 结构

ES6 Map 结构

ES6 Class 类继承

箭头函数

数组的一些方法: includes reduce map forEach

对象的一些方法: Object.keys Object.assign

展开运算符 ...

如果对这些知识生疏,点此学习 (http://es6.ruanyifeng.com/#do…

把这些掌握后,阅读很easy

目录结构

目标是把src 里面的方法都了解会用

└── webpack-chain

├── src

│ ├── Chainable.js

│ ├── ChainedMap.js

│ ├── ChainedSet.js

│ ├── Config.js

│ ├── DevServer.js

│ ├── Module.js

│ ├── Optimization.js

│ ├── Orderable.js

│ ├── Output.js

│ ├── Performance.js

│ ├── Plugin.js

│ ├── Resolve.js

│ ├── ResolveLoader.js

│ ├── Rule.js

│ └── Use.js

文件名全是首字母大写,从命名看,每个里面全是类的定义,用extends来实现继承

Chainable ChainedMap.js ChainedSet.js

ChainedMap.js ChainedSet.js 都继承了 Chainable

Chainable 以able 为后缀表示具有什么能力。这个库维护了 parent ,用end来实现链式。很像jq的end().

ChainedMap.js ChainedSet.js 这两个里面分别包装了 js 原生的 Map, Set 结构。

ChainedMap

// 维护了parent 链,由上文提到的`Chainable`来做的

// 实例化了一个store (仓库) 拥有Map结构的方法

constructor(parent) {

super(parent);

this.store = new Map();

}

// 从 Map 移除所有 配置.

clear()

// 通过键值从 Map 移除单个配置.

// key: *

delete(key)

// 获取 Map 中相应键的值

// key: *

// returns: value

get(key)

// 都是map的原生方法封装

has(key) + set(key, value)

// 传入key 和 函数两个参数

当拥有key的时候 返回获取到的值

如果key 没有定义过,调用函数生成键值对

getOrCompute(key, fn) {

if (!this.has(key)) {

this.set(key, fn());

}

return this.get(key);

}

把对象进行清洗,传参数{a:undefined,

b: [],

c:{},

d:0

}

输出{ d: 0 },会把undefined,[],{}这些过滤掉。

clean(obj)

// when的用法

// when 有断言作用,第2,3参数是函数。函数参数就是this。

// config

// .when(process.env.NODE_ENV === 'production',

// config => config.plugin('minify').use(BabiliWebpackPlugin),

// config => config.devtool('source-map')

// );

when(

condition,

whenTruthy = Function.prototype,

whenFalsy = Function.prototype

) {

if (condition) {

whenTruthy(this);

} else {

whenFalsy(this);

}

return this;

}

extend 参数是数组,会批量往this上绑定一些方法,

绑定方法是用的set,说明再次调用会覆盖掉上次。

例如: this.extend(['watch'])

会生成 this.watch = value => this.set(method, value);

理解了ChainedMap,那ChainedSet也容易

实战配置vue-cli 项目

用vue-cli3生成项目后

vue inspect > default.json

会生成默认配置到default.json

这些配置是从这个包node_modules/@vue/cli-service/lib/config/base.js 生成的

打开这个文件看一下webpack-chain的用法.

vue引入webpack-chain的文件是node_modules/@vue/cli-service/lib/Service.js

在此文章搜索下面三行

const Config = require('webpack-chain') // 会引入webpack-chain库"src/Config.js"文件

// 只实例化一次,chainWebpack 的config参数就是这个实例

const chainableConfig = new Config()

// 会生成配置

let config = chainableConfig.toConfig()

我们看一下webpack-chain 源码 Config.js 文件

toConfig() {

// 入口entry

const entryPoints = this.entryPoints.entries() || {};

// clean 方法上文Map结构有讲

return this.clean(

// this.entries() 全部this.store的值。包含this.extend()方法生成的速记方法

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.toConfig(),

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() }),

{}

),

})

);

}

修改 entry

chainWebpack: config => {

config.entryPoints.clear() // 会把默认的入口清空

config.entry('main').add('./src/main.js')

config.entry('routes').add('./src/app-routes.js')

}

链式调用:end方法

clear方法会把vue-cli默认的.entry('app')清空。可以在同一个chunk,add多个模块。

config.entryPoints.clear().end()

.entry('main').add('./src/main.js').end()

.entry('routes').add('./src/app-routes.js')

vue inspect > entry.json 对比entry.json和default.json的entry字段,成功修改。

速记方法 看上文Map extend 介绍

用速记方法修改简单的字段

config.mode('production')

config.watch(true)

生成文件,查看已变成

mode: 'production',

watch: true,

用速记方法修改proxy

chainWebpack: config => {

config.devServer.port(9898)

.open(true)

.proxy({'/dev': {

target: 'http://123.57.153.106:8080/',

changeOrigin: true,

pathRewrite: {

'^/dev': ''

}

}

})

}

修改别名 resolve.alias

chainWebpack: config => {

config.resolve.alias

.set('assets', '@/assets')

.set('fetch', '@/config/http.config')

.delete('fetch') // 删掉指定的

// .clear() 会把所有别名都删掉

}

添加7牛plugin

const QiniuPlugin = require('qn-webpack')

chainWebpack: config => {

config.plugin('7niu')

.use(QiniuPlugin,[{

accessKey: '1234567654356',

secretKey: '2344344545',

bucket: 'busi-cdn',

path: 'cdn-finance/dist/',

exclude: /index\.html$/ // 排除特定文件,正则表达式

}]);

}

通过阅读Plugin.js源码toConfig方法,发现还可以传字符串类型,还有对象实例

const init = this.get('init'); // 会调用init(plugin, args); 把插件函数和参数传入

let plugin = this.get('plugin'); // 获取plugin

const args = this.get('args');// 获取参数

config

.plugin('7niu')

.use('qn-webpack',[{

accessKey: '1234567654356',

secretKey: '2344344545',

bucket: 'busi-cdn',

path: 'cdn-finance/dist/',

exclude: /index\.html$/ // 排除特定文件,正则表达式

}]);

生成的效果

/* config.plugin('7niu') */

new (require('qn-webpack'))(

{

accessKey: '1234567654356',

secretKey: '2344344545',

bucket: 'busi-cdn',

path: 'cdn-finance/dist/',

exclude: /index\.html$/

}

)

添加clear plugin

用对象实例的方式

const CleanPlugin = require("clean-webpack-plugin");

const clean = new CleanPlugin()

config

.plugin('clean').use(clean)

移除 preload 插件

chainWebpack: config => {

config.plugins.delete('prefetch')

// 移除 preload 插件

config.plugins.delete('preload');

}

删除loader

把vue默认添加的loader 都删掉.

config.module.rules.clear()

删除指定rule

用use添加的在uses,用oneOf添加的在oneOfs

config.module

.rule('vue').uses.clear()

config.module

.rule('scss').oneOfs.clear()

输出后效果:

/* config.module.rule('scss') */

{

test: /\.scss$/

},

/* config.module.rule('vue') */

{

test: /\.vue$/

},

添加loader

从@vue/cli-service/lib/config/base.js 的一段代码来参考

webpackConfig.module

.rule('vue') // 会得到Rule实例 new Rule()

.test(/\.vue$/) // 速记方法调用的set,每次test()会覆盖掉之前的

.use('cache-loader') // new Use()实例参数是this.name。 loader和options是shorthands 调用set赋值

.loader('cache-loader')

.options(vueLoaderCacheConfig)

.end()

.use('vue-loader')

.loader('vue-loader')

.options(Object.assign({

compilerOptions: {

preserveWhitespace: false

}

}, vueLoaderCacheConfig))

Rule源码

const Rule = Orderable(

class extends ChainedMap {

constructor(parent, name) {

super(parent);

this.name = name;

this.names = [];

this.uses = new ChainedMap(this); // 所有的use

this.include = new ChainedSet(this); // 包含

this.exclude = new ChainedSet(this); // 排除

this.oneOfs = new ChainedMap(this); // 所有的oneOf

// 速记方法,使用Map的Set 方法再次调用会覆盖掉上次

this.extend([

'enforce',

'parser',

'resource',

'resourceQuery',

'sideEffects',

'test',

'type',

]);

}

use(name) {

// Use 是 ChainedMap,有就get返回,木有就调用会在this.uses注册一个

return this.uses.getOrCompute(name, () => new Use(this, name));

}

oneOf(name) {

// Rule 是 ChainedMap,有就get返回,木有就调用会在this.oneOfs注册一个

return this.oneOfs.getOrCompute(name, () => new Rule(this, name));

}

单独调试

const Config = require('webpack-chain');

const config = new Config();

const CleanPlugin = require("clean-webpack-plugin");

config

.plugin('clean')

.use(CleanPlugin);

let r = config.toConfig()

console.log(r)

vue去掉console.log

configureWebpack: config => {

if (process.env.NODE_ENV === 'production') {

config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true

}

}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP