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.
Nous avons introduit les ressources JS comme indiqué ci-dessus, je pense que c'est rarement vu maintenant. 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 supplier.js une fois emballé fait environ 1,2 Mo ( après Après la compression gzip), et echarts n'a pas été utilisé sur la page d'accueil, j'ai donc ensuite utilisé des externes pour introduire 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' },
1. La clé dans les externes est utilisée dans l'importation
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' //日志级别。可以是'信息','警告','错误'或'沉默'。 })
2. La valeur dans externals est appelée sous window
Parlons ensuite de la raison pour laquelle la sortie utilise trunkhash au lieu du cache tronc. 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 finalement les mêmes, de sorte que tous les fichiers ne seront pas mis en cache, le cache perdra donc son sens.
trunkhash:根据每个文件生成不同的hash值,当文件变化时hash会改变且只会改变相应的文件
然后我们肯定是要用到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.
Il y a trois paramètres ici. Le premier est le trunkid de mon fichier actuel. C'est un identifiant unique, qui fait référence au trunkid de main. Le deuxième est la fonction du module de tous les fichiers empaquetés. est la fonction de mon module trunkid qui doit être exécutée immédiatement.
ok, c'est assez d'introduction.
Alors revenons en arrière et voyons pourquoi notre soi-disant commonschunkPlugin a changé. Comme je le disais tout à l'heure, il y a autant de trunkids que de js.
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 n'augmentera pas. être 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, laissez-moi 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. Cependant, l'explication officielle est d'apporter des modifications au CDN en modifiant le fichier de configuration. Si cela est fait, toute ma sortie passera par CDN, puis toutes les requêtes ajax. sera 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 .
Le contenu ci-dessus est un résumé de l'optimisation des performances frontales du didacticiel d'apprentissage du webpack. J'espère qu'il pourra aider tout le monde.
Recommandations associées :
Emballage de code côté serveur Webpack
Présentation en détail d'exemples de traitement CSS de webpack
Explication détaillée du fichier de configuration de webpack
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!