Heim  >  Artikel  >  Web-Frontend  >  Vue-Paketoptimierungscode spliting_vue.js

Vue-Paketoptimierungscode spliting_vue.js

不言
不言Original
2018-04-10 14:45:431257Durchsuche

In diesem Artikel wird hauptsächlich die Codeaufteilung der Vue-Verpackungsoptimierung ausführlich erläutert. Jetzt können Freunde in Not darauf zurückgreifen.

Im Zeitalter von http1 ist dies eine häufige Leistungsoptimierung In Bezug auf die Anzahl der Anfragen führen wir normalerweise viele JS-Codes zusammen, aber wenn die Größe eines JS-Pakets besonders groß ist, ist dies zur Leistungsverbesserung etwas übertrieben. Und wenn wir den gesamten Code sinnvoll aufteilen, den ersten Bildschirm- und den nicht-ersten Bildschirmcode abziehen, den Geschäftscode und den Basisbibliothekscode aufteilen und dann bei Bedarf einen bestimmten Codeabschnitt laden, wenn nötig, beim nächsten Mal Wenn Sie es erneut verwenden, können Sie den Browser-Cache besser nutzen. Zweitens kann es die Ladegeschwindigkeit des ersten Bildschirms verbessern, was das Benutzererlebnis erheblich verbessert.

Kernidee

Trennung von Geschäftscode und Basisbibliothek

Dies ist eigentlich leicht zu verstehen. Geschäftscode wird normalerweise häufig aktualisiert und iteriert Basisbibliotheken Normalerweise sind Aktualisierungen langsam. Wenn Sie sie hier aufteilen, können Sie den Browser-Cache vollständig nutzen, um den Basisbibliothekscode zu laden.

Asynchrones Laden bei Bedarf

Dies löst hauptsächlich das Problem der ersten Bildschirmanforderungsgröße. Beim Zugriff auf den ersten Bildschirm müssen wir nur die dafür erforderliche Logik laden erster Bildschirm und nicht der Code, der alle Routen lädt.

Praktischer Kampf

Vor kurzem habe ich vuetify verwendet, um ein internes System zu transformieren. Zu Beginn habe ich die am häufigsten verwendete Webpack-Konfiguration verwendet. Aber sobald ich es verpackt habe, ist der Effekt nicht sehr offensichtlich.

Hier sehen wir uns die Verpackungsverteilung an Hier können Sie Vue und Vuetify deutlich erkennen. Es gibt Fälle, in denen Module wiederholt gepackt werden.

Hier veröffentlichen wir zuerst die Konfiguration und verwenden sie später zur Analyse:

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

Ventor-Eintrag Hier haben wir festgestellt, dass alle referenzierten Module unter node_module, wie z. B. axios, nicht herausgefiltert wurden, also wurden sie in app.js gepackt. Hier führen wir die Trennung durch

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

Dann gibt es hier noch ein weiteres Problem. Zu diesem Zeitpunkt ist es für mich nicht möglich, den Lüfter automatisch zu trennen. Hier müssen wir minChunks einführen. In der Konfiguration können wir die unter mode_module referenzierten Module wie folgt packen und ändern:

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$/)
  )
 }),

Nach den oben genannten Optimierungsschritten Schauen wir uns die Dateiverteilung an. Sie werden feststellen, dass die Module unter node_module alle unter „vendor“ gesammelt sind.

Hier können wir Erfahrungen sammeln, d.h. in einem Projekt können wir die Module unter node_module gezielt verpacken und optimieren. Wenn Sie hier jedoch vorsichtig sind, stellen Sie möglicherweise fest, dass sich die Codemirror-Komponente auch in node_module befindet. Warum wird sie jedoch nicht gepackt, sondern wiederholt in andere einzelne Seiten gepackt? Tatsächlich bedeutet dies, dass die Verwendung des Namensattributs in commonChunk tatsächlich nur folgt Der Eintragseingang, um die abhängigen Pakete zu finden, wird hier nicht gepackt. Lassen Sie uns nun das Routing-Lazy-Loading der dbmanage- und Systemseiten entfernen und sie in „Direkt einführen“ ändern 🎜>

// 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'

Zu diesem Zeitpunkt können wir feststellen, dass der Codespiegel verpackt wurde. Die Frage ist also: Ist das gut?

asynchron

Die Antwort auf die obige Frage ist ja, nein. Offensichtlich ist ventor unser Zugangscode. Auf dem ersten Bildschirm müssen wir diese Codemirror-Komponente überhaupt nicht laden. Wir stellen die Routing-Änderung gerade erst wieder her, aber dann gibt es ein neues Problem. Unser Codemirror ist gleichzeitig in zwei einzelne Seiten gepackt Sie werden einzeln verpackt. Komponenten wie MTable oder MDataTable werden ebenfalls wiederholt verpackt. Und der Codespiegel ist sehr groß. Das gleichzeitige Laden von zwei einzelnen Seiten verursacht auch ein großes Leistungsproblem. Vereinfacht gesagt sollten wir den Codespiegel nicht auf der zweiten Seite laden. Um dieses Problem zu lösen, können wir hier die asynchrone Methode von CommonsChunkPlugin und die count-Methode in minChunnks verwenden, um die Menge zu bestimmen, solange sie mehr als zwei Mal wiederverwendet wird, einschließlich zweier asynchroner Lademodule (dh des durch import () generierten Blocks). , wir werden es in Betracht ziehen. Es kann als öffentlich markiert werden. Hier fügen wir eine Konfiguration hinzu.

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 &#39;vuetify/dist/vuetify.css&#39;

再修改webpack配置,新增externals

externals: {
 &#39;vue&#39;:&#39;Vue&#39;,
 "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" */&#39;../component/MCode.vue&#39;)
 },

重新打包下,可以看到 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
 })
 ])
}

相关推荐:

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

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

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

Das obige ist der detaillierte Inhalt vonVue-Paketoptimierungscode spliting_vue.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn