关闭

在前端中如何更好地优化打包资源

时间: 2019-08-27阅读: 429标签: 打包

前端中但凡谈到打包,肯定要提及到 webpack,毕竟它现在已经是最为流行的打包工具。但 webpack 更多地是表现在 术 上,于是我决定写这篇文章,更多地讲解一些关于 道 的。

对于一个前端而言,生产环境的静态资源优化,它既是面试中的高频问题,同时也最容易成为平时工作中的 OKR/KPI。如果你经常致力于优化前端打包提及,必然会对一些数字极为敏感,比如:

  1. lodash 和 react gzip 后的体积是多少 (定性,可以给出范围)
  2. 打包 moment 时会有什么问题
  3. 你们线上前端项目首屏静态资源 gzip 后的体积是多少

如果你负责了你们前端项目的打包优化,如果以上问题连一个都不了解那么是说不通的。以我作为面试官的两年经验中,如果候选人对这些问题有所了解的话,往往对打包以及webpack的了解就会相对深入一些


原则

一般谈到打包会有两方面的意思,第一在于提高打包的速度,第二在于对打包后的静态资源的优化。而对于静态资源的优化又不仅仅是打包提及的缩减。

对于打包资源优化的总体原则,在于尽可能的减少或者延迟模块的引用。主要遵循以下三点

  1. 减小打包的整体体积
  2. Code Splitting: 按需加载,优化页面首次加载体积。如根据路由按需加载,根据是否可见按需加载
  3. Bundle Splitting:分包,根据模块更改频率分层次打包,充分利用缓存

接下来本篇文章将会结合实例分别阐述这三点


01 减小打包的整体体积

第一种方法是减小打包的整体体积。减小打包的总体积有多种方式,这往往也是打包资源优化的着力点,一方面操作性高易于实践,~另一方面有具体数据支撑易于写PPT来晋升~。我从网站性能优化的实践角度,来分为以下几个方面

代码压缩

代码压缩可以非常可观地减小资源打包体积,但是它的可操作性空间过小。可操作性低的意思是这一项不太容易出现在晋级评审的PPT上,如同 CDN 在网站性能优化的重要程度一样,重要但不归你做(或者傻瓜式配置)。

它良好的模块化,以致于 webpack 就自作主张在生产环境中默认把这件事给做了。

那它是如何压缩代码的?最典型的两种方法就是空白符替换以及缩短变量名,如代码所示,仅仅通过这两种方式就大大压缩了 JavaScript 资源:

// 压缩前
function sum (first, second) {
  return first + second;  
}

// 压缩后
function s(x,y){return a+b}

关于代码压缩,可以参考山月的前端高级进阶系列javascript 代码的体积是如何被压缩的

移除不必要的模块

这句话好像是废话,但它却是真正有用并且极为容易实现的一点。

在以下代码中,对 lodash 这个模块进行了引入,但在之后的代码中并无使用 lodash,那在 webpack 中这个模块还会继续打包吗?

很遗憾,仍会对它进行打包。但好消息是这一点优化起来相当简单。

// 仅仅引入而未在代码中使用,该模块仍然会被打包
import _ from 'lodash'

对于这类问题总应该防患于未然,扼杀于摇篮中。eslint 的用武之地来了,它除了统一团队的代码风格以外,也用来提高团队的代码质量以及性能。

选择可替代的体积较小的模块

针对这一条,有一个典型的例子是以体积过大而臭名昭著的 moment.js 模块,它仅仅用于 DateTime 的格式化及各种计算。但你 import 之后它的体积竟然达到了 200kb+,gzip 后仍然有 69kb。以至于在 github 上有一个仓库专门用来介绍如何优化它,How to optimize moment.js with webpack

此时可以选择一个可替代它功能,但体积更小的模块。与 moment.js API 兼容的 day.js,它 gzip 后体积仅仅只有 2kb。

按需引入模块

当你面对一个巨无霸的,捆绑式的大型模块时,可能你并不会使用到它的所有的功能,你只需要按照你的需求引入模块就可以了。那经常会有哪些巨无霸模块呢?

如 lodash (勉强算),antd,echarts,我相信这三个模块对于以 react 为主的前端工程师都或多或少使用过。对你所需要使用的模块单独引入:

import DatePicker from 'antd/es/date-picker'; // for js
import 'antd/es/date-picker/style/css'; // for css

import get from 'lodash.get'


02 Code Splitting: 按需加载,优化页面首次加载体积

懒加载,如果面试中提到懒加载的话,大概率面试官此时是想问你关于图片懒加载的问题。

前端开发中的图片懒加载如何实现

通过 Code Splitting 可以只加载当前所需要的核心资源:

  1. 如果你处在首页,并且首页中有占用资源过重的图表,需要对图表懒加载,否则它会大幅拖垮应用的首次渲染,加大白屏时间
  2. 如果你处在首页,你无需加载当前不可见屏幕下方的复杂组件
  3. 如果你处在页面 A,你没有必要加载页面 B 的资源

他们实现起来均需要额外编写代码,所以可操作性中等,但是好在它能够带来极大的益处,投资回报率较高,操作起来也极为简单,接下来就属于体力活了:

  • 使用 import() 动态加载模块
  • 使用 React.lazy() 动态加载组件
  • 使用 lodable-component 动态加载路由,组件或者模块

大部分情况下,你只要做一个莫得感情的 API 工程师调用以上三个 API 就可以解决问题,大幅度降低页面的首次加载体积。但是在前往高级前端工程师的路上,你有可能需要了解其中的原理,(有可能并不需要,数据比原理重要) 来做更加精细化的控制,比如针对缓存。

Code Splitting 的原理是什么?


03 Bundle Splitting

除了资源体积上的优化,另一个大的优化就是缓存。单页应用有一个最好的方面,就是所有资源都是带有指纹信息的,这意味着所有的资源都是能够设置永久缓存的。

但仅仅如此了吗?

如果你所有的 js 资源都打包成一个文件,它确实有永久缓存的优势。但是当有一行文件进行修改时,这一个大包的指纹信息发生改变,永久缓存失效。

所以我们现在需要做到的是:当修改文件后,造成最小范围的缓存失效,这样便能够更充分的利用缓存,减小宽带,减小服务器费用。一个好消息是 webpack 等打包工具虽然在 optimization 上内置了很多性能优化,但它不会帮你做这件事,它并不知道你有哪些模块,以及这些模块的重要紧急程度,你终于可以大展拳脚了。

此时我们可以对资源进行分层次缓存的打包方案,这是一个建议方案

  1. webpack-runtime: 应用中的 webpack 的版本比较稳定,分离出来,保证长久的永久缓存
  2. react-runtime: react 的版本更新频次也较低
  3. vundor: 常用的第三方模块打包在一起,如 lodash,classnames 基本上每个页面都会引用到,但是它们的更新频率会更高一些

随着 http2 的发展,特别是多路复用,初始页面的静态资源不受资源数量的影响。因此为了更好的缓存效果以及按需加载,也有很多方案建议把所有的第三方模块进行单模块打包。

在 webpack 中,使用 splitChunks.cacheGroups

{
  splitChunks: {
    cacheGroups: {
      react: {
        test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
        name: 'react',
        chunks: 'all'
      },
      vendor: {

      }
    }
  },
  runtimeChunk: {
    name: entrypoint => `runtime-${entrypoint.name}`,
  },
}


小结

毫无疑问在前端中更好地优化打包资源属于网站性能优化强操作性部分的重中之重,整理下本篇文章关于资源优化的所有内

  1. 减小打包的整体体积

    • 代码压缩
    • 移除不必要的模块
    • 按需引入模块
    • 选择可以替代的体积较小的模块
  2. Code Splitting: 按需加载,优化页面首次加载体积。如根据路由按需加载,根据是否可见按需加载

    1. 使用 import() 动态加载模块
    2. 使用 React.lazy() 动态加载组件
    3. 使用 lodable-component 动态加载路由,组件或者模块
  3. Bundle Splitting:分包,根据模块更改频率分层次打包,充分利用缓存
原文:https://segmentfault.com/a/1190000021831705


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/7780

关闭

Webpack 打包太慢? 试试 Dllplugin

webpack在build包的时候,有时候会遇到打包时间很长的问题,这里提供了一个解决方案,让打包如丝般顺滑~在用 Webpack 打包的时候,对于一些不经常更新的第三方库

解决webpack打包速度慢的解决办法

webpack在打包的时候第一次总是会做很长的准备工作,包括加载插件之类的。在刚接触webpack的时候总是webpack一下-测一下-改一下-再webpack一下,这种方式最后让很多人崩溃了觉得webpack一点都不好用

webpack4 打包静态资源

准备一个空文件夹,然后执行下列命令:然后创建一个 dist 目录,并在里面创建一个 indedx.html:接着创建一个 src 目录,在里面创建一个 lib 文件夹,创建一个 until.js:再创建 components 文件夹,再写入几个 js:

vue-cli3.0中自定css、js和图片的打包路径

我们有时候因为一些特殊需求,可能需要将js/css/img等资源文件都打包到根路径下,但vue-cli3.0的路径配置中仅有assetsDir配置项能够配置所有的静态文件所在的文件夹,并不能针对css/js/img等资源文件分别来做设置,那么请看我如何尝试的吧!

Webpack 打包含动态加载的类库

在编写库的时候,我们有时候会希望按需加载某些依赖,例如如果代码的运行环境不支持某些功能的话,就加载相关的Polyfill。webpack作为当前最流行的打包工具,早已支持动态加载的功能了。本文将讨论一种用webpack打包含动态加载的类库的方法。

webpack如何编译ES6打包

随着ES的普及我们越来越多的开始使用ES6的语法了,当然也随着mvvm框架的流行少不了js模块化,那js模块化又有那些呢?在很早的时候大家都用的命名空间,现在也有人用(库名.类别名.方法名)

webpack打包时删除console.log,和debugger

开发过程中我们不可避免的需要console.log调试,然而在上线时如果不删除这些console.log可能会造成内存泄漏,因为console.log出来的变量是不会被GC的,webpack给我们提供了一个非常棒的插件,看代码:

vue实现分环境打包步骤

在新建好的项目中,一般执行npm run build就是打包了,但此时只能打包到一个环境,不同环境需要配置不同的地址,可以手动更改接口的地址,也可以自行配置命令而不需要每次打包进行地址切换

解决webpack引入moment包过大的问题

在vue工程中,在引入moment时,发现build之后的包比不引入moment的包文件大了整整两百多kb,后来发现webpack会把moment的语言包也一起打包

webpack打包优化的四种方法(多进程打包,多进程压缩,资源 CDN,动态 polyfill)

如今,webpack 毫无疑问是前端构建领域里最耀眼的一颗星,无论你前端走哪条路线,都需要有很强的webpack 知识。webpack 的基本用法这里就不展开讲了。主要探讨一下如何提高 webpack 的打包速度。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!