Skip to content

前端优化 #81

@et-hh

Description

@et-hh

白屏优化

  1. 路由懒加载

    {
        path: '/login',
        component: () => import('@aicc/components/login/index')
    }
  2. 使用v-if代替v-show

    好处是可以减少首屏渲染dom数量(除非是一些会频繁变换显隐的元素,这样的元素应该用v-show)

  3. 不直接显示的组件做懒加载

    常见的场景是:el-tabs组件内从第二个tab开始渲染的组件都可以懒加载,目的是减少根据此路由完成首屏渲染时需加载的代码量

    比如vue项目内的

     import pageComponent from './pageComponent'
    
     export default {
       name: 'Recharge',
       components: {
         pageComponent,
       },
     ...

    改成

    export default {
       name: 'Recharge',
       components: {
         pageComponent: () => import('./pageComponent'),
       },
     ...
  4. 使用resolutions统一依赖版本

    假设主项目依赖包A@1.1.0,主项目依赖的包B依赖A@1.1.1,此时yarn会在node_modules根路径和node_modules/B/node_modules分别安装A的两个版本,并都会打包到最终bundle。此时可以在package.json中使用resolutions强行统一A的版本

    "resolutions": {
         "a": "1.1.1"
     }
  5. 组件库按需加载

    包括项目使用的第三方组件库、公司内部组件库、项目components目录内的组件
    这些都可以使用babel-plugin-import插件实现,babel.config.js如下:

    const babelPluginImportForComponents = [
       'import',
       {
         libraryName: '@/components',
         libraryDirectory: '',
         camel2DashComponentName: false,
         customName: name => {
           return `@/components/${name}`
         }
       }
     ]
    
     module.exports = {
       ...
       'plugins': [
         ...
         babelPluginImportForComponents
       ]
     }
  6. 资源预加载

    场景比如:使用element的项目打包出来的css内会通过@font-face去加载字体,也就是说字体会等css加载完并开始解析了再去加载,这样我们可以预加载字体,无需等待css

    这个一般是处理字体资源:<link rel="preload" href="/ai-engine/static/fonts/element-icons.woff" as="font" type="font/woff" crossorigin="anonymous">或者其他任何首屏必须加载,却要等待其他资源先加载的资源

  7. defer

    一些对渲染影响不大的js资源可以在script上加defer,这样这些js不会阻塞渲染也不影响加载,比如iconfont的彩色字体js文件

  8. CDN

    部分静态资源可以放CDN上,好处是请求这些资源时不会带本网站的cookie,减少流量。一些优秀的CDN也会加快资源加载速度,比如七牛、ali

  9. 减少css加载

    原因是css的加载会阻塞dom的渲染,因为浏览器去渲染dom会先构建两棵树:dom树和css规则树,然后再做渲染。
    所以应该只加载首屏需要的css,并且最好先通过<style>内置到index.html

  10. gzip

    打包的时候就打成gzip包,不需要服务器再去做压缩

  11. 静态文件缓存

    目前前端资源一般通过hash区分版本,如果hash没变,可以一直缓存,在服务端设置相应的缓存策略

  12. 服务端渲染/预渲染

这个可以说是终极杀器,因为访问url直接就请求下来一段html和样式,可以直接渲染出来,其他的资源非阻塞式加载就好了。可以说使用此方案会减少很多优化工作量

首屏优化

其实上面的方案也都是首屏优化方案,这里重在强调白屏结束后的处理

  1. 骨架屏/loading动效

    假如首屏上有些内容要通过接口请求数据再渲染,可以先渲染出骨架屏或者loading效果,让用户觉得页面是在加载的

  2. 后端数据层缓存

    一些频繁查询的数据可以设置缓存,比如淘宝首页商品列表

  3. 图片懒加载(可以配合骨架屏方案)

  4. 图片压缩

    tinyPng

  5. 尽量使用css代替图片。项目初期一些特效可能通过图片实现,后期有时间可以通过代码实现,因为图片的体积肯定会远大于实现代码的体积

如何判断优化效果

本地可以使用lighthouse(chrome浏览器自带的分析器)分析页面渲染情况

远程监控用户白屏时间

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>白屏</title>
  <script type="text/javascript">
    // 不兼容performance.timing 的浏览器,如IE8
    window.pageStartTime = Date.now();
  </script>
  <!-- 页面 CSS 资源 -->
  <link rel="stylesheet" href="common.css">
  <link rel="stylesheet" href="page.css">
  <script type="text/javascript">
    // 白屏时间�结束点
    window.firstPaint = Date.now();
  </script>
</head>
<body>
  <!-- 页面内容 -->
</body>
</html>

兼容Performance API时
白屏时间 = firstPaint - performance.timing.navigationStart
不兼容Performance API时
白屏时间 = firstPaint - pageStartTime

远程监控用户首屏时间

  • 首屏模块标签标记法
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>首屏</title>
  <script type="text/javascript">
    window.pageStartTime = Date.now();
  </script>
  <link rel="stylesheet" href="common.css">
  <link rel="stylesheet" href="page.css">
</head>
<body>
  <!-- 首屏可见元素1 -->
  <div></div>
  <!-- 首屏可见元素2 -->
  <div></div>
  <script type="text/javascript">
    window.firstScreen = Date.now();
  </script>
  <!-- 首屏不可见元素3 -->
  <div></div>
    <!-- 首屏不可见元素4 -->
  <div></div>
</body>
</html>

首屏时间 = firstScreen - performance.timing.navigationStart

  • 统计首屏内图片完成加载的时间

  • 自定义模块内容计算法
    只考虑首屏的主要模块,而不是严格意义首屏线以上的所有内容。这种更简单易行,按第一种方法还需要确定到具体元素,相对复杂

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions