Maison  >  Article  >  interface Web  >  Quelles sont les méthodes d’optimisation du packaging pour Vue ?

Quelles sont les méthodes d’optimisation du packaging pour Vue ?

php中世界最好的语言
php中世界最好的语言original
2018-06-09 10:35:583763parcourir

Cette fois, je vais vous présenter les méthodes d'optimisation du packaging de Vue et les précautions pour l'optimisation du packaging de Vue. Ce qui suit est un cas pratique, jetons un coup d'œil.

À l'ère de http1, une optimisation des performances courante consiste à fusionner le nombre de requêtes http. Habituellement, nous fusionnons de nombreux codes js ensemble, mais si la taille d'un package js est particulièrement grande, cela n'améliorera pas la qualité. performance. C'est un peu exagéré. 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 emballé, j'ai trouvé que l'effet n'est pas très évident. Il existe de nombreux gros packages

Ici, nous regardons la distribution des emballages. Le webpack-bundle-analyzer 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
 })
 ])
}

CommonChunkPlugin

À l'entrée du ventor, 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é empaquetés dans app.js. Ici, nous nous sommes séparés

entry: {
 vendor: ['vue', 'vue-router', 'vuetify', 'axios'],
 app: './src/main.js'
 },

Ensuite, un autre problème se pose ici. Maintenant, il m'est impossible de saisir le module manuellement. À ce stade, nous devrons peut-être séparer automatiquement le ventor. 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: ['vue', 'vue-router', 'vuetify', 'axios'], //删除
 app: './src/main.js'
 }
new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: ({ resource }) => (
   resource &&
   resource.indexOf('node_modules') >= 0 &&
   resource.match(/\.js$/)
  )
 }),
Après les étapes d'optimisation ci-dessus, nous examinons la distribution des fichiers et constatons que les modules sous node_module ont été 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 <.>

. À l'heure actuelle, lorsque nous reconditionnons, nous pouvons constater que codemirror a été empaqueté. La question est donc : est-ce bon ?
// const dbmanage = () => import(/* webpackChunkName: "dbmanage" */'../views/dbmanage.vue')
// const system = () => import(/* webpackChunkName: "system" */'../views/system.vue')
import dbmanage from '../views/dbmanage.vue'
import system from '../views/system.vue'

asynchrone

上面的问题答案是肯定的,不可以的,很明显ventor是我们的入口代码即首屏,我们完全没有必要去加载这个codemirror组件,我们先把刚才的路由修改恢复回去,但是这时又有了新问题,我们的codemirror被同时打包进了两个单页面,并且还有些自己封装的components,例如MTable或是MDataTable等也出现了重复打包。并且codemirror特别大,同时加载到两个单页面也会造成很大的性能问题,简单说就是,我们在访问第一个单页面加载了codemirror之后,在第二个页面其实就不应该再加载了。 要解决这个问题,这里我们可以使用 CommonsChunkPlugin 的 async 并在 minChunnks 里的count方法来判断数量,只要是 重用次数 超过两个包括两个的异步加载模块(即 import () 产生的chunk )我们都认为是 可以 打成公共的 ,这里我们增加一项配置。

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

再次打包,我们发现所有服用的组件被重新打到了 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 'vuetify/dist/vuetify.css'

再修改webpack配置,新增externals

externals: {
 'vue':'Vue',
 "vuetify":"Vuetify"
 }

再重新打包,可以看到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" */'../component/MCode.vue')
 },

重新打包下,可以看到 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: {
 'vue':'Vue',
 "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
 })
 ])
}

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

实战项目中如何使用vue组件

vue select操作组件开启

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