编译阶段的优化
主要是webpack
开发环境时重复构建更快
1.include
缩小编译的范围 rules: [ { test: /\.js$/, use: [ { loader: 'babel-loader', options: { cacheDirectory: true, persets: [ '@babel/preset-react' ], plugins: [ '@babel/plugin-proposal-class-properties' ] } } ], include: path.resovle('src'), exclude: /node_modules/ } ]
2.resolve
配置解析 … const bootstrap = path.resolve(“node_modules/boostrap/dist/css/bootstrap.css”) … resolve: { modules: [path.resolve(‘node_modules’)] // 查找范围 extensions: [‘.js’, ‘.ts’], // 扩展 名 越少越好 alias: { bootstrap }, fallback: { cryto: false, // 假如说你引用的一个包里面有node核心模块 它会帮你跳过这个node核心模块的引用 让你最后打出来的包体积更小 buffer: false, stream: false } }, module: { rules: […] },
3.alias
上面提到了
4.external
如果配置了这个插件 就不会打包lodash模块 会引入 _ 这个全局变量 new HtmlWebpackExternalsPlugin({ externals: [ { module: 'lodash', entry: 'https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/loadash.js', global: '_' } ] })
5.编译缓存
{ loader: 'babel-loader', options: { cachDirectory: true, // 开启缓存 } } 但如果是webpack5 可以配置持久化缓存 以前是没有的 devtool:... cache: { // 开启持久化缓存 type: 'filesystem' // 改为 memory会更快 }, entry: ...
6.开启多进程
entry:… optimization: { minimize: isEnvProduction, // 生产环境会开启压缩 minimizer: [ new TerserPlugin({parallel: true}), // 压缩js 多进程压缩 new OptimizeCSSAssetsPlugin() // 压缩css ], splitChunks: … }生产环境时文件更小 加载更快 1.开启tree-sharking import {join} from ‘lodash’ 仅仅只会打包join这一个方法 2.scope-hositing 将作用域提升 可以减小包的体积 3.splitChunks 代码分割 懒加载 optimization: { minimize: isEnvProduction, minimizer: [ new TerserPlugin({parallel: true}), new OptimizeCSSAssetsPlugin() ], splitChunks: { chunks: ‘all’, // 支持 asynchronous和同步 minSize: 0, // 最小大小 minRemainingSize: 0, //分割出去剩下的大小 maxSize: 0, // 最大大小 minChunks: 1, // 最小引用次数 maxAsyncRequests: 30, // 异步模块最大并发请求数 import(‘…’) maxInitialRequests: 30, // 同步模块最大并发请求数 import enforceSizeThreshold: 50000, // 如果一个代码块的大小超过这个数就强行打包webpack新属性 cacheGroups: { // 缓存组 defaultVendors: { // 第三方的模块如果在node_modules里面的话会进行一个单独的分割 test: /[\/]node_modules[\/]/, priority: -10, // 优先级 reuseExistingChunk: true // 是否使用已经分割出的代码块 }, default: { minChunks: 2, // 如果一个模块被引用2次的话 会单独提取为一个代码块 priority: -20, reuseExistingChunk: true } } }, runtimeChunk: { // 运行时代码 单独分割 name: entrypoint => runtime-${entrypoint.name} }, moduleIds: isEnvProduction ? ‘deterministic’ : ‘named’, chunkIds: isEnvProduction ? ‘deterministic’ : ‘named’ }
4.提供node的空mocks
我们上面在fallback中已经配置了
5.持久化缓存
webpack5新增功能
上面在代码分割后的相关moduleIds配置项
moduleIds: ‘deterministic’
路由切换的优化 懒加载
更新阶段的优化
PureComponent 只要属性不更新 组件就不会重新渲染
实现PureComponent以及memo
但上述的属性对比仅仅是浅比较 所以存在缺陷
所以我们需要用到 immutable.js
import {Map} from ‘immutable’;
Map 为不可变数据
每次操作都会返回一个不同的对象引用地址
但是每次会尽可能复用老的属性 另外可以非常快速进行深度比较 性能特别高
class App … { constructor() { … this.state = {counter:Map({number:0})}; } add = (amount) => { let count = this.state.count.set(‘number’, this.state.count.get(‘number’) + amount);
this.setState(count); } render() { ... return ( <button onClick={()=>this.add(1)}> ) }
}
可视化工具 React Developer Tools
优化redux
通过reselect
简单实现一个createSelector
最新版react-router-dom 中 useSelector和上面的功能是一样的(缓存中间的计算结果 提高一定的性能)
大数据渲染优化
时间分片优化前
时间分片优化后
虚拟列表
具体虚拟列表会专门开一个专题看虚拟列表专题吧
骨架屏
在真实内容渲染前 有一个loading效果
我们要写一个webpack插件
在编译阶段就生成一个svg图 插入值
中去
skeleton.js (src/skeleton.js)
在根目录下(与webpack.config.js平行)
新建SkeletonWebpackPlugin.js
weback.base.js
webpack.config.js
webpack.seleton.js
通过webpack进行预渲染
由于spa项目普通的爬虫无法爬取项目的静态文本的内容 通过预渲染插件prerender-spa-plugin解决spa项目的seo问题
prerender-spa-plugin利用了Puppeteer的爬取页面的功能
Puppeteer是一个Chrome官方出品的headless Chrome node库 它提供了一系列的API 可以在无UI的情况下调用Chrome的功能 适用于爬虫 自动化处理等各种场景
原理是在webpack构建阶段的最后 在本地启动一个Puppeteer的服务 访问配置了预渲染的路由 然后将Puppeteer中渲染的页面输出到html文件中 并建立路由对应的目录
注意:不适合不同的用户看都会不同的页面 这种类型的页面不适用预渲染 对于一些经常发生变化的页面 如体育比赛等 会导致编译后的数据不是实时更新的
虚拟列表
还有
React hooks性能优化
Error Boundaries
通过DOM-DIFF原理进行性能优化
响应式数据的精细化渲染
图片懒加载等优化手段