zoukankan      html  css  js  c++  java
  • 用 Webpack 解决应用性能问题

    1. 影响页面加载时长的 Top3 因素

    1. 页面初载时,加载大量 JavaScript 脚本;
    2. 页面初载时,加载大量 CSS 文件;
    3. 页面初载时,加载大量网络资源;

    页面加载的越久,页面不可交互的时间就越长,用户的体验就越差。


    2. 页面优化的目标

    1. 页面初载时,未压缩的 JavaScript 脚本大小: <=200KB ;
    2. 页面初载时,未压缩的 CSS 资源大小: <=100KB ;
    3. HTTP 协议下,请求资源数: <=6 个 ;
    4. HTTP/2 协议下,请求资源数: <=20 个 ;
    5. 90% 的代码覆盖率(仅允许 10% 的未使用代码);

    只有 Chrome 能够查看你的代码覆盖率。

    遵从这个目标,应用将能在任何平台(PC,Mobile Phone...)都拥有良好的性能:

    1. 未来的网络世界在移动端;
    2. 平均每个移动端网站需要花费 14 秒时间达到可交互状态;
    3. 加载的代码越少,页面达到可交互的时间越短;

    3. 查看代码覆盖率

    1. 打开 Chrome Dev Tool;
    2. 按下 Cmd + Shift + P or Ctrl + Shift + P ;
    3. 输入 Coverage ,选择第一个出现的选项:

    Xnip2019-06-18_10-48-49.jpg

    1. 点击面板上的 reload 按钮,查看整个应用 JavaScript 的代码覆盖率:

    Xnip2019-06-18_10-50-46.jpg


    4. 如何做到?

    (1)代码分割(code splitting)

    什么是 code splitting?
    将部分代码在构建时转变为异步加载的过程。

    (1.1)代码分割原理

    代码分割的核心是异步加载资源,而异步加载功能使用到 stage 3 规范:whatwg/loader。
    import() 允许你在浏览器端运行时动态获取资源,虽然它存在以下一些问题:

    1. 安全问题;
    2. 浏览器支持问题;

    (1.2)代码分割的两种类型

    1. 静态的;
    2. “动态的”(在 webpack 中,并不是真的动态):“动态”是指你能够在代码运行时决定应该引入什么 JavaScript 模块;

    (1.3)静态代码分割

    何时使用静态的代码分割?
    1. **你正在使用一个非常大的库或框架 **:如果在页面初始化时你不需要使用它,就不要在页面初载时加载它;
    2. **任何临时的资源 **:指不在页面初始化时被使用,被使用后又会立即被销毁的资源,例如模态框,对话框,tooltip等(任何一开始不显示在页面上的东西都可以有条件的加载);
    3. 路由 :既然用户不会一下子看到所有页面,那么只把当前页面相关资源给用户就是个明智的做法;

    代码示例
    import Listener from './listeners.js'
    
    const getModal = () => import('./src/modal.js')
    
    Listener.on('didSomethingToWarrentModalBeingLoaded', () => {
    	// Async fetching modal code from a separate chunk
      getModal().then((module) => {
      	const modalTarget = document.getElementById('Modal')
        module.initModal(modalTarget)
      })
    })
    

    注意:

    1. 在 Vue 中,可以直接使用 import() 关键字,在 React 中,使用 react-loadable 完成同样的事;
    2. 每当你使用动态代码分割时,函数将返回一个 Promise 对象;

    (1.4)“动态”代码分割

    何时使用“动态”代码分割?
    1. **A/B Test **:你不需要在代码中引入不需要的 UI 代码;
    2. **主题 **:动态加载相应的主题;
    3. 为了方便 :本质上,你可以用静态代码分割代替“动态”代码分割,但是后者比前者拥有更少的代码量;

    代码示例
    const getTheme = (themeName) => import(`./src/themes/${themeName}`)
    
    // using `import()` 'dynamically'
    if (window.feeling.stylish) {
    	getTheme('stylish').then((module) => {
      	module.applyTheme()
      })
    } else if (window.feeling.trendy) {
    	getTheme('trendy').then((module) => {
      	module.applyTheme()
      })
    }
    

    这背后的原理是,webpack 将目录中所有可以分离的 JavaScript 文件都生成了被称为 contextModule 的模块,所以本质上仍然是静态的。

    (2)魔术注释

    魔术注释技术是为代码分割技术服务的,它表现为在 import 关键字前使用指定注释来控制 webpack 生成的分割后代码片段。

    代码示例
    import (
    	/* webpackChunkName: "my-chunk-name" */
      './footer'
    )
    

    同时,你需要在 webapck.config.js 中添加配置:

    {
    	output: {
      	filename: "bundle.js",
        chunkFilename: "[name].lazy-chunk.js"
      }
    }
    

    (2.1)webpack Modes

    webpack 提供了一些注释让我们能够选择异步加载的模块应该被怎样组织:

    import (
    	/* webpackChunkName: "my-chunk-name" */
      /* webpackMode: lazy */
      './someModule'
    )
    

    webpackMode 的默认值为 lazy ,指所有异步模块都会被单独抽离成单一的 chunk,通过使用 lazy-once 值,可以将所有的异步加载模块放在同一个 chunk 中。

    (2.2)Prefetch & Preload

    通过开启 prefetch ,我们可以通过使用 <link rel="prefetch>" 的特性,让浏览器在空闲时帮我们预先加载我们的异步资源,这有助于提升应用性能。

    import(
    	/* webpackPrefetch: true */
      './someModule'
    )
    

    注意 :当你确保你的异步代码在未来一定会用到时,再开启该功能。


    5. 参考链接

  • 相关阅读:
    UVa 12174 (滑动窗口) Shuffle
    UVa 1607 (二分) Gates
    CodeForces ZeptoLab Code Rush 2015
    HDU 1525 (博弈) Euclid's Game
    HDU 2147 (博弈) kiki's game
    UVa 11093 Just Finish it up
    UVa 10954 (Huffman 优先队列) Add All
    CodeForces Round #298 Div.2
    UVa 12627 (递归 计数 找规律) Erratic Expansion
    UVa 714 (二分) Copying Books
  • 原文地址:https://www.cnblogs.com/libinfs/p/11045384.html
Copyright © 2011-2022 走看看