打算系统的整理一下,webpack 的一些知识点,也是时候结合项目中使用的一些 案例,做一些总结了。
webpack系列 打算从 webpack核心功能 -> 常用扩展 -> CSS 工程化 -> JS 兼容性 -> 性能优化 这几个方面开始记录。
以及结合一些案例,方便大家阅读和实践,以备 开箱即用。
仓库地址:PantherVkin/webpack-note (github.com)
清除输出目录
clean-webpack-plugin - npm (npmjs.com)
- 安装
$ npm i -D clean-webpack-plugin
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'target'),
filename: '[name].[chunkhash:5].js'
},
plugins: [new CleanWebpackPlugin()]
}
自动生成页面
html-webpack-plugin - npm (npmjs.com)
简单配置
- 安装
$ npm i -D html-webpack-plugin
- 创建模板文件
public/template.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>Document</title>
</head>
<body>
<h1>webpack</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Assumenda, deserunt ducimus. Et iure labore debitis tempora praesentium atque velit provident recusandae dolor harum fugiat facere totam, maiores repudiandae illum aliquid?
</p>
</body>
</html>
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'target'),
filename: '[name].[chunkhash:5].js'
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/template.html',
filename: 'a.html'
})
]
}
多入口
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: {
home: './src/index.js',
a: './src/a.js'
},
output: {
path: path.resolve(__dirname, 'target'),
filename: '[name].[chunkhash:5].js'
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/template.html',
filename: 'a.html'
})
]
}
单页面方式
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: {
home: './src/index.js',
a: './src/a.js'
},
output: {
path: path.resolve(__dirname, 'target'),
filename: 'scripts/[name].[chunkhash:5].js'
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/template.html',
filename: 'home.html',
chunks: ['home']
}),
new HtmlWebpackPlugin({
template: './public/template.html',
filename: 'a.html',
chunks: ['a']
})
]
}
复制静态资源
copy-webpack-plugin - npm (npmjs.com)
- 安装
$ npm i -D copy-webpack-plugin
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'target'),
filename: 'scripts/[name].[chunkhash:5].js'
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new CopyPlugin({
patterns: [{from: './public/*', to: './'}]
})
]
}
开发服务器
开发中 Server(devServer) | webpack 中文网 (webpackjs.com)
- 安装
$ npm i -D webpack-dev-server
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'target'),
filename: 'scripts/[name].[chunkhash:5].js'
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html'
})
],
devServer: {
port: 8000,
open: true,
proxy: {
//代理规则
'/api': {
target: 'http://open.xxxx',
changeOrigin: true //更改请求头中的host和origin
}
}
},
stats: {
modules: false,
colors: true
}
}
- 执行
npx webpack-dev-server
webpack-dev-server命令几乎支持所有的webpack命令参数,如--config、-env等等,你可以把它当作webpack命令使用。这个命令是专门为开发阶段服务的,真正部署的时候还是得使用webpack命令。
- 当我们执行
webpack-dev-server命令后,它做了以下操作
内部执行webpack命令,传递命令参数。
开启watch。
注册hooks:类似于plugin,webpack-dev-server会向webpack中注册一些
钩子函数,主要功能如下:将资源列表(aseets)保存起来。 禁止webpack输出文件。 用express开启一个服务器,监听某个端口,当请求到达后,根据请求的路径,给予相应的资源内容。
普通文件处理
file-loader
- 原理
生成依赖的文件到输出目录,然后将模块文件设置为:导出一个路径。
//file-loader
function loader(source){
// source:文件内容(图片内容 buffer)
// 1. 生成一个具有相同文件内容的文件到输出目录
// 2. 返回一段代码 export default "文件名"
}
- 安装
$ npm i -D file-loader
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'target'),
filename: 'scripts/[name].[chunkhash:5].js'
},
module: {
rules: [
{
test: /\.(png)|(gif)|(jpg)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'imgs/[name].[hash:5].[ext]'
}
}
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html'
})
],
stats: {
modules: false,
colors: true
}
}
- 完整案例
webpack-note/examples/2.5-普通文件处理/1-file-loader at master · PantherVkin/webpack-note (github.com)
url-loader
- 原理
将依赖的文件转换为:导出一个base64格式的字符串。
//-loader
function loader(source){
// source:文件内容(图片内容 buffer)
// 1. 根据buffer生成一个base64编码
// 2. 返回一段代码 export default "base64编码"
}
- 安装
url-loader 封装了 file-loader, 所以我们可以只需要安装 url-loader就可以了。
$ npm i -D url-loader
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'target'),
filename: 'scripts/[name].[chunkhash:5].js'
},
module: {
rules: [
{
test: /\.(png)|(gif)|(jpg)$/,
use: [
{
loader: 'url-loader',
options: {
// limit: false //不限制任何大小,所有经过loader的文件进行base64编码返回
limit: 10 * 1024, //只要文件不超过 10*1024 字节,则使用base64编码,否则,交给file-loader进行处理
name: 'imgs/[name].[hash:5].[ext]'
}
}
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html'
})
],
stats: {
modules: false,
colors: true
}
}
- 完整案例
webpack-note/examples/2.5-普通文件处理/2-url-loader at master · PantherVkin/webpack-note (github.com)
解决路径问题
webpack4
在使用file-loader或url-loader时,可能会遇到一个非常有趣的问题?
- 比如,通过webpack打包的目录结构如下:
dist
|—— img
|—— a.png #file-loader生成的文件
|—— scripts
|—— main.js #export default "img/a.png"
|—— html
|—— index.html #<script src="../scripts/main.js" ></script>
- 这种问题发生的根本原因:
模块中的路径来自于某个loader或plugin,当产生路径时,loader或plugin只有相对于dist目录的路径,并不知道该路径将在哪个资源中使用,从而无法确定最终正确的路径。
- 面对这种情况,需要依靠webpack的配置publicPath解决。
会把路径拼接到publicPath后面。
- 完整案例
webpack-note/examples/2.6-解决路径问题/1-webpack4 at master · PantherVkin/webpack-note (github.com)
webpack5
不会存在这个问题。
- 完整案例
webpack-note/examples/2.6-解决路径问题/2-webpack5 at master · PantherVkin/webpack-note (github.com)
webpack内置插件
所有的webpack内置插件都作为webpack的静态属性存在的,使用下面的方式即可创建一个插件对象。
const webpack = require("webpack")
new webpack.插件名(options)
DefinePlugin
全局常量定义插件,使用该插件通常定义一些常量值,例如:
new webpack.DefinePlugin({
PI: `Math.PI`, // PI = Math.PI
VERSION: `"1.0.0"`, // VERSION = "1.0.0"
DOMAIN: JSON.stringify("duyi.com")
})
这样一来,在源码中,我们可以直接使用插件中提供的常量,当webpack编译完成后,会自动替换为常量的值
BannerPlugin
它可以为每个chunk生成的文件头部添加一行注释,一般用于添加作者、公司、版权等信息
new webpack.BannerPlugin({
banner: `
hash:[hash]
chunkhash:[chunkhash]
name:[name]
author:yuanjin
corporation:duyi
`
})
ProvidePlugin
自动加载模块,而不必到处 import 或 require
new webpack.ProvidePlugin({
$: 'jquery',
_: 'lodash'
})
然后在我们任意源码中:
$('#item'); // <= 起作用
_.drop([1, 2, 3], 2); // <= 起作用