Maison >interface Web >js tutoriel >À propos de l'optimisation des performances frontales du webpack (tutoriel détaillé)

À propos de l'optimisation des performances frontales du webpack (tutoriel détaillé)

亚连
亚连original
2018-06-22 17:08:132251parcourir

Webpack est le chargeur de modules et l'outil d'empaquetage le plus populaire récemment. Il peut utiliser diverses ressources, telles que JS (y compris JSX), le café, les styles (y compris less/sass), les images, etc. Cet article résume et présente principalement des informations pertinentes sur l'optimisation des performances frontales du didacticiel d'apprentissage du webpack. Les amis dans le besoin peuvent s'y référer.

Avant-propos

Il était une fois, nous avons introduit les ressources JS comme indiqué ci-dessus, je le crois. est très populaire maintenant. On le voit moins souvent. Ces dernières années, le domaine du développement Web front-end a évolué vers un développement standardisé. Cela se reflète dans les deux points suivants :

1. Architecture R&D MVC. De nombreux avantages (logique claire, le programme se concentre sur la séparation des données et des performances, forte lisibilité, ce qui est utile pour éviter et résoudre les problèmes...)

2. Il existe une infinité d'outils de construction. De nombreux avantages (amélioration de la collaboration en équipe, de l'exploitation et de la maintenance de l'ingénierie, et évitement du traitement manuel de travaux triviaux et répétitifs)

  • Développement modulaire

  • Intégrer le front-end Implémentation de la théorie de l'optimisation des performances, de la compression de code, de la fusion, du contrôle du cache, de l'extraction du code public, etc.

  • D'autres incluent, par exemple, vous pouvez utiliser ES 6 ou CoffeeScript pour écrire le code source, puis créer le support du navigateur ES5

Donc, le front-end est tellement amusant, s'il y a encore des projets sans séparation front-end et back-end, c'est vraiment trop conservateur.

Outils de build grand public

Il existe de nombreux outils de build sur le marché, notamment Grunt, Gulp, Browserify, etc. Ceux-ci et WebPack sont tous des outils de packaging. Mais WebPack présente également les caractéristiques suivantes :

Par rapport à Grunt, WebPack possède non seulement un riche ensemble de plug-ins, mais dispose également d'un système de chargement (Loader). Faites-lui prendre en charge plusieurs méthodes de chargement standard, notamment ES6, CommonJS, AMD, etc., que Grunt et Gulp n'ont pas.

Du point de vue de l'obscurcissement du code, WebPack est encore plus extrême

Le code est fragmenté en unités de traitement (au lieu de fichiers), ce qui rend la fragmentation des fichiers plus flexible.

P.S. Ceci est juste une simple comparaison, peu importe laquelle est meilleure ou pire. En fait, les outils peuvent répondre aux besoins. La clé est de savoir comment les utiliser. Derrière l'utilisation des outils se cache la compréhension de l'optimisation des performances frontales.

Introduction

Récemment, j'utilise webpack pour optimiser les performances de chargement du premier écran. Après avoir utilisé plusieurs plug-ins, notre vitesse avant et. après la mise en ligne a doublé. Permettez-moi simplement de le partager ici, d'abord une image comparative du rendu du premier écran avant et après l'optimisation.

Vous pouvez voir que le temps total de téléchargement est réduit de 3800 ms à 1600 ms.

Lorsque nous utilisons webpack, nous choisissons généralement plusieurs fichiers d'entrée afin de séparer notre propre code source du code de la bibliothèque tierce. Il s'agit du code précédent.

entry: {
 entry: './src/main.js',
 vendor: ['vue', 'vue-router', 'vuex', 'element-ui','echarts']
},
output: {
 path: config.build.assetsRoot,
 filename: utils.assetsPath('js/[name].[chunkhash].js'),
 chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
}

echarts est très volumineux, donc le package supplier.js fait environ 1,2 Mo (après compression gzip), et echarts n'est pas utilisé sur la page d'accueil, j'ai donc utilisé des externes plus tard. . Présentez la bibliothèque tierce via cdn. Voici le code optimisé

entry: {
 entry: './src/main.js',
 vendor: ['vue', 'vue-router', 'vuex', 'element-ui']
 },
 // 这里的output为base中的output,不是生产的output
 output: {
 path: config.build.assetsRoot,
 filename: '[name].js',
 libraryTarget: "umd",
 publicPath: process.env.NODE_ENV === 'production' ?
  config.build.assetsPublicPath : config.dev.assetsPublicPath
 },
 externals: {
 echarts: 'echarts',
 _: 'lodash'
 },

Voici la comparaison avant et après. optimisation.

Ensuite il faut aller dans le html pour citer le cdn en externals sous la forme d'une balise script. Après cela, vous pouvez l'importer dans le fichier correspondant. Son avantage est que peu importe le nombre de fois que vous le référencez dans de nombreux fichiers vue, il ne sera pas empaqueté dans tous les troncs (tronc' fait ici référence au chargement à la demande, qui sera détaillé plus loin. Description), c'est l'effet montré à l'aide du plug-in webpack-bundle-analyzer.

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
new BundleAnalyzerPlugin({
  // 可以是`server`,`static`或`disabled`。
  // 在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。
  // 在“静态”模式下,会生成带有报告的单个HTML文件。
  // 在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
  analyzerMode: 'server',
  // 将在“服务器”模式下使用的主机启动HTTP服务器。
  analyzerHost: '127.0.0.1',
  // 将在“服务器”模式下使用的端口启动HTTP服务器。
  analyzerPort: 8888, 
  // 路径捆绑,将在`static`模式下生成的报告文件。
  // 相对于捆绑输出目录。
  reportFilename: 'report.html',
  // 模块大小默认显示在报告中。
  // 应该是`stat`,`parsed`或者`gzip`中的一个。
  // 有关更多信息,请参见“定义”一节。
  defaultSizes: 'parsed',
  // 在默认浏览器中自动打开报告
  openAnalyzer: true,
  // 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
  generateStatsFile: false, 
  // 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
  // 相对于捆绑输出目录。
  statsFilename: 'stats.json',
  // stats.toJson()方法的选项。
  // 例如,您可以使用`source:false`选项排除统计文件中模块的来源。
  // 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
  statsOptions: null,
  logLevel: 'info' //日志级别。可以是'信息','警告','错误'或'沉默'。
 })

Nous verrons qu'il n'y aura pas d'echarts similaires dans tous les js sans externes et après avoir utilisé des externes et le lodash. La bibliothèque apparaît (même si vous l'importez 10 000 fois, elle ne la conditionnera pas une seule fois, c'est incroyable ~~).

Deux autres points sur les externes -

1. La clé dans les externes est utilisée dans l'importation

import lodash from "_";
import echarts from "echarts";

2. La valeur dans les externes est appelée sous la fenêtre

.

Parlons ensuite de la raison pour laquelle la sortie utilise trunkhash au lieu de trunk. Ceci est pour la mise en cache persistante. Parlons brièvement de la différence entre les deux -

trunk : La version après chaque build signifie que les valeurs de hachage de tous les fichiers après la build sont les mêmes. Par exemple, si je ne modifie qu'un seul fichier. , tous les hachages de fichiers seront les mêmes à la fin, de sorte que tous les fichiers n'iront pas dans le cache, le cache perdra donc son sens.

trunkhash : génère différentes valeurs de hachage en fonction de chaque fichier. Lorsque le fichier change, le hachage changera et seul le fichier correspondant sera modifié

.

然后我们肯定是要用到CommonsChunkPlugin,这个插件是用来抽取公共代码的,基本上99%的配置都是长这样子或者类似这样子用两个不同的commonschunkPlugin,但这从某方面来说并没有实现真正意义上的持久化缓存,这个一会我会通过webpack打包原理来详细解释其中的原因。。。。。。

new webpack.optimize.CommonsChunkPlugin({
 names: ['vendor','manifest']
})

在没用这个插件之前,我们的main.js和vendor.js会是这样子。。。

大家会看到我们这两个文件会有公共的部分,比如vue和element-ui,所以我们要抽取公共代码到vendor中,所以我们可以先这样配置

new webpack.optimize.CommonsChunkPlugin({
 name: 'vendor',
}),

但这样的话虽然可以提取公共代码,但我们会把runtime(webpack运行时的代码,一会在打包原理中会再次提到)也放到vendor中,这里面会维护一个trunk的文件列表,类似于这样,就是说我们改任意的代码,这个table里面的hash会变,所以vendor的hash也会变

,所以这没有实现真正的持久化缓存。这个hash table是按需缓存的打包出来的trunk包,一般都是通过require.ensure(就是vue-router中配置的page对应页面,按需加载)

所以我们就把name改为names,就是上面那个配置。因为使用这个插件,我们会把公共代码抽到第一个name中,把runtime放到最后一个name中,也就是我们所谓的“manifest”文件。

并且这个文件会比较小,通常都是2kb左右,所以build后会生成一个script标签,但这样的话就多了一个http请求,所以我们可以用另外一个插件(InlineManifestWebpackPlugin)将manifest.js内联进去。就会长这样子

再回到我们的CommonsChunkPlugin,现在我们随便改任何已存在的文件,vendor.js的hash都不会变,是的,貌似这就实现了持久化缓存。但是当我们新增一个模块,并且在入口文件中import一下,我们的vendor就会跟main一起变。很奇怪对吧,我们明明已经做了自己的源码跟第三方库分离,为什么vendor还会变(到现在应该没有任何一篇博客对此进行详细的说明)。下面我就详细的给大家解释下我的看法,如果大家发现有不对的地方还请指正。

再解释为什么之前,我们先简单了解下webpack的打包规则。

webpack一个entry对应一个bundle,这个bundle包括入口文件和其依赖的模块。其他按需加载的则打包成其他的bundle。还有一个比较重要的文件时manifest,它是最先加载的,负责打包其他的bundle并按需加载和执行。

manifest是一个自执行函数,熟悉angular的同学看第一行应该很了解,因为anguar1.3版本的源码中启动就是angular.bootstrap,对,这里也是一样。里面的modules变量就是对应模块函数,它是webpack处理的基本单位,就是说对应打包前的一个文件

这是js源文件,

这是打包后的文件,

所有的模块函数索引都是连续的(每个js文件生成一个trunkid!!!!!),像这种 /* 4 */ 对应的就是js文件,他通过打包就变成了一个个trunkid,仔细看会看到咱们打包前js文件里的export和require依赖都会统一转换成webpack模块。咱们说的webpackJsonp就是除manifest之外打包其他的文件的函数体。

简单说下main吧,这个图的trunkid是连续的,为了在一张图上显示,我截掉了trunk3-7.

这里面一共有三个参数,第一个是我当前文件的trunkid,它是唯一标识符,就是指main的trunkid,第二个就是打包的所有文件的模块函数,第三个是我要立即执行的trunkid模块函数。

ok,介绍这些就足够了。

然后我们再回过头来看看为什么我们所谓的commonschunkPlugin会变。刚才说过,有几个js就有几个trunkid。

Ainsi, lorsque nous ajoutons un nouveau js et l'introduisons dans l'entrée principale, webpack le conditionne à nouveau, et mon fichier principal aura une fonction de module supplémentaire. Comme je viens de le dire, le trunkid augmente en séquence et ne sera pas répété. Par conséquent, l'ID du fournisseur correspondant sera +1. C'est un changement si subtil qui entraîne une modification du hachage.

Regardez bien, ces deux fournisseurs ont tous deux 10272 lignes. La seule différence est que je veux. pour auto-exécuter cette bibliothèque de fournisseur. J'ai cité jquery ici, donc ce fichier n'a que jquery. L'auto-exécution doit avoir des fonctions de module, trunkid+1, donc le hachage changera. Rappelons-le attentivement. En fait, cela illustre également l'importance de ce plug-in. Je veux juste extraire la bibliothèque publique. OK, ce plug-in le fait, mais à cause du mécanisme de packaging du webpack, différents fichiers génèrent des turnkids différents. , c'est donc une mouche dans la pommade. Rappelons que nous ne modifions généralement pas main.js avec désinvolture, donc d'un autre point de vue, il s'agit de la mise en œuvre d'une mise en cache persistante. Mais que se passe-t-il si je souhaite simplement conserver le hachage du fournisseur inchangé ?

Ce code peut être implémenté Oui, si vous connaissez bien vue-cli, c'est la démo officielle de vue-cli. Quant à savoir pourquoi c'est possible, je le ferai. discutez-en plus tard Expliquez à tout le monde (je ne peux vraiment plus écrire...).

Enfin, j'aimerais vous présenter une chose super utile, qui est le CDN. Notre demande actuelle est de laisser les images aller sur CDN et js pour être mises en ligne, mais l'explication officielle est d'apporter des modifications au CDN en modifiant le fichier de configuration. Si vous faites cela, toutes mes sorties seront envoyées au CDN et toutes les requêtes ajax le seront. inter-domaines.

Ma solution au début était de remplacer les fichiers sources un par un, ce qui serait plus lent. Plus important encore, l'image cdn a également une valeur de hachage When I When. vous remplacez l'image à l'avenir, vous devrez à nouveau modifier le hachage correspondant. Existe-t-il un moyen de lui permettre d'obtenir automatiquement le hachage ?

Oui, nous devons configurer le cdn séparément dans le chargeur d'url afin que js puisse accéder au chemin en ligne et que les ressources statiques utilisent le cdn. Les deux ne s'affectent pas.

Un bref rappel, url-loader ne peut pas détecter l'arrière-plan dans js, donc toute adresse que nous référençons dans js doit d'abord importer cette image, url -loader l'analysera et l'emballera .

Ce qui précède est ce que j'ai compilé pour vous. J'espère que cela vous sera utile à l'avenir.

Articles connexes :

Comment utiliser le composant vidéo pour lire des vidéos dans le mini programme WeChat

Comment utiliser le composant audio dans le mini programme WeChat

Comment implémenter l'encapsulation secondaire axios dans vue

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn