安装
现在学习的是 webpack4 的最新版,新建文件夹,npm init -y 初始化一下,然后执行下面命令进行安装,需要同时安装 webpack 和 webpack-cli。
npm install webpack@4.43.0 webpack-cli@3.3.12 -D不建议全局安装 webpack, 因为全局安装会锁定版本,多个项目之间可能依赖的 webpack 版本不同, 所以还是建议项目内安装。
可以根目录下新建 .npmrc 文件,指定当前项目安装依赖的源地址
registry=https://registry.npm.taobao.orgwebpack 的零配置
webpack 宣传的一个噱头就是零配置构建, 也就是什么配置都不写就可以进行打包,虽然确实是可以执行,但其实是满足不了实际开发需要的。
先来随便跑一下,新建 src/index.js 文件。我们在 index.js 中 只写一行
console.log("hello, webpack !")然后执行
代码语言:javascript复制npx webpack -vnpx 在当前项目下查找并启动 webpack 。可以看到根目录下生成 dist/main.js 文件。
建议在 package.json 文件中,添加构建命令,便于添加构建参数,也更加易读。
"scripts": {
"dev": "webpack"
},
虽然我只写了一行代码,但是打包出来却有这么多字符,看下面的进度条就知道后面还有很多了。
是因为 webpack 默认给做了很多兼容,这也是相对于其他构建工具,出现了很多的冗余代码。
但其实问题不大, webpack5 进行了一些优化,但是当模块变的越来越多时候,就没有什么太大改变了。
构建信息
看一下构建时都输出了什么信息

打包出来的文件内容有很多,但是主结构很简单,其实就是一个自执行函数,如下
代码语言:javascript复制(function(modules) {
// todo
})({
"./src/login.js": (function(module, exports) {
eval("xxxxx")
})
})在这个结构中,可以看到自执行函数的参数是一个对象,对象的每个 key 的 value 都包含一个 chunk,也就是 代码片段。
也可以包含多个 chunk , 被称为 chunks, chunk组 ,还可以被称为 chunk Names 。
这一整个对象中可以包含多个 key:value,被称为依赖图谱。
构建后产生的资源文件, 称呼为 bundle 文件 。
几者遵循以下关系:
- 一个
bundle对应至少一个chunks - 一个
chunks对应至少一个module - 一个
module对应至少一个chunk
一句话总结:
module,chunk 和 bundle 其实就是同一份逻辑代码在不同转换场景下的取了三个名字:
我们直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。
webpack的配置文件
如果没有添加配置文件,会走它的默认配置,也就是所谓的零配置,如果添加了配置文件 webpack 会按照配置文件里的配置进行打包。
通常情况下 webpack 的配置文件的文件名叫做 webpack.config.js ,其实也可以通过配置修改成别的,但是基本上没什么必要。
修改 package.json 文件,在 script 中 新建命令即可
--config 指定配置文件
"warbler": "webpack --config ./warbler.config.js"由于配置文件的内容是非常多的,语法也很难一时全记下来,所以我们可以通过一点点小技巧,就可以让配置文件具有语法提示。
首先安装 @types/webpack。
npm i -D @types/webpack然后再配置文件中注明类型就可以了。
代码语言:javascript复制// webpack.config.js
/**
* @type {import('webpack').Configuration}
*/
module.exports = {
}babel.config.js 也是支持同样方式的。
npm i -D @types/babel__core
/**
* @type {import('@babel/core').TransformOptions}
*/vue.config.js 也是可以的,且不用安装其他包。
/**
* @type {import('@vue/cli-service').ProjectOptions}
*/webpack的配置参数
webpack 是基于 nodejs 的, 所有的 nodejs 核心模块的 api 都可以直接引入使用。
entry
执行打包任务的入口,默认是 src/index ,支持相对路径, 也支持绝对路径。
entry: "./src/index.js"支持 string, arr, object 如果传入的是字符串,也会在构建期间被转换成对象结构,上面的代码和下面的代码结果是一样的。
entry: {
main: "./src/index.js"
},支持 spa(单入口) 和 mpa(多入口)。多入口会输出多个 bundle 文件。
entry: {
index: "./src/index.js",
login: "./src/login.js",
home: "./src/home.js"
},output
输出资源文件的信息 , 包括 存储位置 , 文件名称
path: 存储位置,打包出来的文件放在哪里 默认是dist要求是绝对路径;filename: 文件名称,打包出来的文件叫什么。
output: {
path: path.resolve(__dirname, './dist'),
filename: "main.js"
},但是如果 entry 设置了多入口的话,就会产生多个 main.js 这样就会报错。

解决方法就是使用 占位符,语法如下
代码语言:javascript复制filename: "[name].js"作用就是 entry 中的 key 叫什么,打包后的 filename 就叫什么,多个入口就会对应多个出口了。
mode
打包模式,默认是生产模式,生产模式下会做代码压缩,摇树等操作。
development开发模式production生产模式none默认
plugins
插件,插件的本质就是一个类。后面会单独讲解各种常用插件的配置。
plugins 的执行顺序是从上到下的。
plugins:[]module
模块,webpack 默认只支持 .js, .json 文件,像我们平时常用的 .vue, .png, .scss, .css, .ts 等都是不支持的。
所以如果想要 webpack 支持其他类型的文件,就需要不同类型的 loader 进行解析。
下面这个配置的意思就是,当检测(test)到 .css 后缀文件的时候,使用(use) 什么 loader 来进行处理。
// webpack.config.js
module: {
rules: [
{
test: /.css$/,
use: ["style-loader", "css-loader"]
},
]
}- css-loader :把
css模块序列化,让webpack认识css语法并可以生成chunk。 - style-loader :把
css整合在html文件的head标签的style中。
当多个 loader 作用于 一个模块的时候, 是按照自右向左的顺序执行的,也就是先执行 css-loader 在执行 style-loader 。
其实一个 loader 也可以搞定上面两件事,但是建议一个 loader 只做一件事情,也就是遵循 单一职责 原则。
也可以给 loader 书写配置,这个时候就要用对象的结构了。
// webpack.config.js
module: {
rules: [
{
test: /.less$/,
use: [
{
loader: 'style-loader',
},
{
loader: "css-loader",
options: {
modules: true
}
},
{
loader: 'postcss-loader',
},
{
loader: 'less-loader',
}
]
}
]
}- less-loader :把
less语法 转化为css语法。 - postcss-loader :
postcss是一个 工具集 ,这个就十分强大了,postcss对css的意义,就等同于babel对于js的意义,他自身作为插件,还可以携带插件。
resolveLoader
解析 loader, 告知 webpack 如何匹配 loader。当我们自定义一些 loader 的时候。可以通过绝对路径的方式导入,但是过于繁琐,当我们通过这个字段指定文件夹的时候,就可以像使用第三方 loader 一样直接写 loader 的名字了。
// webpack.config.js
resolveLoader: {
// 默认是 node_modules
modules: ["node_modules", "./myLoaders"]
},常用插件的常用配置
html-webpack-plugin
版本:4.5.2
- template:使用指定模板生成
html。 - filename:打包后的
html文件名。 - chunks:打包后的
html会包含哪些chunk。
// webpack.config.js
plugins: [
// 自动生成 html 文件 , 引入 bundle 文件, 压缩 html
new htmlWebpackPlugin({
// 模板匹配
template: "./src/index.html",
filename: "index.html",
chunks: ["index", 'login'],
}),
]如果要生成多个 html,只需要创建多个实例即可。
// webpack.config.js
plugins: [
// 自动生成html 文件 ,引入bundle文件,压缩html
new htmlWebpackPlugin({
// 模板匹配
template: "./src/index.html",
filename: "index.html",
chunks: ["index", 'login'],
}),
// 自动生成html 文件 ,引入bundle文件,压缩html
new htmlWebpackPlugin({
// 模板匹配
template: "./src/index.html",
filename: "login.html",
chunks: ["login"],
}),
// 自动生成html 文件 ,引入bundle文件,压缩html
new htmlWebpackPlugin({
// 模板匹配
template: "./src/index.html",
filename: "home.html",
chunks: ["home"],
}),
]但是作为能懒则懒得程序员,是万万不可能写这种代码的,因为 webpack 的配置文件本身就是一个对象。所以我们当然可以利用一些方法来自动生成配置项。
首先要规定好结构,本例中每个文件夹中存放一个 index.html 和 index.js ,结构如下。当然可以自己随意定义结构,然后自己编写对应的函数体就可以了。
├── src
├── list
│ ├── index.html
│ └── index.js
├── login
│ ├── index.html
│ └── index.js
├── detail
│ ├── index.html
│ └── index.js
├── index
│ ├── index.html
│ └── index.js配置如下,利用 setMap 方法自动生成 entry 和 htmlWebpackPlugins,这样每次添加文件都不用我们修改配置了。
// webpack.config.js
const path = require('path')
const htmlWebpackPlugin = require("html-webpack-plugin")
// 模糊匹配路径
const glob = require('glob')
// 自动生成 entry 和 htmlWebpackPlugins
const setMap = () => {
const entry = {};
const htmlWebpackPlugins = []
// 模糊匹配 src 目录下 任意目录下的 index.js 返回的是文件的绝对路径
const entryFiles = glob.sync(path.join(__dirname, "./src/*/index.js"))
// 遍历匹配到的结果
entryFiles.forEach((entryFile) => {
// 获取到文件名
const pageName = entryFile.match(/src/(.*)/index.js$/)[1]
// 生成 entry
entry[pageName] = entryFile
// 生成 htmlWebpackPlugins
htmlWebpackPlugins.push(
new htmlWebpackPlugin({
template: `./src/${pageName}/index.html`,
filename: `${pageName}.html`,
chunks: [pageName]
}))
})
return {
entry,
htmlWebpackPlugins
}
}
const { entry, htmlWebpackPlugins } = setMap()
// 配置文件
module.exports = {
entry,
// 输出资源文件的信息
output: {
// 存储位置
path: path.resolve(__dirname, './dist'),
// 文件名称
filename: " [name].js"
},
// 打包模式
mode: "development",
// 插件
plugins: [
...htmlWebpackPlugins,
],
}postcss
postcss 也有他自己的配置文件,根目录下新建 postcss.config.js ,也是个模块,通过require("autoprefixer") 安装插件。
// postcss.config.js
module.exports = {
plugins: [
require("autoprefixer"),
require("cssnano")
]
}postcss的插件autoprefixer
autoprefixer 自动给 css 属性加前缀,使用 can i use 的数据。
但是这样还不会生效,需要设置 browserslist ,目标浏览器集合 ,也就是 需要兼容的浏览器版本,用到浏览器集合的工具会根据 browserslist 的描述, 针对性的输出兼容性的代码。
browserslist 的设置有两种方式。
你可以直接在 package.json 文件中添加属性如下
"browserslist": [
">1%",
"last 2 versions"
]也可以根目录下新建 .browserslistrc 文件,直接写,什么括号都不用。
// .browserslistrc
>1%
last 2 versions- >1% : 全球市场占有率 大于1%的浏览器。
- last 2 versions : 兼容浏览器的最近两个大版本。
可以使用 npx browserslist 查询兼容的浏览器版本。
postcss的插件cssnano
压缩 css 代码。
mini-css-extract-plugin
把 css 代码抽离出来单独放到一个文件里,可以指定文件名,支持绝对路径,会自动生成文件夹。需要在写 loader的位置, 使用 minicss.loader 替换 style-loader。
// webpack.config.js
const minicss = require("mini-css-extract-plugin")
module.exports = {
plugins: [
new minicss({
filename: 'style/index.css'
})
],
module: {
rules: [
{
test: /.less$/,
use: [
minicss.loader,
{
loader: "css-loader",
options: {
modules: true
}
},
{
loader: 'postcss-loader',
},
{
loader: 'less-loader',
}
]
}
]
}
}clean-webpack-plugin
每次打包之前清理打包目录。
代码语言:javascript复制// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
plugins: [
new CleanWebpackPlugin()
],
}实现自定义loader
loader的引用
根目录下新建 myLoaders/a-loader.js 文件,然后在 module 中需要使用绝对路径的方式引入。
// webpack.config.js
module: {
rules: [
{
test: /.js$/,
use: [
{
loader: path.resolve(__dirname, './myLoaders/a-loader.js'),
},
]
},
]
}loader的结构
loader 就是一个函数。接收一个参数 source,source 就是符合 test 中正则的模块内容,本例中就是 .js 后缀的文件内容。
- 这个函数不可以是 箭头函数,因为
webpack提供了loader api都是挂载到this上的。 - 这个函数必须有 返回值,否则会报错。
// a-loader.js
module.exports = function(source) {
console.log('


