一. webpack简介
webpack是什么
webpack是一种前端资源构建工具,一个静态模块打包器
在webpack中,前端的所有的文件资源(js/json/css/img/less)都会当作模块处理。它会根据模块的依赖关系进行静态分析,打包生成对应的静态资源。
html
<!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">
<title>Document</title>
// 记录处理less
<link rel="stylesheet" href="./index.less">
</head>
<body>
<div id="box">hello 哈哈哈</div>
记录处理js文件中的es6语法
<script src="./index.js"></script>
</body>
</html>
从入口文件进入,按照不同的模块进行记录,形成一个代码块chunk
,然后根据不同的模块进行处理,然后输出出去,形成bundle
。
核心概念
- Entry
入口,指示webpack以哪个文件为入口起点开始打包,分析构建内部依赖图
- Output
输出,指示webpack打包后的资源bundles输出到哪里
- Loader
loader让webpack能够去处理那些非js文件(webpack自身只理解js)
- Plugins
插件,可以执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。
- Mode
模式,指示webpack使用相应的模式的配置
二. 基本用法
- 初始化包文件
js
npm init
- 下载包文件(全局安装)
js
npm i webpack webpack-cli -g
三. 打包样式文件
- webpack.config.js
webpack
的配置文件
作用:指示webpack做那些事(当运行webpack指令时,会加载里面的配置)
所有的构建工具都是基于nodejs平台运行的,模块化默认采用commonjs
- 基本配置
安装style-loader
和css-loader
js
npm i style-loader css-loader -D
新建webpack.config.js文件
js
const { resolve } = require("path");
// webpack 配置
// 入口起点
module.exports = {
//输出
entry: './src/index.js',
output: {
//输出文件名
filename: 'built.js',
//输出路径
//__dirname nodejs变量, 代表当前文件目录的绝对路径
path: resolve(__dirname, 'build')
},
//loader配置
module: {
rules: [
// 详细的loader配置
// 不同文件必须配置不同的loader进行处理
{
// 用于匹配那些文件
test: /.css$/,
// 使用那些loader进行处理
use: [
// use数组中的执行顺序:从左至右,从上到下,依次执行
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// 将css文件变成commonjs模块加载到js中,里面的内容是样式字符串
'css-loader'
]
}
]
},
//plugins配置
plugins: [
//详细的plugin的配置内容
],
//模式
mode: 'development'
// mode: 'production'
}
- 处理css文件
js
{
// 用于匹配那些文件
test: /.css$/,
// 使用那些loader进行处理
use: [
// use数组中的执行顺序:从左至右,从上到下,依次执行
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// 将css文件变成commonjs模块加载到js中,里面的内容是样式字符串
// css-loader?minimize 中的 minimize 告诉 css-loader 要开启 CSS 压缩
'css-loader?minimize'
]
}
Loader 可以看作具有文件转换功能的翻译员,配置里的 module.rules
数组配置了一组规则,告诉 Webpack 在遇到哪些文件时使用哪些 Loader 去加载和转换。 如上配置告诉 Webpack 在遇到以 .css
结尾的文件时先使用 css-loader
读取 CSS 文件,再交给 style-loader
把 CSS 内容注入到 JavaScript 里。
还可以采用Object的方式:
js
use: [
'style-loader',
{
loader:'css-loader',
options:{
minimize:true,
}
}
]
- 处理less文件
安装less和less-loader
markdown
{
test: /.less$/,
use: [
'style-loader',
'css-loader',
// 将less文件编译成css文件
// 需要下载less-loader和less
'less-loader'
]
}
除了在 webpack.config.js
配置文件中配置 Loader 外,还可以在源码中指定用什么 Loader 去处理文件。 以加载 CSS 文件为例,修改上面例子中的 main.js
如下:
js
// 入口文件,引入css文件的地方
require('style-loader!css-loader?minimize!./main.css');
这样就能指定对 ./main.css
这个文件先采用 css-loader 再采用 style-loader 转换。
- 处理sass文件
安装sass-loader
js
{
// 增加对 SCSS 文件的支持
test: /.scss$/,
// SCSS 文件的处理顺序为先 sass-loader 再 css-loader 再 style-loader
use: ['style-loader', 'css-loader', 'sass-loader'],
},
四. 打包html资源
- 下载插件
js
npm i html-webpack-plugin -D
- loader与plugins的使用路径
loader: 1. 下载 2. 使用(配置loader)
plugins: 1. 下载 2. 引入 3. 使用
- 使用html-webpack-plugin处理打包html资源
js
const { resolve } = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules:[
]
},
plugins: [
// plugins的配置
// html-webpack-plugin
// 功能: 默认会创建一个空的html,自动引入打包输出的所有资源(js/css)
// 需求: 需要有结构的html文件
new HtmlWebpackPlugin({
// 设置index.html文件中的title
title: 'html-webpack-plugin',
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(js/css)
template: './src/index.html'
})
// 内置DefinePlugin插件,用于配置index.html模版参数
new DefinePlugin({
BASE_URL: '"./"'
})
],
mode: 'development'
}
五. 打包图片资源
- 下载插件
js
npm i url-loader -D
- 处理less文件中的图片引用
js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /.less$/,
// 要使用多个loader处理用use
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 问题:默认处理不了html中img图片
// 处理图片资源
test: /.(jpe?g|png|gif)$/,
// 使用一个loader
// 下载 url-loader file-loader
loader: 'url-loader',
options: {
// 图片大小小于8kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
// 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
// 解析时会出问题:[object Module]
// 解决:关闭url-loader的es6模块化,使用commonjs解析
esModule: false,
// 给图片进行重命名
// [hash:10]取图片的hash的前10位
// [ext]取文件原来扩展名
name: '[name].[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
处理html文件中的图片引用
js
{
test: /.html$/,
// 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
loader: 'html-loader',
options: {
esModule: false
}
}
处理图片几种loader的差别;
- url-loader:base64,文件,减少请求次数
- file-loader:将资源拷贝至指定目录,分开请求
- url-loader内部也可以调用file-loader
asset处理文件
- asset/resource ---> file-loader
- asset/inline ---> url-loader
- asset/source ---> raw-loader
- asset
解决图片资源单独打包成单独的文件夹
- 在output中进行配置
js
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
assetModuleFilename: "img/[name].[hash:4][ext]"
}
- 单独配置
js
{
test: /.(png|svg|gif|jpe?g)$/,
type: 'asset/resource',
generator: {
filename: "img/[name].[hash:4][ext]"
}
}
asset/inline
js
{
test: /.(png|svg|gif|jpe?g)$/,
type: 'asset/inline'
}
asset
js
{
test: /.(png|svg|gif|jpe?g)$/,
type: 'asset',
generator: {
filename: "img/[name].[hash:4][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024
}
}
}
处理iconfont文件
js
{
test: /.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: "font/[name].[hash:3][ext]"
}
}
处理ts语法
- 利用ts-loader
js
// 安装ts-loader
{
test: /.ts$/,
use: ['ts-loader']
}
优点:
可以做语法校验
缺点:
无法处理promise等polyfill语法
- 利用babel
js
{
test: /.ts$/,
use: ['ts-loader']
}
// 在babel.config.js中:
module.exports = {
presets: [
['@babel/preser-env', {
useBuiltIns: 'usage',
corejs: 3
}],
['@babel/preset-typescript']
]
}
优点:
可以做polyfill填充
缺点:
运行时才会出现错误
处理vue文件
js
// 如果版本不对
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module: {
rules: [
{
test: /.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'postcss-loader',
'less-loader'
]
},
{
test: /.vue$/,
use: ['vue-loader']
}
]
}
plugins: [
new VueLoaderPlugin()
]
六. 打包其他资源
- 安装插件
js
npm i file-loader -D
- 在loader中配置
js
module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/css/js资源以外的资源)
{
// 排除
exclude: /.(css|js|html)$/,
loader: 'file-loader',
option: {
esModule: false, // 不转为esModule
name: '[hash:10].[ext]',
// 设置路径
outputPath: 'img',
// 或
name: 'img/[name].[hash:6].[ext]'
}
}
]
}
七. devServer(自动化)
- 安装devServer插件
js
npm i webpack-dev-server -D
- 使用
开发服务器 devServer:用来自动化(自动化编译,自动化打开浏览器,自动化刷新浏览器)
特点:只会在内存中进行编译,而不会有任何输出,而上文中的webpack启动会生成build文件夹输出所有的打包文件。
js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { resolve } = require("path");
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader']
},
{
exclude: /.(css|js|html)$/,
loader: 'file-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
// 开发服务器 devServer:用来自动化(自动化编译,自动化打开浏览器,自动化刷新浏览器)
// 特点:只会在内存中进行编译,而不会有任何输出
// 启动 devServer的指令为:npx webpack-dev-server
devServer: {
// 项目构建后路径
contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true
}
}
启动命令为
js
webpack serve
八. 开发环境配置
当使用webpack命令打包时,指定输出路径:
将入口js文件输出文件:
js
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
将loader文件输出指定路径:
js
{
test: /.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
esModule: false,
name: '[hash:10].[ext]',
outputPath: 'images'
}
}
将会在输出的图片文件放入images文件中
完整开发环境配置:
js
/*
开发环境配置:能让代码运行
运行项目指令:
webpack 会将打包结果输出出去
npx webpack-dev-server 只会在内存中编译打包,没有输出
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 处理css资源
test: /.css$/,
use: ['style-loader', 'css-loader']
},
{
// 处理图片资源
test: /.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,
outputPath: 'imgs'
}
},
{
// 处理html中img资源
test: /.html$/,
loader: 'html-loader'
},
{
// 处理其他资源
exclude: /.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true
}
};
九. 将css打包成单独的文件
- 安装插件
js
npm i mini-css-extract-plugin -D
- 使用MiniCssExtractPlugin中的loader将style-loader进行替换,并引入插件重命名
js
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /.css$/,
use: [
// 创建style标签,将样式放入
// 'style-loader',
// 这个loader取代style-loader
// 作用:提取js中的css成为单独文件
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
// 对输出的css文件进行重命名
filename: 'css/built.css'
})
],
mode: 'development'
}
十. css兼容性处理
- 安装插件
js
npm i postcss-loader postcss-preset-env -D
- 配置规则
js
// >1%
// default
// dead
// last 2 version
- 方式一:在package.json中
js
"browserslist": {
// 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
// 生产环境:默认是看生产环境
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
- 方式二:在.browserslistrc中进行配置
.browserslistrc文件中:
js
> 1%
last 2 version
not dead
- 方式一:webpack.config.js文件中配置:
js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 设置nodejs环境变量
// process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
// 指遇到import语法时,向上返回一层
options: {
importLoaders: 1
}
}
/*
css兼容性处理:postcss --> postcss-loader postcss-preset-env
帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
*/
// 使用loader的默认配置
// 'postcss-loader',
// 修改loader的配置
// postcss-preset-env:预设,插件集合
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [['postcss-preset-env',{}]]
}
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
})
],
mode: 'development'
};
- 方式二:postcss.config.js文件
java
module.exports = {
plugins: [
'postcss-preset-env'
]
}
// webpack.config.js中配置
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
- 生成css后
十一. 压缩css
- 安装插件
js
npm i optimize-css-assets-webpack-plugin -D
js
// 引入插件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
// 压缩css
new OptimizeCssAssetsWebpackPlugin()
]
十二. js语法检查(eslint)
编译打包时根据eslint所指定的语法规则进行提示错误。
- 安装插件
js
npm i eslint-loader eslint -D
npm i eslint-config-airbnb-base eslint-plugin-import -D
- 设置语法规则,在package.json中设置
js
// 设置语法规则
"eslintConfig": {
"extends": "airbnb-base"
}
- 使用
js
const { resolve } = require("path");
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// 注意:只检查自己写的代码,第三方库的代码是不需要检查的
{
test: /.js$/,
// 排除第三方库的代码
exclude: /node_modules/,
loader: 'eslint-loader',
// 开启自动修复eslint检查的错误
options: {
fix: true
}
}
]
},
plugins: [
],
mode: 'development'
}
注意
js
// 下一行eslint所有规则失效(下一行不进行eslint代码的检查)
// eslint-disable-next-line
console.log(add(3,4))
十三. js兼容性处理
基本js兼容性处理
A. 安装插件
js
npm i babel-loader @babel/core @babel/preset-env -D
问题:只能转换基本语法,如promise高级语法不能转换
js
{
test: /.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env']
]
}
}
全部js兼容性处理
问题:只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~
A. 安装插件
js
npm i @babel/polyfill -D
直接在js代码中引入
js
// 引入@babel/polyfill
import '@babel/polyfill';
const add = (x, y) => {
return x + y;
};
console.log(add(2, 5));
const promise = new Promise(resolve => {
setTimeout(() => {
console.log('定时器执行完了~');
resolve();
}, 1000);
});
console.log(promise);
按需加载(推荐)
A. 安装插件
js
npm i core-js -D
结合第一种方式进行使用:
js
const { resolve } = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 预设:指示babel做怎么样的兼容性处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
]
},
plugins: [
],
mode: 'development'
};
十四. 压缩html和js
js压缩
将mode改为production环境后,自动启用js压缩
js
mode: 'production'
html压缩
js
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩html代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
})
]
十五. 生产环境配置
- 需处理的文件类型
- Html
插件(plugins):
A. 处理html文件 ---> html-webpack-plugin
B. 处理html压缩
- Css
插件(plugins):
A. 将css打包成单独文件 ---> mini-css-extract-plugin
B. 开启css压缩 ---> optimize-css-assets-webpack-plugin
Loader:
A. 打包成单独文件 ---> MiniCssExtractPlugin.loader
B. 处理css文件 ---> css-loader
C. 处理css样式兼容性 ---> postcss-loader (需要package.json中定义browserslist)
D. 处理less文件 ---> less-loader
E. 不生成单独文件,css与js在一起 ---> style-loader
- Js
Loader:
A. js代码检查 ---> eslint-loader
B. js代码兼容性 ---> babel-loader + corejs (需要指定版本)
C. js代码自动压缩
- 图片
Loader:
A. 处理css文件内的图片资源 ---> url-loader
B. 处理html文件中的图片资源 ---> html-loader
- 其他文件
Loader:
A. 处理其他文件 ---> file-loader
- 详细配置
js
const { resolve } = require('path');
// 将css打包成单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// css压缩
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
// 处理html文件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// css兼容性处理 postcss-loader
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins:['postcss-preset-env',[]]
}
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /.css$/,
use: [...commonCssLoader]
},
{
test: /.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
// js语法检查eslint
// 在package.json中eslintConfig --> airbnb
test: /.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// js兼容性处理babel-loader + corejs
test: /.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options:{
presets: [
'@babel/preset-env',
{
useBuiltInt: 'usage',
corejs: {
verson: 3
},
target: {
chrome: '60',
firebox: '60'
}
}
]
}
},
{
// 图片处理:css文件内
test: /.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
// 图片处理:html文件内
test: /.html$/,
loader: 'html-loader',
options: {
esModule: false,
name: '[hash:10].[ext]'
}
},
{
// 其他文件处理
exclude: /.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
};
十六. 自动清除打包文件
下次打包生成文件时,自动删除上次生成的
js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
plugins: [
new CleanWebpackPlugin()
]
十七. 拷贝文件
js
const { CopyWebpackPlugin } = require('copy-webpack-plugin')
plugins: [
new CopyWebpackPlugin({
patterns: [
{
// 来源文件夹名称
from: 'public',
// 设置
globOptions: {
// 排除文件名称
// **/用于补充文件路径 === public
ignore: ['**/index.html']
}
}
]
})
]