持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
1. webpack简介
Webpack 是⼀个现代 JavaScript 应⽤程序的静态模块打包器(module bundler)。当 webpack 处理应⽤程序时,它会递归地构建⼀个依赖关系图(dependency graph),其中包含应⽤程序需要的每个模块,然后将所有这些模块打包成⼀个或多个 bundle。
Webpack是⼀个打包模块化JavaScript的⼯具,它会从⼊⼝模块出发,识别出源码中的模块化导⼊语句,递归地找出⼊⼝⽂件的所有依赖,将⼊⼝和其所有的依赖打包到⼀个单独的⽂件中。
是⼯程化、⾃动化思想在前端开发中的体现。
2. webpack 安装
环境准备
- nodeJs :nodejs.org/en/
版本参考官⽹发布的最新版本,可以提升webpack的打包速度。
安装⽅式
- 局部安装(推荐)
npm init -y # 初始化npm配置⽂件
npm install --save-dev webpack # 安装核⼼库
npm install --save-dev webpack-cli # 安装命令⾏⼯具
安装指定版本 npm i -D webpack@<version>
- 全局安装(不推荐)
# 安装webpack V4+版本时,需要额外安装webpack-cli
npm install webpack webpack-cli -g
# 检查版本
webpack -v
# 卸载
npm uninstall webpack webpack-cli -g
全局安装webpack,这会将你项⽬中的webpack锁定到指定版本,造成不同的项⽬中因为webpack依赖不同版本⽽导致冲突,构建失败。
3. 启动webpack
webpack默认配置
- webpack 默认⽀持 JS 模块和 JSON 模块
- ⽀持 CommonJS Es moudule AMD 等模块类型
- webpack ⽀持零配置使⽤, 但是很弱,稍微复杂些的场景都需要额外扩展
准备执⾏构建
- 新建src⽂件夹
- 新建src/index.js、src/index.json、src/other.js
// index.js
const json = require("./index.json"); //commonJS
import { add } from "./other.js"; //es module
console.log(json, add(2, 3));
// index.json
{
"name": "JSON"
}
// other.js
export function add(n1, n2) {
return n1 + n2;
}
执⾏构建
# npx⽅式
npx webpack
# npm script
npm run test
修改package.json⽂件:
"scripts": {
"test": "webpack"
},
原理就是通过shell脚本在node_modules/.bin⽬录下创建⼀个软链接。
构建成功
我们会发现⽬录下多出⼀个 dist ⽬录,⾥⾯有个 main.js ,这个⽂件是⼀个可执⾏的JavaScript⽂件,⾥⾯包含 webpackBootstrap 启动函数。
默认配置
const path = require("path");
module.exports = {
// 必填 webpack执⾏构建⼊⼝
entry: "./src/index.js",
output: {
// 将所有依赖的模块合并输出到main.js
filename: "main.js",
// 输出⽂件的存放路径,必须是绝对路径
path: path.resolve(__dirname, "./dist")
}
};
4. webpack配置核⼼概念
- chunk:指代码块,⼀个 chunk 可能由多个模块组合⽽成,也⽤于代码合并与分割。
- bundle:资源经过Webpack 流程解析编译后最终结输出的成果⽂件。
- entry:顾名思义,就是⼊⼝起点,⽤来告诉webpack⽤哪个⽂件作为构建依赖图的起点。webpack会根据entry递归的去寻找依赖,每个依赖都将被它处理,最后输出到打包成果中。
- output:output配置描述了webpack打包的输出配置,包含输出⽂件的命名、位置等信息。
- loader:默认情况下,webpack仅⽀持 .js .json ⽂件,通过loader,可以让它解析其他类型的⽂件,充当翻译官的⻆⾊。理论上只要有相应的loader,就可以处理任何类型的⽂件。
- plugin:loader主要的职责是让webpack认识更多的⽂件类型,⽽plugin的职责则是让其可以控制构建流程,从⽽执⾏⼀些特殊的任务。插件的功能⾮常强⼤,可以完成各种各样的任务。
webpack.config.js 配置基础结构
module.exports = {
entry: "./src/index.js", //打包⼊⼝⽂件
output: "./dist", //输出结构
mode: "production", //打包环境
module: {
rules: [
//loader模块处理
// webpack5中, 使用MiniCssExtractPlugin.loader代替style-loader
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
// webpack5 识别静态文件
test: /.(svg|eot|ttf|woff)$/,
type: 'asset/resource',
},
]
},
plugins: [new HtmlWebpackPlugin()] //插件配置
};
entry:
指定webpack打包⼊⼝⽂件。Webpack 执⾏构建的第⼀步将从 entry 开始,可抽象成输⼊:
// 单⼊⼝ SPA,本质是个字符串
entry:{
main: './src/index.js'
}
// ==相当于简写===
entry:"./src/index.js"
// 多⼊⼝ entry是个对象
entry:{
index:"./src/index.js",
login:"./src/login.js"
}
output:
打包转换后的⽂件输出到磁盘位置。在 Webpack 经过⼀系列处理并得出最终想要的代码后输出结果。
output: {
filename: "bundle.js",//输出⽂件的名称
path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
},
//多⼊⼝的处理
output: {
filename: "[name][chunkhash:8].js",//利⽤占位符,⽂件名称不要重复
path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
},
mode
mode ⽤来指定当前的构建环境
- production
- development
- none
设置mode可以⾃动触发webpack内置的函数,达到优化的效果, 开发阶段的开启会有利于热更新的处理,识别哪个模块变化;⽣产阶段的开启会有帮助模块压缩,处理副作⽤等⼀些功能。
loader
模块转换器。⽤于把模块原内容按照需求转换成新内容。webpack是模块打包⼯具,⽽模块不仅仅是js,还可以是css,图⽚或者其他格式。但是webpack默认只知道如何处理js和JSON模块,那么其他格式的模块处理,和处理⽅式就需要loader了。
常⻅的loader:
style-loader
css-loader
less-loader
sass-loader
ts-loader //将Ts转换成js
babel-loader //转换ES6、7等js新特性语法
file-loader //处理图⽚⼦图
eslint-loader
...
moudle
在 Webpack ⾥⼀切皆模块,⼀个模块对应着⼀个⽂件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。当webpack处理到不认识的模块时,需要在webpack中的module处进⾏配置,当检测到是什么格式的模块,使⽤什么loader来处理。
loading可以是一个数组,['style-loader', 'css-loader'],解析顺序从右至左。
module:{
rules:[
{
test:/\.xxx$/,//指定匹配规则
use:{
loader: 'xxx-load'//指定使⽤的loader
}
}
]
}
Plugins:webpack的扩展补充
作⽤于webpack打包整个过程。plugin 可以在webpack运⾏到某个阶段的时候,帮你做⼀些事情,类似于⽣命周期的概念。
- HtmlWebpackPlugin
在打包结束后,⾃动⽣成⼀个html⽂件,并把打包⽣成的js模块引⼊到该html中:
const path = require("path");
const htmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
...
plugins: [
new htmlWebpackPlugin({
title: "My App",
filename: "app.html",
template: "./src/index.html"
})
]
};
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
配置项解释
- title: ⽤来⽣成⻚⾯的 title 元素
- filename: 输出的 HTML ⽂件名,默认是 index.html, 也可以直接配置带有⼦⽬录。
- template: 模板⽂件路径,⽀持加载器,⽐如 html!./index.html
- inject: true | 'head' | 'body' | false ,注⼊所有的资源到特定的 template 或者templateContent 中,如果设置为 true 或者 body,所有的 javascript 资源将被放置到 body元素的底部,'head' 将放置到 head 元素中。
- favicon: 添加特定的 favicon 路径到输出的 HTML ⽂件中。
- minify: {} | false , 传递 html-minifier 选项给 minify 输出
- hash: true | false, 如果为 true, 将添加⼀个唯⼀的 webpack 编译 hash 到所有包含的脚本和CSS ⽂件,对于解除 cache 很有⽤。
- cache: true | false,如果为 true, 这是默认值,仅仅在⽂件修改之后才会发布⽂件。
- showErrors: true | false, 如果为 true, 这是默认值,错误信息会写⼊到 HTML ⻚⾯中
- chunks: 允许只添加某些块 (⽐如,仅仅 unit test 块)
- chunksSortMode: 允许控制块在添加到⻚⾯之前的排序⽅式,⽀持的值:'none' | 'default' | {function}-default:'auto'
- excludeChunks: 允许跳过某些块,(⽐如,跳过单元测试的块)
- clean-webpack-plugin
如何做到dist⽬录下某个⽂件或⽬录不被清空: 使⽤配置项:cleanOnceBeforeBuildPatterns:
cleanOnceBeforeBuildPatterns: ["/*", "!dll", "!dll/"]
!感叹号相当于exclude 排除,意思是清空操作排除dll⽬录,和dll⽬录下所有⽂件。 注意:数组列表⾥的“/*”是默认值,不可忽略,否则不做清空操作。
5. WebpackDevServer
提升开发效率的利器。每次改完代码都需要重新打包⼀次,打开浏览器,刷新⼀次,很麻烦,我们可以安装使⽤webpackdevserver来改善这块的体验。
npm install webpack-dev-server@3.11.0 -D
修改下package.json
"scripts": {
"server": "webpack-dev-server"
},
配置 webpack.config.js:
devServer: {
contentBase: "./dist",
open: true,
port: 8081,
hot: true,
// 热更新模块
hotOnly:true
},
启动
npm run server
启动服务后,会发现dist⽬录没有了,这是因为devServer把打包后的模块不会放在dist⽬录下,⽽是放到内存中,从⽽提升速度。
webpack5 与 4.x 区别
wp5升级后的新特性,官方说法如下:
- 通过持久化缓存提高性能,采用更好的持久化缓存算法和默认行为
- 内置了 terser-webpack-plugin 插件;
- 合并模块:optimization.concatenateModules = true;
- 内置缓存
cache: {
type: 'filesystem',
// 默认缓存到 node_modules/.cache/webpack 中
// 1. 可以自定义缓存目录,cache.cacheDirectory 选项仅当 cache.type 被设置成 filesystem 才可用。
cacheDirectory:path.resolve(__dirname,'node_modules/.cac/webpack')
buildDependencies : {
// 2. 将配置添加为 buildDependency 以使配置更改时缓存失效
config : [__filename]
// 3. 如果您有其他构建所依赖的东西你可以在这里添加它们
// 请注意,webpack、加载器和从你的配置中引用的所有模块都会自动添加
}
}
- 通过优化 Tree Shaking 和代码生成来减小Bundle体积
- Webpack 4 不会去分析导入和导出模块之间的依赖关系;Webpack5 里面会通过 optimization.innerGraph记录依赖关系,对于嵌套依赖模块有更好的效果。
- 可设置副作用 sideEffects 处理优化;
- 可以同时支持 ESM 和 commonJS 的 treeShaking。
- 提高 Web 平台的兼容性
- 清除之前为了实现 Webpack4 没有不兼容性变更导致的不合理 state
- loader优化(内置静态资源构建)
- raw-loader 将文件导入为字符串
- url-loader 将文件作为 data url 内联到 bundle文件中
- file-loader 将文件发送到输出目录中
- asset/resource 替换 file-loader (发送单独文件)
- asset/inline 替换 url-loader (导出 url)
- asset/source 替换 raw-loader(识别资源文件)
- MinicssExtractPlugin.loader 替换 style-loader
- 其他
- 内置使用 webpack serve 启动;
- webpack 可以实现 应用程序和应用程序之间的引用(微前端);
- 热更新配置项修改;
- Webpack 生成的代码不再仅仅是ES5,也会生成 ES6 的代码;
- Node.js 的最小支持版本从 6 升级到了 10