webpack
前言:
现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法
模块化,
让我们可以把复杂的程序细化为小的文件;类似于TypeScript这种在JavaScript基础上拓展的开发语言:使我们能够实现目前版本的JavaScript不能直接使用的特性,并且之后还能转换JavaScript文件使浏览器可以识别;Scss,less等CSS预处理器;
这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让
浏览器识别,而手动处理又是非常繁琐的,这就为WebPack类的工具的出现提供了需求。
什么是webpack?
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一
些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器。
新建项目
下面我们来创建一个webpack项目:
1.先在根目录下使用npm init命令创建package.json文件,然后再创建其他的文件以及文件夹。
以下是目录的结构:
webpack_demo/
┣ src/
┃ ┣ components/
┃ ┃ ┣ common.js
┃ ┃ ┗ util.js
┃ ┗ app.js
┣ index.html
┗ package.json
2.我们现在创建一个src文件夹,然后在里边创建一个app.js文件(需要打包的文件)以及一个components文件夹,在components文件夹中创建两个文件,一个是common.js文件,另一个是util.js文件,两个文件里边是要默认导出的数据。然后在app.js文件里边导入components文件夹里的两个文件并暴露出去。
3.在根目录下创建一个index.html文件,引入app.js。
4.此时我们是运行是无法打印components文件夹里的两个文件中需要打印的内容。我们需要使用webpack的命令将components中的两个文件打包成一个文件,从而使浏览器能够识别。我们可以使用:
npx webpack ./src/app.js
这个命令将 两个文件打包合并成一个文件,这个文件默认会放在dist文件夹中,并且会命名为main.js。
5.我们还可以对main.js文件进行压缩,可以使用:
npx webpack --config ./webpack.config.js
命令进行打包压缩。
webpack 的配置
基本配置
entry**:**表示 webpack 的入口,指定打包的文件,可以一个或多个。
output**:**表示输出文件的路径和文件名。
mode**:**表示打包环境,可设置 production 或 development 值。
const path = require('path')
module.exports = {
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
clean: true
},
mode: 'development'
}
Loader
格式:
module.exports = {
....
module: {
rules: []
}
}
处理css
先在 src 下创建 css 文件夹,然后新建一个 css 文件,里边写一些样式代码,在 index.html 中新增
div,使样式生效,然后在 app.js 中引入,此时项目结构为:
webpack_demo/
┣ src/
┃ ┣ components/
┃ ┃ ┣ common.js
┃ ┃ ┗ util.js
┃ ┣ css/
┃ ┃ ┗ index.css
┃ ┗ app.js
┣ index.html
┣ package.json
┗ webpack.config.js
我们先安装css的依赖
pnpm i css-loader style-loader -D
插入的内容
module: {
rules: [
{
test: /\.css$/,
//解析的顺序是从右往左的,所以loader的顺序是有要求的
use: ['style-loader', 'css-loader']
}
]
}
index.css 的内容为
.box1 {
width: 100px;
height: 100px;
background-color: red;
}
我们需要再app.js中引入css文件,app.js 内的内容为:
import common from "./components/common";
import util from "./components/util";
import './css/index.css' // 新增的引入 css
common()
util()
index.html 的内容为
<script src="./dist/main.js"></script>
<body>
<div class="box1"></div> <!-- 新增的div -->
</body>
完成以上步骤后重新打包
处理 Sass、Less
他的步骤和css的步骤是一样的,同样我们也要安装他们的依赖包
pnpm i less less-loader sass sass-loader -D
插入的内容
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader'],
},
// 处理 sass
{
test: /\.s[ac]ss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
}
处理图片:
我们需要再src文件夹中在新建一个文件夹用于放置图片
webpack_demo/
┣ src/
┃ ┣ components/
┃ ┃ ┣ common.js
┃ ┃ ┗ util.js
┃ ┣ css/
┃ ┃ ┣ index.css
┃ ┃ ┣ index.less
┃ ┃ ┗ index.sass
┃ ┣ images/
┃ ┃ ┣ 1.jpg
┃ ┃ ┗ 2.jpg
┃ ┗ app.js
┣ index.html
┣ package.json
┗ webpack.config.js
我们现在index.css文件中将图片设置好
.img1 {
width: 150px;
height: 200px;
background-image: url('../images/1.jpg');
background-size: cover;
}
.img2 {
width: 150px;
height: 200px;
background-image: url('../images/2.jpg');
background-size: cover;
}
index.html 中新增的内容为
<div class="img1"></div>
<div class="img2"></div>
因为内置了依赖包所以我们不用下载依赖包
新增的loader
{
test: /\.(png|jpe?g|gif|svg|webp)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 200 * 1024
}
}
}
更改 放置图片的路径
图片打包后的输出目录与 main.js 在同一目录,那如果要把图片打包放到dist/static/images 目录下呢,那么就可以 使用 generator 字段:
{
test: /\.(png|jpe?g|gif|svg|webp)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 200 * 1024
}
},
generator: {
filename: 'static/images/[hash][ext][query]'
}
}
generator 中的 filename 指定存放的目录
[hash]: 表示hash值,后面可携带自定义位数,例如[hash:8]
[ext]:原文件扩展名
[query]:添加之前的query参数
处理字体图标:
老样子,在 src 下新建一个 fonts 文件夹,然后在阿里巴巴矢量图标库中下载图标(这里使用 Font class的使用方式),将下载的字体文件放到 fonts 文件夹中,将下载的 iconfont.css 文件放到 css 文件夹中,然后在 app.js 中引入,并在 index.html 中新增标签:
目录结构
webpack_demo/
┣ src/
┃ ┣ components/
┃ ┃ ┣ common.js
┃ ┃ ┗ util.js
┃ ┣ css/
┃ ┃ ┣ iconfont.css
┃ ┃ ┣ index.css
┃ ┃ ┣ index.less
┃ ┃ ┗ index.sass
┃ ┣ fonts/
┃ ┃ ┣ iconfont.ttf
┃ ┃ ┣ iconfont.woff
┃ ┃ ┗ iconfont.woff2
┃ ┣ images/
┃ ┃ ┣ 1.jpg
┃ ┃ ┗ 2.jpg
┃ ┗ app.js
┣ index.html
┣ package.json
┗ webpack.config.js
在app.js中引入iconfont.css
import './css/iconfont.css'
index.html 新增内容为
<span style="font-size: 36px; color: red;" class="iconfont icon-aixin">
</span>
增加loader
{
test: /\.(ttf|woff|woff2)$/,
type: 'asset/resource',
generator: {
filename: 'static/font/[hash][ext][query]'
}
}
处理 CSS 兼容性
通过 loader,可以将一些较新的 CSS 语法能够在低版本浏览器中使用,而这个 loader 就是 postcssloader,但这个 loader 还依赖 postcss 和 postcss-preset-env,所以需要安装三个模块:
安装依赖包
pnpm i postcss-loader postcss postcss-preset-env -D
修改css的loader
除了修改以上配置以外,在 package.json 中新增:"browserslist": ["ie >= 7"]
{
"name": "webpack_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack --config ./webpack.config.js"
},
"author": "",
"devDependencies": {
....
},
"browserslist": ["ie >= 7"]
}
在 index.css 中新增 display: flex;
完成以上步骤后打包
处理 JS 兼容性
通过 loader ,还可以将 JS 语法在较低的浏览器版本中使用,主要就是通过 babel,同样需要安装三个模块,一个 loader,一个核心库,一个预设,分别就是 babel-loader、@babel/core、@babel/presetenv:
pnpm i babel-loader @babel/core @babel/preset-env -D
babel-loader 使用 Babel 加载 ES2015+ 代码并将其转换为 ES5
@babel/core Babel 编译的核心包
@babel/preset-env Babel 编译的预设,可以理解为 Babel 插件的超集
增加loader
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader']
}
新增bable.config.js
在项目根目录新建一个 babel.config.js 配置文件
module.exports = {
presets: ['@babel/preset-env']
}
在app.js文件中新增测试代码
function count(...arg) {
console.log(arg[0] + arg[1])
}
count(1,2)
Plugin
webpack 的插件能够增强 webapck 的功能,本身 webpack 只是解析依赖从而打包,loader 使
webpack 能够转化文件,而 plugins 则使 webpack 能够拥有压缩,提取等更大强大的功能。
webpack 的插件主要在 plugins 字段上,是个数组,也就是可以使用多个插件,每个插件在使用的时候都必须传入一个 new 实例。
提取 CSS 为单独文件
安装这个插件
pnpm i mini-css-extract-plugin -D
然后修改 webpack 的配置
引入 mini-css-extract-plugin,然后在 plugins 中设置,最后将 style-loader 替换成
MiniCssExtractPlugin.loader
打包
手动引入
打包后确实将 css 提取到单独的文件里了,但是 html 中还需要手动引入
自动引入 JS 和 CSS
上面打包后,不管是 JS 还是 CSS 打包为单独文件时,在 index.html 中都需要手动引入相应的资源,如果修改了 webpack 打包 JS 和 CSS 文件的路径,那么 index.html 也需要修改。
基于以上问题,可以通过 HtmlWebpackPlugin 插件解决。
安装依赖
pnpm i html-webpack-plugin -D
修改webpack配置
先引入 html-webpack-plugin,然后将其添加到 plugins 中,同时将 index.html 中引入 css 和 js 的代码
注释。
打包后,可看到在 dist 下有一个 index.html
压缩 CSS
安装依赖
pnpm i css-minimizer-webpack-plugin -D
修改 webpack :
还是那样,引入 css-minimizer-webpack-plugin,然后在 plugins 中添加,最后修改 mode(cssminimizer-webpack-plugin 默认在生产模式在才生效),打包后效果如下
自动清空打包目录
每次打包的时候,打包目录都会遗留上次打包的文件,为了保持打包目录的纯净,我们需要在打包前将打包目录清空这里我们可以使用插件 clean-webpack-plugin 来实现
安装
pnpm i clean-webpack-plugin -D
配置
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 引入插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
// ...
plugins:[ // 配置插件
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CleanWebpackPlugin() // 引入插件
]
}
DevServer
devserver 可以在本地启动一个服务,使我们可以使用 http 协议去访问 index.html ,并且当修改代码时,能够监听当前项目的文件变动从而实现自动打包,而不用每次修改后都要手动打包:
在 webpack 配置中添加 devServe 字段,里边配置 host、port等。同时还需要安装 webpack-dev
server 模块:
安装
pnpm i webpack-dev-server -D
同时,webpack 打包命令也需要添加一个 serve 参数才能调用 webpack-dev-server:
启动 server 前,可以先将 dist 目录下的文件清空,然后再运行 npm run dev,可以发现 dist 下并没有
生成任何文件,这是因为server 打包后是放在内存中的,所以 dist 下也不需要任何文件,server 一般是在开发环境下使用的,如果在生产环境,就需要打包到本地了。
开发模式与生产模式
经过上面的配置,webpack 配置是有 development 和 production 区分的,在开发环境下,通过 devserver 启动,就不会生成 dist 文件夹,而生产模式下又恰恰需要,为了避免在两种模式打包而需要 来回修改 webpack 的配置文件的内容,可以通过判断当前打包环境,从而决定是否需要 devServer 或者 设置 mode 值等:
添加 build 命令
pnpm i cross-env -D
同时修改 scripts:
webpack的优化
1、OneOf
// webpack.config.js
module.exports = {
module: {
rules: [
{
oneOf: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
//OneOf配置内的其他规则
],
},
],
},
};
include/Exclude
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
//具有包含和排除配置的其他规则
],
},
};
SourceMap
// webpack.config.js
module.exports = {
devtool: 'source-map',
//其他配置项
};
Babel缓存
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true, // 启用缓存
}
}
}
]
优化resolve配置
在 webpack 中,alias 用于创建模块的别名,以便更轻松地引用模块。要配置 alias,可以在 webpack 的配置文件中使用 resolve.alias 选项。通过将 resolve.alias 添加到 webpack 配置中,可以使用短名称来引用长路径,使代码更易读和易维护。
const path = require('path');
module.exports = {
resolve: {
alias: {
// 将 'components' 别名指向 './src/components' 目录
components: path.resolve(__dirname, 'src/components'),
// 将 'utils' 别名指向 './src/utils' 目录
utils: path.resolve(__dirname, 'src/utils')
}
}
};
extensions
在Webpack中,extensions
选项用于配置在导入模块时可以省略的文件扩展名。这使开发时能够在导入模块时不必指定完整的文件名,从而简化代码。通过配置 extensions
选项,可以告诉Webpack在导入模块时自动解析指定的文件扩展名。例如:
resolve: {
extensions: ['.js', '.jsx']
}
thread-loader
thread-loader
是JS代码块进行处理的 Webpack 加载器。它可以将这些代码块放入 worker 池中以进行并行处理,从而提高构建性能。
首先在终端输入以下命令进行安装
pnpm i -D thread-loader
要在 Webpack 中使用 thread-loader
,需要webpack.config.js
文件中配置相应的 loader 规则:
use: [
{
loader: 'thread-loader', // 开启多进程打包
options: {
worker: 3,
}
},
'babel-loader',
]