Maison > interface Web > js tutoriel > Code d'optimisation de l'empaquetage Vue spliting_vue.js

Code d'optimisation de l'empaquetage Vue spliting_vue.js

不言
Libérer: 2018-04-10 14:45:43
original
1337 Les gens l'ont consulté

Cet article présente principalement l'explication détaillée du fractionnement de code pour l'optimisation du packaging Vue. Maintenant, je le partage avec vous. Les amis dans le besoin peuvent s'y référer

À l'ère de http1, une optimisation des performances courante consiste à. fusionner http. En ce qui concerne le nombre de requêtes, nous fusionnons généralement de nombreux codes js ensemble, mais si la taille d'un package js est particulièrement grande, c'est un peu excessif pour l'amélioration des performances. Et si nous divisons raisonnablement tout le code, décollons le code du premier écran et celui qui ne figure pas sur le premier écran, divisons le code métier et le code de la bibliothèque de base, puis chargeons un certain morceau de code lorsque cela est nécessaire, la prochaine fois si vous Si vous devez l'utiliser à nouveau, lisez-le à partir du cache. Premièrement, vous pouvez mieux utiliser le cache du navigateur. Deuxièmement, cela peut améliorer la vitesse de chargement du premier écran, ce qui améliore considérablement l'expérience utilisateur.

Idée de base

Séparation du code métier et de la bibliothèque de base

Ceci est en fait facile à comprendre. Le code métier est généralement mis à jour et itéré fréquemment, tandis que. bibliothèques de base Les mises à jour sont généralement lentes. Si vous les divisez ici, vous pouvez utiliser pleinement le cache du navigateur pour charger le code de la bibliothèque de base.

Chargement asynchrone à la demande

Cela résout principalement le problème de la taille de la demande du premier écran. Lors de l'accès au premier écran, il suffit de charger la logique requise pour le. premier écran, et non le code qui charge tous les itinéraires.

Combat pratique

Récemment, j'ai utilisé vuetify pour transformer un système interne Au début, j'ai utilisé la configuration webpack la plus couramment utilisée Les fonctions ont été rapidement développées, mais une fois que je l'ai emballé, j'ai trouvé que l'effet n'est pas très évident. Il existe de nombreux gros packages

Nous regardons ici la distribution des emballages. est utilisé ici. Vous pouvez clairement voir vue et vuetify Il existe des cas où les modules sont empaquetés à plusieurs reprises.

Ici, nous publierons d'abord la configuration et l'utiliserons pour l'analyse plus tard :

const path = require('path')
const webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const generateHtml = new HtmlWebpackPlugin({
 title: '逍遥系统',
 template: './src/index.html',
 minify: {
 removeComments: true
 }
})

module.exports = {
 entry: {
 vendor: ['vue', 'vue-router', 'vuetify'],
 app: './src/main.js'
 },
 output: {
 path: path.resolve(__dirname, './dist'),
 filename: '[name].[hash].js',
 chunkFilename:'[id].[name].[chunkhash].js'
 },
 resolve: {
 extensions: ['.js', '.vue'],
 alias: {
  'vue$': 'vue/dist/vue.esm.js',
  'public': path.resolve(__dirname, './public')
 }
 },
 module: {
 rules: [
  {
  test: /\.vue$/,
  loader: 'vue-loader',
  options: {
   loaders: {
   }
   // other vue-loader options go here
  }
  },
  {
  test: /\.js$/,
  loader: 'babel-loader',
  exclude: /node_modules/
  },
  {
  test: /\.(png|jpg|gif|svg)$/,
  loader: 'file-loader',
  options: {
   objectAssign: 'Object.assign'
  }
  },
  {
  test: /\.css$/,
  loader: ['style-loader', 'css-loader']
  },
  {
  test: /\.styl$/,
  loader: ['style-loader', 'css-loader', 'stylus-loader']
  }
 ]
 },
 devServer: {
 historyApiFallback: true,
 noInfo: true
 },
 performance: {
 hints: false
 },
 devtool: '#eval-source-map',
 plugins: [
  new BundleAnalyzerPlugin(),
  new CleanWebpackPlugin(['dist']),
  generateHtml,
  new webpack.optimize.CommonsChunkPlugin({
  name: 'ventor'
  }),
 ]
}

if (process.env.NODE_ENV === 'production') {
 module.exports.devtool = '#source-map'
 // http://vue-loader.vuejs.org/en/workflow/production.html
 module.exports.plugins = (module.exports.plugins || []).concat([
 new webpack.DefinePlugin({
  'process.env': {
  NODE_ENV: '"production"'
  }
 }),
 new webpack.optimize.UglifyJsPlugin({
  sourceMap: true,
  compress: {
  warnings: false
  }
 }),
 new webpack.LoaderOptionsPlugin({
  minimize: true
 })
 ])
}
Copier après la connexion

CommonChunkPlugin

entrée ventor Ici, nous avons constaté que tous les modules référencés sous node_module, tels que axios, n'étaient pas filtrés, ils ont donc été regroupés dans app.js. Ici, nous effectuons la séparation<🎜. >

entry: {
 vendor: [&#39;vue&#39;, &#39;vue-router&#39;, &#39;vuetify&#39;, &#39;axios&#39;],
 app: &#39;./src/main.js&#39;
 },
Copier après la connexion

Ensuite, il y a un autre problème ici. Il m'est impossible d'entrer dans le module manuellement. À ce moment-là, nous devrons peut-être séparer automatiquement le vent. Ici, nous devons introduire minChunks. Dans la configuration, nous pouvons empaqueter et modifier les modules référencés sous mode_module comme suit

entry: {
 //vendor: [&#39;vue&#39;, &#39;vue-router&#39;, &#39;vuetify&#39;, &#39;axios&#39;], //删除
 app: &#39;./src/main.js&#39;
 }

new webpack.optimize.CommonsChunkPlugin({
  name: &#39;vendor&#39;,
  minChunks: ({ resource }) => (
   resource &&
   resource.indexOf(&#39;node_modules&#39;) >= 0 &&
   resource.match(/\.js$/)
  )
 }),
Copier après la connexion

Après les étapes d'optimisation ci-dessus. , regardons la distribution des fichiers, vous constaterez que les modules sous node_module sont tous collectés sous supplier.

Ici, nous pouvons acquérir une expérience, c'est-à-dire que dans un projet, nous pouvons spécifiquement empaqueter et optimiser les modules sous node_module. Mais si vous êtes prudent ici, vous constaterez peut-être que le composant codemirror se trouve également dans node_module, mais pourquoi n'est-il pas empaqueté mais empaqueté à plusieurs reprises sur d'autres pages uniques. En fait, c'est parce que l'utilisation de l'attribut name dans commonChunk signifie en fait que Follow ? l'entrée d'entrée pour trouver les packages dépendants. Puisque nos composants sont chargés de manière asynchrone, ils ne seront pas empaquetés ici Faisons une expérience pour vérifier. Maintenant, nous supprimons le chargement paresseux de routage des pages dbmanage et système et les modifions en Introduire directement <. 🎜>

// const dbmanage = () => import(/* webpackChunkName: "dbmanage" */&#39;../views/dbmanage.vue&#39;)
// const system = () => import(/* webpackChunkName: "system" */&#39;../views/system.vue&#39;)
import dbmanage from &#39;../views/dbmanage.vue&#39;
import system from &#39;../views/system.vue&#39;
Copier après la connexion

À ce moment-là, lorsque nous reconditionnons, nous pouvons constater que le codemirror a été empaqueté. La question est donc : est-ce bon ?

async

La réponse à la question ci-dessus est oui, non. Évidemment, ventor est notre code d'entrée, c'est-à-dire. Dans le premier écran, nous n'avons pas du tout besoin de charger ce composant codemirror. Nous restaurons d'abord la modification de routage tout à l'heure, mais il y a ensuite un nouveau problème. Notre codemirror est regroupé en deux pages en même temps, et certaines d'entre elles. ils sont empaquetés par eux-mêmes. Des composants tels que MTable ou MDataTable sont également empaquetés à plusieurs reprises. Et le codemirror est très volumineux, le chargement de deux pages simples en même temps entraînera également un gros problème de performances, pour faire simple, après avoir chargé le codemirror sur la première page, nous ne devrions pas le charger sur la deuxième page. Pour résoudre ce problème, nous pouvons ici utiliser l'async de CommonsChunkPlugin et la méthode count dans minChunnks pour déterminer la quantité, à condition qu'elle soit réutilisée plus de deux fois, y compris deux modules de chargement asynchrones (c'est-à-dire le morceau généré par import ()). , nous le considérerons. Il peut être marqué comme public. Ici, nous ajoutons une configuration.

new webpack.optimize.CommonsChunkPlugin({
 async: &#39;used-twice&#39;,
 minChunks: (module, count) => (
 count >= 2
 ),
})
Copier après la connexion

再次打包,我们发现所有服用的组件被重新打到了 0.used-twice-app.js中了,这样各个单页面大小也有所下降,平均小了近10k左右

可是,这里我们发现vuetify.js和vuetify.css实在太庞大了,导致我们的打包的代码很大,这里,我们考虑把它提取出来,这里为了避免重复打包,需要使用external,并将vue以及vuetify的代码采用cdn读取的方式,首先修改index.html

//css引入
<link href=&#39;https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons&#39; rel="stylesheet" type="text/css">
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="external nofollow" rel="stylesheet">
//js引入
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify/dist/vuetify.js"></script>

//去掉main.js中之前对vuetifycss的引入
//import &#39;vuetify/dist/vuetify.css&#39;
Copier après la connexion

再修改webpack配置,新增externals

externals: {
 &#39;vue&#39;:&#39;Vue&#39;,
 "vuetify":"Vuetify"
 }
Copier après la connexion

再重新打包,可以看到vue相关的代码已经没有了,目前也只有used-twice-app.js比较大了,app.js缩小了近200kb。

但是新问题又来了,codemirror很大,而used-twice又是首屏需要的,这个打包在首屏肯定不是很好,这里我们要将system和dbmanage页面的codemirror组件改为异步加载,单独打包,修改如下:

// import MCode from "../component/MCode.vue"; //注释掉

components: {
  MDialog,
  MCode: () => import(/* webpackChunkName: "MCode" */&#39;../component/MCode.vue&#39;)
 },
Copier après la connexion

重新打包下,可以看到 codemirror被抽离了,首屏代码进一步得到了减少,used-twice-app.js代码缩小了近150k。

做了上面这么多的优化之后,业务测的js基本都被拆到了50kb一下(忽略map文件),算是优化成功了。

总结

可能会有朋友会问,单独分拆vue和vuetify会导致请求数增加,这里我想补充下,我们的业务现在已经切换成http2了,由于多路复用,并且加上浏览器缓存,我们分拆出的请求数其实也算是控制在合理的范畴内。

这里最后贴一下优化后的webpack配置,大家一起交流学习下哈。

const path = require('path')
const webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const generateHtml = new HtmlWebpackPlugin({
 title: '逍遥系统',
 template: './src/index.html',
 minify: {
 removeComments: true
 }
})

module.exports = {
 entry: {
 app: './src/main.js'
 },
 output: {
 path: path.resolve(__dirname, './dist'),
 filename: '[name].[hash].js',
 chunkFilename:'[id].[name].[chunkhash].js'
 },
 resolve: {
 extensions: ['.js', '.vue'],
 alias: {
  'vue$': 'vue/dist/vue.esm.js',
  'public': path.resolve(__dirname, './public')
 }
 },
 externals: {
 &#39;vue&#39;:&#39;Vue&#39;,
 "vuetify":"Vuetify"
 },
 module: {
 rules: [
  {
  test: /\.vue$/,
  loader: 'vue-loader',
  options: {
   loaders: {
   }
   // other vue-loader options go here
  }
  },
  {
  test: /\.js$/,
  loader: 'babel-loader',
  exclude: /node_modules/
  },
  {
  test: /\.(png|jpg|gif|svg)$/,
  loader: 'file-loader',
  options: {
   objectAssign: 'Object.assign'
  }
  },
  {
  test: /\.css$/,
  loader: ['style-loader', 'css-loader']
  },
  {
  test: /\.styl$/,
  loader: ['style-loader', 'css-loader', 'stylus-loader']
  }
 ]
 },
 devServer: {
 historyApiFallback: true,
 noInfo: true
 },
 performance: {
 hints: false
 },
 devtool: '#eval-source-map',
 plugins: [
  new CleanWebpackPlugin(['dist']),
  generateHtml
 ]
}

if (process.env.NODE_ENV === 'production') {
 module.exports.devtool = '#source-map'
 module.exports.plugins = (module.exports.plugins || []).concat([
 new BundleAnalyzerPlugin(),
 new webpack.optimize.CommonsChunkPlugin({
  name: 'ventor',
  minChunks: ({ resource }) => (
  resource &&
  resource.indexOf('node_modules') >= 0 &&
  resource.match(/\.js$/)
  )
 }),

 new webpack.optimize.CommonsChunkPlugin({
  async: 'used-twice',
  minChunks: (module, count) => (
  count >= 2
  ),
 }),

 new webpack.DefinePlugin({
  'process.env': {
  NODE_ENV: '"production"'
  }
 }),
 new webpack.optimize.UglifyJsPlugin({
  sourceMap: true,
  compress: {
  warnings: false
  }
 }),
 new webpack.LoaderOptionsPlugin({
  minimize: true
 })
 ])
}
Copier après la connexion

相关推荐:

vue.js中created方法的使用详解

如何修改Vue.js中scoped模式下的子组件内部标签样式

Vue中computed与methods的区别详解_vue.js

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal