本文使用的webpack版本为 4.46.0
目录
1、安装webpack及其脚手架
首先在工作目录使用npm init
生成package.json
,再运行以下命令下载webpack
和webpack-cli
(使用脚本命令运行webpack必须的脚手架工具)。
npm i -D webpack@4 webpack-cli@3
在当前目录创建webpack.config.js
文件,做如下配置:
const { resolve } = require("path");
module.exports = {
entry: "main.js", // 入口文件
output: {
path: "dist", // 打包文件夹名称
filename: "js/bundle.js", // 打包后的文件相对路径(相对于path)
},
mode: "development", // 打包模式,分为 production(生产模式) 和 development(开发模式)
};
然后在package.json
中配置脚本命令:
"scripts": {
"build": "webpack"
}
这时在main.js
中写代码,运行npm run build
即可打包文件。如果提示webpack
的错误信息,则可尝试全局安装webpack
。
npm i -g webpack@4
2、安装webpack-dev-server启动服务器
webpack-dev-server
可以启动一个服务器,具有实时更新代码、自动打开浏览器等功能。
npm i -D webpack-dev-server@3
安装完毕后,在webpack.config.js
的module.exports
中添加如下代码:
devServer: {
open: true, // 自动打开默认浏览器,
compress: true, // 启动 gzip 压缩
port: 3000, // 启动的服务器端口号
clientLogLevel: true, // 取消服务器运行时的控制台打印信息
}
然后在package.json
的scripts
中添加:
"dev": "webpack-dev-server --progress --color" // --progress 用于显示编译进度 --color 运行编译时关键字用不同颜色表示
运行npm run dev
即可打开默认浏览器运行http://localhost:3000
。
3、使用html-webpack-plugin生成index.html文件
webpack
默认只打包js文件,在单页面程序中我们通常需要一个index.html
文件,这个文件可以使用html-webpack-plugin
生成。
npm i -D html-webpack-plugin@3
在webpack.config.js
中写入如下代码:
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 引入插件
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: resolve(__dirname, "public/index.html"), // index.html模板路径,如果不提供则默认生成一个空的 index.html 文件
filename: "index.html", // 生成的html文件名,默认为index.html
favicon: resolve(__dirname, "public/favicon.ico"), // ico图标路径
title: "studying webpack~~", // 自定义的一些属性,在 index.html 模板中可以通过 htmlWebpackPlugin.options.title 访问,类似 vue 的$options
})
]
};
html-webpack-plugin
默认提供ejs
语法解析。因此可以在index.html
模板中使用ejs
语法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 使用 ejs 语法 -->
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
<!-- 因为最终运行的是 webpack 打包后的代码,所以此处要得到打包后的路径 -->
<img src="<%= require('../imgs/cute.jpg').default %>" alt="image load error" />
</body>
</html>
也可以将index.html
模板替换成index.ejs
。
4、打包css、scss、less文件
打包css
文件需要用到两个loader
,分别是css-loader
和style-loader
。前一个用于解析css
文件,后一个用于生成一个style
标签插入head
标签。
npm i -D css-loader@5 style-loader@2
在webpack.config.js
的module.exports
中加入:
module: {
rules: [
{
test: /\.css$/, // 匹配到css文件
use: ["style-loader", "css-loader"]
}
]
}
如果要解析sass
和less
文件,则需要下载sass
、less
以及对应的loader
,将sass
和less
语法转化成css
。
npm i sass@1 sass-loader@10 less@2 less-loader@7
在webpack.config.js
的module.exports
中加入:
module: {
rules: [
{
test: /\.less$/, // 匹配到less文件
use: ["style-loader", "css-loader", "less-loader"]
},
{
test: /\.s[ac]ss$/, // 匹配到.sass文件和.scss文件
use: ["style-loader", "css-loader", "sass-loader"]
}
]
}
5、打包图片
图片通常出现在背景或者img
标签中,这里主要打包背景图片。使用url-loader
解析background
的url
属性。
npm i -D url-loader@4 file-loader@6 // 注意:由于 url-loader 基于 file-loader,所以两个都要下载
在webpack.config.js
的module.exports
中加入:
module: {
rules: [
{
test: /\.(jpg|jpeg|png|gif)$/i, // 匹配到图片文件
loader: "url-loader",
options: {
limit: 3 * 1024, // 设置一个文件大小上限,低于这个大小会被转化成base64格式,单位为字节
outputPath: "assets/imgs/", // 打包输出路径
name: "[name].[contenthash:10].[ext]", // 打包后的文件名 其中 [name]表示源文件名,contenthash表示根据文件内容生成的哈希值,:10表示取10位,[ext]表示文件扩展名
}
}
]
}
6、打包其他文件
其余文件可以通过file-loader
打包。
module.exports = {
rules: [
{
exclude: /\.(js|html|css|scss|sass|less|png|jpg|jpeg|gif)$/i,
loader: "file-loader",
options: {
outputPath: "static",
name: "[name].[contenthash:10].[ext]"
}
}
]
};
7、打包时自动清除上次打包后的文件
打包后通常需要去掉上次打包后生成的文件,否则每次打包后都会新增一批文件会导致打包后的文件越来越多。使用clean-webpack-plugin
解决这个问题。
npm i -D clean-webpack-plugin@2
在webpack.config.js
中加入:
const CleanWebpackPlugin = require("clean-webpack-plugin");
module.exports = {
plugins: [
new CleanWebpackPlugin() // 默认情况下清除 output.path 中设置的文件夹路径中的文件
]
};
8、css兼容性处理
css兼容性处理使用postcss-loader
和autoprefixer
。
npm i -D postcss-loader@4 autoprefixer@10
然后需要指定适配的浏览器范围,指定方式有多种,常见的有在package.json
中添加browserslist
字段(官方推荐)和添加.browserslistrc
文件两种方式。
// package.json文件 逗号表示或者,也可用 or 表示,and表示并且,not表示排除这个版本
"browserslist": {
"development": [ // 开发环境
"last 1 chrome version", // 最近的一个chrome版本,下同
"last 1 firefox version",
"last 1 edge version"
],
"production": [ // 生产环境
"> 0.2%", // 用户比例不小于 0.2%
"not dead", // 最近24个月内官方更新过的浏览器,注意 not dead 不能写在开头
"ie >= 9" // ie浏览器的版本最低为ie9
]
}
或者:
# .browserslistrc文件,使用#表示注释,换行表示或者,其余同上
[development] # 开发环境
last 1 chrome version
last 1 firefox version
last 1 edge version
[production] # 生产环境
> 0.2%
not dead
ie >= 9
查看browserslist
配置是否成功可以通过命令npx browserslist
检查,如果成功则会输出符合条件的浏览器版本。其余配置可看browserslist;
最后在webpack.config.js
添加如下内容,注意要在调用css-loader
前,sass-loader
或者less-loader
后。
// 以 css 为例,sass-loader、less-loader相同
module.exports = {
module: {
rules: [
test: /\.css$/,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["autoprefixer"]
}
}
}
]
]
}
};
其中postcss-loader
的postcssOptions
配置可以用postcss.config.js
文件替换:
// postcss.config.js文件
module.exports = {
plugins: ["autoprefixer"]
};
9、js兼容性处理
js兼容性处理使用babel
,需要下载babel-loader
、@babel/core
、@babel/preset-env
、core-js
。其中babel-loader
用于解析babel
、@babel/core
是babel
的核心库,@babel/preset-env
是用于指定浏览器环境,core-js
库则是自定义的一些方法等。
npm i babel-loader@8 @babel/core@7 @babel/preset-env@7 core-js@3
首先需要指定浏览器环境,有两种方法,一种是和css一样通过browserslist
指定(即package.json中的browserslist
或者.browserslistrc
文件),令一种方式是通过targets
指定。
在webpack.config.js
中添加以下内容:
// 入口文件方式
module.exports = {
module: {
rules: [
{
test: /\.js$/,
{
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "entry", // 指定babel处理polyfill的方式是根据入口文件
corejs: 3, // 必须指定corejs版本,和安装版本一致
}
]
]
}
}
}
]
}
};
// targets方式
module.exports = {
module: {
rules: [
{
test: /\.js$/,
{
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage",
corejs: 3, // 必须指定corejs版本,和安装版本一致
targets: { // 指定浏览器最低版本,
chrome: 60,
ie: 9,
edge: 17
}
// 也可以和browserslist一样
// targets: ">= 0.2%, not dead"
}
]
]
}
}
}
]
}
};
如果useBuiltIns
的值是entry
,表明是从入口文件main.js
引入polyfill
,这时需要在入口文件main.js
中按需引入自定义方法(不推荐)。例如只需要数组方法:
import "core-js/es/array";
以此类推。详细用法可看官网。
10、eslint的配置
首先安装eslint
、eslint-loader
。
npm i -D eslint@7 eslint-loader@4
然后需要指定eslint
的规则,通常使用一个已经配置好的规则,这里使用airbnb
。安装airbnb
的规则集和对应的包。
npm i -D eslint-config-airbnb-base@14 eslint-plugin-import@2
然后配置eslint
。首先在webpack.config.js
中配置eslint-loader
。
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: "eslint-loader",
enforce: "pre", // 优先执行 eslint-loader
options: {
fix: true // 根据eslint规则尝试自动修复
}
}
]
}
};
然后需要配置eslint
的规则。配置方式有两种,一种是在package.json
中添加eslintConfig
字段,一种是将规则写在.eslintrc
文件中。
// package.json
"eslintConfig": {
"extends": "aribnb-base",
"rules": {
// 自定义规则,可以覆盖 aribnb-base 中的规则
"quotes": ["warn", "double"] // 配置引号为双引号,并提供警告信息
}
}
// .eslintrc
{
"extends": "aribnb-base",
"rules": {
// 自定义规则,可以覆盖 aribnb-base 中的规则
"quotes": ["warn", "double"] // 配置引号为双引号,并提供警告信息
}
}
注意.eslintrc
相当于把package.json
中的eslint
配置抽离出来。所以两者几乎等价。
接下来简单介绍一点eslint
的配置。
1、关闭eslint
关闭eslint
分为几种情况,一种是针对文件,如果要对某些文件不使用eslint
检查,有以下几种方法:
- 在文件的最上方的注释写上
eslint-disable
- 设置文件白名单
/* eslint-disable */
// 注意如果使用注释的方式关闭 eslint ,则在注释内部的部分会被 eslint 解析,此时如果想添加说明则需要使用 -- 开头,如下
/* eslint-disable -- 我是eslint注释 */
设置文件白名单,有多种方法,下面介绍两种:
- 在配置中添加
ignorePatterns
字段,值为一个字符串数组,每个元素是文件路径 - 在
.eslintignore
文件中添加要忽略的文件路径
// 如果是配置文件
{
"extends": "aribnb-base",
"rules": {
// 自定义规则,可以覆盖 aribnb-base 中的规则
"quotes": ["warn", "double"] // 配置引号为双引号,并提供警告信息
},
"ignorePatterns": ["a.js", "**/verdor/*.js"]
}
# 如果是 .eslintignore 文件,直接添加文件路径即可,注意这里注释使用 # 开头
a.js
**/verdor/*.js
上面两种方法等价。此外需要注意node_modules
和以 . 开头的文件(如.eslintrc)或文件夹(如.build)
都默认添加到白名单中。
有时候也需要对一部分代码规避eslint
检查,这时可以使用eslint-disable
和eslint-enable
。
/* eslint-disable */
// 这中间的代码都不被检查
/* eslint-enable */
也可以使用eslint-disable-nextline
对下一行代码规避eslint
检查。
// eslint-disable-nextline
console.log("hello, world~"); // 这行代码不会被 eslint 检查
或者对当前行规避eslint
检查。
alert('foo'); // eslint-disable-line -- 这行代码不会被 eslint 检查
也可以指定关闭的规则,例如不需要检查alert
,则需要关闭no-alert
规则。
/* eslint-disable no-alert */
// 这中间的代码都不被检查
alert("hello, world~");
/* eslint-enable no-alert */
// eslint-disable-nextline no-alert
alert("hello, world~"); // 这行代码不会被 eslint 检查
2、手动添加规则
手动添加规则如上,在rules
中加入对应规则名和检查方式即可。
"eslintConfig": {
"rules": {
"quotes": ["warn", "double"]
}
}
上述代码是对quotes(引号)
做了定义,规定只能使用双引号(double
),并且报错级别为警告
。
注意规则名对应的值通常为一个数组,第一项和第二项为字符串,第三项为一个对象。
第一项可选值有off(或者0)
、warn(或者1)
、error(或者2)
,分别表示关闭此规则、不符合规则打印警告和不符合规则打印错误信息。第二项为每个规则对应的可选项,例如这里double
表示双引号,single
表示单引号,backtick
表示使用模板字符串。第三项可以填写{ "allowTemplateLiterals": true }
表示同时允许使用模板字符串。
例如:配置引号规则为使用单引号且可以使用模板字符串,提示信息为警告
"eslintConfig": {
"rules": {
"quotes": ["warn", "single", { "allowTemplateLiterals": true }]
}
}
3、指定ECMA环境
eslint
默认识别es5
的语法,如果要识别新的语法例如??
需要重新指定es
环境。
因为eslint
也可用于node
,所以还可以指定环境为浏览器。
// 在package.json中
"eslintConfig": {
"env": {
"browser": true, // 指定浏览器环境
"ecmaVersion": "latest" // 指定ECMA环境为最近的一个版本
}
}
更多详细的配置可以看eslint官网。
11、打包css到文件夹
前面我们使用style-loader
生成一个style
标签来存放css
代码,但这样可能造成一个问题,由于这样css代码
实际是打包到js
文件中,即每次加载的时候都需要先加载完js
文件才能加载css
,这样如果js
文件加载失败样式也无法渲染,且浏览器生成渲染树是需要生成DOM
和生成css渲染树
都执行完毕后,再将css渲染树
和DOM树
合并成渲染树,因此css渲染树
的生成通常应该是和DOM
树的合成并行执行。综上,在生产环境通常把css
单独抽离出来,用link
引入。使用mini-css-extract-plugin
可以实现这个效果。
npm i -D mini-css-extract-plugin@4
// webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
],
plugins: [
new MiniCssExtractPlugin({
filename: "css/main.css"
})
]
}
};
12、压缩css
生产环境需要压缩css
,使用optimize-css-assets-webpack-plugin
插件实现。
npm i -D optimize-css-assets-webpack-plugin@4
// webpack.config.js
const OptimizeCssAssetsWebpackPlugin= require("optimize-css-assets-webpack-plugin");
module.exports = {
module: {
plugins: [
new OptimizeCssAssetsWebpackPlugin()
]
}
};
13、压缩html
压缩只要在html-webpack-plugin
的配置中添加如下minify
选项:
// webpack.config.js
const OptimizeCssAssetsWebpackPlugin= require("optimize-css-assets-webpack-plugin");
module.exports = {
module: {
plugins: [
new HtmlWebpackPlugin({
template: "public/index.html",
title: "webpack study~~",
favicon: "public/webpack.svg",
minify: {
collapseWhitespace: true, // 合并空格等
removeComments: true // 移除注释
}
})
]
}
};