一、邂逅Webpack
Webpack是什么
webpack是一个静态的模块化打包工具,为现代的JavaScript应用程序;
-
打包bundler:webpack可以将帮助我们进行打包,所以它是一个打包工具
-
静态的static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器);
-
模块化module:webpack默认支持各种模块化开发,ES Module、CommonJS、AMD等;
-
现代的modern:我们前端说过,正是因为现代前端开发面临各种各样的问题,才催生了webpack的出现和发展;
二、webpack配置和css处理
webpack配置文件
1、出口、入口的配置
我们可以在根目录下创建一个webpack.config.js文件,来作为webpack的配置文件:
module.exports = {
entry: " 指定入口路径",
output: {
filename:"bundle.js", // 出口名字
path: '出口路径'
}
}
2、css-loader的使用
loader是什么
-
loader 可以用于对模块的源代码进行转换;
-
我们可以将css文件也看成是一个模块,我们是通过import来加载这个模块的;
-
在加载这个模块时,webpack其实并不知道如何对其进行加载,我们必须制定对应的loader来完成这个功能;
module.rules的配置如下:
-
test属性:用于对resource(资源)进行匹配的,通常会设置成正则表达式;
-
use属性:对应的值时一个数组:[UseEntry]
-
UseEntry是一个对象,可以通过对象的属性来设置一些其他属性
-
loader:必须有一个loader属性,对应的值是一个字符串;
-
options:可选的属性,值是一个字符串或者对象,值会被传入到loader中;
-
query:目前已经使用options来替代;
-
-
传递字符串(如:use: [ 'style-loader' ])是loader 属性的简写方式(如:use: [ { loader: 'style-loader'} ])
-
-
loader属性:Rule.use: [ { loader } ] 的简写。
module.exports = {
entry: " 指定入口路径",
output: {
filename:"bundle.js", // 出口名字
path: '出口路径'
},
module: {
rules: [
{
test:/\.css$/,
// loader:"css-loader" // 写法一
// use:["css-loader"] //写法二
// 写法三
use:[
{loader:"css-loader"}
]
}
]
}
}
3、style-loader
当我们通过css-loader来加载css文件时,代码没有生效。这是因为css-loader只是将.css文件进行解析,并不会将解析之后的css插入到页面中,而style-loader将完成插入style的操作
注意:因为loader的执行顺序是从右向左(或者说从下到上,或者说从后到前的),所以我们需要将styleloader写到css-loader的前面;
use:[
{loader:"style-loader"},
{loader:"css-loader"}
]
4、less-loader
use:[
{loader:"style-loader"},
{loader:"css-loader"}
{loader:"less-loader"}
]
5、浏览器的兼容性
认识browserslist工具
-
Browserslist编写规则一:
-
defaults:Browserslist的默认浏览器(> 0.5%, last 2 versions, Firefox ESR, not dead)。
-
5%:通过全局使用情况统计信息选择的浏览器版本。>=,<和<=工作过。
-
dead:24个月内没有官方支持或更新的浏览器。现在是IE 10,IE_Mob11,BlackBerry 10,BlackBerry 7,Samsung 4和OperaMobile12.1。
-
last 2 versions:每个浏览器的最后2个版本。
-
配置browserslist
-
方案一:在package.json中配置;
"browserslist": [ "last 2 version", "not dead", "> 0.2%" ]
-
方案二:单独的一个配置文件.browserslistrc文件;
last 2 version not dead > 0.2%
6、认识postCss工具
PostCSS是一个通过JavaScript来转换样式的工具,这个工具可以帮助我们进行一些CSS的转换和适配,比如自动添加浏览器前缀、css样式的重置;
如何使用
安装工具:postcss、postcss-cli
npm install postcss postcss-cli -D
插件autoprefixer
添加浏览器前缀需要安装autoprefixer
npm install autoprefixer -D
直接使用使用postcss工具,并且制定使用autoprefixer
npx postcss --use autoprefixer -o end.css ./src/css/style.css
postcss-loader
-
借助构建工具进行css处理
npm install postcss-loader -D
{
loader:"postcss-loader",
options: {
postcssOptions: {
plugins: [
require('autoprefixer')
]
}
}
},
-
单独的postcss配置
在跟目录下创建postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
-
postcss-preset-env
在项目中配置postcss-loader时,我们一般不使用autoprefixer。而是使用另一插件postcss-preset-env
-
postcss-preset-env也是一个postcss的插件;
-
它可以帮助我们将一些现代的CSS特性,转成大多数浏览器认识的CSS,并且会根据目标浏览器或者运行时环境添加所需的polyfill;
-
也包括会自动帮助我们添加autoprefixer(所以相当于已经内置了autoprefixer);
安装
npm install postcss-preset-env -D
使用
module.exports = {
plugins: [
require('postcss-preset-env')
]
}
三、加载和处理其他资源
1、file-loader
用来处理jpg、png等格式的图片
-
file-loader的作用就是帮助我们处理import/require()方式引入的一个文件资源,并且会将它放到我们输出的文件夹中;
安装
npm install file-loader -D
配置:
{
test:/\.(png|jpe?g|svg|gif)$/i,
use: {
loader: "file-loader"
}
}
1、文件名称规则
对处理后的文件名称按照一定的规则进行显示,一般使用PlaceHolders来完成,webpack给我们提供了大量的PlaceHolders来显示不同的内容:
介绍几个最常用的placeholder:
-
[ext]:处理文件的扩展名;
-
[name]:处理文件的名称;
-
[hash]:文件的内容,使用MD4的散列函数处理,生成的一个128位的hash值(32个十六进制);
-
[contentHash]:在file-loader中和[hash]结果是一致的(在webpack的一些其他地方不一样,后面会讲到);
-
[hash:<length>]:截图hash的长度,默认32个字符太长了;
-
[path]:文件相对于webpack配置文件的路径;
2、设置文件名称和存放路径
{
test:/\.(png|jpe?g|svg|gif)$/i,
use: {
loader: "file-loader"
options: {
name: "img/[name].[hash:8].[ext]",
outputPath: "img"
}
}
}
2、url-loader
将较小的文件转换为base64的URI
安装:
npm install url-loader -D
配置:
{
test:/\.(png|jpe?g|svg|gif)$/i,
use: {
loader: "url-loader"
options: {
name: "img/[name].[hash:8].[ext]",
outputPath: "img"
}
}
}
打包之后的显示结果跟file-loader一样,但是在打包好的dist文件夹中,看不到图片文件,而是转换为base64格式存储。
limit属性
限制转换base64格式的图片大小(比如小于100kb)
{
test:/\.(png|jpe?g|svg|gif)$/i,
use: {
loader: "url-loader"
options: {
limit:100 * 1024,
name: "img/[name].[hash:8].[ext]",
outputPath: "img"
}
}
}
3、asset module type
1、介绍
-
webpack5之前,加载这些资源我们需要使用一些loader,比如raw-loader 、url-loader、file-loader
-
webpack5之后,我们可以直接使用资源模块类型(asset module type),来替代上面的这些loader;
资源模块类型(asset module type),通过添加4 种新的模块类型,来替换所有这些loader
-
asset/resource发送一个单独的文件并导出URL。之前通过使用file-loader 实现
-
asset/inline导出一个资源的data URI。之前通过使用url-loader 实现;
-
asset/source导出资源的源代码。之前通过使用raw-loader 实现;
-
asset在导出一个data URI 和发送一个单独的文件之间自动选择。之前通过使用url-loader,并且配置资源体积限制实现;
2、使用
{
test: /\.(png|jpe?g|svg|gif)$/i,
type: "asset/resource",
},
-
如何自定义文件的输出路径和文件名
方式一:修改output,添加assetModuleFilename属性;
output: {
filename: "bundle.js", // 出口名字
path: "出口路径",
assetModuleFilename:"img/[name].[hash:6][ext]"
},
方式二:在Rule中,添加一个generator属性,并且设置filename;
{
test: /\.(png|jpe?g|svg|gif)$/i,
type: "asset/resource",
generator: {
filename: "img/[name].[hash:6][ext]",
},
},
-
url-loader中的limit限制图片大小效果
{
test: /\.(png|jpe?g|svg|gif)$/i,
type: "asset", // 注意
generator: {
filename: "img/[name].[hash:6][ext]",
},
parser: {
dataUrlCondition: {
maxSize: 100 *1024
}
}
},
4、加载字体文件
处理特殊字体或者字体图标的使用
我们可以选择使用file-loader来处理,也可以选择直接使用webpack5的资源模块类型来处理;
{
test: /\.(woff2?|eot|ttf)$/,
type: "asset/resource",
generator: {
filename: "img/[name].[hash:6][ext]",
},
},
四、认识plugin
-
Loader是用于特定的模块类型进行转换;
-
Plugin可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等;
1、CleanWebpackPlugin
每次修改了一些配置,重新打包时,都需要手动删除dist文件夹,CleanWebpackPlugin可以帮助我们完成这个功能。
安装:
npm install clean-webpack-plugin -D
配置:
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
plugins : [
new CleanWebpackPlugin()
]
};
2、HtmlWebpackPlugin
HtmlWebpackPlugin用来对HTML进行打包处理
安装:
npm install html-webpack-plugin -D
配置:
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
titile: "webpack案例",
}),
],
};
3、自定义HTML模板
如果我们想在自己的模块中加入一些比较特别的内容:
-
添加一个noscript标签,在用户的JavaScript被关闭时,给予响应的提示;
-
比如在开发vue或者react项目时,我们需要一个可以挂载后续组件的根标签<div id="app"></div>;
自定义模板数据填充
上面的代码中,会有一些类似这样的语法<%变量%>,这个是EJS模块填充数据的方式。
在配置HtmlWebpackPlugin时,我们可以添加如下配置:
-
template:指定我们要使用的模块所在的路径;
-
title:在进行htmlWebpackPlugin.options.title读取时,就会读到该信息;
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
titile: "webpack案例",
template: "./public/index.html"
}),
],
};
4、DefinePlugin的介绍
当在我们的模块中还使用到一个BASE_URL的常量,我们需要设置这个常量,这个时候我们可以使用DefinePlugin插件;
使用:
DefinePlugin允许在编译时创建配置的全局常量,是一个webpack内置的插件(不需要单独安装):
const { DefinePlugin } = require("webpack");
module.exports = {
plugins: [
new DefinePlugin({
BASE_URL:'"./"' // 注意需要多一层包裹
})
],
};
5、CopyWebpackPlugin
vue的打包过程中,如果我们将一些文件放到public的目录下,那么这个目录会被复制到dist文件夹中。这个复制的功能,我们可以使用CopyWebpackPlugin来完成;
安装:
npm install copy-webpack-plugin -D
配置:
-
from:设置从哪一个源中开始复制;
-
to:复制到的位置,可以省略,会默认复制到打包的目录下;
-
globOptions:设置一些额外的选项,其中可以编写需要忽略的文件:
-
.DS_Store:mac目录下回自动生成的一个文件;
-
index.html:也不需要复制,因为我们已经通过HtmlWebpackPlugin完成了index.html的生成;
-
new CopyWebpackPlugin({
patterns: [
{
from:"public",
globOptions: {
ignore: [
'**/.DS_Store',
'**/index.html'
]
}
}
]
})
五、source-map
source-map是从已转换的代码,映射到原始的源文件。使浏览器可以重构原始源并在调试器中显示重建的原始源
使用:
第一步:根据源文件,生成source-map文件,webpack在打包时,可以通过配置生成source-map;
第二步:在转换后的代码,最后添加一个注释,它指向sourcemap;
//# sourceMappingURL=common.bundle.js.map
浏览器会根据我们的注释,查找响应的source-map,并且根据source-map还原我们的代码,方便进行调试。
分析source-map
-
version:当前使用的版本,也就是最新的第三版;
-
sources:从哪些文件转换过来的source-map和打包的代码(最初始的文件);
-
names:转换前的变量和属性名称(因为我目前使用的是development模式,所以不需要保留转换前的名称);
-
mappings:source-map用来和源文件映射的信息(比如位置信息等),一串base64VLQ(veriablelengthquantity可变长度值)编码;
-
file:打包后的文件(浏览器加载的文件);
-
sourceContent:转换前的具体代码信息(和sources是对应的关系);
-
sourceRoot:所有的sources相对的根目录;
生成source-map
webpack为我们提供了非常多的选项,目前为止是26个,来处理source-map,选择不同的值,打包形成的代码会有性能的差异,可以根据不同情况进行选择
-
不会生成source-map的配置项
-
false:不使用source-map,也就是没有任何和source-map相关的内容。
-
nnone:production模式下的默认值,不生成source-map。
-
eval:development模式下的默认值,不生成source-map
-
但是它会在eval执行的代码中,添加//#sourceURL=;
-
它会被浏览器在执行时解析,并且在调试面板中生成对应的一些文件目录,方便我们调试代码;
-
-
source-map值
生成一个独立的source-map文件,并且在bundle文件中有一个注释,指向source-map文件;
bundle文件中有如下的注释:
//# sourceMappingURL=bundle.js.map
eval-source-map值
eval-source-map:会生成sourcemap,但是source-map是以DataUrl添加到eval函数的后面
inline-source-map值
inline-source-map:会生成sourcemap,但是source-map是以DataUrl添加到bundle文件的后面
cheap-source-map
cheap-source-map:
-
会生成sourcemap,但是会更加高效一些(cheap低开销),因为它没有生成列映射(Column Mapping)
cheap-module-source-map值
会生成sourcemap,类似于cheap-source-map,但是对源自loader的sourcemap处理会更好。
hidden-source-map值
-
会生成sourcemap,但是不会对source-map文件进行引用;
-
相当于删除了打包文件中对sourcemap的引用注释;
// 被删除掉的
//# sourceMappingURL=bundle.js.map
nosources-source-map值
会生成sourcemap,但是生成的sourcemap只有错误信息的提示,不会生成源代码文件;
多个值的组合(重要)
事实上,webpack提供给我们的26个值,是可以进行多组合的。
组合的规则如下:
-
inline-|hidden-|eval:三个值时三选一;
-
nosources:可选值;
-
cheap可选值,并且可以跟随module的值;
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
在开发中,最佳的实践是什么呢?
-
开发阶段:推荐使用source-map或者cheap-module-source-map
-
测试阶段:推荐使用source-map或者cheap-module-source-map
-
发布阶段:false、缺省值(不写)
六、Babel深入理解
1、babel是什么东西,用来做什么的
-
Babel是一个工具链,主要用于旧浏览器或者缓解中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript;
-
语法转换、源代码转换、Polyfill实现目标缓解缺少的功能等;
Babel命令行使用
-
@babel/core:babel的核心代码,必须安装;
-
@babel/cli:可以让我们在命令行使用babel;
npm install @babel/cli @babel/core
使用babel来处理我们的源代码:
-
src:是源文件的目录;
-
--out-dir:指定要输出的文件夹dist;
npx babel src--out-dirdist
插件的使用
比如我们需要转换箭头函数,那么我们就可以使用箭头函数转换相关的插件:
npm install @babel/plugin-transform-arrow-functions -D
npx babel src--out-dirdist--plugins=@babel/plugin-transform-arrow-functions
查看转换后的结果,我们会发现const 并没有转成var,这是因为plugin-transform-arrow-functions,并没有提供这样的功能,我们需要使用plugin-transform-block-scoping 来完成这样的功能。
npm install @babel/plugin-transform-block-scoping -D
npx babel src--out-dirdist--plugins=@babel/plugin-transform-block-scoping @babel/plugin-transform-arrow-functions
Babel的预设preset
如果要转换的内容过多,一个个设置是比较麻烦的,我们可以使用预设(preset)
安装 :
npm install @babel/preset-env -D
执行:
npx babel src--out-dirdist--presets=@babel/preset-env
2、Babel的底层原理
工作流程:
-
解析阶段(Parsing)
-
转换阶段(Transformation)
-
生成阶段(CodeGeneration)
流程图:
3、babel-loader
安装:
npm install babel-loader @babel/core
使用:
module.exports = {
module: {
rules: [
{
test:/\.js$/,
use: {
loader: "babel-loader"
}
}
]
}
}
指定使用的插件
我们必须指定使用的插件才会生效
module: {
rules: [
{
test:/\.js$/,
use: {
loader: "babel-loader",
options: {
plugins: [
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-arrow-functions"
]
}
}
}
]
}
babel-preset
如果我们一个个去安装使用插件,那么需要手动来管理大量的babel插件,我们可以直接给webpack提供一个preset,webpack会根据我们的预设来加载对应的插件列表,并且将其传递给babel。
常见的预设:
-
env
-
react
-
TypeScript
安装preset-env:
npm install @babel/preset-env
{
test:/\.js$/,
use: {
loader: "babel-loader",
options: {
plugins: [
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-arrow-functions"
]
}
}
}
Babel的Stage-X设置
在babel7之前(比如babel6中),我们会经常看到这种设置方式:
-
它表达的含义是使用对应的babel-preset-stage-x预设;
-
从babel7开始,已经不建议使用了,建议使用preset-env来设置;
4、Babel的配置文件
我们可以将babel的配置信息放到一个独立的文件中,babel给我们提供了两种配置文件的编写:
-
babel.config.json(或者.js,.cjs,.mjs)文件;
-
.babelrc.json(或者.babelrc,.js,.cjs,.mjs)文件;
区别:
-
.babelrc.json:早期使用较多的配置方式,但是对于配置Monorepos项目是比较麻烦的;
-
babel.config.json(babel7):可以直接作用于Monorepos项目的子包,更加推荐;
5、认识polyfill
更像是应该填充物(垫片),一个补丁,可以帮助我们更好的使用JavaScript;
使用场景:
比如我们使用了一些语法特性(例如:Promise,Generator,Symbol等以及实例方法例如Array.prototype.includes等),但是某些浏览器压根不认识这些特性,必然会报错,我们可以使用polyfill来填充或者说打一个补丁,那么就会包含该特性了;
可以通过单独引入core-js和regenerator-runtime来完成polyfill的使用:
npm install core-js regenerator-runtime --save
{
test:/\.m?js$/,
exclude:/node_modules/,
use:"babel-loader"
}
配置babel.config.js
我们需要在babel.config.js文件中进行配置,给preset-env配置一些属性:
-
useBuiltIns:设置以什么样的方式来使用polyfill;
-
corejs:设置corejs的版本
-
另外corejs可以设置是否对提议阶段的特性进行支持;
-
设置proposals属性为true即可;
-
useBuiltIns属性设置
-
useBuiltIns属性有三个常见的值
第一个值:false
-
打包后的文件不使用polyfill来进行适配;
-
并且这个时候是不需要设置corejs属性的;
第二个值:usage
-
会根据源代码中出现的语言特性,自动检测所需要的polyfill;
-
这样可以确保最终包里的polyfill数量的最小化,打包的包相对会小一些;
-
可以设置corejs属性来确定使用的corejs的版本;
第三个值:entry
-
如果我们依赖的某一个库本身使用了某些polyfill的特性,但是因为我们使用的是usage,所以之后用户浏览器可能会报错,果你担心出现这种情况,可以使用entry;
-
需要在入口文件中添加`import 'core-js/stable'; import 'regenerator-runtime/runtime';
-
这样做会根据browserslist目标导入所有的polyfill,但是对应的包也会变大;
-
6、认识Plugin-transform-runtime(了解)
在前面我们使用的polyfill,默认情况是添加的所有特性都是全局的,如果我们正在编写一个工具库,这个工具库需要使用polyfill,别人在使用我们工具时,工具库通过polyfill添加的特性,可能会污染它们的代码,所以,当编写工具时,babel更推荐我们使用一个插件:@babel/plugin-transform-runtime来完成polyfill的功能;
7、React的jsx支持
安装:
npm install @babel/preset-react -D
使用:
presets: [
["@babel/preset-env", {
useBuiltIns:"usage",
corejs: 3.8
}],
["@babel/preset-react"]
]
8、TypeScript的编译
TypeScript通过compiler来转换成JavaScript
安装:
npm install typescript -D
TypeScript的编译配置信息我们通常会编写一个tsconfig.json文件:
tsc --init
之后我们可以运行npxtsc来编译自己的ts代码:
npx tsc
1、使用ts-loader编译TS
安装:
npm install ts-loader -D
配置:
{
test:'/\.ts$/',
exclude: /node_modules/,
use: [
"ts-loader"
]
}
2、使用babel-loader编译TS
Babel是有对TypeScript进行支持
-
我们可以使用插件:@babel/tranform-typescript;
-
但是更推荐直接使用preset:@babel/preset-typescript;
安装:
npm install @babel/preset-typescript -D
配置:
{
test:'/\.ts$/',
exclude: /node_modules/,
use: [
"babel-loader"
]
}
七、大数据中关于代码格式校验(Eslint和prettierrc )
大数据中关于eslint的配置
/*
* @Description: eslint 配置
* @ 规则依赖于 @umijs/fabric,在此基础上,可自行添加自己的规则进行配置
* @Author: 贾永昌
* @Date: 2022-05-01 13:55:14
* @LastEditTime: 2022-05-02 17:35:45
*/
module.exports = {
extends: [require.resolve('@umijs/fabric/dist/eslint')],
// in antd-design-pro
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
page: true,
},
rules: {
// 强制语句有分号结尾
semi: [2, 'always'],
// ? 操作符前后必须有空格 bad: 1||2 good: 1 || 2
'space-infix-ops': 2,
// ? 对象字面量中冒号前面禁止有空格,后面必须有空格 bad: {a :'a'} good:{a: 'a'}
'key-spacing': 2,
// ? 花括号首尾必须有空格
'object-curly-spacing': [2, 'always'],
// ? 语句块(if、function、class、try...catch等的大括号) 的前面必须要有空格
'space-before-blocks': 2,
// ? 箭头函数的箭头与后面的{}之间需要空格
'arrow-spacing': 2,
// ? 禁止多余的空格
'no-multi-spaces': 2,
// ? 禁止代码行结束后面有多余空格
'no-trailing-spaces': 2,
// ? 禁止多余空行
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 1, maxEOF: 1 }],
// ? 允许标识符中使用悬空下划线(标识符的开头或末尾的下划线)
'no-underscore-dangle': 0,
// ? 允许逻辑短路、三元运算符等表达式求值
'no-unused-expressions': 0,
// ? 禁止使用嵌套的三元表达式
'no-nested-ternary': 2,
// ? 禁止对函数参数再赋值(保证react函数式编程纯函数的概念)
'no-param-reassign': 2,
// ? 禁止使用 var 定义变量
'no-var': 2,
// ? 禁止修改const声明的变量
'no-const-assign': 2,
// ? 函数调用时 函数名与()之间不能有空格
'no-spaced-func': 2,
// ? jsx 属性中强制使用双引号
'jsx-quotes': [2, 'prefer-double'],
// ? 禁止 jsx 属性对象的引用括号里 两边加空格
'react/jsx-curly-spacing': [2, 'never'],
// ? JSX 中前标签传有属性换行展示的话,其后面的 > 也需换行对齐展示
'react/jsx-closing-bracket-location': 2,
// ? 校验 jsx 中所有换行属性值缩进
'react/jsx-indent-props': [2, 2],
// ? jsx 中传入属性值是Boolean值且为true时,省略传入
'react/jsx-boolean-value': 2,
// ? 在 JSX 属性中禁止等号前后存在空格
'react/jsx-equals-spacing': 2,
// ? 关闭此规则,允许 useEffect 的依赖为空数组
'react-hooks/exhaustive-deps': 0,
// ? 未使用的变量警告提醒
'@typescript-eslint/no-unused-vars': ['warn'],
// ? 禁用使用在前,保证 useEffct 使用在最前面,这时候里面如果使用了外部的函数就会报这错
'@typescript-eslint/no-use-before-define': 0,
// ? 允许空的 ts 接口定义 eg: interface IProps {}
'@typescript-eslint/no-empty-interface': 0,
},
};
大数据中 .prettierrc 配置
{
"printWidth": 80,
"tabWidth": 2,
"singleQuote": true,
"useTabs": false,
"semi": true,
"jsxSingleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "always",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"htmlWhitespaceSensitivity": "css",
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}
八、DevServer
为什么需要搭建本地服务器?
我们希望可以做到,当文件发生变化时,可以自动完成编译和展示
-
webpack watch mode
-
webpack-dev-server
-
webpack-dev-middleware
1、Webpack watch(基本不用)
webpack给我们提供了watch模式:
-
在该模式下,webpack依赖图中的所有文件,只要有一个发生了更新,那么代码将被重新编译(损耗性能)
开启watch的两种方式
-
方式一:在导出的配置中,添加watch: true;
-
方式二:在启动webpack的命令中,添加--watch的标识;
"scripts" : {
"watch":"webpack --watch"
}
2、webpack-dev-server(必会,常用)
除了可以监听到文件的变化,还可以具备实时重新加载的功能
安装:
npm install --save-dev webpack-dev-server
配置:
"scripts" : {
"watch":"webpack --watch"
"serve":"webpack serve --config wk.config.js"
}
webpack-dev-server 在编译之后不会写入到任何输出文件。而是将bundle 文件保留在内存中:
-
事实上webpack-dev-server使用了一个库叫memfs(memory-fswebpack自己写的)
3、webpack-dev-middleware(基本不用)
如果我们想要有更好的自由度,可以使用webpack-dev-middleware;
定义:
webpack-dev-middleware 是一个封装器(wrapper),它可以把webpack处理过的文件发送到一个server,webpack-dev-server 在内部使用了它,然而它也可以作为一个单独的package 来使用,以便根据需求进行更多自定义设置;
4、output的publicPath(outPut中的配置)
output中还有一个publicPath属性,该属性是指定index.html文件打包引用的一个基本路径
-
它的默认值是一个空字符串,所以我们打包后引入js文件时,路径是bundle.js;
-
在开发中,我们也将其设置为/,路径是/bundle.js,那么浏览器会根据所在的域名+路径去请求对应的资源;
-
如果我们希望在本地直接打开html文件来运行,会将其设置为./,路径时./bundle.js,可以根据相对路径去查找资源;
module.exports = { entry: " 指定入口路径", output: { filename:"bundle.js", // 出口名字 path: '出口路径' publicPath:'./' } }
5、devServer的publicPath
devServer中也有一个publicPath的属性,该属性是指定本地服务所在的文件夹
-
它的默认值是/,也就是我们直接访问端口即可访问其中的资源http://localhost:8080
-
如果我们将其设置为了/abc,那么我们需要通过http://localhost:8080/abc才能访问到对应的打包后的资源
-
并且这个时候,我们其中的bundle.js通过http://localhost:8080/bundle.js也是无法访问的:
-
所以必须将output.publicPath也设置为/abc;
-
官方其实有提到,建议devServer.publicPath与output.publicPath相同;
-
6、devServer的contentBase(不常用)
主要作用是如果我们打包后的资源,又依赖于其他的一些资源,那么就需要指定从哪里来查找这个内容
-
比如在index.html中,我们需要依赖一个abc.js文件,这个文件我们存放在public文件中
-
在index.html中,我们应该如何去引入这个文件
-
比如代码是这样的:<script src="./public/abc.js"></script>
-
但是这样打包后浏览器是无法通过相对路径去找到这个文件夹的;
-
所以代码是这样的:<script src="/abc.js"></script>;
-
但是我们如何让它去查找到这个文件的存在呢?设置contentBase即可
-
devserver: {
contentBase: path.resolve(__dirname,"why"),
watchContentBase:true //监听contentBase发生变化后重新编译
}
7、hotOnly、hos、port、open、compress配置
-
hotOnly是当代码编译失败时,是否刷新整个页面
-
port设置监听的端口,默认情况下是8080
-
host设置主机地址
-
open是否打开浏览器
-
compress是否为静态文件开启gzip compression
devserver: {
contentBase: path.resolve(__dirname,"why"),
watchContentBase:true, //监听contentBase发生变化后重新编译
hotOnly:true,
host: 0.0.0.0,
port: 3000,
open: true,
compress:true
}
8、Proxy代理(解决跨域问题)注意:在开发环境中使用
我们可以将请求先发送到一个代理服务器,代理服务器和API服务器没有跨域的问题,就可以解决我们的跨域问题了
配置:
-
target:表示的是代理到的目标地址,比如/api-hy/moment会被代理到http://localhost:8888/api-hy/moment;
-
pathRewrite:默认情况下,我们的/api-hy也会被写入到URL中,如果希望删除,可以使用pathRewrite;
-
secure:默认情况下不接收转发到https的服务器上,如果希望支持,可以设置为false;
-
changeOrigin:它表示是否更新代理后请求的headers中host地址;
devserver: {
'/api': {
// 标识需要进行转换的请求的url
target: 'http://172.16.188.188:8000', // 服务端域名
changeOrigin: true, // 允许域名进行转换
pathRewrite: {
// 将请求url里的ci去掉
'^/api': '',
},
logLevel: 'debug',
secure: false, // 将该属性设置为false,将允许在https上运行或者运行在证书无效的后端服务器
},
},
9、historyApiFallback
-
historyApiFallback是开发中一个非常常见的属性,它主要的作用是解决SPA页面在路由跳转之后,进行页面刷新时,返回404的错误。
-
boolean值:默认是false
-
如果设置为true,那么在刷新时,返回404错误时,会自动返回index.html的内容;
-
-
object类型的值,可以配置rewrites属性:
-
可以配置from来匹配路径,决定要跳转到哪一个页面;
-
devserver: {
'/api': {
// 标识需要进行转换的请求的url
target: 'http://172.16.188.188:8000', // 服务端域名
changeOrigin: true, // 允许域名进行转换
pathRewrite: {
// 将请求url里的ci去掉
'^/api': '',
},
logLevel: 'debug',
secure: false, // 将该属性设置为false,将允许在https上运行或者运行在证书无效的后端服务器
},
historyApiFallback: {
rewrites:[
{from: /abc/, to:"/index.html"}
]
}
},
九、模块热替换(HMR)
什么是HMR
-
HMR的全称是Hot Module Replacement,翻译为模块热替换;
-
模块热替换是指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个页面;
如何使用HMR
-
默认情况下,webpack-dev-server已经支持HMR,我们只需要开启即可;
-
在不开启HMR的情况下,当我们修改了源代码之后,整个页面会自动刷新,使用的是live reloading;
1、开启HMR
// 在webpack.config.js 中添加以下配置
devserver: {
hot:true
}
同时还需要指定发生更新的模块
if(module.hot) {
module.hot.accept("./*文件路径",() => {
console.log()
})
}
2、框架中的HMR
项目中已经有非常成熟的方案,别操心了
-
vue开发中,我们使用vue-loader,此loader支持vue组件的HMR,提供开箱即用的体验
-
react开发中,有React HotLoader,实时调整react组件(目前React官方已经弃用了,改成使用reactrefresh);
3、HMR的原理
HMR的原理是什么
-
webpack-dev-server会创建两个服务:提供静态资源的服务(express)和Socket服务(net.Socket)
-
express server负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析);
HMR Socket Server,是一个socket的长连接:(想想webSocket,需要及时通信)
-
长连接有一个最好的好处是建立连接后双方可以通信(服务器可以直接发送文件到客户端)
-
当服务器监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk);
-
通过长连接,可以直接将这两个文件主动发送给客户端(浏览器)
-
浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新;
十、resolve模块解析
resolve用于设置模块如何被解析:
-
resolve可以帮助webpack从每个require/import 语句中,找到需要引入到合适的模块代码;
-
webpack 使用enhanced-resolve来解析文件路径;
webpack能解析三种文件路径:
-
绝对路径
-
相对路径
-
模块路径:在resolve.modules中指定的所有目录检索模块,默认值是['node_modules'],所以默认会从node_modules中查找文件;
1、extensions和alias配置
extensions是解析到文件时自动添加扩展名:
-
默认值是['.wasm','.mjs','.js','.json'];
配置:
module.exports = { entry: " 指定入口路径", output: { filename:"bundle.js", // 出口名字 path: '出口路径' }, resolve:{ extensions:['.wasm','.mjs','.js','.json','.jsx','.ts'], } }
我们可以使用alias给某些常见的路径起一个别名;
resolve:{
extensions:['.wasm','.mjs','.js','.json','.jsx','.ts'],
alias: {
"@":resolveApp('./src'),
pages:resolveApp('./src/pages')
}
}
十一、环境分离和代码分离
1、入口文件解析
context的作用是用于解析入口(entry point)和加载器(loader)
默认是webpack的启动目录
module.exports = {
context:path.resolve(__dirname,'./')
entry:"../src/index.js"
}
2、配置文件的分离
-
将原来的webpack.config.js划分为webpack.comm.conf.js(通用配置)、webpack.dev.conf.js(开发环境)、webpack.prod.conf.js(生产环境)三部分
-
利用mode配置项,区分开发环境和生产环境。用利用merge将用到的环境配置和通用配置合并
3、认识代码分离
代码分离(CodeSplitting)主要的目的是将代码分离到不同的bundle中,之后我们可以按需加载,或者并行加载这些文件;
Webpack中常用的代码分离有三种
-
入口起点:使用entry配置手动分离代码;
-
防止重复:使用EntryDependencies或者SplitChunksPlugin去重和分离代码;
-
动态导入:通过模块的内联函数调用来分离代码;
1、多入口起点
entry: {
index:"./src/index.js",
main:"./src/main.js"
}
output: {
filename:"[name].bundle.js",
path:resolveApp("./build")
}
2、EntryDependencies(入口依赖)
假如我们的index.js和main.js都依赖两个库:lodash、dayjs
-
如果我们单纯的进行入口分离,那么打包后的两个bunlde都有会有一份lodash和dayjs;
entry: { index: {import:"./src/index.js",dependOn:"shared"}, main:{import:"./src/main.js",dependOn:"shared"}, shared:['lodash','axios'] } output: { filename:"[name].bundle.js", path:resolveApp("./build"), publicPath: "" }
3、SplitChunks
另外一种分包的模式是splitChunk,它是使用SplitChunksPlugin来实现的:
Webpack提供了SplitChunksPlugin默认的配置,我们也可以手动来修改它的配置:
-
比如默认配置中,chunks仅仅针对于异步(async)请求,我们可以设置为initial或者all;
optimization: {
splitChunks: {
chunks:'all'
}
}
4、SplitChunks自定义配置
SplitChunks: {
chunks:'all',
// 拆分包的大小,至少为minsize
// 如果一个包拆分出来不到minsize,那么将不会被拆分
minsize:100,
// 将大于maxMize的包,拆分成不小于minSize 的包
maxsize:1000,
// 至少包被引入的次数
minChunks:2,
// 最大异步请求数量
maxAsyncRequests:30,
// 最大的初始化请求数量
cacheGroups: {
venders: {
test:/[\\/]node_modules[\\/]/,
priority: -10,
filename: "[id]_[hash:6]_vendor.js"
},
foo: {
test:/foo/,
priority: -20,
filename: "foo_[id]_[name]_.js"
}
}
}
配置解析:
-
Chunks
-
默认值是async
-
另一个值是initial,表示对通过的代码进行处理
-
all表示对同步和异步代码都进行处理
-
-
minSize
-
拆分包的大小, 至少为minSize;
-
如果一个包拆分出来达不到minSize,那么这个包就不会拆分;
-
-
maxSize
-
将大于maxSize的包,拆分为不小于minSize的包;
-
-
minChunks
-
至少被引入的次数,默认是1;
-
如果我们写一个2,但是引入了一次,那么不会被单独拆分;
-
-
name:设置拆包的名称
-
可以设置一个名称,也可以设置为false;
-
设置为false后,需要在cacheGroups中设置名称;
-
-
cacheGroups
-
用于对拆分的包就行分组,比如一个lodash在拆分之后,并不会立即打包,而是会等到有没有其他符合规则的包一起来打包;
-
test属性:匹配符合规则的包;
-
name属性:拆分包的name属性;
-
filename属性:拆分包的名称,可以自己使用placeholder属性;
-
5、动态导入(dynamic import)
使用ECMAScript中的import()语法来完成,也是目前推荐的方式;
注意:
-
在webpack中,通过动态导入获取到一个对象;
-
真正导出的内容,在改对象的default属性中,所以我们需要做一个简单的解构;
动态导入的文件命名
它的命名我们通常会在output中,通过chunkFilename属性来命名
output: {
filename: "[name].bundle.js",
path:resolveApp("./build"),
chunkFilename: "chunk_[id]_[name].js"
}
默认情况下我们获取到的[name]是和id的名称保持一致的
-
我们希望修改name的值,可以通过magic comments(魔法注释)的方式
import(/* webpackChunkName:"bar"*/ "./bar").then(({default:bar}) => {
bar()
})
6、optimization.chunkIds配置
optimization.chunkIds配置用于告知webpack模块的id采用什么算法生成。
-
natural:按照数字的顺序使用id;
-
named:development下的默认值,一个可读的名称的id;
-
deterministic:确定性的,在不同的编译中不变的短数字id
最佳实践:
-
开发过程中,我们推荐使用named;
-
打包过程中,我们推荐使用deterministic;
7、optimization. runtimeChunk配置
配置runtime相关的代码是否抽取到一个单独的chunk中:
-
抽离出来后,有利于浏览器缓存的策略:
-
设置的值
-
true/multiple:针对每个入口打包一个runtime文件;
-
single:打包一个runtime文件;
-
对象:name属性决定runtimeChunk的名称;
optimization:{ chunkIds:"deterministic", runtimeChunk: { name:"runtime" } }
-
8、Prefetch和Preload
-
webpack v4.6.0+增加了对预获取和预加载的支持。
-
prefetch(预获取):将来某些导航下可能需要的资源
-
preload(预加载):当前导航下可能需要资源
import(/* webpackChunkName:"bar"*/ /* webpackpeload:true */ "./bar").then(({default:bar}) => { bar() })
-
-
区别
-
preload chunk 会在父chunk 加载时,以并行方式开始加载。prefetch chunk 会在父chunk 加载结束后开始加载。
-
preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
-
preload chunk 会在父chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。
-
9、CDN
CDN称之为内容分发网络(ContentDeliveryNetwork或ContentDistributionNetwork,缩写:CDN)
开发中的应用方式:
-
方式一:打包的所有静态资源,放到CDN服务器,用户所有资源都是通过CDN服务器加载的;
-
方式二:一些第三方资源放到CDN服务器上;
方式一花钱,直接说方式二
一些比较出名的开源框架都会将打包后的源码放到一些比较出名的、免费的CDN服务器上
使用方法:
-
第一步,我们可以通过webpack配置,来排除一些库的打包:
externals: { lodash: "_", dayjs: "dayjs" }
-
第二步,在html模块中,加入CDN服务器地址:
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.core.js"></script>
10、认识shimming
-
shimming是一个概念,是某一类功能的统称:
-
比如我们现在依赖一个第三方的库,这个第三方的库本身依赖lodash,但是默认没有对lodash进行导入(认为全局存在lodash),那么我们就可以通过ProvidePlugin来实现shimming的效果;
-
-
注意:webpack并不推荐随意的使用shimming
-
Webpack背后的整个理念是使前端开发更加模块化;
-
也就是说,需要编写具有封闭性的、不存在隐含依赖(比如全局变量)的彼此隔离的模块;
-
11、MiniCssExtractPlugin
MiniCssExtractPlugin可以帮助我们将css提取到一个独立的css文件中,该插件需要在webpack4+才可以使用。
安装:
npm install mini-css-extract-plugin -D
配置:
plugins: [
new MiniCssExtractPlugin({
filename:"css/[name].[contenthash:8].css",
chunkfilename: "css/[name].[contenthash:8].css"
})
],
module:{
rules: [
{
test:/\.css$/i,
use:[MiniCssExtractPlugin.loader,'css-loader']
}
]
}
12、Hash、ContentHash、ChunkHash
-
hash值的生成和整个项目有关系:
-
比如我们现在有两个入口index.js和main.js;
-
它们分别会输出到不同的bundle文件中,并且在文件名称中我们有使用hash;
-
这个时候,如果修改了index.js文件中的内容,那么hash会发生变化;
-
那就意味着两个文件的名称都会发生变化;
-
-
chunkhash可以有效的解决上面的问题,它会根据不同的入口进行借来解析来生成hash值:
比如我们修改了index.js,那么main.js的chunkhash是不会发生改变的;
-
contenthash表示生成的文件hash名称,只和内容有关系:
-
比如我们的index.js,引入了一个style.css,style.css有被抽取到一个独立的css文件中;
-
这个css文件在命名时,如果我们使用的是chunkhash;
-
那么当index.js文件的内容发生变化时,css文件的命名也会发生变化;
-
这个时候我们可以使用contenthash;
-
十二、DLL_Tree Shaking
认识DLL库(了解一下)
-
DLL全程是动态链接库(Dynamic Link Library),是为软件在Windows中实现共享函数库的一种实现方式;
-
webpack中也有内置DLL的功能,它指的是我们可以将可以共享,并且不经常改变的代码,抽取成一个共享的库;
Terser介绍和安装(一般使用默认配置)
-
Terser是一个JavaScript的解释(Parser)、Mangler(绞肉机)/Compressor(压缩机)的工具集;
-
早期我们会使用uglify-js来压缩、丑化我们的JavaScript代码,但是目前已经不再维护,并且不支持ES6+的语法;
-
-
Terser可以帮助我们压缩、丑化我们的代码,让我们的bundle变得更小。
安装:
npm install terser -g // 可以进行局部安装,也可以全局安装
命令行使用
terser [input files] [options]
常见的配置项:
Compress option
-
arrows:class或者object中的函数,转换成箭头函数;
-
arguments:将函数中使用arguments[index]转成对应的形参名称;
-
dead_code:移除不可达的代码(tree shaking);
-
等等其他属性,详情看官方文档
Mangle option
-
toplevel:默认值是false,顶层作用域中的变量名称,进行丑化(转换)
-
keep_classnames:默认值是false,是否保持依赖的类名称;
-
keep_fnames:默认值是false,是否保持原来的函数名称;
Terser在webpack中配置使用
-
(注意)真实开发中,我们不需要手动的通过terser来处理我们的代码,我们可以直接通过webpack来处理:
-
在webpack中有一个minimizer属性,在production模式下,默认就是使用TerserPlugin来处理我们的代码的;
-
如果我们对默认的配置不满意,也可以自己来创建TerserPlugin的实例,并且覆盖相关的配置;(基本不会手动配置)
-
module.exports = {
optimization: {
minimize:true,
minimizer: [
new TerserPlugin({
parallel:true, // 使用多进程并发运行提高构建的速度,默认值是true,
extractComments:false, // 默认值为true,表示会将注释抽取到一个单独的文件中
terserOptions: { // 设置我们的terser相关的配置
compress: { // 设置压缩相关的选项;
arguments:true,
dead_code:true
},
mangle:true, // 设置丑化相关的选项,可以直接设置为true;
toplevel:true, // 底层变量是否进行转换
keep_classnames:false,// 保留类的名称
keep_fnames:false// 保留函数的名称;
}
})
]
}
}
CSS的压缩
安装:
npm install css-minimizer-webpack-plugin -D
在optimization.minimizer中配置:
minimizer: [
new CssMinimizerplugin({
parallel: true
})
]
提升作用域 Scope Hoisting
-
Scope Hoisting从webpack3开始增加的一个新功能,功能是对作用域进行提升,并且让webpack打包后的代码更小、运行更快;
-
默认情况下webpack打包会有很多的函数作用域,Scope Hoisting可以将函数合并到一个模块中来运行
-
使用:
-
在production模式下,默认这个模块就会启用;
-
在development模式下,我们需要自己来打开该模块;
new webpack.optimize.ModuleConcatenationPlugin()
-
Tree Shaking
定义:最早的想法起源于LISP,用于消除未调用的代码(纯函数无副作用,可以放心的消除,这也是为什么要求我们在进行函数式编程时,尽量使用纯函数的原因之一)
webpack实现TreeShaking
两种方法:
-
在optimization中配置usedExports为true,来帮助Terser进行优化;
-
在package.json中配置sideEffects,直接对模块进行优化;
usedExports
在usedExports设置为true时,会有一段注释:unused harmony export mul,这段注释告知Terser在优化时,可以删除掉这段代码
注意:
-
配置该属性时,需要将mode设置为development模式
-
usedExports实现tree Shaking是结合terse来完成的
sideEffects
sideEffects用于告知webpack compiler哪些模块时有副作用的(副作用的意思是这里面的代码有执行一些特殊的任务,不能仅仅通过export来判断这段代码的意义;)
-
在package.json中设置sideEffects的值:
-
false:告知webpack可以安全的删除未用到的exports;
-
如果有一些希望保留,可以设置数组
-
"sideEffects": [
"./src/util/format.js",
"*.css"
]
CSS实现TreeShaking
我们可以使用一个库来完成CSS的Tree Shaking:PurgeCSS,帮助我们删除未使用的CSS的工具
安装:
npm install purgecss-webpack-plugin -D
配置:
-
paths:表示要检测哪些目录下的内容需要被分析,这里我们可以使用glob;
-
默认情况下,Purgecss会将我们的html标签的样式移除掉,如果我们希望保留,可以添加一个safelist的属性;
-
purgecss也可以对less文件进行处理(所以它是对打包后的css进行tree shaking操作)
new PurgecssPlugin({
paths:glob.sync(`${resolveApp(./src)}/**/*`,{nodir:true}),
safelist: function() {
return {
standard:['html']
}
}
})
HTTP压缩
定义:HTTP压缩是一种内置在服务器和客户端之间的,以改进传输速度和带宽利用率的方式
流程:
第一步:HTTP数据在服务器发送前就已经被压缩了
第二步:兼容的浏览器在向服务器发送请求时,会告知服务器自己支持哪些压缩格式
第三步:服务器在浏览器支持的压缩格式下,直接返回对应的压缩后的文件,并且在响应头中告知浏览器;
目前的压缩格式
-
compress–UNIX的“compress”程序的方法(历史性原因,不推荐大多数应用使用,应该使用gzip或deflate);
-
deflate–基于deflate算法(定义于RFC1951)的压缩,使用zlib数据格式封装;
-
gzip–GNUzip格式(定义于RFC1952),是目前使用比较广泛的压缩算法;
-
br–一种新的开源压缩算法,专为HTTP内容的编码而设计;
Webpack对文件压缩
webpack中相当于是实现了HTTP压缩的第一步操作,我们可以使用CompressionPlugin。
安装:
npm install compression-webpack-plugin -D
配置:
new CompressionPlugin({
test:/\.(css|js)$/, // 匹配哪些文件需要压缩
threshold:500, // 设置文件多大开始压缩
minRatio: 0.7, // 至少采用的压缩比例
algorithm: "gzip" // 采用的压缩算法
})
HTML文件中代码的压缩
我们之前使用了HtmlWebpackPlugin插件来生成HTML的模板,事实上它还有一些其他的配置:
-
inject:设置打包的资源插入的位置
-
true、false、body、head
-
-
cache:设置为true,只有当文件改变时,才会生成新的文件(默认值也是true)
-
minify:默认会使用一个插件html-minifier-terser
InlineChunkHtmlPlugin
可以辅助将一些chunk出来的模块,内联到html中
安装
npm install react-dev-utils -D
在production的plugins中进行配置:
module.exports = {
plugin:[
new InlineChunkHtmlPlugin(HtmlWebpackPlugin,[/runtime.+\.js/])
]
}
十三、webpack打包分析
分析一:打包的时间分析
speed-measure-webpack-plugin 可以帮助我们看到每一个loader、每一个plugin的打包时间
安装:
npm install speed-measure-webpack-plugin -D
配置:
const smp = new SpeedMeasurePlugin();
cpnst webpackConfig = smp.wrap({
plugins: [new MyPlugin(),new MyOtherPlugin()]
})
分析二:打包后文件分析
使用webpack-bundle-analyzer工具
安装:
npm install webpack-bundle-analyzer -D
配置
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}
Compiler和Compilation的区别(面试题)
-
Compiler中webpack构建的之初就会创建的一个对象, 并且在webpack的整个生命周期都会存在(before -run -beforeCompiler-compile -make -finishMake-afterCompiler-done)
-
只要是做webpack的编译, 都会先创建一个Compiler
-
-
Compilation是到准备编译模块(比如main.js), 才会创建Compilation对象
-
watch -> 源代码发生改变就需要重新编译模块
-
主要是存在于compile -make 阶段主要使用的对象
-
-
Compiler可以继续使用(如果我修改webpack的配置, 那么需要重新执行run run build)
-
Compilation需要创建一个新的Compilation对象