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 }) ]) }
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: ['vue', 'vue-router', 'vuetify', 'axios'], app: './src/main.js' },
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$/) ) }),
// 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'
À ce moment-là, lorsque nous reconditionnons, nous pouvons constater que le codemirror a été empaqueté. La question est donc : est-ce bon ?
asyncLa 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: '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='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' 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 }) ]) }
相关推荐:
如何修改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!