BLOOK

GP's blog and book

webpack-chain源码 vue-cli配置webpack

获取源码

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

1
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/#docs/class)
把这些掌握后,阅读很easy

目录结构

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
└── 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// 维护了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生成项目后

1
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

在此文章搜索下面三行

1
2
3
4
5
6
7
const Config = require('webpack-chain') // 会引入webpack-chain库"src/Config.js"文件
// 只实例化一次,chainWebpack 的config参数就是这个实例
const chainableConfig = new Config()
// 会生成配置
let config = chainableConfig.toConfig()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
1
2
3
4
5
6
7
8
9
10
11
12
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 介绍
    用速记方法修改简单的字段
1
2
3
4
5
6
config.mode('production')
config.watch(true)
生成文件,查看已变成
mode: 'production',
watch: true,
用速记方法修改proxy
1
2
3
4
5
6
7
8
9
10
11
12
chainWebpack: config => {
config.devServer.port(9898)
.open(true)
.proxy({'/dev': {
target: 'http://123.57.153.106:8080/',
changeOrigin: true,
pathRewrite: {
'^/dev': ''
}
}
})
}
修改别名 resolve.alias
1
2
3
4
5
6
7
chainWebpack: config => {
config.resolve.alias
.set('assets', '@/assets')
.set('fetch', '@/config/http.config')
.delete('fetch') // 删掉指定的
// .clear() 会把所有别名都删掉
}
添加7牛plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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

用对象实例的方式

1
2
3
4
5
6
7
const CleanPlugin = require("clean-webpack-plugin");
const clean = new CleanPlugin()
config
.plugin('clean').use(clean)

删除loader

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 的一段代码来参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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));
}

单独调试

1
2
3
4
5
6
7
8
9
10
11
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)

link之preload

1
2
3
4
5
6
7
8
9
10
11
12
只是预加载,并不运行。
用下面两种方法即可加载完运行
// 预加载Css
<link rel="preload" as="style" href="async_style.css" onload="this.rel='stylesheet'">
// 预加载js
<link rel="preload" as="script" href="async_script.js"
onload="var script = document.createElement('script');
script.src = this.href;
document.body.appendChild(script);">

参考MDN
参考
DEMO

1
2
3
4
<link rel="prefetch"> 已经被许多浏览器支持了相当长的时间,但它是意图预获取一些资源,
以备下一个导航/页面使用(比如,当你去到下一个页面时)。
这很好,但对当前的页面并没有什么助益。
此外,浏览器会给使用prefetch的资源一个相对较低的优先级——与使用preload的资源相比。毕竟,当前的页面比下一个页面相对更加重要。查看Link prefetching FAQ可以了解更多细节。

NVM的安装和命令

mac下的安装

mac下面的安装,其实就可以按照linux的安装就可以了!安装的命令我们可以在nvm的github的资源上面得到安装方法:

1
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash

module require源码解析

require 的用法

1
2
3
4
5
require():加载一个外部模块
· require.resolve():解析一个模块名到它的绝对路径
· require.main:主模块
· require.cache:所有缓存好的模块
· ·require.extensions:根据其扩展名,对于每个有效的文件类型可使用的编制方法

nginx学习笔记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
########### 每个指令必须有分号结束。#################
#user administrator administrators; #配置用户或者组,默认为nobody nobody。
#worker_processes 2; #允许生成的进程数,默认为1
#pid /nginx/pid/nginx.pid; #指定nginx进程运行文件存放地址
error_log log/error.log debug; #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别以此为:debug|info|notice|warn|error|crit|alert|emerg
events {
accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on
multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
#use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections 1024; #最大连接数,默认为512
}
http {
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型,默认为text/plain
#access_log off; #取消服务日志
log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定义格式
access_log log/access.log myFormat; #combined为日志格式的默认值
sendfile on; #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
sendfile_max_chunk 100k; #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
keepalive_timeout 65; #连接超时时间,默认为75s,可以在http,server,location块。
upstream mysvr {
server 127.0.0.1:7878;
server 192.168.10.121:3333 backup; #热备
}
error_page 404 https://www.baidu.com; #错误页
server {
keepalive_requests 120; #单连接请求上限次数。
listen 4545; #监听端口
server_name 127.0.0.1; #监听地址
location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
#root path; #根目录
#index vv.txt; #设置默认页
proxy_pass http://mysvr; #请求转向mysvr 定义的服务器列表
deny 127.0.0.1; #拒绝的ip
allow 172.18.5.54; #允许的ip
}
}
}

计算机网络相关

  • 计算机通信 是两个运行的进程之间的通信
  • 网络边缘边通信分两种: 1、客户-服务器方式(c/s)(b/s 是一种特例); 2、对等方式p2p (peer)
  • OSI: open systems interconnection 开放系统互连基本参考模型

五层协议?

五层协议

Daily English

12.13
【Daily English#About shopping】
Show window 橱窗
Fitting room 试衣间
Try on 穿上试试
Wrap up 包起来
Free of charge 不收费
Check out 结帐
On hold 预留
Refund 退款
Invoice 发票
Receipt 收据
Counter 柜台
Small change 零钱
Promotion Code 促销码
BOGO 买一赠一
BOGO 50% OFF 第二件半价
Mix and match 混合搭配(以满足获得优惠的条件)
Free shipping 包邮
Price match 比价
Return policy 退货