webpack4读书笔记(二)

上篇文章整理了几个点,这篇文章接着记录下我觉得有总结意义的点。


loader 和 pugin的区别

loader上篇总结了:webpack只知道处理 js 类的文件,对于很多其他类型的模块如图片,字体等他不知道怎么处理,这时候就可以设置相关的loader,告诉它怎么处理这些模块。

plugin跟loader不同,我理解plugin是可以在webpack分析执行的某些节点或者生命周期时,做的某些操作。

webpackHtmlPlugin,在打包最后处理,生成html文件。 cleanWebpackPlugin,在webpack打包的最开始,把dist目录清空。

plugin有点像react.vue里的如mounted, beforeRouteEnter等节点,在某个时刻做某些事情。

1
2
3
4
5
6
plugins: [
new cleanWebpackPlugin(),
new htmlWebpackPlugin({
template: "src/index.html"
})
]

理解sourceMap和webpack4中sourcemap的使用

sourcemap 是一个映射关系,映射了打包后的某个代码位置对应于打包前的代码位置,方便开发者定位问题。

webpack4中设置 sourcemap 可以使用 devtool 的值,或者使用SourceMapDevToolPluginEvalSourceMapDevToolPlugin,两个不可同时使用。

webpack4, development模式默认的devtool模式是 eval, 若mode=production并且不设置 devtool 则没有 sourcemap。

所有的 sourcemap 可以设置的值,有如下:

sourcemap devtool

我觉得可以不用去分别去记忆有哪些类型的sourcemap,所有的sourcemap都是几种关键字组合而成,每种可能代表一个含义,理解其中的关键字,然后再去翻看文档需要哪种即可。

下面看下这几种关键字,理解后再来看上述的就可以理解了。


1、 eval

使用eval包裹模块代码

1
eval("// import Test from './Test'\n// import './1.png'\n// import './1.css'\n// new Test()\n\nconsele.log('log data')\n\n\n//# sourceURL=webpack:///./src/index.js?");

2、 source-map

产生 .map 文件,sourcemap 不会和 js 代码耦合在一起。

1
2
main.bundle.js
main.bundle.js.map

3、 cheap

不包含列信息,正常情况下我们只用知道是哪一行就可以了。如果加上哪一列相当于解析更费时间。

如:eval, 此时光标是值在出错的行及列。
eval

而:cheap-eval-source-map,此时光标只在最前面。
cheap

4、inline

将 .map 文件作为 DataURI嵌入,这种情况将不单独生成 .map 文件,而是跟bundle文件在一个文件里。

1
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vc3JjL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGtEQUEwQyxnQ0FBZ0M7QUFDMUU7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnRUFBd0Qsa0JBQWtCO0FBQzFFO0FBQ0EseURBQWlELGNBQWM7QUFDL0Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlEQUF5QyxpQ0FBaUM7QUFDMUUsd0hBQWdILG1CQUFtQixFQUFFO0FBQ3JJO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUNBQTJCLDBCQUEwQixFQUFFO0FBQ3ZELHlDQUFpQyxlQUFlO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhEQUFzRCwrREFBK0Q7O0FBRXJIO0FBQ0E7OztBQUdBO0FBQ0E7Ozs7Ozs7Ozs7OztBQ2xGQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSIsImZpbGUiOiJtYWluLmJ1bmRsZS5qcyIsInNvdXJjZXNDb250ZW50IjpbIiBcdC8vIFRoZSBtb2R1bGUgY2FjaGVcbiBcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG5cbiBcdC8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG4gXHRmdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cbiBcdFx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG4gXHRcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKSB7XG4gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4gXHRcdH1cbiBcdFx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcbiBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuIFx0XHRcdGk6IG1vZHVsZUlkLFxuIFx0XHRcdGw6IGZhbHNlLFxuIFx0XHRcdGV4cG9ydHM6IHt9XG4gXHRcdH07XG5cbiBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG4gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbiBcdFx0bW9kdWxlLmwgPSB0cnVlO1xuXG4gXHRcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG4gXHRcdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbiBcdH1cblxuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZXMgb2JqZWN0IChfX3dlYnBhY2tfbW9kdWxlc19fKVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5tID0gbW9kdWxlcztcblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcbiBcdF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG5cbiBcdC8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb24gZm9yIGhhcm1vbnkgZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XG4gXHRcdGlmKCFfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZXhwb3J0cywgbmFtZSkpIHtcbiBcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgbmFtZSwgeyBlbnVtZXJhYmxlOiB0cnVlLCBnZXQ6IGdldHRlciB9KTtcbiBcdFx0fVxuIFx0fTtcblxuIFx0Ly8gZGVmaW5lIF9fZXNNb2R1bGUgb24gZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5yID0gZnVuY3Rpb24oZXhwb3J0cykge1xuIFx0XHRpZih0eXBlb2YgU3ltYm9sICE9PSAndW5kZWZpbmVkJyAmJiBTeW1ib2wudG9TdHJpbmdUYWcpIHtcbiBcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgU3ltYm9sLnRvU3RyaW5nVGFnLCB7IHZhbHVlOiAnTW9kdWxlJyB9KTtcbiBcdFx0fVxuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xuIFx0fTtcblxuIFx0Ly8gY3JlYXRlIGEgZmFrZSBuYW1lc3BhY2Ugb2JqZWN0XG4gXHQvLyBtb2RlICYgMTogdmFsdWUgaXMgYSBtb2R1bGUgaWQsIHJlcXVpcmUgaXRcbiBcdC8vIG1vZGUgJiAyOiBtZXJnZSBhbGwgcHJvcGVydGllcyBvZiB2YWx1ZSBpbnRvIHRoZSBuc1xuIFx0Ly8gbW9kZSAmIDQ6IHJldHVybiB2YWx1ZSB3aGVuIGFscmVhZHkgbnMgb2JqZWN0XG4gXHQvLyBtb2RlICYgOHwxOiBiZWhhdmUgbGlrZSByZXF1aXJlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnQgPSBmdW5jdGlvbih2YWx1ZSwgbW9kZSkge1xuIFx0XHRpZihtb2RlICYgMSkgdmFsdWUgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKHZhbHVlKTtcbiBcdFx0aWYobW9kZSAmIDgpIHJldHVybiB2YWx1ZTtcbiBcdFx0aWYoKG1vZGUgJiA0KSAmJiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICYmIHZhbHVlLl9fZXNNb2R1bGUpIHJldHVybiB2YWx1ZTtcbiBcdFx0dmFyIG5zID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5yKG5zKTtcbiBcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KG5zLCAnZGVmYXVsdCcsIHsgZW51bWVyYWJsZTogdHJ1ZSwgdmFsdWU6IHZhbHVlIH0pO1xuIFx0XHRpZihtb2RlICYgMiAmJiB0eXBlb2YgdmFsdWUgIT0gJ3N0cmluZycpIGZvcih2YXIga2V5IGluIHZhbHVlKSBfX3dlYnBhY2tfcmVxdWlyZV9fLmQobnMsIGtleSwgZnVuY3Rpb24oa2V5KSB7IHJldHVybiB2YWx1ZVtrZXldOyB9LmJpbmQobnVsbCwga2V5KSk7XG4gXHRcdHJldHVybiBucztcbiBcdH07XG5cbiBcdC8vIGdldERlZmF1bHRFeHBvcnQgZnVuY3Rpb24gZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBub24taGFybW9ueSBtb2R1bGVzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm4gPSBmdW5jdGlvbihtb2R1bGUpIHtcbiBcdFx0dmFyIGdldHRlciA9IG1vZHVsZSAmJiBtb2R1bGUuX19lc01vZHVsZSA/XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0RGVmYXVsdCgpIHsgcmV0dXJuIG1vZHVsZVsnZGVmYXVsdCddOyB9IDpcbiBcdFx0XHRmdW5jdGlvbiBnZXRNb2R1bGVFeHBvcnRzKCkgeyByZXR1cm4gbW9kdWxlOyB9O1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQoZ2V0dGVyLCAnYScsIGdldHRlcik7XG4gXHRcdHJldHVybiBnZXR0ZXI7XG4gXHR9O1xuXG4gXHQvLyBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGxcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubyA9IGZ1bmN0aW9uKG9iamVjdCwgcHJvcGVydHkpIHsgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KTsgfTtcblxuIFx0Ly8gX193ZWJwYWNrX3B1YmxpY19wYXRoX19cbiBcdF9fd2VicGFja19yZXF1aXJlX18ucCA9IFwiXCI7XG5cblxuIFx0Ly8gTG9hZCBlbnRyeSBtb2R1bGUgYW5kIHJldHVybiBleHBvcnRzXG4gXHRyZXR1cm4gX193ZWJwYWNrX3JlcXVpcmVfXyhfX3dlYnBhY2tfcmVxdWlyZV9fLnMgPSBcIi4vc3JjL2luZGV4LmpzXCIpO1xuIiwiLy8gaW1wb3J0IFRlc3QgZnJvbSAnLi9UZXN0J1xuLy8gaW1wb3J0ICcuLzEucG5nJ1xuLy8gaW1wb3J0ICcuLzEuY3NzJ1xuLy8gbmV3IFRlc3QoKVxuXG5jb25zZWxlLmxvZygnbG9nIGRhdGEnKVxuIl0sInNvdXJjZVJvb3QiOiIifQ=

5、module

除了提示业务代码本身的map外,其他模块如loader,也会被映射有相应的sourcemap。

其实看官方文档会更加清楚,它会讲为什么有些类型是不适合生产或者开发环境,或者能够告诉你什么是 origin code 或者 transformed code

sourcemap的更加细节的原理,可以参考JavaScript Source Map 详解-阮一峰


webpack-dev-server HMR

webpack4中开启

  1. 开启 devsever hot: true, hotOnly: true
  2. 使用 new webpack.HotModuleReplacementPlugin()
1
2
3
4
5
6
devServer: {
contentBase: './dist', // 服务器根目录
hot: true, // 开启热更新
open: true, // 自动打开浏览器
hotOnly: true // 人更新失败,也不要跟新浏览器
}

这样还不够能实现js的热更新,如果要形成js的热更新,你还要告诉在代码里告诉webpack,我这个模块如果被修改了,要执行什么操作,如:

1
2
3
4
5
6
if (module.hot) {
module.hot.accept('./print.js', function() {
console.log('Accepting the updated printMe module!');
printMe();
})
}

这告诉了我们如果print.js改变了,则会打印一句话。若果每个地方都这么干,我们写代码会很累,所以可以:

  1. 借助Vue LoaderReact Hot Loader, 此 loader 支持 vue 组件的 HMR,提供开箱即用体验,不用自己再去写module.hot
  2. 借助于style-loader,使用模块热替换来加载 CSS ,此 loader 在幕后使用了 module.hot.accept,在 CSS 依赖模块更新之后,会将其 patch(修补) 到 <style> 标签中。

webpack babel

下面大概记录下整体的流程,以及几个模块之间的联系、区别及注意事项:

  1. 安装babel-loader,babel-core
  2. babel-core是babel的核心库,babel-loader是babel与webpack关系的桥梁
  3. module rule里设置,若是js文件结尾,用babel-loader处理
  4. 注意babel-loader只是与webpack打通,不进行es6转换
  5. 所以需要安装babel-preset-env,他负责转换新的es6的语法(syntax),但是不会去转换map或者promise,weakmap, find这种对象和函数。只转换语法如箭头函数或者const这种语法
  6. 所以需要babel-polyfill,为当前环境提供垫片,转换为新的api,
  7. 如果直接引用,所有的都会被打包,所以需要添加useBuiltIns,实现方法转换的按需加载,减少文件提示,根据业务代码里使用情况来打包,体积会减少很多。
  8. 但是babel-polyfill是在window上的,会污染全局变量,如果是打包类库或者第三方库就不合适了。
  9. 所以需要@babel/plugin-transform-runtime这个插件,这样可以不用污染全局变量。
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
// 如果是自己的业务代码
import "@babel/polyfill"

module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: 'node_modules',
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
targets: {
chrome: "64"
},
useBuiltIns: 'usage'
}
]
]
}
}
]
}
}

// **如果是第三方类库**
// npm install --save-dev @babel/plugin-transform-runtime
// npm install --save @babel/runtime
// npm install --save @babel/runtime-corejs2

module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: 'node_modules',
loader: 'babel-loader',
options: {
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 2,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
}
]
}
}

备注下,babel-preset-env不会转换的有:

  1. 全局对象,如 Promise, map, WeakMap
  2. 全局函数,如 Array.from, Object,assign
  3. 示例方法,如 Array.prototype.includes

注意presets的执行顺序也是从下往上,从右往左的顺序。如果是第三方类库:

事实上这些配置都可以放在.babelrc文件中。


总结

本篇文章主要是自我知识的梳理及记录。

周末在家,总觉得那种没啥事,不用出门,也不用加班,看看游戏视频,看看书遛遛狗的日子,才叫周末。📚🌲