webpack学习之路(实践篇)
前言
在上篇 《学习 Webpack5 之路(基础篇)》
中介绍了 Webpack 是什么,为什么选择 Webpack,Webpack 的基本概念介绍 3 个问题。
本篇将从实践出发,在第一章节《基础配置》中使用 webpack 搭建一个基础的支持模块化开发的项目,在第二章节《进阶配置》中使用 webpack 搭建一个 SASS + TS + React 的项目。
本文依赖的 webpack 版本信息如下:
webpack-cli@4.7.2
webpack@5.46.0
一、基础配置
接下来一起配置一个基础的 Webpack。
将支持以下功能:
分离开发环境、生产环境配置;
模块化开发;
sourceMap 定位警告和错误;
动态生成引入 bundle.js 的 HTML5 文件;
实时编译;
封装编译、打包命令。
想直接看配置的同学 -> 本文源码地址:webpack Demo0
新建项目
新建一个空项目:
1 | // 新建 webpack-demo 文件夹 |
新建 2 个 js 文件,并进行模块化开发:
1 | // 进入项目目录 |
index.js
:
1 |
|
hello.js
:
1 | // hello.js |
项目结构如下:
1 | - src |
安装
安装 Node
Node 需要是最新版本,推荐使用 nvm 来管理 Node 版本。
将 Node.js 更新到最新版本,也有助于提高性能。除此之外,将你的 package 管理工具(例如 npm 或者 yarn)更新到最新版本,也有助于提高性能。较新的版本能够建立更高效的模块树以及提高解析速度。我安装的版本信息如下:
node v14.17.3
npm v6.14.13)安装 webpack
1
npm install webpack webpack-cli --save-dev
新建配置文件
development
(开发环境) 和 production
(生产环境) 这两个环境下的构建目标存在着巨大差异。为代码清晰简明,为每个环境编写彼此独立的 webpack 配置。
1 | // 进入项目目录 |
webpack-merge
使用 webpack-marge
合并通用配置和特定环境配置。
安装 webpack-merge
:
1 | npm i webpack-merge -D |
通用环境配置
:
1 | // webpack.common.js |
开发环境配置
:
1 | // webpack.dev.js |
生产环境配置
:
1 | // webpack.prod.js |
项目结构如下:
1 | - config |
入口(entry)
入口起点(entry point) 指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
在本例中,使用 src/index.js
作为项目入口,webpack 以 src/index.js 为起点,查找所有依赖的模块。
修改 webpack.commom.js
:
1 | module.exports = merge(common, { |
输出(output)
output
属性告诉 webpack
在哪里输出它所创建的 bundle,以及如何命名这些文件。
生产环境的 output 需要通过 contenthash 值来区分版本和变动,可达到清缓存的效果,而本地环境为了构建效率,则不引人 contenthash。
新增 paths.js,封装路径方法:
1 | const fs = require('fs') |
修改开发环境配置文件 webpack.dev.js
:
1 | module.exports = merge(common, { |
修改生产环境配置文件 webpack.prod.js
:
1 | module.exports = merge(common, { |
上述 filename 的占位符解释如下:
[name]
- chunk name(例如 [name]
.js -> app.js)。如果 chunk 没有名称,则会使用其 id 作为名称[contenthash]
- 输出文件内容的 md4-hash(例如 [contenthash]
.js -> 4ea6ff1de66c537eb9b2.js)
模式(mode)
选项 | 描述 |
---|---|
development |
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development . 为模块和 chunk 启用有效的名。 |
production |
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production 。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin ,FlagIncludedChunksPlugin ,ModuleConcatenationPlugin ,NoEmitOnErrorsPlugin 和 TerserPlugin 。 |
通过 mode 配置选项,告知 webpack
使用相应模式的内置优化。
修改开发环境配置文件 webpack.dev.js
:
1 | module.exports = merge(common, { |
修改生产环境配置文件 webpack.prod.js
:
1 | module.exports = merge(common, { |
Source Map
当 webpack
打包源代码时,可能会很难追踪到 error
和 warning
在源代码中的原始位置。
为了更容易地追踪 error
和 warning
,JavaScript
提供了 source maps
功能,可以将编译后的代码映射回原始源代码。
修改开发环境配置文件 webpack.dev.js
:
1 |
|
source map
有许多 可用选项。本例选择的是 eval-cheap-module-source-map
注:为加快生产环境打包速度,不为生产环境配置 devtool
。
完成上述配置后,可以通过 npx webpack --config config/webpack.prod.js
打包编译。
编译后,会生成这样的目录结构:
HtmlWebpackPlugin
npx webpack --config config/webpack.prod.js
后仅生成了 bundle.js
,我们还需要一个 HTML5 文件,用来动态引入打包生成的 bundle 文件。
引入 HtmlWebpackPlugin
插件,生成一个 HTML5 文件, 其中包括使用 script 标签的 body 中的所有 webpack
包。
安装:
npm install --save-dev html-webpack-plugin
修改通用环境配置文件 webpack.commom.js
:
1 | module.exports = { |
重新 webpack 编译 npx webpack --config config/webpack.prod.js
,生成的目录结构如下:
新生成了 index.html
,动态引入了 bundle.js
文件:
1 |
|
DevServer
在每次编译代码时,手动运行 npx webpack --config config/webpack.prod.js
会显得很麻烦,webpack-dev-server
帮助我们在代码发生变化后自动编译代码。webpack-dev-server
提供了一个基本的 web server
,并且具有实时重新加载功能。webpack-dev-server
默认配置 conpress: true
,为每个静态文件开启 gzip compression
。
安装:npm install --save-dev webpack-dev-server
修改开发环境配置文件 webpack.dev.js
:
1 | module.exports = merge(common, { |
完成上述配置后,可以通过 npx webpack serve --open --config config/webpack.dev.js
实时编译。
效果如图:
执行命令
上述配置文件完成后,优化 webpack 的实时编译、打包编译指令。
通过 cross-env
配置环境变量,区分开发环境和生产环境。
安装:npm install --save-dev cross-env
修改 package.json
:
1 | { |
现在可以运行 webpack 指令:
npm run dev
:本地构建;npm run build
:生产打包。
以上我们完成了一个基于 webpack
编译的支持模块化开发的简单项目。
源码地址:webpack Demo0
二、进阶配置
本章节将继续完善配置,在上述配置基础上,用 Webpack 搭建一个 SASS + TS + React 的项目。
将支持以下功能:
- 加载图片;
- 加载字体;
- 加载 CSS;
- 使用 SASS;
- 使用 PostCSS,并自动为 CSS 规则添加前缀,解析最新的 CSS 语法,引入 css-modules 解决全局命名冲突问题;
- 使用 React;
- 使用 TypeScript。
想直接看配置的同学 -> 本文源码地址:webpack Demo1
1.加载图片(Image)
在 webpack 5
中,可以使用内置的 Asset Modules,将 images 图像混入我们的系统中。
修改通用环境配置文件 webpack.commom.js
:
1 | const paths = require('./paths'); |
2.加载字体(Font)
使用 Asset Modules
接收字体文件。
修改通用环境配置文件 webpack.commom.js
:
1 | module.exports = { |
在这里我发现,我不新增对 ttf 文件的配置,也能够引入字体不报错,不知道是什么问题,先记录一下,有知道原因的大佬移步评论区。
在实际开发过程中,推荐将字体文件压缩上传至 CDN,提高加载速度。如配置字体的文字是固定的,还可以针对固定的文字生成字体文件,可以大幅缩小字体文件体积。
3.加载 CSS
为了在 JavaScript 模块中 import
一个 CSS 文件,需要安装并配置 style-loader
和 css-loader
。
1.style-loader
style-loader 用于将 CSS 插入到 DOM 中,通过使用多个 <style></style>
自动把 styles
插入到 DOM
中.
2.css-loader
css-loader
对 @import
和 url()
进行处理,就像 js 解析 import/require()
一样,让 CSS 也能模块化开发。
3.安装配置
安装 CSS 相关依赖:
1 | npm install --save-dev style-loader css-loader |
修改通用环境配置文件 webpack.commom.js
:
1 | const paths = require('./paths'); |
4. 使用 SASS
1.Sass
Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量、嵌套、混合、导入等高级功能。
2.sass-loader
sass-loader
加载 Sass/SCSS
文件并将他们编译为 CSS
。
3.安装配置
安装 SASS 相关依赖:
1 | npm install --save-dev sass-loader sass |
修改通用环境配置文件 webpack.commom.js
:
1 | const paths = require('./paths'); |
5.使用 PostCSS
1.PostCSS
PostCSS
是一个用 JavaScript 工具和插件转换 CSS 代码的工具。
可以自动为 CSS 规则添加前缀;
将最新的 CSS 语法转换成大多数浏览器都能理解的语法;css-modules
解决全局命名冲突问题。
2.postcss-loader
postcss-loader
使用 PostCSS 处理 CSS 的 loader。
3.安装配置
安装 PostCSS
相关依赖:
1 | npm install --save-dev postcss-loader postcss postcss-preset-env |
修改通用环境配置文件 webpack.commom.js
:
1 | const paths = require('./paths'); |
为提升构建效率,为 loader
指定 include
,通过使用 include
字段,仅将 loader
应用在实际需要将其转换的模块。
6.使用 React + TypeScript
为了让项目的配置灵活性更高,不使用 create-reate-app
一键搭建项目,而是手动搭建 React
对应的配置项。
安装 React 相关:
1 | npm i react react-dom @types/react @types/react-dom -D |
安装 TypeScript 相关:
1 | npm i -D typescript esbuild-loader |
为提高性能,摒弃了传统的 ts-loader
,选择最新的 esbuild-loader
。
修改通用环境配置文件 webpack.commom.js
:
1 | const paths = require('./paths'); |
TypeScript
是 JavaScript 的超集,为其增加了类型系统,可以编译为普通 JavaScript 代码。
为兼容 TypeScript 文件,新增 typescript 配置文件 tsconfig.json
:
1 | { |
TypeScript 是 JavaScript 的超集,为其增加了类型系统,可以编译为普通 JavaScript 代码。
为兼容 TypeScript 文件,新增 typescript 配置文件 tsconfig.json
:
1 | { |
如果想在 TypeScript 中保留如
import _ from 'lodash';
的语法被让它作为一种默认的导入方式,需要在文件tsconfig.json
中设置"allowSyntheticDefaultImports" : true
和"esModuleInterop" : true
。
注意:这儿有坑
"allowSyntheticDefaultImports": true
配置TypeScript
配置文件tsconfig.json
需要加"allowSyntheticDefaultImports": true
配置,否则会提示can only be default-imported using the 'allowSyntheticDefaultImports' flag。
1
2
3
4
5{
"compilerOptions": {
"allowSyntheticDefaultImports": true
},
}不加
"allowSyntheticDefaultImports": true
的加报错信息如下:tsx 和 jsx 不能混合使用
在 tsx 中引入 jsx 文件报错如下:
以上我们完成了一个基于 webpack 编译的 SASS + TS + React 项目。