为什么需要使用打包工具?
开发时使用的框架、es6 语法 、less 等浏览器无法识别。
需要经过编译成浏览器能识别的css、js才可以运行。
打包工具可以帮我们编译,还可以做代码压缩、兼容处理、性能优化。
常见的打包工具有什么?
vite、webpack、glup、grunt
webapck最基本的使用?
是一个静态资源打包工具,以一个或多个文件为打包入口,将项目中所有文件编译组合成输入一个或多个文件。这个输出的文件我们叫budle,他就是经过编译可以在浏览器运行的文件。
webpack本身的功能是有限的?
开发模式:仅仅编译js modle语法
生产模式:编译js modle语法、压缩js代码
package.json 是什么文件?
通常我们需要安装一些依赖包,而在下载这个包之前,我们需要包描述文件。通常描述这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证、如何启动项目、运行脚本等元数据。
package.json 一般在项目创建之初创建。创建方式可以手动(直接在项目根目录新建一个 package.json 文件)、也可以npm init -y 初始化一个,y 就是要使用配置的默认值
package.json文件就是一个JSON对象,该对象的每一个成员就是当前项目的一项设置
webpack 安装文档,不建议全局安装
练习步骤:
1、新建一个包,名称不能和webpack重复
2、创建基本的mani.js 文件、src、public文件、写入es6 模块化语法,报错,浏览器无法识别。
3、试试使用webpack 后能否识别呢?无法解析modle语法
4、引入之前需要初始化一个包描述文件 npm init -y
5、npm install webpack webpack-cli --save-dev
6、安装成功后执行npx webpack ./src/main.js --mode=development
,npx 会将node—module 的bin 下面的内容临时添加到环境变量。
7、执行上面即可打包了。默认输出到dist,可以观察输出文件,是编译后的文件。
8、npx webpack ./src/main.js --mode=production
生产模式,会压缩代码
webapck的五大核心概念
入口entry
输入output
loader webpack本身只能处理js、json等资源,其他资源需要借助loader
plugin 拓展功能
mode 模式:生产、开发
练习步骤:
1、安装好之后建一个webpack的配置文件,在根路径下,并且文件名必须是webpack.config.js
2、添加基本配置
3、我们之前打包执行的是npx webpack ./src/main.js --mode=development
这个命令,写了webpack的配置文件中设置了入口后,可以直接使用npx webpack 执行了。上面是使用cli的方式运行本地的webpack,但这样还是有些麻烦。
4、在 package.json 文件中添加一个 npm script: “build”: “webpack”
现在,可以使用 npm run build 命令替代之前使用的 npx 命令。注意,使用 npm scripts 便可以像使用 npx 那样通过模块名引用本地安装的 npm packages。
拓展,可以学习下npm中文文档
资源管理
1、使用style样式,需要借助loader
2、npm install --save-dev style-loader css-loader
3、添加配置,参考官网
1、使用less资源
2、npm install less less-loader --save-dev
3、添加配置,参考官网
1、图片资源的使用
2、不需要要下载,使用内置的asset即可。资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。``关于这块配置webpack官网介绍
3、添加配置,
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
1、对文件的加载,如 JSON 文件、CSV、TSV 和 XML。
2、npm install --save-dev csv-loader xml-loader
3、添加配置,参考官网
调整文件打包输出目录
每一次打包都会在dist下多一些文件,而且很混乱。我们在下一次打包之前手动删除dist,再重新打包。
并设置输出路径,文件资源可设置输出路径。
为特定资源指定输出路径
generator: {
filename: 'asset/[hash:10][ext][query]'
}
可不可以不每次都需要手动删除呢?
能不能自动清除dist文件上次内容?可以,在output 对象中配置clean:true 即可。
处理js资源
webpack对于js资源的处理是有限的,只能处理model语法,对于es6新语法不兼容,我们需要使用babel
在转换之前先介绍一下eslint ,用于检查js和jsx语法的工具。更多介绍eslint官网
在webpack中使用eslint
1、npm install eslint-webpack-plugin --save-dev
2、npm install eslint --save-dev
3、添加配置,参考官网
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
// ...
plugins: [new ESLintPlugin({
context:path.resolve(__dirname,'src'),
})]
// ...
};
4、运行起来报错,缺少eslint的配置文件。我们在根目录下新建 .eslintrc.js 文件名不能改。
然后具体的配置可以参考官网,可以继承推荐的默认配置。
5、发现dist下定义的文件也被eslint 检查了,但我们并不需要检查这些文件。在根目录下创建一个 .eslintignore 文件,写上需要忽略的文件路径即可。
在webpack中使用babel
关于bable的介绍可以看bable官网
1、npm install -D babel-loader @babel/core @babel/preset-env webpack
2、配置,参考官网 bable配置
3、配置可以直接写在webpack的配置文件中,也可以在根目录创建 babel.config.js 配置。
处理html资源
1、原本html中引入的js资源是这么写的
<script src="../dist/main.js"></script>
引入的是打包编译后的文件,如果更改入口起点的名称,或者添加一个新的入口,那么会在构建时重新命名生成的 bundle,但是 index.html 仍然在引用旧的名称!而且如果需要引入很多资源,手动维护非常困难。
我们可以使用 HtmlWebpackPlugin (为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中)来解决这个问题。
安装:
npm install --save-dev html-webpack-plugin
配置:
new HtmlWebpackPlugin({
title: '管理输出',
// 模板:以public/index.html 文件创建新的html 这样打包之后的html不会把之前的东西丢掉
template:path.resolve(__dirname,'public/index.html')
}),
使用了这个插件,我们无需在html中手动引入,他会自动帮我们引入并且在输出文件中新增一个html文件。
搭建开发服务器
我们之前每次改动了src的内容,都需要编译之后才能看到效果,需要手动执行npx webapck ,我们希望webpack能自动化,可以使用
webpack-dev-server,他相当于webpack 启动了一个服务器,他会帮我们监听src下所有的改动,只有有改动会帮我们自动打包编译。
安装
npm install --save-dev webpack-dev-server
配置
devServer:{
host:'localhost',// 启动服务器的域名
port:'8080',// 启动服务器端口号,
open:true,// 是否自动打开浏览器
static: './dist', // 将 dist 目录下的文件 serve 哒服务器
},
执行命令
npx webpack serve
添加一个可以直接运行 dev server 的 script:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"start": "webpack serve --open",
"build": "webpack"
},
在命令行中运行 npm start,会看到浏览器自动加载页面。
eee,报错了!
报错内容:
Error: Cannot find module ‘ajv/dist/compile/codegen’
解决办法:
npm i ajv
npm install ajv-errors@1.0.1
再次启动
eee,又报错了!
报错内容:
Error: Conflict: Multiple chunks emit assets to the same filename static/js/bundle.js (chunks main and vendors-node_modules_react-hot-loader_patch_js-node_modules_react_jsx-dev-runtime_js-node_mod-4610d2)
解决办法:
让它工作不得不改变filename: "static/js/bundle.js"至filename: "static/js/[name].js"
output: {
path: undefined,
publicPath: "/",
filename: "static/js/[name].js",
chunkFilename: "static/js/[name].chunk.js",
}
再次启动可以了
webpack-dev-server 在编译之后不会写入到任何输出文件,而是将 bundle 文件保留在内存中,然后将它们 serve 到 server 中,就好像它们是挂载在 server 根路径上的真实文件一样。如果你的页面希望在其他不同路径中找到 bundle 文件,可以通过 dev server 配置中的 devMiddleware.publicPath 选项进行修改。
意思就是开发模式下不会生成打包后的文件,尝试把dist删除,保存后自动打包确实没有生成dist文件了
修改js文件内容页面自动更新了。
生产和开发环境两套配置
development(开发环境) 和 production(生产环境) 这两个环境下的构建目标存在着巨大差异。在开发环境中,我们需要:强大的 source map 和一个有着 live reloading(实时重新加载) 或 hot module replacement(热模块替换) 能力的 localhost server。而生产环境目标则转移至其他方面,关注点在于压缩 bundle、更轻量的 source map、资源优化等,通过这些优化方式改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。
首先我们新建一个config文件夹,分别新建webpack.dev.js 和 webpack.prod.js 两个文件
将文件中使用相对路径的地方加个…/
template:path.resolve(__dirname,'../public/index.html')
但是入口文件路径不改变,因为配置文件运行时在根目录
entry:'./src/main.js',
生产环境不需要dev-server
分别添加两个命令
"build": "webpack --config ./config/webpack.prod.js",
"start": "webpack serve --config ./config/webpack.dev.js"
执行对应的命令,生产环境下的budle 有压缩。
虽然,以上我们将 生产环境 和 开发环境 做了细微区分,但是,请注意,我们还是会遵循不重复原则(Don’t repeat yourself - DRY),保留一个 “common(通用)” 配置。为了将这些配置合并在一起,我们将使用一个名为 webpack-merge 的工具。此工具会引用 “common” 配置,因此我们不必再在环境特定(environment-specific)的配置中编写重复代码。
我们先从安装 webpack-merge 开始,并将之前指南中已经成型的那些代码进行分离:
npm install --save-dev webpack-merge
新建一个webpack.common.js文件,写入公共配置
在生产和开发文件中分别引入即可。
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
});
提取css成单独文件
我们可以看到,现在我们的css文件,是被打包到了js中,当js文件加载时,会创建一个style 标签来生成样式。
只有js加载完了,页面才会出现样式,给用户闪屏的感觉,体验不好。
应该是将样式抽离到单独的css文件中,通过link标签引入,加载的性能才好
借助插件MiniCssExtractPlugin来实现,官网介绍
1、安装:
npm install --save-dev mini-css-extract-plugin
2、配置
官方建议 mini-css-extract-plugin 与 css-loader 一起使用。
将styel-loader 替换为MiniCssExtractPlugin.loader,因为插件会将 CSS 提取到单独的文件中,
为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
不再需要创建style 标签了
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
use: [MiniCssExtractPlugin.loader, 'css-loader'],
现在已经被打包到main.css 中了
css 兼容性处理
postcss-loader 官网介绍
可以帮我们处理一些样式兼容性问题
1、安装
npm install --save-dev postcss-loader postcss postcss-preset-env
2、配置,必须写在css-loder 后面
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
[
'postcss-preset-env',
{
// 其他选项
},
],
],
},
},
3、在package.json 中添加配置
设置浏览器兼容需要做到什么程度。
最近一个版本,99%任然再使用的浏览器
"browserslist" :[
"last 2 version",
"< 1%",
"not dead"
]
css压缩处理
通过观察可以发现,我们dist目录下的资源,js和html都压缩了。但css文件没有压缩处理。
我们可以借助CssMinimizerWebpackPlugin 插件,官网介绍
1、安装
npm install css-minimizer-webpack-plugin --save-dev
2、配置
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
optimization: {
minimizer: [
// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
// `...`,
new CssMinimizerPlugin(),
],
},
再次打包已经被压缩了
打包优化
1、提升开发体验
2、提升打包构建速度
3、减少代码体积
4、优化代码性能
sourceMap
开发时我们运行的代码是编译之后的,如果有报错,只能定位到编译后的位置,不便于我们排查问题。
sourceMap(源代码映射) 是一个用来生成源代码和映射代码构建的方案
他会生成xx.map 文件,里面包含源代码码和构建好的代码每一行,每一列的关系。从而让浏览器提示源文件的出错位置,从而帮我们快速定位错误。
如何使用devtool?官网介绍
具体配置:
开发模式:
mode:'development',
devtool:'cheap-module-source-map',
生成模式:
mode:'production',
devtool:'source-map',
经过测试,已经定位到具体一行了
HotModlueReplcaement
当我们在开发时只修改了某一个模块的代码,webpack在打包时会重新打包,速度很慢,页面整体重新刷新了。我们希望它只编译需要打包的模块,其他模块不变。
HotModlueReplcaement(热模块替换)在程序运行中,替换、添加、删除模块,而无需加载整页面,
如何使用?
从 webpack-dev-server v4.0.0 开始,热模块替换是默认开启的。
devServer:{
host:'localhost',// 启动服务器的域名
port:'8080',// 启动服务器端口号,
open:true,// 是否自动打开浏览器
static: './dist',
hot:true // 只应用与开发环境,生产环境不需要,默认开启
},
但是只有css/html 可以做到,对于js 需要在入口文件manjs中
if(module.hot) {
// 判断是否支持热模块替换功能,有的话需要一个个js文件添加
module.hot.accept('./js/sum.js')
}
每个js文件都需要手动引入,太麻烦?
当然了,vue-loader,react-hot-loder 已经帮我们做了这些事情。
oneOf
打包时每个文件都会经过所有 loader 处理,例如一个css文件也会进过js文件的判断,虽然因为 test 正则原因实际没有处理上,但是都要过一遍比较慢。所以使用OneOf,匹配上一个 loader, 剩下的就不匹配了,开发模式和生产模式都可以用
module: {//loader规则
rules: [
// 比如是css文件,匹配到之后处理use对应的一组loader,后续不再匹配
{
//每个文件只能被其中一个loader配置处理
oneOf: [
{
test: /\.css$/i, // 用来匹配 .css 结尾的文件
use: [
"style-loader", //将js中css通过创建style标签添加到html中
"css-loader" //该模块将css资源编译成commonjs的模块到js中
],//use 数组里面 Loader 执行顺序是从右到左(从下到上)
},
{
test: /\.less$/i, // 用来匹配 .less 结尾的文件
//loader:"xxx"只能使用1个loader
use: [//use可以使用多个loader
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',//将less变成css文件
],
},
eslint 和babel 缓存
每次打包的时候js文件都需要经过eslint检查和babel编译,速度很慢。
我们如果能缓存之前的结果,第二次打包的速度就会快很多
对babel的配置
{
test:/\.js$/,
include:path.resolve(__dirname,'../src'),
loader:'babel-loader',
options:{
cacheDirectory:true, // 开启babel缓存
cacheCompression:false // 关闭缓存文件压缩
}
}
对eslin的配置
new ESLintPlugin({
context:path.resolve(__dirname,'../src'),
exclude:"node_modules",
// cache:true,// 开启缓存
// cacheLocation:path.resolve(__dirname,'../node_modules/.cache/eslintcache')
}),
多进程打包
我们打包的速度大部分时候是处理js文件的速度,而处理js文件主要就是eslint、bable、terser这三个工具,我们要提升他们的运行速度,可以开启多线程同时处理。
但是需要注意的是,仅在特别耗时的项目中使用,因为每个进程启动大约有600ms的开销
我们启动进程的数量就是cpu的核数。
如何获取自己电脑cpu的核数?
const os = require('os');
const threads = os.cpus().length;
还需要借助
npm i thread-loader -D
配置
{
test:/\.js$/,
include:path.resolve(__dirname,'../src'),
use:[
{
loader:'thread-loader',// 开启多进程
options :{
works:threads // 进程数量
}
},
{
loader:'babel-loader',
options:{
cacheDirectory:true, // 开启babel缓存
cacheCompression:false // 关闭缓存文件压缩
}
}
],
}
还需要引入一个插件
optimization: {
minimizer: [
// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
// `...`,
new CssMinimizerPlugin(),
new TerserWebpackPlugin({
parallel:threads
})
],
},
什么是tree-shaking
我们定义或引入了一些第三方工具函数或组件库,如果没做特殊处理的话,打包的时候会引入整个库,即使我们使用的是很小一部分功能。
依赖es model ,移除没有被引用的代码
webpack 默认开启了这个功能,无需配置
减少babel的体积
babel 会为每个编译后的文件添加辅助代码
Babel 对一些公共方法使用了非常小的辅助代码,比如 extend 。默认情况下会被添加到每一个需要它的文件中。
你可以将这些辅助代码作为一个独立模块,来避免重复引入。
babel/plugin-transform-runtime是什么
禁用了 Babel 自动对每个文件的 runtime 注入,而是引入babel/plugin-transform-runtime并且使所有辅助代码从这里引用babel/plugin-transform-runtime
1、安装
npm i @babel/plugin-transform-runtime -D
2、配置
{
loader:'babel-loader',
options:{
cacheDirectory:true, // 开启babel缓存
cacheCompression:false, // 关闭缓存文件压缩
plugins:["@babel/plugin-transform-runtime"],// 减少代码体积
}
}
图片压缩
插件官网介绍,使用方式直接参考官网,这里不记录了
代码分割,优化代码运行性能
我们打包时会将所有的js文件都打包到一个文件中,体积太大。如果我们只渲染首页,那么应该只加载首页的js文件,其他文件不需要加载。
所以我们就需要将打包生成的文件进行代码分割,生成多个js文件,渲染哪个页面就只加载某个页面的js文件,这样加载的资源减少,速度就更快。
代码分割主要做了两件事情:
1、将打包生成的文件分为多个js文件
2、按需加载,需要哪个文件就加载哪个文件。
多入口文件
entry:{
main:'./src/main.js',
app:'./src/app.js'
},
output:{
// path 是所有文件输出的路径
path:path.resolve(__dirname,'../dist'),// 当前文件的文件夹目录的dist下面
filename:'static/js/[name].js',
clean:true
},
设置了多个入口文件,就会有多个输出文件。
但是如果多个文件中引入了公共的函数,我们可以发现打包后的两个js文件中都引入了一边。
我们希望,将公共的代码抽离出来,只需要写一次。
可以在webpack的配置文件中添加配置,官网介绍
optimization: {
splitChunks:{
chunks:'all',// 对所有模块都进行分割
//修改配置
cacheGroups: {// 组,哪些模块要打包到一个组
default:{
// 没有写的都是使用默认配置,单独写的会覆盖默认配置
minSize:0
}
}
},
/*
以下都是默认配置
minSize:20000 分割代码最小的大小
minRemainingSize: 0,// 类似于minsize,最后确保提取的文件大小不能为0,
minChunks: 1,// 至少被引用的次数,满足条件才会代码分割
maxAsyncRequests: 30,// 按需加较时并行加战的文件的最大数量
maxInitialRequests: 30,// 入口js文件最大并行请求数量
enforceSizeThreshold: 50000,// 超过5kb一定会单独打包(此时会忽略minRemainingSize
cacheGroups: {// 组,哪些模块要打包到一个组
defaultVendors:{ // 组名
test: /[\V]node_modules[\V]/,// 需要打包到一起的模块
priority: -10,// 权重《越大越高》
reuseExistingChunk: true,// 如果当前 chunk 包含已从主 bundle 中拆分出的模块
},
default:{// 其他没有写的配置会使用上面的默认值
minChunks:2,// 这里的minChunks权重更大
priority: -20,
reuseExistingChunk: true.
}
}
*/
minimizer: [
// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
// `...`,
new CssMinimizerPlugin(),
new TerserWebpackPlugin({
parallel:threads
})
],
},
添加完配置之后再次打包,多了一些文件
按需加载
尽管我们实现了多模块输出,但是对于初始化时不需要加载的js文件,还是一次性加载了
例如countjs文件中的方法,仅仅在按钮点击时才会触发,我们希望能异步加载整个文件。
动态引入,将文件代码分割,拆分成单独的模块,在需要使用的时候自动加载
注意当调用 ES6 模块的 import() 方法(引入模块)时,必须指向模块的 .default 值,因为它才是 promise 被处理后返回的实际的 module 对象
document.getElementById("btn").onclick = function () {
import('./js/count').then((res)=>{
console.log(res.default(9,1),'res');
})
.catch((err)=>{
console.log('模块引入失败',err);
})
}
这样我们可以看到只有点了按钮后才会加载count文件,manjs中没有引入
管理打包输出的文件名
对于动态加载的文件
添加配置
少了个]
查看效果
所有type为asset 的资源都可以在 output中统一设置输出
assetModuleFilename:'static/css/[hash:10][ext][query]',
preload、prefetch
前面已经做了代码分割,同时会使用import 动态导入语法来进行代码按需加载(路由懒加载就是这样实现的)
但是如果动态加载的资源比较大,用户会感觉到明显的卡顿。
所以我们希望浏览器在空闲的时候,能加载后续需要的资源、
preload: 告诉浏览器立即加载资源,但是并不执行。优先级更高。只能加载当前页面资源。兼容性大约92%
prefetch:告诉浏览器在空闲时间才开始加载资源。优先级低,可以加载当页面的也可以加载下一个页面的。兼容性大约72%
缓存
官网缓存介绍
我们将dist文件部署到服务器后,客户端就可以通过访问站点来获取资源,浏览器都使用了一种缓存技术。
然而,如果在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。
我们可以给输出文件添加hash值,当内容变化再次构建时,hash会发生变化
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
那如果什么也不改,hash应该不变吧?
还是变了!
为什么呢?
首页写我们先看下,在打包的时候想要把公共的模块提取出来,只加载一次。
将 optimization.runtimeChunk 设置为 true 或 ‘multiple’,会为每个入口添加一个只含有 runtime 的额外 chunk。
值 “single” 会创建一个在所有生成 chunk 之间共享的运行时文件。此设置是如下设置的别名:
由于像 lodash 或 react 这样的第三方库很少像本地源代码一样频繁修改,因此通常推荐将第三方库提取到单独的 vendor chunk 中。这一步将减少客户端对服务器的请求,同时保证自身代码与服务器一致。
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
这样可以大大减少mainjs 打包后的体积。
回到上面的问题,为什么没有什么改动hash也变化 了?
这是因为每个 module.id 会默认基于解析顺序(resolve order)增量。换言之,当解析顺序发生变化,ID 也会随之改变。简要概括便是:
main bundle 会随着自身的新增内容的修改,而发生变化。
vendor bundle 会随着自身的 module.id 的变化,而发生变化。
manifest runtime 会因为现在包含一个新模块的引用,而发生变化。
上面的第一点与最后一点都是符合预期的行为,而 vendor 的哈希值发生变化是我们要修复的。试试将 optimization.moduleIds 设置为 ‘deterministic’:
optimization: {
moduleIds: 'deterministic',
现在,不论是否添加任何新的本地依赖,对于前后两次构建,vendor 的哈希值都应保持一致
core-js
过去我们引用了babel对js代码进行兼容性处理,其中使用@babel/preset-env 智能预设来处理兼容性问题。
它能将es6的语法进行编译转换,但如果是async,promse等es6+的语法。它没办法处理。
此时我们的js代码依然存在兼容性问题。
core-js 是专门用老做es6 及以上api 的 polyfill(垫片)
就是用社区上提供的一段代码。让我们在不兼容某些特性的浏览器上能够兼容。
1、安装
npm i core-js
2、引入
import ‘core-js’
3、上面全部引入,体积太大,我们只想引入某一个
import “core-js/es/promise”
4、每次使用一个都需要手动引入吗,太麻烦了。我们希望它能够实现自动引入,使用了那个就自动引入那个
我们只需要在babel的配置文件中添加配置即可。
module.export = {
presets: [['@babel/preset-env',{
useBuiltIns:'usage',// 按需自动引入
corejs:3 // corejs的版本
}]]
}
PWA
什么是pwa ? 渐进式网络应用程序
一种可以提供类似于navtie app 体验的技术。
在离线状态下应用程序依然能够继续运行。
内部通过ServiceWorks 技术实现。
webapck 应该帮我们封装好了,我们只需要使用即可。
pwa的使用
使用过程中报错了
因为我们注册的文件在dist下面
我们可以下载一个专门用来部署静态资源服务器的库
npm i serve -g
安装好后,通过
serve dist
然后我们就可以看到效果了,设置为离线状态再加载页面,页面缓存了刚才的内容。
但是这个技术,目前兼容性并不好
webpack 优化总结
官网给的优化建议
总结
我们从 4 个角度对 webpack 和代码进行了优化:
一、提升开发体验
1、使用 source Map 让开发或上线时代码报错能有更加准确的错误提示。
二、提升 webpack 提升打包构建速度
1、使用HotModuleReplacement 让开发时只重新编译打包更新变化了的代码,不变的代码使用须存,从而使更新速度更快。
2、使用 oneof 让资源文件一旦被某个loader 处理了,就不会继续遍历了,打包速度更快。
3、使用 Include/Exclude 排除或只检测某些文件,处理的文件更少,速度更快。
4、使用 Cache 对 eslint 和 babel 处理的结果进行缓存,让第二次打包速度更快。
5、便用 Thead 多进程处理 eslint 和 babel 任务,速度更快(需要注意的是,进程启动通信都有开销的,要在比较多代码处理时使用才有效果)
三、减少代码体积
1、使用 Tree shaking 剔除了没有使用的多余代码,让代码体积更小。
2、使用 @babel/plugin-transfor-runtime 插件对 babel 进行处理,让辅助代码从中入,而不是每个文件都生成辅助代码,从而体积更小
3、使用 Image Minimizer 对项目中图片进行压缩,体积更小,请求速度更快。(需要注意的是,如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。)
四、优化代码运行性能
1、便用 code Split 对代码进行分割成多个js 文件,从而使单个文件体积更小,并行加载 js 速度更快。并通过 import 动态导入语法进行按需加载,从而达到需要使用时才加载该资源,不用时不加载资源。
2、使用 Preload / Prefetch 对代码进行提前加载,等未来需要使用时就能直接使用,从而用户体验更好。
3、便用 Network Cache 能对输出资源文件进行更好的命名,将来好做缓存,使用optimization.splitChunks 的cacheGroups 缓存第三方库,从而用户体验更好。
4、使用 core-js对js 进行兼容性处理,让我们es6+代码能运行在低版本浏览器。
5、使用 PWA 能让代码离线也能访问,从而提升用户体验。
在react-cli 中配置webpack
待学习
在vue-cli 中配置webpack
待学习
下面部分是原理,了解即可
loader 介绍
我们前面用到了各种各样的loader,他可以帮助webpack将不同类型的文件转换成webpack可以识别的模块。
loader的分类
1、pre 前置
2、normal 普通,默认
3、inline 内联
4、post 后置
执行顺序:pre > normal > inline > post
相同优先级的loader执行顺序为:从右到左,从下到上
使用loader的两种方式
1、配置方法
2、内联方式,在import 语法中显示指定loader
不想写了,放个截图吧,不推荐使用这种方式引入
定义一个简单的loader
定义
使用,相当于是一个函数
同步和异步loader
/*
err d代表是否有错误
content 处理后的内容
source-map 继续传递给下一个loader
meta 参数传递给下一个loader
同步loader中不能进行异步处理
*/
module.exports = function (content,map,meta) {
this.callback(null,content,map,meta)
};
// 异步loader
module.exports = function (content,map,meta) {
const callback = this.async();
setTimeout(()=>{
callback(null,content,map,meta)
},1000)
}
// raw loader 用于处理如本、字体等,接受的content 是buffer数据,二进制
function rawLoader (content,map,meta) {
return content;
}
rawLoader.raw = true;
module.exports = rawLoader;
//pitch loader 优先于normal 执行,并且是从左到右执行
module.exports.pitch = function (content,map,meta) {
return content;
}
loader API
更多关于api的介绍
我们需要了解的几个
自定义loader文章来源:https://www.toymoban.com/news/detail-731585.html
// 自定义loader1
module.exports = function (content) {
// 清楚文件内容中所有的console
return content.replace(/console\.log\(.*\);?/g,'');
}
还有一些pulgin的原理,不想看了,就学到这吧文章来源地址https://www.toymoban.com/news/detail-731585.html
到了这里,关于尚硅谷webpack课程学习笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!