打包工具之Webpack篇(二) | 青训营笔记

118 阅读5分钟

这是我参与第四届青训营笔记创作活动的第九天

问题1思考

Q1: Loader 有什么作用?为什么这里需要用到css-loader、style-loader

A1:

  • Webpack Loader 最核心的只能是实现内容转换器 —— 将各式各样的资源转化为标准 JavaScript 内容格式,且带有副作用。

  • 为什么这里需要用到css-loader、style-loader本质上是因为 Webpack 只认识符合 JavaScript 规范的文本css-loader将 css 内容包装成类似 module.exports = "${css}" 的内容,包装后的内容符合 JavaScript 语法,style-loader做的事情非常简单,就是将 css 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签。

Q2: 与旧时代-在HTML 文件中维护css 相比,这种方式会有什么优劣处?

A2:

  • 优势:多个 Loader 分别完成内容转化工作的一部分,形成从右到左的调用链条。链式调用这种设计有两个好处,一是保持单个 Loader 的单一职责,一定程度上降低代码的复杂度;二是细粒度的功能能够被组装成复杂而灵活的处理链条,提升单个 Loader 的可复用性。

  • 劣势:不过,这只是链式调用的一部分,这里面有两个问题:一是Loader 链条一旦启动之后,需要所有 Loader 都执行完毕才会结束,没有中断的机会,除非显式抛出异常。二是某些场景下并不需要关心资源的具体内容,但 Loader 需要在 source 内容被读取出来之后才会执行。不过loader响应也给出了pitch,达到阻断的作用。

Q3:有没有接触过 Less、Sass、Stylus 这一类CSS 预编译框架?如何在Webpack接 跳入这些工具?

A3:有接触过,跳入的话其实跟css差不多,也是用的一些loader。这个在上一篇讲到了。

好了,回归今天的内容。

处理字体图标资源

字体图标这里的话不用下载loader,只需要引入使用然后配置就行了。

配置

image.png

处理其他资源

处理其他资源如音视频等可以在处理字体图标资源基础上增加其他文件类型,统一处理即可。

image.png

处理 js 资源

有人可能会问,js 资源 Webpack 不能已经处理了吗,为什么我们还要处理呢?

原因是 Webpack 对 js 处理是有限的,只能编译 js 中 ES 模块化语法,不能编译其他语法,导致 js 不能在 IE 等浏览器运行,所以我们希望做一些兼容性处理。

其次开发中,团队对代码格式是有严格要求的,我们不能由肉眼去检测代码格式,需要使用专业的工具来检测。

  • 针对 js 兼容性处理,我们使用 Babel 来完成
  • 针对代码格式,我们使用 Eslint 来完成

我们先完成 Eslint,检测代码格式无误后,在由 Babel 做代码兼容性处理

Eslint

可组装的 JavaScript 和 JSX 检查工具。它是用来检测 js 和 jsx 语法的工具,可以配置各项功能

我们使用 Eslint,关键是写 Eslint 配置文件,里面写上各种 rules 规则,将来运行 Eslint 时就会以写的规则对代码进行检查。

1. 配置文件

配置文件由很多种写法:

  • .eslintrc.*:新建文件,位于项目根目录。.eslintrc,.eslintrc.js.eslintrc.json都可以,他们的区别在于配置格式不一样。

  • package.json 中 eslintConfig:不需要创建文件,在原有文件基础上写

ESLint 会查找和自动读取它们,所以以上配置文件只需要存在一个即可

2. 具体配置

我们以 .eslintrc.js 配置文件为例:

module.exports = {
  // 解析选项
  parserOptions: {},
  // 具体检查规则
  rules: {},
  // 继承其他规则
  extends: [],
  // ...
};

其他规则详见:eslint.bootcss.com/docs/user-g…

接下来我们按照每一个具体展开:

1、首先是 parserOptions 解析选项

parserOptions: {
  ecmaVersion: 6, // ES 语法版本
  sourceType: "module", // ES 模块化
  ecmaFeatures: { // ES 其他特性
    jsx: true // 如果是 React 项目,就需要开启 jsx 语法
  }
}

2、接着是rule具体规则

  • "off" 或 0:关闭规则
  • "warn" 或 1:开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • "error" 或 2:开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
rules: {
 semi: "error", // 禁止使用分号
 'array-callback-return': 'warn', // 强制数组方法的回调函数中有 return 语句,否则警告
 'default-case': [
   'warn', // 要求 switch 语句中有 default 分支,否则警告
   { commentPattern: '^no default$' } // 允许在最后注释 no default, 就不会有警告了
 ],
 eqeqeq: [
   'warn', // 强制使用 === 和 !==,否则警告
   'smart' // https://eslint.bootcss.com/docs/rules/eqeqeq#smart 除了少数情况下不会有警告
 ],
}

更多规则详见:规则文档

3、extends 继承

开发中一点点写 rules 规则太费劲了,所以有更好的办法,继承现有的规则。 现有以下较为有名的规则:

例如在React项目中,我们可以这么写

image.png

3. 在 Webpack 中使用

1、下载包

npm i eslint-webpack-plugin eslint -D

2、定义 Eslint 配置文件

对于.eslintrc.js

image.png

3、配置

webpack.config.js文件

image.png 运行后在控制台查看 Eslint 检查效果

4、 插件

其实已经有这一类的插件了,比如vscode里面的Eslint 插件。打开 VSCode,下载 Eslint 插件,即可不用编译就能看到错误,可以提前解决。但是此时就会对项目所有文件默认进行 Eslint 检查了,我们 dist 目录下的打包后文件就会报错。但是我们只需要检查 src 下面的文件,不需要检查 dist 下面的文件。

所以可以使用 Eslint 忽略文件解决。在项目根目录新建下面文件:

  • .eslintignore
# 忽略dist目录下所有文件
dist

Babel

是JavaScript 编译器。主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

1. 配置文件

配置文件由很多种写法:

  • babel.config.*:新建文件,位于项目根目录

    • babel.config.js
    • babel.config.json
  • .babelrc.*:新建文件,位于项目根目录

    • .babelrc
    • .babelrc.js
    • .babelrc.json
  • package.json 中 babel:不需要创建文件,在原有文件基础上写

Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可。

2. 具体配置

我们以 babel.config.js 配置文件为例:

image.png

presets 预设:简单理解:就是一组 Babel 插件, 扩展 Babel 功能。

  • @babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。
  • @babel/preset-react:一个用来编译 React jsx 语法的预设
  • @babel/preset-typescript:一个用来编译 TypeScript 语法的预设

3. 在 Webpack 中使用

1、 下载包

npm i babel-loader @babel/core @babel/preset-env -D

2、 定义 Babel 配置文件

babel.config.js image.png

3、配置

image.png

在main.js里面随便写一个箭头函数,运行后打开打包后的 dist/static/js/main.js 文件查看,会发现箭头函数等 ES6 语法已经转换了。

问题2:

Q1: Babel 具体有什么功能?

A1:是JavaScript 编译器。主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

Q2: Babel与Webpack分别解决了什么问题?为何两者能协作到一起了?

A2:webpack和babel通常配合起来使用, babel是js编译工具,能将es6或者一些特殊语法做一些转换,只做文件转义,不做文件整合。而webpack是一个打包工具,内置只能处理js,但是它可以加载很多的loader处理css,img,ts,vue等其他文件,最终输出js文件。且webpac可以通过使用babel-loader使用Babel

参考资料:

Babel-loader

Babel 官网

@babel/preset-env

@babel/preset-react

@babel/preset-typescript

处理 Html 资源

1. 下载包

npm i html-webpack-plugin -D

2. 配置

webpack.config.js文件

image.png

image.png

此时可以在index.html去掉引入的 js 文件,因为 HtmlWebpackPlugin 会自动引入。运行后 dist 目录就会输出一个 index.html 文件。

问题3:

Q:相比于手工维护 HTML 内容,这种自动生成的方式有什么优缺点?

A:优点是打包完之后会自动生成HTML文件,并自动引入打包后的js文件。缺点是可能会不太灵活,如果是我们平时自己写的话其实可以随便插入一些代码片段,但是HtmlWebpackPlugin的话其实是以一个指定模板来的,所以面对一些比较复杂的东西可能得考虑很多。

参考资料:

html-webpack-plugin

插播一个webpack的工具线: image.png


热模块替换

即Hot Module Replacement,写的代码会被立刻更新到浏览器上。

1.开启HMR

module.exports={ 
    // ... 
    devServer: { 
        hot:true; // 必需 
    } 
};

2. 启动webpack

这次不再是npx webpack,而是

npx webpack serve

image.png 图源范文杰老师

原理可参考:Webpack 原理系列十:HMR 原理全解析

Tree-Shaking

指的树摇,用于删除Dead Code。那么什么叫Dead Code?就是一些代码没有被用到,不可到达;或者代码的执行结果不会被用到;或者代码只读不写等。在Tree-Shaking这一块,经常用于模块导出了,但未被其他模块使用的情况,如下图。

image.png
那我们怎么开启Tree-Shaking?

设置mode: “production”以及optimization: {usedExports: true},我们看刚刚那个例子的执行结果,在main.js里面,可以看到只有用到的模块在里面。

image.png

其他工具

其实还有很多工具,这里就不一一介绍了,具体的话有缓存、Sourcemap、性能监控、日志、代码压缩以及分包相关的工具。那就留下几个问题作为下次的开篇吧!

问题4

1、除上面提到的内容,还有哪些配置可划分为“流程类”配置?

2、工具类配置具体有什么作用?包括devtool/cache/stat

好了,今天的笔记就先到这里。最后的最后,谢谢大家这么厉害还来看我,如果发现问题或者需要补充的点麻烦大家通过评论告诉我。博取众长,共同进步!