>웹 프론트엔드 >JS 튜토리얼 >Vue 패키징 최적화 코드 Spliting_vue.js

Vue 패키징 최적화 코드 Spliting_vue.js

不言
不言원래의
2018-04-10 14:45:431313검색

이 글은 주로 Vue 패키징 최적화를 위한 코드 분할에 대한 자세한 설명을 소개합니다. 이제 공유하겠습니다. 도움이 필요한 친구들이 참고할 수 있습니다.

http1 시대에 일반적인 성능 최적화는 http 수를 병합하는 것입니다. 일반적으로 우리는 많은 js 코드를 함께 병합하지만 js 패키지의 크기가 특히 큰 경우 성능 향상을 위해 약간 과잉입니다. 그리고 모든 코드를 합리적으로 분할했다면 첫 화면 코드와 첫 화면이 아닌 코드를 떼어내고 비즈니스 코드와 기본 라이브러리 코드를 분할한 뒤 필요할 때 특정 코드 조각을 로드하면 다음 번에는 다시 사용하려면 캐시에서 읽어야 합니다. 첫째, 브라우저 캐시를 더 잘 활용할 수 있습니다. 둘째, 첫 번째 화면의 로딩 속도를 향상시켜 사용자 경험을 크게 향상시킬 수 있습니다.

핵심 아이디어

비즈니스 코드와 기본 라이브러리의 분리

이것은 실제로 이해하기 쉽습니다. 비즈니스 코드는 일반적으로 자주 업데이트되고 반복되는 반면 기본 라이브러리는 일반적으로 여기서 분할하면 쉽게 만들 수 있습니다. 브라우저 캐시를 완전히 사용합니다. 기본 라이브러리 코드를 로드합니다.

주문형 비동기 로딩

이것은 주로 첫 번째 화면 요청 크기 문제를 해결합니다. 첫 번째 화면에 액세스할 때 모든 라우팅 코드를 로드하는 대신 첫 번째 화면에 필요한 로직만 로드하면 됩니다.

실용적인 전투

최근에는 vuetify를 사용하여 내부 시스템을 변환했는데 처음에는 가장 일반적으로 사용되는 웹팩 구성을 사용했는데 기능이 빠르게 개발되었지만 패키징하고 나니 효과가 나타났습니다. 명확하지 않았고, 많은 대형 패키지가 생성되었습니다

여기서 우리는 webpack-bundle-analyzer를 사용하여 vue 및 vuetify와 같은 모듈이 반복적으로 사용되는 것을 볼 수 있습니다. 포장.

여기서 구성을 먼저 게시하고 나중에 분석에 사용할 것입니다.

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 입구 여기에서 axios와 같은 node_module 아래의 모든 참조 모듈이 필터링되지는 않았음을 발견했습니다. 그래서 app.js에 패키징됩니다. 여기서는 분리를 수행합니다.

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

여기에는 또 다른 문제가 있습니다. 이 때 모듈을 자동으로 분리해야 할 수도 있습니다. 여기에서 MinChunk를 도입해야 합니다. 다음과 같이 mode_module에서 참조되는 모듈을 패키징하고 수정할 수 있습니다.

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

위 단계의 최적화 후 파일 배포를 살펴보고 찾습니다. node_module 아래의 모듈은 모두 공급업체 아래에 수집됩니다.

여기서 경험을 얻을 수 있습니다. 즉, 프로젝트에서 node_module 아래의 모듈을 구체적으로 패키징하고 최적화할 수 있습니다. 그런데 여기서 조심하면 node_module에도 codemirror 컴포넌트가 있는 것을 알 수 있는데 왜 패키징되지 않고 다른 단일 페이지에 반복적으로 패키징되는 걸까요? 사실 commonChunk에서 name 속성을 사용한다는 것은 실제로 Follow만 한다는 의미이기 때문입니다. 종속 패키지를 찾기 위한 항목입니다. 구성 요소가 비동기적으로 로드되므로 여기에 패키지되지 않습니다. 이제 dbmanage 및 시스템 페이지의 라우팅 지연 로딩을 제거하고 직접 도입

으로 변경합니다.

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

이때, 리패키징을 해보면 codemirror가 패키징되어 있는 걸 볼 수 있는데, 이게 좋은 걸까?

async

위 질문에 대한 대답은 '예', '아니요'입니다. 분명히 Ventor는 첫 번째 화면이므로 이 코드 미러 구성 요소를 전혀 로드할 필요가 없습니다. 방금 라우팅 수정이 복원되었지만 이제 새로운 문제가 발생했습니다. 우리의 코드 미러가 동시에 두 개의 단일 페이지로 패키징되었으며 MTable 또는 MDataTable과 같은 일부 자체 캡슐화 구성 요소도 반복적으로 패키징되었습니다. 그리고 코드미러는 매우 커서 두 개의 단일 페이지를 동시에 로드하면 큰 성능 문제가 발생합니다. 간단히 말해서 첫 번째 단일 페이지에 코드미러를 로드한 후에는 두 번째 페이지에 로드하면 안 됩니다. 이 문제를 해결하기 위해 여기서는 두 개의 비동기 로딩 모듈(즉, import()에 의해 생성된 청크)을 포함하여 두 번 이상 재사용되는 한 minChunks의 async 및 count 메서드를 사용할 수 있습니다. , 우리는 그것을 공개로 표시할 수 있습니다. 여기에 구성을 추가합니다.

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

위 내용은 Vue 패키징 최적화 코드 Spliting_vue.js의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.