
四、webpack-模块化&source map
一、Mode 配置
这里要简单讲一下,后面还会提到它的其他用法。
Mode 配置选项,可以告知 webpack 使用相应模式的内置优化:
- 默认值是 production
- 可选值有:’none’ | ‘development’ | ‘production’
这几个选项有什么样的区别呢?
1 | const path = require("path"); |
mode: 'development',
这样编译完的代码不会进行压缩丑化。
Mode 配置代表更多 ,后续再了解。
二、模块化原理
webpack 支持 CommoJS 原理
1 | // 定义了一个对象 |
webpack 支持 ES6 Module 原理
1 | // 1.定义了一个对象, 对象里面放的是我们的模块映射 |
CommonJS 与 ES6 Module 相互导入原理
1 | var __webpack_modules__ = { |
源码问题,慢慢看吧
三、 source-map
我们的代码通常运行在浏览器上时,是通过打包压缩的:
也就是真实跑在浏览器上的代码,和我们编写的代码其实是有差异的
- 比如 ES6 的代码可能被转换成 ES5
- 比如对应的代码行号、列号在经过编译后肯定会不一致
- 比如代码进行丑化压缩时,会将编码名称等修改
- 比如我们使用了 TypeScript 等方式编写的代码,最终转换成 JavaScript
但是,当代码报错需要调试时(debug),调试转换后的代码是很困难的,况且我们不能保证代码不出错,那么如何可以调试这种转换后不一致的代码呢?答案就是 source-map
- source-map 是从已转换(压缩后的)的代码,映射到原始的源文件(npm run build 之前的)一种类型文件
- 使浏览器可以重构原始源并在调试器中显示重建的原始源
如何使用
第一步:根据源文件,生成 source-map 文件,webpack 在打包时,可以通过配置生成 source-map
1 | devtool: "source-map"; |
第二步:在转换后的代码,最后添加一个注释,它指向 sourcemap
1 | //# sourceMappingURL=common.bundle.js.map |
浏览器会根据我们的注释,查找相应的 source-map,并且根据 source-map 还原我们的代码,方便进行调试。
正常情况下压缩丑化后,不使用 source-map,报错后我们无法准确的找到错误处,尤其项目过大时。
使用 source-map:
1 | entry: './src/main.js', |
此时浏览器报错可以快速定位:
分析 source-map
最初 source-map 生成的文件带下是原始文件的 10 倍,第二版减少了约 50%,第三版又减少了 50%,所以目前一个 133kb 的文件,最终的 source-map 的大小大概在 300kb。
目前的 source-map 长什么样子呢?
- version:当前使用的版本,也就是最新的第三版
- sources:从哪些文件转换过来的 source-map 和打包的代码(最初始的文件)
- names:转换前的变量和属性名称(因为我目前使用的是 development 模式,所以不需要保留转换前的名 称)
- mappings:source-map 用来和源文件映射的信息(比如位置信息等),一串 base64 VLQ(veriablelength quantity 可变长度值)编码
- file:打包后的文件(浏览器加载的文件)
- sourceContent:转换前的具体代码信息(和 sources 是对应的关系)
- sourceRoot:所有的 sources 相对的根目录
1 | { |
生成 source-map
如何在使用 webpack 打包的时候,生成对应的 source-map 呢?
- webpack 提供了非常多的选项(目前是 26 个),来处理 source-map https://webpack.docschina.org/configuration/devtool/
- 选择不同的值,生成的 source-map 会稍微有差异,打包的过程也会有性能的差异,可以根据不同的情况进行选择
不生成 source-map
- false:不使用 source-map,也就是没有任何和 source-map 相关的内容。
- none:production 模式下的默认值,不生成 source-map。
- eval:development 模式下的默认值,不生成 source-map
- 但是它会在 eval 执行的代码中,添加
//# sourceURL=;
会被浏览器在执行时解析,并且在调试面板中生成对应的一些文件目录,方便我们调试代码;
比如:
1 | eval( |
source-map
生成一个独立的 source-map 文件,并且在 bundle 文件中有一个注释,指向 source-map 文件
bundle 文件中有如下的注释: //# sourceMappingURL=bundle.js.map
开发工具会根据这个注释找到 source-map 文件,并且解析
对应的就是上上面的 source-map。
eval-source-map
生成 sourcemap,但是 source-map 是以 DataUrl 添加到 eval 函数的后面
1 | eval( |
inline-source-map
会生成 sourcemap,但是 source-map 是以 DataUrl添加到 bundle 文件的后面
1 | !(function () { |
….这老长。
cheap-source-map
会生成 sourcemap,但是会更加高效一些(cheap 低开销)
因为它没有生成列映射(Column Mapping)
因为在开发中,我们只需要行信息通常就可以定位到错误了
cheap-module-source-map
会生成 sourcemap,类似于 cheap-source-map,但是对源自 loader 的 sourcemap 处理会更好
这里有一个很模糊的概念:对源自 loader 的 sourcemap 处理会更好,官方也没有给出很好的解释
其实是如果 loader 对我们的源码进行了特殊的处理,比如 babel,代码不贴了,看下 cheap-source-map 和 cheap-module-source-map 生成文件的区别:
可以看出,cheap-module-source-map 生成的文件更贴近我们的源代码。
hidden-source-map
会生成 sourcemap,但是不会对 source-map 文件进行引用
相当于删除了打包文件中对 sourcemap 的引用注释
如果我们手动添加进来,那么 sourcemap 就会生效了
1 | // 被删除掉的 |
nosources-source-map
会生成 sourcemap,但是生成的 sourcemap 只有错误信息的提示,不会生成源代码文件;
多个值组合
webpack 提供给我们的 26 个值,是可以进行多组合的。
组合的规则如下:
- inline-|hidden-|eval:三个值时三选一
- nosources:可选值
- cheap 可选值,并且可以跟随 module 的值
那么在开发中,最佳的实践是什么呢?
- 开发阶段:推荐使用 source-map 或者 cheap-module-source-map
- 这分别是 vue 和 react 使用的值,可以获取调试信息,方便快速开发
- 测试阶段:推荐使用 source-map 或者 cheap-module-source-map
- 测试阶段我们也希望在浏览器下看到正确的错误提示
- 发布阶段:false、缺省值(不写)