webpack工程化之收拾包袱🤷‍♂️

391 阅读7分钟

babel-loader

能够把es6高级内容变为es5的loader名称为 babel-loader

es6/es7/es8等等高级标准有很多(let、箭头函数、对象解构赋值、...展开运算符、反勾号字符串等等),每个标准都需要一个独立的plugin进行降级处理,如果使用许多高级标准内容,那么势必要为此安装许多plugin,这样工作比较繁琐,系统已经考虑到这点了,其通过preset把许多常用的plugin给做了集合,因此一般性的使用只需要安装preset即可搞定(如果项目应用到了一个生僻的高级标准内容,preset处理不来,就还需要再安装对应的plugin处理)

let----降级---->plugin

箭头函数----降级--->plugin

npm官网: babel-loader

babel官网:www.babeljs.cn/setup#insta…

步骤:

  1. 安装依赖包
npm i babel-loader @babel/core @babel/preset-env -D
  1. 在webpack.config.js中做如下配置:
{
    test: /.js$/,
        exclude: /node_modules/,  // 排除目录
        use: [
                {
                    loader:'babel-loader',
                 	options: {
                        presets: ['@babel/preset-env']
                    }
                }
        ]  // es6转es5
}

说明: @babel/preset-env用来指定按什么样的预设来进行降级处理

  1. 打包测试
    打包之后,去打包后的文件中检查是否已经把const和箭头函数这种es6的代码转成了es5的代码。

source map的说明

目标: source map概念, 用于在浏览器调试错误使用, 记录代码打包前原始位置

  1. 准备: src/main.js产生一个未定义变量的报错, 启动webpack服务器
console.log(abc); // 不要声明abc变量
  1. 问题: 看浏览器-控制台报错信息, 但是发现看不出哪行代码报错了
    原因: webpack对代码, 压缩, 混淆, 减小文件的体积(提高文件的加载效率)
  • 变量被替换成没有任何语义的名称
  • 空行和注释被剔除, 压缩到一行

解决方案: 启用source map

开发环境

  1. webpack.config.js - 配置
module.exports = {
  // ...其他配置
  mode: 'development', 
  // 开发模式 是development
  // webpack内部不会使用内置优化, 不压缩代码
  // 使用'production'上线生产模式, 会压缩代码
  
  devtool: 'cheap-module-source-map', 
  // cheap-module-source-map 开发模式下使用, 保证运行时的行数 和 源代码行数 一致  (默认不写是eval模式)
}
  1. 重新启动开发服务器/打包, 观察是否有错误代码打包前的位置信息了

生产环境

  1. 不显示源码, 但是可以看到哪行报错
devtool: 'nosources-source-map'

  1. 显示源码
devtool: 'source-map'

devtool值说明

规则字符串列表:webpack.docschina.org/configurati…

格式: [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map  (了解即可)

规则值速度位置说明
false建立:最快 重建:最快不开启sourcemap(规则值写错也是这个)
inline建立:最慢 重建:最慢内嵌报错信息, 以及源码和源码位置信息
hidden建立:最慢 重建:最慢独立map文件报错信息, 没有源码和源码位置信息
eval建立:快 重建:最快内嵌报错信息, 以及源码 (mode为development时使用这个值)
cheap建立:固定 重建:慢独立map文件报错信息, 以及源码和源码的行数(没有列)
module建立:慢 重建:快速与别的一起用是否为loaders加载器生成source map
[xxx-...]source-map建立:最慢 重建:最慢独立map文件报错信息, 以及源码和源码位置信息
nosource建立:最慢 重建:最慢独立map文件报错信息, 不显示源码

总结: 名字如何组合, 还要看上面文档, 不记录  快于  内嵌 快于  独立文件

devtool常用组合

使用es6模块化

webpack中也是支持es6模块化的。

新建tooles6.js文件,内容如下:

const log = (content) => {
  console.log(Date.now(),content)
}

// es6 的导入
export { log }

注意,这里采用的是es6中的模块化导出。

接下来,在index.js中引入,并使用这个模块

// nodejs中的模块化
const { updateDom } = require('./tool')
// es6中的模块化
import {log} from './tooles6'

updateDom ('app','index.html')
log('test')

最后,打包 index.js ,在index.html中测试。

它可以处理es6的模块化和nodejs中的模块化

Question

1、webpack的构建流程是什么?

   webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  1. 初始化参数:从配置文件读取与合并参数,得出最终的参数
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,开始执行编译
  3. 确定入口:根据配置中的 entry 找出所有的入口文件
  4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
  5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
  6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
  7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。 在以上过程中,webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 webpack 提供的 API 改变 webpack 的运行结果

2、说一下 webpack 的热更新原理

webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。

HMR的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上 WDS(webpack-dev-server) 与浏览器之间维护了一个 Websocket,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该chunk的增量更新。

后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由 HotModulePlugin 来完成,提供了相关 API 以供开发者针对自身场景进行处理,像react-hot-loader 和 vue-loader 都是借助这些 API 实现 HMR。

3、有哪些常见的Loader?他们是解决什么问题的?

1、  file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件

2、  url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去

3、  source-map-loader:加载额外的 Source Map 文件,以方便断点调试

4、  image-loader:加载并且压缩图片文件

5、  babel-loader:把 ES6 转换成 ES5

6、  css-loader:加载 CSS,支持模块化、压缩、文件导入等特性

7、  style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。

8、  eslint-loader:通过 ESLint 检查 JavaScript 代码

4、Loader和Plugin的不同?

(1) 不同的作用

loader直译为"加载器"。webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。

Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 webpack 提供的 API 改变输出结果。

(2) 不同的用法

Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)

 Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入

Snipaste_2022-05-03_09-06-34.png