最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React项目优化

    正文概述 掘金(baby_hu)   2020-12-18   596

    前言

    记录在项目中使用到的一些优化。

    性能优化

    1.Gzip压缩

    借助CompressionWebpackPlugin插件来提前对文件进行Gzip压缩,服务器查找到有与源文件同名的.gz文件就会直接读取,不会主动压缩,降低cpu负载,优化了服务器性能。 安装

    npm install --save-dev compression-webpack-plugin@1.1.12
    

    webpackconfig.plugin中增加如下配置:

      new CompressionWebpackPlugin({
        filename: '[path].gz[query]',
        algorithm: 'gzip',
        test: new RegExp('\\.(js|css)$'),
        threshold: 10240,
        minRatio: 0.8, //压缩比例
        deleteOriginalAssets: false //是否删除源文件
      })
    

    nginx中增加gzip相关配置:

    注:gzip_types中不要配置image相关

        gzip on;
        gzip_static on;    
        gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
        gzip_proxied  any;
        gzip_vary on;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
    

    开启Gzip后: React项目优化 React项目优化 文件体积减小至原来的1/4,测试平均整体加载时间减少20%。 文件体积越大效果越明显。

    2.Code Split

    • 第三库一般比较稳定,不会轻易改变,单独提取出来,做长期缓存。
    • 可以拆分代码块,避免代码块体积过大,加载时间长

    在webpack config文件的optimization中增加配置

    splitChunks: {
          cacheGroups: {
            vendors: {
              test: /[\\/]node_modules[\\/]/, //用于控制哪些模块被这个缓存组匹配到。原封不动传递出去的话,它默                                           认会选择所有的模块。可以传递的值类型:RegExp、String和                                                   Function;
              chunks: 'initial',  //同步(initial)、异步(async)、所有模块有效(all)
              minSize: 30000, //最小尺寸
              name: 'vendors', // 打包的chunks的名字
              priority: -10, //优先级,表示抽取权重,数字越大表示优先级越高
              enforce: true,
              reuseExistingChunk: true   // 可设置是否重用已用chunk 不再创建新的chunk
            },
            styles: {
              name: 'styles',
              test: /\.(css|less)$/,
              chunks: 'all',
              enforce: true,
            } 
          }
        }
    

    3.React.lazy、React.Suspense按需动态加载

    React.lazy 可以让我们像渲染常规组件一样处理动态引入的组件,结合 Suspense 可以更优雅地展现组件懒加载的过渡动画以及处理加载异常的场景。

    import React, { lazy } from 'react' const SmsManager = lazy(() => import(/* webpackChunkName: "manager" */ 'manager'))

    动态加载遇到的问题:

    • 因为网络问题导致加载失败,报错Loading chunk failed
    • 用户使用过程中,如果重新发布,因为浏览器缓存为旧的文件,和服务器文件名不一致,会导致文件下载失败报错Loading chunk failed

    解决办法: 针对网络问题,可以通过webpack-retry-chunk-load-plugin重新加载

    let {RetryChunkLoadPlugin} = require('webpack-retry-chunk-load-plugin')
    //plugins中新增配置
      plugins: [
        new RetryChunkLoadPlugin({
          cacheBust: `function() {
            return Date.now();
          }`,
          maxRetries: 2,//加载失败最多尝试次数
        })
      ]
    

    针对使用过程中发布导致下载失败的问题,可以通过重新加载的方式解决(这种方式不算特别好,如果有更好的方法我再补充)

    import React from 'react'
    import { observer, inject } from 'mobx-react'
    import Component from 'edt-components/Component'
    import { sessionStorage } from 'utils/storage'
    import FullLoading from 'edt-components/FullLoading'
    import _ from 'lodash'
    @observer
    class ErrorBoundary extends Component {
      constructor(props) {
        super(props)
        this.data = {
          hasError: false,
          errorType: null
        }
        this.clearLoadingChunk()
      }
      componentDidCatch(error, errorInfo) {
        this.handleError(error, errorInfo)
      }
      clearLoadingChunk = () => {
        window.clearTimeout(this.clearTimer)
        this.clearTimer = window.setTimeout(() => {
          sessionStorage.removeItem('loadingChunk')
        }, 60000)
      }
      handleError = (error, errorInfo) => {
        this.setData({hasError: true})
        this.handleLoadingChunkError(error)
      }
      handleLoadingChunkError = (error, errorInfo) => {
        //页面浏览期间重新发布,会出现浏览器缓存文件名和服务器文件名不一致,导致下载js失败白屏的问题
        const loadFaild = new RegExp(/Loading chunk (\d)+ failed/g)
        if (error && error.message && error.message.match(loadFaild)) {
          this.setData({errorType: ERROR_ENUM.RE_LOADING})
          let loadingChunk = sessionStorage.getItem('loadingChunk')
          loadingChunk = _.isNumber(loadingChunk) ? loadingChunk + 1 : 1
          if (loadingChunk > 2) {
            this.setData({errorType: ERROR_ENUM.LOAD_FAIL})
            //当前流程结束,重置loadingChunk
            sessionStorage.setItem('loadingChunk', 0)
          } else {
            sessionStorage.setItem('loadingChunk', loadingChunk)
            window.location.reload()
          }
        }
      }
      renderErrorContent = () => {
        const {errorType} = this.data
        if (errorType === ERROR_ENUM.LOAD_FAIL) {
          return (
            <h3>页面加载失败, 请刷新页面重新加载...</h3>
          )
        }
        if (errorType === ERROR_ENUM.RE_LOADING) {
          return (
            <FullLoading/>
          )
        }
      }
      render() {
        return this.data.hasError ? this.renderErrorContent() : this.props.children
      }
    }
    
    //页面错误类型枚举
    const ERROR_ENUM = {
      LOAD_FAIL: 'LOAD_FAIL',
      RE_LOADING: 'RE_LOADING'
    }
    
    export default ErrorBoundary
    

    4.Js压缩UglifyJsPlugin

      optimization: _.assignIn({}, commonConfig.optimization, {
        minimizer: [
          new UglifyJsPlugin({
            cache: true,
            parallel: true,
            sourceMap: true // set to true if you want JS source maps
          })
        ],
      })
    

    5.Css压缩 MiniCssExtractPlugin

      new MiniCssExtractPlugin({
        filename: '[id]_' + config.version + '_[hash].css',
        chunkFilename: '[id]_' + config.version + '_[hash].css'
      }),
    

    6.HTML压缩

      plugins: [
        new HtmlWebpackPlugin({
          title: config.title,
          template: config.template,
          inject: true
        })
      ]
    

    7.长列表虚拟加载

    使用react-virtualized 源代码结合列表代码实现虚拟加载

    代码优化

    1.Css自动化重构

    项目中原来没有依据配色规范等,有一个公共的样式文件来对项目样式文件进行管理,如果需要支持主题更换,则需要重新提取整合项目中的css样式。 可以使用Css自动化重构工具lemonj,自动提取整合,不需要人工收集和整理,开发人员只需要修改变量名就行了。

    安装

    npm install lemonj -g
    

    分析项目css代码,components为需要分析的文件名

    lemonj analysis components
    

    得到整体分析结果(坏味道代码),和两个文件mappings.less和result.json mappings.less:

    @color_8: rgba(0, 0, 0, 0.1);
    // components\TransferPicker\style.less:4
    @color_9: #fff;
    // components\ATable\style.less:171
    // components\ATable\style.less:177
    @color_10: #e6f7ff;
    // components\ATable\style.less:284
    // components\ATable\style.less:295
    @color_11: #fbfdff;
    // components\NavigationBar\style.less:30
    @color_12: #929598;
    // components\Card\style.less:45
    @color_13: #F8F9FA;
    

    修改mappings.less中的变量名,如color_8改为primary_color,保存,执行命令:

    lemonj refactor componnets
    

    项目中的所有对应样式则会改成mappings.less中对应的样式变量名

    2. 复杂列表逻辑分层

    原来的复杂列表代码,所有的数据查询,渲染,事件全部放在一个js中,随着功能扩展,代码量越来越大, 不易维护。 因此将列表使用高阶组件设计分层,分为数据层,事件层,代码层。

    import Data from './Data'
    import Event from './Event'
    import Render from './Render'
    ...
    
    @Data
    @Event
    @Render
    class List {
    ...
    }
    

    项目工程化

    1.组件库

    由于刚开始只有一个系统,后续拓展新增项目后,时间紧急就直接把组件代码复制到新项目中,但是多个系统维护一套组件很麻烦,时间长了导致组件不统一,而且迭代功能有时候需要多个系统重复修改。 因此抽离公共组件库,多个系统共用一套组件库。

    2.组件库展示网站

    抽取组件库之后,遇到了以下问题

    • 多个系统共用一个组件库,策划方的组件UI设计没有对应示例可以查看,无法与组件库的样式和交互保持统一
    • 组件库目前难以管理,组件的改动会同时影响多个系统中组件的展示和交互,开发人员对组件改动带来的影响 难以把控
    • 项目中组件库使用频繁,但是查阅组件API繁琐,需要翻阅组件代码
    • 无法直观全面地了解每个组件具备的功能,对新人学习成本较高,组件新增功能也无法快速让组内其他人了解
    • 组件测试

    因此参考bisheng ,打造一个组件库文档网站,以解决上述问题。

    使用框架:bisheng

    参考链接:文档工具bisheng的使用

    3.单元测试

    抽离组件库后,必须增加单元测试。

    jest是facebook推出的一个前端测框架,搭配enzyme可以轻松实现对React应用的单元测试

    • jest
    • enzyme

    待优化

    • 使用tree-shaking(由于原来对lodash等引用不当,测试过使用tree-shaking作用不大,所以可能需要后续再进行代码整 理)
    • css模块化(平时写代码的过程中偶尔会遇到样式被其他模块样式覆盖的问题,这一部分已经做过很多尝试,比如css-module,react-css-module,babel-plugin-react-css-modules等,主要问题在于在原项目的基础上向前兼容很麻烦,改动范围较大。用过的最好的是babel-plugin-react-css-modules,但是还是兼容还是有点麻烦,推动比较难。目前并没有找到特别好的办法)
    • 使用TypeScript(目前可能比较难推进,迭代成本较高)
    • 引入前端监控(需要经过组长同意,并部署到内网,感觉实现有点难度)
    • 公共组件优化(表单配置化,表单拓展,部分组件功能拓展)

    起源地下载网 » React项目优化

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元