1.为什么需要使用打包工具
在现在的前端开发中,我们一般会使用React,Vue等前端开发框架,ES6模块语法,Less/Sass等css预处理器语法进行开发。
但是浏览器不认识这些代码,所以需要编译成浏览器能识别的HTML,JS,CSS才能运行,所以需要打包工具。
并且打包工具还能压缩代码,做兼容性处理,提升代码性能等。
2.WebPack是什么?
WebPack是静态资源打包工具。它会以一个文件或者多个文件作为打包的入口,将项目所有文件编译组合成一个或者多个文件输出出去。
输出的文件就是编译好的文件,就可以在浏览器运行了。
我们将WebPack输出的文件叫做bundle。
WebPack本身功能较少,只能处理JS资源,一旦遇到样式资源、图片资源、HTML资源等其他资源就会报错。
其实学习WebPack主要就是学习如何处理其他资源。
3.基本配置
五大核心概念
Webpack 将来都通过 webpack.config.js 文件进行配置,来增强 Webpack 的功能
我们会对Webpack配置文件区分为开发模式和生产模式来进行配置。
- entry(入口)
指示Webpack从哪个文件开始打包。- output(输出)
指示Webpack打包的文件输出到哪里去,如何命名等。- loader(加载器)
webpack本身只能处理js等资源,其它资源都需要借助loader,Webpack才能解析。- plugins(插件)
扩展Webpack的功能。- mode(模式)
开发模式:仅能编译JS中的ES Module语法。
生产模式:能编译JS中的ES Module语法,并且进行JS压缩。
-
常用Loader
loaders,这里面是Webpack官方文档,可以在这里面寻找我们所需要的loader。但凡遇到Webpack无法识别的资源,都需要去官方寻找loader。loader写在module模块中的rules数组中。
module:{
rules:[
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
]
}
css-loader
less-loader
scss-loader
babel-loader
babel-loader的作用就是将ES6语法编写的代码转化为向后兼容的JavaScript语法,以便能够运行在当前和旧版本的浏览器和其它环境中。并且可以开启缓存,避免重复进行balbel编译。
babel主要用法是使用present预设, 扩展babel的功能,主要使用的预设有如下几点:
1.@babel/preset-env:智能预设,将ES6语法编译为普通的JS代码
2.@babel/preset/react:用来编译React JSX语法的预设
3.@babel/preset-typescript:用来编译TypeScript语法的预设
Babel 对一些公共方法使用了非常小的辅助代码,比如 _extend。默认情况下会被添加到每一个需要它的文件中。
可以引入 Babel runtime 作为一个独立模块,来避免重复引入。
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory:true, //开启babel缓存
cacheCompression:false, //关闭缓存文件压缩
plugins: ['@babel/plugin-transform-runtime']
}
}
}
postcss-loader
postcss-loader一般用于css兼容性处理,我们除了按照官网所需要的配置loader,我们还需要在package.json设置browserslist数组控制当前项目兼容的浏览器
"browserslist":["last 2 version","> 1%","not dead"]
thread-loader
配置多进程处理耗时loader,例如我们在项目中遇到耗时的loader,例如babel编译,eslint检查。我们就可以多线程打包。我们可以通过node知道目前CPU核数,然后开启多个进程数。要把该loader放在需要多线程处理的loader之前。
const os = require("os");
const threads = os.cpus().length;
{
test: /\.m?js$/,
exclude: /node_modules/,
use:[
{
loader:'thread-loader',
options:{
works:threads
}
},
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory:true, //开启babel缓存
cacheCompression:false //关闭缓存文件压缩
}
}
]
}
-
常用Plugin
html-webpack-plugin
该插件会生成一个HTML文件,并且将我们输出的JS、CSS文件,会自动引入到该HTML中,并且我们还可以配置template,也就是模板HTML。
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'public/index.html')
})
mini-css-extract-plugin
之前的css文件是被JS加载执行生成style标签,所以会存在闪屏的问题,需要等待JS执行完了,样式才生效,该插件可以单独输出样式文件,然后html-webpack-plugin则会通过link标签帮助我们引入到HTML中。
css-minimizer-webpack-plugin
主要作用是压缩CSS
terser-webpack-plugin
主要作用是压缩JS,生产环境下会默认使用此插件,并且可以自定义配置多线程进行压缩。
const TerserPlugin = require("terser-webpack-plugin");
const os = require("os");
const threads = os.cpus().length;
new TerserPlugin({
parallel:threads
})
image-minimizer-webpack-plugin
主要作用是用于压缩图片
eslint-webpack-plugin
主要是配置ESLint,ESLint是来检测 js 和 jsx 语法的工具,一般会在根目录创建.eslintrc.js,一般我们很少手写规则,一般会继承已有的规则。
// 例如在React项目中,我们可以这样写配置
module.exports = {
extends: ["react-app"],
rules: {
// 我们的规则会覆盖掉react-app的规则
// 所以想要修改规则直接改就是了
eqeqeq: ["warn", "smart"],
},
};
-
资源模块
webpack5中,自身都可以进行图片处理,因为内置了资源模块,不需要使用file-loader和url-loader进行处理,
type: "asset/resource"
和type: "asset"
的区别:
-
type: "asset/resource"
相当于file-loader
, 将文件转化成 Webpack 能识别的资源,其他不做处理 -
type: "asset"
相当于url-loader
, 将文件转化成 Webpack 能识别的资源,同时小于某个大小的资源会处理成 data URI 形式
图片处理
我们需要进行优化,也就是对图片小于一定大小,该图片转换为Base64形式。
{
test: /\.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024,
},
},
},
输出图片文件地址和文件名配置,添加下述generator配置,hash值可以选择生成10位或者不设置
{
test: /\.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024,
},
},
generator: {
filename: "static/image/[hash:10][ext][query]",
},
},
字体以及其它资源处理
因为我们仅仅只需要生成文件,不需要转换成base64形式,所以type只需要设置为asset/resource,test中若有其它资源后缀名,继续添加就好。
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:10][ext][query]",
},
},
-
每次打包时自动清空文件夹
output{
clean:true
}
-
开发服务器,文件发生变化,自动编译打包
webpack-dev-server,在src目录下的文件,如果发生改变则会自动编译打包。不会输出任何资源,在内存中编译打包。
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
},
运行命令: npx webpack serve
4.开发模式和生产模式
开发模式我们需要配置devServer等,热更新,不需要输出资源。但是生产模式我们则不需要配置服务器,并且也需要输出资源等。所以我们则需要配置不同的webpackConfig。
但是我们可以只写一份webpack.config.js。我们可以使用cross-env来区分不同的环境。
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js"
},
在webpack.config.js文件中,我们就可以通过process来区分不同的环境
const isProduction = process.env.NODE_ENV === "production";
5.SourceMap(快速定位错误)
SourceMap(源代码映射)是一个用来生成源代码与构建后代码一一映射的文件的方案。从而让浏览器提示源代码文件出错的位置。
一般我们通过查看dev-tool文档,来使用不同的SourceMap方案。一般我们则只需要考虑两种情况
- 开发模式
cheap-module-source-map
- 打包编译速度快,只包含行映射
- 生产模式
source-map
- 打包编译速度慢,包含行/列映射
devtool:"cheap-module-source-map"
6.HMR(热模块替换)
HotModuleReplacement,在开发环境开发代码时,我们每次打包编译都会耗时,会重新刷新页面,如果项目更大的话,耗时会更久。我们可以配合devServer来使用HMR。来实现某个文件更新,只针对某个文件进行重新编译打包。devServer-hot。
样式具备了热模块替换功能,style-loader已经实现了。
devServer{
hot:true
}
但是JS如果更新文件,还是会重新打包,刷新页面,所以我们需要特殊的配置
import count from './js/count';
count(1,2);
if(module.hot){
module.hot.accept('./js/count');
}
一般开发实际项目会使用vue-loader
或者react-refresh-webpack-plugin
来帮助实现热模块替换功能。
7.代码分割
多文件打包
entry:{
app:"./src/app.js",
main:"./src/main.js",
},
output:{
path:path.resolve(__dirname,"dist"),
filename:"[name].js"
}
公共代码打包独立文件
split-chunks
optimization: {
splitChunks: {
chunks: 'all',
},
}
8.PWA
work-box-plugin 渐进式网络应用程序,是一种可以提供类似于native app体验的Web app技术,其中最重要的是,在离线时应用程序能够继续运行。
9.Oneof
使用 OneOf 让资源文件一旦被某个 loader 处理了,就不会继续遍历了,打包速度更快。
module: {
rules: [
{
oneOf: [
{
test: /\.css$/i,
use: getStyleLoaders(),
},
{
test: /\.less$/i,
use: getStyleLoaders("less-loader"),
},
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
},
},
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 4 * 1024,
},
},
},
],
},
],
},
网友评论