俗话说得好,引用依赖一时爽,一直引用一直爽。javascript
在开发项目的过程当中,咱们每每须要引用到大量的第三方模块(node modules)。确实,经过引用第三方模块,能大大的简化开发的过程,提升工程质量。但不免的,也带来了“体积”这个问题。笔者曾经开发过一个简单的网站项目,功能简单,业务逻辑也只是纯粹的查看信息。但在通过了混淆压缩后,依然达到了1M多。是的,这个项目毫无疑问是不及格的。由于即使在现今随随便便百兆网络的时代下,因为服务器、通路等多重因素的影响下,整个项目的加载每每须要数秒钟。在网络上有人是这么描述这几秒钟的:css
若是网页加载时间超过4秒,约有四分之一的人会放弃打开该网页。
若是网页加载时间超过10秒,50%的移动用户会放弃该网页,约五分之三的人不会再返回该网站。html
因此,咱们在可容许的范围内,除了在物理层面上加强咱们的访问速度外,还应该从项目的根源入手,尽量的减小访问须要的时间。
在本文中,笔者总结了以前项目中一些精简项目的方法,但愿能对各位看官有所帮助。vue
通常状况下,webpack是vue项目的不二之选。那么,如何分析使用webpack打包后的包文件呢?在这里就要介绍本文的核心主角包分析工具——webpack-bundle-analyzer
。 java
众所周知的,webpack是一个将网页元素打包的工具。在一个JS文件中,不只包含了javascript的代码,还包含了如“html”、“css”等等元素。若是纯粹的经过直接分析包中的内容,或者经过分析webpack配置(甚至在Vue Cli 三、Angular Cli 3,根本就不存在webpack配置文件),是很是不现实的事情。而webpack-bundle-analyzer
则能够为咱们提供图形化的包分析。 node
在webpack-bundle-analyzer中,咱们能够看到各个模块所占项目的比例,以及模块在Stat
、Parsed
、Gzipped
状态下的大小。嗯,是的,这样咱们就能找出使项目臃肿的元凶了!webpack
--report
便可生成分析报告。webpack-bundle-analyzer
# NPM npm install --save-dev webpack-bundle-analyzer # Yarn yarn add -D webpack-bundle-analyzer 复制代码
而后,添加到项目的配置文件中:git
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { plugins: [ new BundleAnalyzerPlugin() ] } 复制代码
编译完毕后,即会生成分析报告。github
--stats-json
将会生成一个json文件。既然咱们如今已经知道了“元凶”是谁了,那咱们如今应该去处理它了。对于,不一样的第三方模块咱们有不一样的方法去解决它:web
通常最经常使用的import形式是这样的:
import crypto from 'crypto-js' ... crypto.HmacSHA1() ... 复制代码
这种方法将会引入整个crypto(第三方模块)。然而,咱们每每仅须要其中的一两个方法。这是一个很是不划算的行为,同时也是项目中最多见的臃肿的缘由。经过局部引入须要的方法,咱们即可以很大程度的减小项目的臃肿程度:
import HmacSHA1 from 'crypto-js/hmac-sha1' ... HmacSHA1() ... 复制代码
至于如何找到局部引入的文件,由于不一样模块的项目结构不尽一致,因此没有一个标准的答案。不过,最多见的方法,就是查看第三方模块的入口文件或者查阅官方的文档,每每能够找到最小化引入的方法。
影响首屏加载速度的,是那些随着html文件“同步”下载的js文件。有很多第三方模块是不会在首屏加载时用到的,并且他们没法经过“最小化引入”有效减小它们的大小。此时,便应该考虑将一些无需随着首屏加载的内容,经过异步的形式,在它们须要的时候加载。
熟悉Vue的各位大佬们大概都早已熟知Vue异步组件的写法
... components: { asyncComponent: () => import('./asyncComponent.vue') // function(){ // return import('./asyncComponent.vue') // } } ... 复制代码
但对于新手而言,他们可能会误认为这是Vue中提供的异步组件加载的方式。但实际上,这是webpack进行异步模块加载的方法。import能够运用在各个方面,如:加载Echarts
const Echarts = () => import('echarts') ... Echarts().then(echarts => { echarts.xxx() }) ... 复制代码
此方法也能够在Angular 8中使用
不少流行的UI库是没法直接按需引入须要的组件的(其实不少都是能够的,但小部分组件会出现问题)。如:Element、ant-design-vue、iView 、Mint UI等等。但他们每每很是的“庞大”,多数可达2~3M。对于网页应用而言,这确定是没法接受的。不过万幸的是,它们均可以经过babel-plugin-component
进行按需引入(或者直接按需引入)。具体的方法能够参阅它们各自的官方文档。须要注意的是,因为css文件是全局引入的,须要注意样式被污染的问题。
对于一些特殊的模块而言,他们可能没法使用“按需引入”的方法进行瘦身。就好比“moment.js”,在引入其本体的同时,它会附带所有的多语言支持的模块。但这些每每是咱们不须要的。
ContextReplacementPlugin 能够经过正则表达式或其余过滤条件忽略引入的第三方模块的某些文件,从而达到瘦身的需求。
在webpack的官方文档中,正是以moment.js做为实例的。
new webpack.ContextReplacementPlugin( /moment[\/\\]locale$/, /de|fr|hu/ ) 复制代码
在全部的方法都没法知足功能需求>文件体积的时候,为什么不尝试换一个模块试试呢?
在npm中充斥着大量的功能类似的module,好比:querystring,我所知的就有qs\query-string\querystringify...它们大多功能类似,但因为实现的方法、考量的形式不一样等等方面,致使了它们之间存在很多的差别。所以,为了减小没必要要的文件体积,咱们能够尝试选择与之类似的或者功能没有如此强大的但刚好符合咱们需求的模块。就如“moment.js”在多数的状况下,能够被“dayjs”所替代。然后者则宣称它只占用2kb的空间。
固然,在选择第三方模块的时候,也须要考量这个模块是否足够的成熟。
第三方模块能帮助咱们解决不少问题。但并非全部的“复杂”功能都须要经过引入第三方模块来解决。
举个简单的栗子:
若是你只须要获取URL中的参数,你不须要引入Vue Router或者XXX Router。你只须要qs.parse(location.search)便可.甚至连qs库都无需引入:
Object.fromEntries( location.search .slice(1) .split('&') .map(v => v.split('=')) ) 复制代码