一、核心概念——entry
Entry用于指定webpack打包的入口
1、单入口(entry是一个字符串)
module.exports = {
entry: './src/index.js'
}
2、多入口(entry是一个对象)
module.exports = {
entry:{
app: './app.js',
adminApp: './src/adminApp.js'
}
}
二、核心概念——output
output用来告诉webpack如何将编译后的文件输出到磁盘
1、单入口
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
}
}
2、多入口
module.exports = {
entry:{
app: './app.js',
adminApp: './src/adminApp.js'
},
output: {
filename: '[name].js', // 通过占位符确保文件名的唯一
path: __dirname + '/dist'
}
}
三、核心概念——loaders
webpack默认只支持js和json两种文件类型,通过loaders去支持其他文件类型并且把他们转化成有效的模块,并且可以添加到依赖图中。
本身是一个函数,接受源文件作为参数,返回转换的结果。
1、常见的loader
名称 | 描述 |
---|---|
babel-loader | 转换ES6、ES7等JS新特性语法 |
css-loader | 支持.css文件的加载和解析 |
less-loader | 将less转换为css |
ts-loader | 将TS转换成JS |
file-loader | 进行图片、字体的打包 |
raw-loader | 将文件以字符串的形式导入 |
thread-loader | 多进程打包JS和CSS |
2、loader的用法
module:{
rules: [
{
test: /\.txt$/, // test:指定匹配规则
use: 'raw-loader' // use:指定使用的loader名称
}
]
}
四、核心概念——plugins
插件用于bundle文件的优化,资源管理和环境变量注入
作用于整个构建过程
1、常见的plugins
名称 | 描述 |
---|---|
CommonsChunkPlugin | 将chunks相同的模块代码提取成公共js |
CleanWebpackPlugin | 清理构建目录 |
ExtractTextWebpackPlugin | 将css从bundle文件里提取成一个独立的css文件 |
CopyWebpackPlugin | 将文件或者文件夹拷贝到构建的输出目录 |
HtmlWebpackPlugin | 创建html文件去承载输出的bundle |
UglifyjsWebpackPlugin | 压缩JS |
ZipWebpackPlugin | 将打包的资源输出生成一个zip包 |
2、plugins用法
plugins:[
new HtmlWebpackPlugin({ // 放到plugins数组里
template: './src/index.html'
})
]
五、核心概念——mode
mode用来指定当前的构建环境是:production、develoment还是node
设置mode可以使用webpack内置的函数,默认值为production
1、mode的内置函数功能
选项 | 描述 |
---|---|
development | 设置 process.env.NODE_ENV 的值为 development.开启 NamedChunksPlugin 和 NamedModulesPlugin . |
production | 设置 process.env.NODE_ENV 的值为 production.开启 FlagDependencyUsagePlugin , FlagInclu dedChunksPlugin ModuleConcatenationPlugin , NoEmitOnE rrorsPlugin , Occurrence0rderPlugin ,SideEffectsFl agPlugin 和 TerserPlugin . |
none | 不开启任何优化选项 |
六、使用
1、使用babel-loader解析ES6和React JSX
babel的配置文件是:.babelrc
(1)安装
npm install -D babel-loader @babel/core @babel/preset-env @babel/preset-react
npm i react react-dom
(2)增加ES6的babel preset配置 (.babelrc)
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
(3)新增文件reactTest.js
'use strict';
import React from "react";
import ReactDOM from "react-dom";
class ReactComponents extends React.Component {
render() {
return <div>Hello React</div>;
}
}
ReactDOM.render(
<ReactComponents />,
document.getElementById('root')
)
(4) 修改webpack.config.js
'use strict'
const path = require('path');
module.exports = {
entry: {
main: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
mode: 'production',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
}
2、css、less、sass解析
css-loader用于加载.css文件,并且转换成commonjs对象
style-loader将样式通过<style>标签插入head中
(1)安装依赖
npm i css-loader style-loader -D
(2)修改webpack.config.js
'use strict'
const path = require('path');
module.exports = {
entry: {
main: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
mode: 'production',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
'style-loader',
'css-loader',
]
}
]
}
}
(3)新增文件reactTest.css
.react-test{
font-size: 20px;
color: red;
}
(4)修改reactTest.js
'use strict';
import React from "react";
import ReactDOM from "react-dom";
import './reactTest.css';
class ReactComponents extends React.Component {
render() {
return <div className="react-test">Hello React</div>;
}
}
ReactDOM.render(
<ReactComponents />,
document.getElementById('root')
)
(5)解析less和sass
less-loader用于将less转换成css
npm i less less-loader -D
'use strict'
const path = require('path');
module.exports = {
entry: {
main: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
mode: 'production',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
]
}
}
3、解析图片和字体——file-loader
file-loader用于处理文件,也可以用来解析字体
(1)安装依赖
npm i file-loader -D
(2)修改webpack.config.js
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: 'file-loader'
},
{
test: /\.(woff|woff2|eot|ttf|otf)/,
use: 'file-loader'
}
]
}
4、解析图片和字体——url-loader
url-loader也可以处理图片和字体
可以设置较小资源自动base64
(1)安装依赖
npm i url-loader -D
(2)修改webpack.config.js
'use strict'
const path = require('path');
module.exports = {
entry: {
main: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
mode: 'production',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)/,
use: 'file-loader'
},
]
}
}
5、webpack中的文件监听
文件监听是在发现源码发生变化时,自动重新构建出新的输出文件
webpack开启监听模式,有两种方式:
- 启动webpack命令时,带上 --watch参数
- 在配置webpack.config.js中设置watch:true
唯一缺陷:每次需要手动刷新浏览器
(1)修改package.json 后运行 npm run watch
{
"name": "webpackExercise",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"watch": "webpack --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.20.2",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"babel-loader": "^9.1.0",
"css-loader": "^6.7.2",
"file-loader": "^6.2.0",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"style-loader": "^3.3.1",
"url-loader": "^4.1.1",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
(2)原理
轮询判断文件的最后编辑时间是否变化
某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等aggregateTimeout
'use strict'
const path = require('path');
module.exports = {
// 默认false,不开启
watch: true,
watchOptions: {
// 忽略监听的文件
ignored: /node_modules/,
// 监听到变化后会等300毫秒再去执行,默认300毫秒
aggregateTimeout: 300,
// 判读文件是否发生变化是通过轮询指定文件,默认每秒轮询1000次
poll: 1000
},
entry: {
main: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
mode: 'production',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)/,
use: 'file-loader'
},
]
}
}
6、热更新:webpack-dev-server(HotModuleReplacementPlugin)
(1)安装依赖
npm i webpack-dev-server -D
webpack-dev-server不刷新浏览器
webpack-dev-server不输出文件,而是放在内存中
使用HotModuleReplacementPlugin插件
(2)修改package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"watch": "webpack --watch",
"dev": "webpack-dev-server --open"
},
(3)修改webpack.config.js
'use strict'
const path = require('path');
const webpack = require('webpack');
module.exports = {
// // 默认false,不开启
// watch: true,
// watchOptions: {
// // 忽略监听的文件
// ignored: /node_modules/,
// // 监听到变化后会等300毫秒再去执行,默认300毫秒
// aggregateTimeout: 300,
// // 判读文件是否发生变化是通过轮询指定文件,默认每秒轮询1000次
// poll: 1000
// },
entry: {
main: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)/,
use: 'file-loader'
},
]
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
static: './dist',
hot: true
}
}
注:在新版的webpack-dev-server中,contentBase已经被移除了,用static替代。
7、热更新:webpack-dev-middleware
webpack-dev-middleware将webpack输出的文件传输给服务器
适用于灵活的定制场景
webpack compile:将js编译成bundleHMR server:将热更新的文件输出给HMR Runtime
bundle server:提供文件在浏览器的访问
HMR runtime:会被注入到浏览器,更新文件的变化
bundle.js:构建输出的文件
8、文件指纹策略
打包后输出的文件名的后缀,通常做的是文件发布的版本管理
(1)文件指纹如何生成
- Hash:和整个项目的构建相关,只要项目文件有修改,整个项目构建的hash值就会更改
- Chunkhash:和webpack打包的chunk有关,不同的enty会生成不同的chunkhash值
- Contenthash:根据文件内容来定义hash,文件内容不变,则contenthash不变
(2)js的文件指纹设置
设置output的filename,使用 [chunkhash]
(3)css的文件指纹设置
// 提取css文件
npm i mini-css-extract-plugin -D
设置MiniCssExtractPlugin的filename,使用 [contenthash]
(4)图片或字体的文件指纹设置
设置file-loader的name,使用 [hash]
占位符名称 | 含义 |
---|---|
[ext] | 资源后缀名 |
[name] | 文件名称 |
[path] | 文件的相对路径 |
[folder] | 文件所在的文件夹 |
[contnthash] | 文件内容的hash,默认md5生成 |
[hash] | 文件内容的hash,默认md5生成 |
[emoji] | 一个随机的指代文件内容的enoj |
(5)修改package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.prod.js",
"watch": "webpack --watch",
"dev": "webpack-dev-server --config webpack.dev.js --open"
},
(6)新建文件webpack.prod.js,并将原有的webpack.config.js改为webpack.dev.js
'use strict'
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: {
main: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[chunkhash:8].js'
},
mode: 'production',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]'
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]'
}
}
]
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css'
})
]
}
9、HTML、CSS、JS压缩
(1)JS压缩
webpack5内置了terser-webpack-plugin,如果需要额外配置需要安装terser-webpack-plugin并进行一系列调整
(2)CSS文件的压缩
webpack5中可使用css-minimizer-webpack-plugin
npm install css-minimizer-webpack-plugin --save-dev
// webpack.prod.js
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// ...
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css',
})
],
optimization: {
minimizer: [
new CssMinimizerPlugin(),
],
},
(3)HTML压缩
npm install --save-dev html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css',
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['index'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),
],
10、一份prod配置
'use strict'
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[chunkhash:8].js'
},
mode: 'production',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]'
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]'
}
}
]
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css',
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/reactTest.html'),
filename: 'reactTest.html',
chunks: ['reactTest'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['index'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),
],
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin(),
],
},
}
11、一份dev配置
'use strict'
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// // 默认false,不开启
// watch: true,
// watchOptions: {
// // 忽略监听的文件
// ignored: /node_modules/,
// // 监听到变化后会等300毫秒再去执行,默认300毫秒
// aggregateTimeout: 300,
// // 判读文件是否发生变化是通过轮询指定文件,默认每秒轮询1000次
// poll: 1000
// },
entry: {
index: './src/index.js',
reactTest: './src/reactTest.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name][chunkhash].js'
},
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
// use数组中是从后往前调用的
use: [
'style-loader',
'css-loader',
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)/,
use: 'file-loader'
},
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/reactTest.html'),
filename: 'reactTest.html',
chunks: ['reactTest'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['index'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),
],
devServer: {
static: './dist',
hot: true
}
}