webpack
成熟的工具,重点在于配置、使用、性能优化,原理不是高优
为什么需要 webpack? webpack作用
- 优化打包效率
- 优化打包后代码: 压缩代码,整合代码,以网页加载更快
- 工程化,构建流程

🤔思考问题
- module chunk bundle 分别是什么意思?有何区别?
- loader和plugin的区别?
- webpack如何实现懒加载
- babel-runtime 和 babel-polyfill的区别
关于webpack5
- webpack5主要是内部效率的优化
- 对比webpack4没有太多的使用上的改动
- 升级webpack5的同时注意升级周边插件
基本配置
安装配置
初始化安装
npm install webpack webpack-cli html-webpack-plugin webpack-dev-server -D
打包命令
- webpack
拆分配置和merge
- webpack.common.js 公共配置
- webpack.dev.js 开发环境
- webpack.prod.js 生产环境
启动本地服务 dev-server 命令
- webpack-dev-server(webpack4)
- webpack serve(webpack5)
Module
rule
module: {
rules: [
{
test: /\.js$/,//Include all modules that pass test assertion.
use: ['babel-loader'],
include: srcPath,
exclude: /node_modules/
}
]
},
解析ES6 -> 编译为ES5
修改配置文件.babelrc
{
"presets": ["@babel/preset-env"]
}
@babel/preset-env 是 babel 7 架構下的一組 preset,能讓你用最新的 JavaScript 語法寫程式,並且智慧地根據瀏覽器的環境引入需要的 polyfill,節省手動管理 syntax transform 的時間,還能夠減少 bundle 檔案大小
devServer
- compress
- 启动gzip compressinon
- hot
- 启用 webpack 的 热模块替换 特性
- open
- 告诉 dev-server 在服务器已经启动后打开浏览器。
- port
- 指定监听请求的端口号
- proxy
- 代理 解决开发时的跨域问题

- 代理 解决开发时的跨域问题
hot hotReload 和 liveReload 的区别
devServer.hot(Hot Module Replacement, HMR): webpack dev server 的一个功能
- 热更新,只更新改动的部分,不会刷新整个页面。JS 模块层面
- 保留在完全重新加载页面期间丢失的应用程序状态。
devServer.liveReload
- 热刷新,整个页面刷新
hotReload
是 vue-loader 的选项
热更新,只更新改动的部分,不会刷新整个页面。Vue 组件层面(修改 .vue 文件)
保留在完全重新加载页面期间丢失的应用程序状态。
点击按钮修改,后再去修改 vue 组件
- 开启:会保存修改后的 message

- 关闭:会恢复 message 初始化的值

- 开启:会保存修改后的 message
源码
<template>
<div>
<h1>{{ message }} - change</h1>
<button @click="changeMessage">Change Message </button>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: 'Hello, World!',
};
},
methods: {
changeMessage() {
this.message = 'Updated Message';
document.getElementsByTagName('h1')[0].style.color = 'red';
},
},
};
</script>
<style scoped>
h1 {
color: blue;
}
</style>
配置
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap((options) => {
options.hotReload = true
return options
})
},
注意📢:在关闭 vue-loader 的时候开启 hot,会导致无法热重载。
解析图片文件
// import img
function insertImgElem(imgFile) {
const img = new Image();
img.src = imgFile;
document.body.appendChild(img)
}
import imgFile1 from './img/1.png';
insertImgElem(imgFile1);
import imgFile2 from './img/2.jpeg';
insertImgElem(imgFile2);
Image() 函数将会创建一个新的HTMLImageElement实例。
它的功能等价于 document.createElement('img')
webpack配置
npm i -D file-loader
npm i -D url-loader
- webpack.dev.js
module: {
rules: [
{
test: /\.(png|jpeg|jpg|git)$/,
use: 'file-loader'
}
]
}
- webpack.prod.js
mode: 'production',
module: {
rules: [
{
test: /\.(png|jpeg|jpg|git)$/,
use: {
loader: 'url-loader',
options: {
// 小于 5kb 的图片 base64 格式产出
// 否侧 依然用 file-loader 的形式,产出 url 格式
limit: 5 * 1024,
// 打包到 img 目錄下
outputPath: '/img1',
// 設置圖片的cdn地址
// publicPath: 'https://cdn.abc.com'
}
}
}
]
},
效果

好处:图片小 用base64 减少一次http请求 减少耗时
处理样式文件
- postcss-loader
- less-loader
- css-loader
- 解析
css文件中的@import和url语句,处理css-modules,并将结果作为一个js模块返回。
- 解析
- style-loader
- 把 CSS 插入到 DOM 中。
npm i -D postcss-loader less-loader css-loader style-loader
配置 webpack.common.js
module: {
rules: [
{
test: /\.css$/,
// loader 的执行顺序是: 从后往前
use: ['style-loader', 'css-loader', 'postcss-loader']// 加了postcss
},
{
test: /\.less$/,
// 增加 ‘less-loader',注意顺序
use: ['style-loader', 'css-loader', 'less-loader']
}
]
},
postcss-loader中配置自动生成前缀postcss.config.js
module.exports = {
plugins: [require('autoprefixer')]
}
transform: rotate(-45deg) 自动添加前缀的效果

高级配置
配置多入口
虽然说现在的项目都是SPA(单页面应用),但项目有时候需要产出多个页面
plugins: [
// 多入口 - 生成 index.html
new HtmlWebpackPlugin({
template: path.join(srcPath, 'index.html'),
filename: 'index.html',
// chunks 表示该页面要引用哪些 chunk (即上面的 index 和 other),默认全部引用
chunks: ['index'] // 只引用 index.js
}),
// 多入口 - 生成 other.html
new HtmlWebpackPlugin({
template: path.join(srcPath, 'other.html'),
filename: 'other.html',
chunks: ['other'] // 只引用 other.js
})
]

打包输出

MiniCssExtractPlugin 抽离和压缩 CSS(重要)

抽离公共代码(重要)
为什么需要抽离公共代码和第三方代码?
- 当引入第三方库时,如果不独立打包,每次修改业务逻辑代码,都会重新打包第三方库,导致加载慢。
- 两个文件引入了同一个模块,会打包两次
配置为独立的chunks

webpack如何实现异步加载JS(懒加载)(重要)
默认支持的语法,不用配置
setTimeout(() => {
import ('./danymic.js').then(res => {// 打包时会独立成一个chunk
console.log('res :>> ', res.default.message);
})
}, 1500)
处理React和Vue
处理React(解析JSX语法)
安装
npm install --save-dev @babel/preset-react.babelrc
注意:
env参数可能很快将被废弃{
"presets": ["@babel/preset-react"]
}配置完webpack中配置了'babel-loader',babel-loader会使用@babel/preset-react 去解析JSX语法
处理vue(vue-loader)

参考:https://www.babeljs.cn/docs/babel-preset-react
- 处理Vue
module chunk bundle的区别
module-各个源码文件,webpack中一切皆模块 (能被引入的文件都是模块,不管是什么类型,比如css js 图片)
chunk-多模块合并成的,如entry、import() 、splitChunk都可以生成chunk
bundle-最终的输出文件

优化构建速度

聊聊webpack的时候,不要跟背书式回答问题,要通过分析问题的思路来回答问题
- 通过问题引出解决问题的办法
- 通过开发遇到的痛点和用户使用的痛点出发
- 加快编译提高开发效率
- 使用 HappyPack 多进程打包
- 单页面应用的痛点,用户首屏加载会将所有的资源下载下来,缩小整体资源情况就是优化的切入点
- 从缩小体积出发
- 按需打包,例如多语言、时间 Memont.js 都可以配置只打包特定的语言和地区时间:IgnorePlugin
- 压缩,通过打开 gzip 压缩,在 NGINX 配置实现
- 通过 CDN 内容分发加速,不过不太适合小公司
- 通过配置 Tree Shaking 剔除无用代码,因为 ES6 的模块化特性,可以通过静态分析方式找到无用代码,例如一些从未被使用的的变量和方法
- 网络层面
- 延迟 js 和 css 的加载,通过给 js script 设置 defer 和 async 属性,defer 是延迟
- 尽量减少 js 和 css 的个数
- 压缩 JS CSS:mini-css-extract-plugin,代码合并 splitChunks
- 从缩小体积出发
- 加快编译提高开发效率
- 通过浏览器原理来解析问题出处
- 浏览器进程:浏览器主进程、网络进程、渲染进程、GPU进程、插件进程
- 浏览器访问 url 流程:
- 浏览器主进程判断 url
- DNS 解析域名,IP 交给网络进程,下载 HTML CSS JS
- HTML 解析器,解析 HTML, 生成 DOM 树,JS 对象。CSS 解析器同理,解析 CSS ,生成 CSSOM 树
- 在渲染 HTML 过程中遇到 JS CSS 链接的时候会暂停渲染去下载,因为下载下来的 JS 和 CSS 可能会影响到接下来的渲染结果
- 在这里如果确定 JS 和 CSS 不需要提前下载,滞后到 body 后面,有助于提高首屏渲染速度,让用户更快看到页面
- 渲染:
- 在渲染进程中实现,里面有主线程、合成线程、
- 主线程进行解析HTML、CSS, 生成 DOM CSSOM 树,根据结构和 position 分层 Layer,布局 Layout,生成绘制指令
- 将绘制指令发送到合成线程中,合成线程执行指令,调用 GPU 进程绘制加速。
- GPU 进程中光栅化
- 渲染进程完成渲染后,将结果发送给浏览器主进程,浏览器主进程将结果显示到屏幕上,并更新浏览器的loading状态和页面
- 在渲染 HTML 过程中遇到 JS CSS 链接的时候会暂停渲染去下载,因为下载下来的 JS 和 CSS 可能会影响到接下来的渲染结果
- 在浏览器输入 url 会发生什么。大体浏览器原理
- 渲染流程
- 重排、回流
- V8 是如何执行 JS 代码的
- 解释器:代码->(词法分析、语法分析)->AST->(词义分析)字节码->解释执行(如果是热代码,会转为机器码)
- 编译器:代码->(词法分析、语法分析)->AST->(词义分析)中间代码->二进制文件->直接执行
- V8 如何执行 JavaScript 代码
- 安全方面
- 跨域: 前后端分离,防止盗版网页随意访问后端接口
- 服务端配置:access-control-allow-origin (接入控制所允许的起源)
- 网页登录信息通过 Cookie 来做验证,恶意脚本可以通过植入脚本到网页中,通过 document.cookie 来使用 Cookie,发起一些危险操作,例如转账
- 解决,配置:http-only,不允许 js 获取 Cookie
- XSS: 因为 HTML 解析的时候遇到 JS 代码会执行,所以 跨站脚本攻击 就是利用这个特性,用不同方式插入脚本到网页中执行
- 评论区输入脚本代码:所以在react vue 中都会讲 insertHTML 的方法标为危险了
- 解决:转义。npm 库也有实现了。例如将 < 转为 <,> 转为 >
- DOM 型
- 评论区输入脚本代码:所以在react vue 中都会讲 insertHTML 的方法标为危险了
- CSRF: 跨站伪造请求攻击。主要是用吸引眼球的方式来伪造成一个链接,通过盗用用户的 Cookie 来发起请求,这也是广撒网式的钓鱼,例如转账
- 所以现在有验证码,多重验证
- eg: 美女弹窗、奖品领取、重磅新闻
总结下来(浏览器开放了两个特权)
- 浏览器为了让用户方便,给引用第三方资源开放了权限,允许跨域。跨站脚本攻击,引入脚本,执行嵌入sql
- 浏览器为了开放js权限。导致js可以获取到cookie,为跨站伪造请求创造了条件。document.cookie
- 模块化
- 核心
- 同步异步问题
模块化的发展也是因为互联网技术发展的一路衍生品。以前,js 都是直接写到html中,直接运行,此时的模块化都是全局污染的。后来,想出了命名空间,就是在根目录下命名一个 变量,再在变量下面定义变量。 nodejs 用的语法是 const a = require()
- AMD
- CMD
- CommonJS
- ESM
- TreeShaking
优化 babel-loader(一般用于开发环境)
module: {
rules: [
// 优化: 1. 开启缓存 2. include exclude明确范围,写其中一个即可以
{
test: /\.js$/,
loader: ['babel-loader?cacheDirectory'], // 开启缓存
include: srcPath,
// exclude: /node_modules/
},
]
}
开启缓存: 用cacheDirectory,只要ES6代码没变,就不会重新编译,会缓存下来 第二次编译时,没改的部分使用缓存
IgnorePlugin(可用于生产环境)
避免一些模块引入。如果不用IgnorePlugin,可能会出现一些问题,比如打包的体积太大,打包慢
例如:moment会支持多语言,如何只引入中文模块?
// 忽略 moment 下的全部 /locale目录
new webpack.IgnorePlugin(/\.\/locale/, /moment/)
按需引入
// 业务代码中动态引入语言包
import 'moment/locale/zh-cn'
noParse(忽略大型的 library 可以提高构建性能)(可用于生产环境)
noParse避免重复打包 module: { noParse: [/react.min.js$/] }
IgnorePlugin和noParse区别:
- IgnorePlugin直接不引入,代码中没有
- noParse(类似vue.min.js已经模块化处理过)引入,但不打包
happyPack 多进程打包(可用于生产环境)
JS单线程,开启多进程打包 提高构建速度(特别是多核CPU)


ParallelUglifyPlugin优化压缩(可用于生产环境)
必须用于生产环境,压缩代码
- webpack内置Uglify工具压缩JS
- JS单线程,开启多线程压缩更快
- 和happypack同理
// 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
plugins: [
new ParallelUglifyPlugin({
// 传递给 UglifyJS 的参数
// (还是使用 UglifyJS 压缩,只不过帮助开启了多进程)
uglifyJS: {
output: {
beautify: false, // 最紧凑的输出
comments: false, // 删除所有的注释
},
compress: {
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
}
}
})
]
- 关于是否需要开启多进程
- 项目较大的时候,开启会加快打包
- 项目较小的时候,开启会变慢,因为多进程开销
自动刷新(不可用于生产环境)
一般不用自我配置,因为开发的时候一般会用devServer,会自动开启自动刷新
// 一般不用自我配置,因为开发的时候一般会用devServer,会自动开启自动刷新
// watch: true, // 开启监听,默认为 false
// // 开启监听后,webpack-dev-server 会自动开启刷新浏览器
// // 监听配置
// watchOptions: {
// ignored: /node_modules/, // 忽略哪些
// // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高
// // 默认为 300ms
// aggregateTimeout: 300,
// // 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的
// // 默认每隔1000毫秒询问一次
// poll: 1000
// }
HotModuleReplacementPlugin 热更新(不可用于生产环境)
区别
- 自动刷新:整个网页全部刷新,速度慢,状态会丢失(比如填写表单时,表单内容会丢失,或者路由跳转了很多层,网页刷新后会跳到首页)
- 热更新:新代码生效,网页不刷新,状态不丢失
开启热更新配置

配置哪些模块需要热更新

DllPlugin 拆分 bundles(不可用于生产环境)
前端框架如vue React 体积大,构建慢
较稳定,不常升级
同一个版本只需要构建一次,不用每次都重新构建
webpack已内置DllPlugin支持
DllPlugin 打包出dll文件(dll 配置将会被移除,因为 Webpack 4 的打包性能足够好的,dll 没有在 Vue ClI 里继续维护的必要了。)
- 打包后产出文件配置参考
- react.dll.js 打包后的内容
- react.manifest.json 索引
- 打包后产出文件
webpack.dll.js
const path = require('path')
const DllPlugin = require('webpack/lib/DllPlugin')
const { srcPath, distPath } = require('./paths')
module.exports = {
mode: 'development',
// JS 执行入口文件
entry: {
// 把 React 相关模块的放到一个单独的动态链接库
react: ['react', 'react-dom']
},
output: {
// 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
// 也就是 entry 中配置的 react 和 polyfill
filename: '[name].dll.js',
// 输出的文件都放到 dist 目录下
path: distPath,
// 存放动态链接库的全局变量名称,例如对应 react 来说就是 _dll_react
// 之所以在前面加上 _dll_ 是为了防止全局变量冲突
library: '_dll_[name]',
},
plugins: [
// 接入 DllPlugin
new DllPlugin({
// 动态链接库的全局变量名称,需要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述动态链接库的 manifest.json 文件输出时的文件名称
path: path.join(distPath, '[name].manifest.json'),
}),
],
}
- DllReferencePlugin 使用dll文件 配置

优化产出代码
- 体积更小
- 合理分包,不重复加载
- 速度更快,内存使用更少
使用生产环境
mode: 'production',打包生产环境代码
- 自动开启代码压缩
- Vue React等框架会自动删掉调试代码(如开发环境的warning)
- 自动开启Tree-Shaking(摇晃树,把没有用的东西摇掉)
什么是Tree-Shaking?实现原理(与模块化有关)
js和css都可以treeShaking
ES6 Module才能让tree-shaking生效,commonjs不可以。因为ES6 Module是静态引入,Commonjs是动态引入
而 ES6 Module 方案则从规范层面规避这一行为,它要求所有的导入导出语句只能出现在模块顶层, 且导入导出的模块名必须为字符串常量,这意味着下述代码在 ESM 方案下是非法的:
if(process.env.NODE_ENV === 'development'){
import bar from 'bar';
export const foo = 'foo';
}
tree-shaking 会把一些没有用到的函数删除
Webpack 原理系列九:Tree-Shaking 实现原理
url-loader 小图片使用base64编码
module: {
rules: [
// 图片 - 考虑 base64 编码的情况
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
// 小于 5kb 的图片用 base64 格式产出
// 否则,依然延用 file-loader 的形式,产出 url 格式
limit: 5 * 1024,
// 打包到 img 目录下
outputPath: '/img1/',
// 设置图片的 cdn 地址(也可以统一在外面的 output 中设置,那将作用于所有静态资源)
// publicPath: 'http://cdn.abc.com'
}
}
},
]
}
bundle加hash

提取公共代码
splitChunks

懒加载
使用CDN加速

webpack的scope hosting(作用域提升)
默认情况不开启scope hosting
- 产生多个函数,每个函数都有一个作用域,对js代码执行和内存消耗非常不友好
开启后
- 多个函数合并为一个函数,作用域减少
- 代码体积更小
- 创建函数作用域更少
- 代码可读性更好
来自:深入浅出webpack
同时,考虑到 Scope Hoisting 依赖源码需采用 ES6 模块化语法,还需要配置
mainFields。 原因在 4-10 使用 TreeShaking 中提到过:因为大部分 Npm 中的第三方库采用了 CommonJS 语法,但部分库会同时提供 ES6 模块化的代码,为了充分发挥 Scope Hoisting 的作用,需要增加以下配置:
module.exports = {
resolve: {
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
};

webpack4升级 webpack5 以及周边插件后
Babel
Babel作用
ES6模块化,浏览器并不完全支持,需要通过Babel来编译成ES5
例如:将let const 编译为var;将class编译为function
环境搭建和基本配置
package.json
{
"devDependencies": {
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/plugin-transform-runtime": "^7.7.5",
"@babel/preset-env": "^7.7.5"
},
"dependencies": {
"@babel/polyfill": "^7.7.0",
"@babel/runtime": "^7.7.5"
}
}
.babelrc 基本配置
{
"presets": [
[
"@babel/preset-env"
]
],
"plugins": [
]
}
presets
- @babel/preset-env是很多plugin的一个集合,可以转换ES6 7 8语法
- 是一个babel插件的集合,预设置,代替我们写很多的plugins
- @babel/preset-flow
- @babel/preset-react(转换jsx语法)
- @babel/preset-typescript(转换ts语法)
babel和babel-loader的区别
- babel是编译ES6的核心工具
- babel-loader是用babel封装后,将babel用于webpack打包流程。类似less和less-loader
babel-polyfill
什么是babel-polyfill?
对一些浏览器不支持的函数做补丁或者兼容
- babel只负责解析语法,不处理API,也不管模块化(webpack处理模块化)
- webpack把babel-polyfill引入进来,babel处理完交给webpack。polyfill解析Promise和includes语法,API就可以在浏览器正常运行
@babel/polyfill与core-js关系
@babel/polyfill可以看作是:core-js加regenerator-runtime。
regenerator-runtime是generator以及async/await的运行时依赖
单独使用@babel/polyfill会将core-js全量导入,造成项目打包体积过大。
从Babel v7.4.0[5]开始,
@babel/polyfill被废弃了,可以直接引用core-js与regenerator-runtime替代
为了解决全量引入core-js造成打包体积过大的问题,我们需要配合使用@babel/preset-env。
babel-polyfill如何按需引入
为什么要按需引入
babel-polyfill文件较大,如果只使用一部分功能,无需全部引入。(已废弃原因)
babel-runtime
babel-polyfill的问题
- 会污染全局环境。如果做一个独立的系统,则没问题,如果做一个第三方库,就会可能产生与使用方命名冲突问题。
babel-runtime: 避免自行引入polyfill时导致的污染全局命名空间的问题
@babel/plugin-transform-runtime 的作用是将 helper 和 polyfill 都改为从一个统一的地方引入,并且引入的对象和全局变量是完全隔离的,这样解决了上面的两个问题。
参考
思考
前端为什么需要打包构建
代码层面
- 打包体积会更小(tree-shaking,代码压缩,合并),加载速度更快
- 编译高级语言语法(TS,ES6,less,scss,模块化)
- 兼容性和错误提示(babel-polyfill、postcss、eslint)
打包流程、前端工程化方面
- 統一、高效的开发环境
- 统一的构建流程和产出标准
- 集成公司的构建规范(提测、上线等)
webpack 中 loader 和 plugin 的区别?
webpack 的流程是,
分析代码、转换代码、编译代码、输出代码
- loader 模块转换器。如 less -> css
- css-loader
- style-loader
- postcss-loader
- sass-loader
- plugin 扩展插件,类似浏览器的插件,主要是扩展和增强功能。原理是基于 webpack 中的事件机制,监听广播事件,再做相应的处理。
- HtmlWebpackPlugin
- MiniCssExtractPlugin
- TreeShakingPlugin:由于
分析代码过程中可知道 - HotModuleReplacementPlugin
- DllPlugin: 将不会经常变动的代码打包成静态资源,提高打包速度,例如react、vue、jquery等固定版本的库

loader,它是一个转换器,将A文件进行编译成B文件,比如:将A.less转换为A.css,单纯的文件转换过程。
plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,webpack打包的整个过程, 它并不直接操作文件,而是基于
事件机制工作,会监听webpack 打包过程中的某些节点,执行广泛的任务
loader
- 在打包前或期间调用
- 调用顺序与书写顺序相反
plugin
- 事件触发调用,监听 webpack 广播的事件
- 不同生命周期改变输出结果
常见的 plugin
- HtmlWebpackPlugin: 创建 HTML,可用于配置 多入口(单页面应用只有一个入口页面)
- MiniCssExtractPlugin: 抽离和压缩 CSS
- IgnorePlugin
- ParallelUglifyPlugin优化压缩
- DllPlugin
- HotModuleReplacementPlugin
babel 和 webpack 的区别
- babel-js 新语法编译工具,不关心模块化
- webpack 是打包构建工具,是多个 loader plugin 的集合
如何产出一个lib
babel-polyfill和babel-runtime的区别
- babel-polyfill会污染全局
- babel-runtime不会污染全局
- 开发第三方lib要用babel-runtime,避免与使用方产生冲突
webpack如何使用懒加载
- import()
- 结合Vue React 异步组件
- 结合Vue-router React-router异步加载路由
为何Proxy不能被Polyfill
因为(function callback是es5语法)
- Class可以用function模拟
- Promise可以用callback来模拟
- 但Proxy的功能用Object.defineProperty无法模拟
Polyfill 是一块代码(通常是 Web 上的 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。 proxy没有任何现成的语法可以模拟到,所以无法Polyfill
常见性能优化方法
从构建速度和产出代码两个方面分析
优化构建速度
- 可用于生产环境的
- 优化babel-loader
- IgnorePlugin
- noParse
- happyPack多进程打包
- ParallelUgifyPlugin优化压缩
- 不能用于生产环境
- 自动更新
- 热更新
- DllPlugin
特别强调:热更新万万不能用于生产环境,在代码中写的热更新范围,在生产打包时一定要删掉,否则生产环境会有问题!
优化产出代码
- 小图片通过base64方式
- bundle加hash
- 懒加载
- 提取公共代码
- 使用cdn加速
- IgnorePlugin
- 使用Production模式
- 开启Scope Hosting
react cli 中的 webpack 做了啥?基于他的基础上做了哪些配置和优化?
- 通过 config-overrides.js 覆盖默认的 webpack,例如做了修改 antd design 的样式变量