最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Angular页面优化——删除未使用的前端代码 | 踩坑日志

    正文概述 掘金(PruPru噗噜噗噜)   2021-03-09   1206

    Angular页面优化——删除未使用的前端代码 | 踩坑日志

    大家好

    我是创意行业中的前端prupru

    是一个虽然面试官说已经没什么人用Angular,

    却依然把Angular技能点满的人。

    前言

    我想推动团队重视网页项目中的优化由来已久,也曾在团队讨论中委婉地提过我们项目的Lighthouse分数不尽人意。虽团队大大们有所认知,但碍于业务的时间紧张和成本限制,往往是我自己抠时间根着教程做一些小修小改。

    直到接下来需要我要上手一个一年一度的项目。

    TL:你看看去年这个活动网站。
    我:嗯……
    TL:今年我们还有这个业务。你不是一直想搞优化嘛?看你年轻力壮爱学习,给你几天时间想点办法把Lighthouse分数整上去
    我:!!!
    (以上对话为虚构)
    

    开心的是,网页优化和最佳实践终于被提上了新项目的日程。

    紧张的是,感觉自己的经验不够用。

    我的目标是整理出一个可被分享的工作流。

    在瞎琢磨了几个小时后,汇报一下初步成果

    -Performance指标3项达标,分数从66到70分。

    -未使用的文件加载速度 1.04秒 降到 0.57秒。

    -覆盖率有所上升(main-es2015.js, style.css)。

    Angular页面优化——删除未使用的前端代码 | 踩坑日志

    Angular页面优化——删除未使用的前端代码 | 踩坑日志

    Angular页面优化——删除未使用的前端代码 | 踩坑日志

    webpack-bundle-analyzer 对比图

    Angular页面优化——删除未使用的前端代码 | 踩坑日志

    步骤

    分为诊断、优化、再测试,以此循环。

    诊断

    1.打包

    ng build --prod --source-map --stats-json --outputPath=dist
    

    在生产环境中打包。和真正部署不同的是,其中--source-map是为了给source-map-explorer提供信息,--stats-json是为了给webpack-bundle-analyzer提供信息。

    在本地serve打包好的文件。

    然后在本地查看webpack-bundle-analyzer或者source-map-explorer的打包情况。

    (工具的安装和使用见各repo)

    2.通过Lighthouse报告,定位prod环境下的问题,从最严重的问题着手开始。

    “做正确且困难的事”

    案例中:通过上图报告得知,“Remove unused javascript” 没有移除未使用的javascript导致的一系列问题,main.js和style.css的覆盖率较低,导致浪费用户的加载时间和流量。

    诊断工具见附录【工具一览】。除了Lighthouse的指导外,各教程文章也有很多。

    3. 分析打包情况

    这也是我觉得困难的地方,因为好多JS优化的文章说到以上的工具就结束了,结果是我看着分析出来的数据和可视化图仍旧满头疑惑。并没有很多文章说如何给出规律如何找到不对劲的包。

    实际上自己上手了之后的确发现每个项目特点不一样,无法以一概全。实施细节也因框架而异。然而还是有共通的思路是可以借鉴的。

    整体思路是通过数据找到“不对劲”的包。我们的目标是每一份加载的文件覆盖率高,单个文件的大小不要过大,并且一次不要加载过多,可以在后期的用户互动懒加载。也就是大化小,并且在大小和请求次数中取平衡之道。

    粗浅的实践经验之后,在我看来“不对劲”有以下几种

    • 1.最明显的是单个文件尺寸过大,或者某一组件/库占比过大。

      方法:- 是否该文件书写不当?
             从代码上优化。
           - 是否引用过多的组件或者库?
             拆分。
      

    案例中:如果是单个angular组件的大小十分扎眼,很有可能是它承担了太多职责,非常冗长。则确认一下该组件是否可以进一步拆成小组件。

    • 2.如果单个文件中,各个组件大小差不多。

      方法:- 是否每个被引用的元素都有使用过(常常忘记)?
             删除没有使用的引用变量。
           - 是否每个被引用的元素都在被加载的第一时间使用?
             拆分非初始渲染需要的部分,再懒加载。
                
      

    案例中:app提前加载了其他页面,下文讲描述Angular的懒加载。

    • 3.不同的文件中重复打包了一个同一个库

      方法: 在全局引用这个库
        
      
    • 4.【Angular】es2015项目却加载了某个CommonJS/AMD模块。

    事实上Angular打包时ng build --prod 也会发出警告。

    Warning: ... depends on .... 
    CommonJS or AMD dependencies can cause optimization bailouts.
    For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
    
    
      方法:- 该库是否有ES模块的替代版本?
             使用该版本。
           - 或根据以上Angular官方文档,mute关于该库的打包警告。
           
    

    angular.io/guide/build…

    优化

    根据项目和问题各取所需。

    1)懒加载模块

    针对分析篇中的第2种“不对劲”的打包现象:首页文件大,但单个文件中各个组件大小差不多。

    先放上官方的懒加载特征模块。总结就是对于首页不需要加载的页面,进行懒加载。

    一个Angular初学者的常见疑惑是,为什么要把多个组件打包成一个模块?本质上还是被app根模块引用,有什么区别?我曾经也不以为然,但是遇到app规模变大、路由很多、难以优化时,就有必要注重按模块分类这些组件。

    因为在Angular模块中,模块Module具有一个Component不具有的特性,即懒加载。

    NgModule默认是加载所有其中组件的,Angular懒加载的具体定义是不在initial bundle中加载,在浏览该模块的路径时才加载。所以也可以把feature module特征模块浅显地理解为页面模块,或者某些条件下出现的功能。

    案例:

    Before app.routing.module.ts

     { path: ‘pathA’, component: AComponent }
    

    把该组件改造成懒加载的模块,步骤

    1.在terminal运行

    ng module AModule —module app —route pathA
    

    第一个参数是新建的模块名,app是指新模块要加入的根模块。

    2.把原本A.component.ts中Acomponent的内容移动到AModule中的A.component.ts。(注意生成模块时的命名冲突)

    After

     { 
       path: 'pathA', 
       loadChildren: () => import('./famitsu/famitsu.module')
                             .then(m => m.FamitsuModule) 
     }
    

    2) 将global library单独打包

    针对分析篇中的第1种“不对劲”的打包现象:单个文件中某个库的比例过大,或者第4种:库是CommonJS/AMD模块。

    根据webpack-bundle-analyzer的可视图,感觉可以从lottie.js这个库下手。lottie占比看上去很大,同时被打包在了main.js内。

    大致思路是webpack中可以划分打包,Angular内置webpack,如何告诉它分开打包呢?

    一顿搜索,发现了宝藏Angular官方文章Adding a library to the runtime global scope 和stackoverflow上的Angular Cli Webpack, How to add or bundle external js files?

    angular.json中的scripts本来用来添加外部库,其实也可以用来指定本地库的打包。

    添加lottie的本地node module路径

    angular.json

    
    "architect": {
      "build": {
        "options": {
          ...
          "styles": [
            "src/styles.scss"
          ],
          "scripts": [
            "../node_modules/lottie-web/build/player/lottie_svg.js"
          ]
        },
      ...
      }
    }
    ...
    

    打包后,dist文件夹中应该出现一个scripts.js

    优点:(推论)如果app发布更新,scripts的部分不变而web app发布新版本,则用户不必重复下载lottie的部分。

    优化x1: 发现了min.js文件

    "scripts": [
      "../node_modules/lottie-web/build/player/lottie_svg.min.js"
    ]
    

    优化x2: 懒加载库

    根据自己对项目的了解,甚至可以将库随着组件懒加载。

    观察dist/index.html

    <script src="scripts.<hash>.js" defer></script>
    

    思路:配置“scripts”后,打包好的scripts.js被插入首页。那其实只要打包scripts.js但默认不插入首页,然后需要的时候添加一个script DOM就好了。

    一顿搜索后,还是上面的Angular官方文章。

    1.修改angular.json配置,默认不插入打包的scripts

    Before

    "scripts": [
      "../node_modules/lottie-web/build/player/lottie_svg.min.js"
    ]
    

    After

    "scripts": [
      {
        "input": "../node_modules/lottie-web/build/player/lottie_svg.min.js",
        "inject": false,
        "bundleName": "lottie"
      }
    ]
    

    2.在组件中懒加载

    这一部偷懒我就没继续了。参考教程 Lazy Loading Scripts and Styles in Angular

    3) 针对库自身的优化

    和lottie还没完。

    在一顿搜索后发现此文Reducing lottie-web bundle size。大意是lottie自带3种渲染器:canvas、html和svg,但是大部分项目在初始化时就指定一种渲染器并且不需要切换。那么只加载该渲染器的部分就够了。

    案例中:只使用了lottie的svg渲染器

    Before

    import lottie from 'lottie-web';
    

    After

    import lottie from 'lottie-web/build/player/lottie_svg';
    

    并且,该方法正是lottie的官方angular组件版ngx-lottie。 所以使用ngx-lottie本身也可以提升优化。

    优化:CSS篇

    打开Coverage,观察未使用的selector的特征。

    案例中:发现都是material组件的style。

    实际上整个项目只使用到material的6个组件。

    我们一般会记得在js/Angular Module里按需取用,却忘了css也是可以如法炮制的。

    这也是上篇针对库自身的优化的一种。

    1)减少import的内容

    Before

    @import '~@angular/material/theming';
    

    观察该引用样式的源代码,和node_modules的库路径的其他文件(或者官方仓库)。

    在此,观察material button组件的样式代码(左边是~@angular/material/theming,右边是~@angular/material/button/button-theme)

    Angular页面优化——删除未使用的前端代码 | 踩坑日志

    可得theming.scss包含两部分core样式定义,和各组件样式代码。由于我们不需要所组件的样式,并且这些未使用过的组件占比很大,将引用改为如下:

    After

    @import '~@angular/material/core/core';
    @import '~@angular/material/checkbox/checkbox-theme';
    ...
    

    再次确认样式显示没有不同。

    2)针对Angular material,减少生成的组件样式。

    Before

    @include angular-material-theme($gweb-play-jp-esports-theme);
    

    以下教程完全来自视频 Remove unused Angular Material CSS (2020)

    同理观察该mixin的源代码

    Angular页面优化——删除未使用的前端代码 | 踩坑日志

    自定义一个mixin,复制该mixin并删除不需要的组件includes。

    After

    /* Copied from mixin angular-material-theme */
    /* @import '~@angular/material/theming'; */
    @mixin custom-theme($theme-or-color-config) {
      $dedupe-key: 'angular-material-theme';
      @include mat-private-check-duplicate-theme-styles($theme-or-color-config, $dedupe-key) {
        @include mat-core-theme($theme-or-color-config);
        @include mat-checkbox-theme($theme-or-color-config);
        ...
      }
    }
    
    @include custom-theme($gweb-play-jp-esports-theme);
    
    

    总结

    减少文件大小效果立竿见影。 96kb -> 32kb,几乎是三分之一。

    Angular页面优化——删除未使用的前端代码 | 踩坑日志

    附录

    工具列表和引用列表

    工具一览

    source-map-explorer

    webpack-bundle-analyzer

    Angular虽然内置webpack,但是不包含webpack-bundle-analyzer,所以仍需要添加这个库到devDenpencies。

    引用一览

    Angular官方文档

    Adding a library to the runtime global scope

    Configuring CommonJS dependencies

    Lazy-loading feature modules

    Angular Cli Webpack, How to add or bundle external js files?

    其他

    Remove unused Angular Material CSS (2020)

    Lazy Loading Scripts and Styles in Angular

    Reducing lottie-web bundle size

    后序

    以上一些步骤,是我根据各平台的文章和自己对项目整体的理解摸索出来的。

    看到数据上的改善很欣慰,但也烦恼整体覆盖率仍是不算高,未使用的css selector还是占了很多。

    在此抛砖引玉,若有点赞或指点不胜感激!


    起源地下载网 » Angular页面优化——删除未使用的前端代码 | 踩坑日志

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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