結合vue-cli來談webpack打包優化

1、按需加載

1.一、爲何須要按需加載

隨着web應用功能愈來愈複雜,模塊打包後體積愈來愈大,這樣會帶來兩個問題:html

  • 全部的js文件打包到一個bundle.js中致使首屏加載時間過長
  • 有時咱們只是修改了一個模塊就得從新打包所用的文件 webpack自然支持多種模塊系統風格,支持靈活的代碼分割

1.二、按需加載的三種方式

webpack支持三種代碼分割方式分別是:vue

  • AMD: require(url, '別名')
  • CommonJS: require.ensure([],func),
  • ES6: import(url)

1.三、vue中如何按需加載

對應的vue中也有三種對應的解決方式:react

  • vue異步組件技術
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
    mode: 'history',
    routes: [
        {
            path: '/vue-async',
            name: 'vueAsync',
            component: resolve => require(['@/components/VueAsync'], resolve)
        }
    ]
})
複製代碼
  • webpack提供的require.ensure()
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)

export default new Router({
    mode: 'history',
    routes: [
        {
            path: '/require-ensure'
            name: 'RequireEnsure',
            component: r => require.ensure([], () => r(require('@/components/RequireEnsure'), 'ensure'))
        }
    ]
})
複製代碼
  • 利用ES6提案的import()函數
import Vue from 'vue'
import Router from 'vue-router'

const EsImport = () => import('@/components/EsImport')
Vue.use(Router)
export default new Router({
    mode: 'history',
    routes: [
    {
        path: '/es-import',
        name: 'EsImport',
        component: EsImport
    }
]
})
複製代碼

第三種方式比較簡單,並且代碼組織也比較明顯,因此也更常被使用jquery

2、合理使用commonsChunkPlugin

2.一、爲何使用commonsChunkPlugin

CommonsChunkPlugin 插件,是一個可選的用於創建一個獨立文件(又稱做 chunk)的功能,這個文件包括多個入口 chunk 的公共模塊。簡單來講CommonsChunkPlugin主要是用來提取第三方庫和公共模塊,避免首屏加載的bundle文件或者按需加載的bundle文件體積過大,從而致使加載時間過長,着實是優化的一把利器。webpack

2.二、commonsPlugin的集中使用場景

  • 提取兩個及兩個以上 Chunk 的公共代碼
  • 將 Code Split 切割出來的 Chunk「就是子 Chunk」,提取到父 Chunk
  • 將 Code Split 切割出來的 Chunk,提取到一個新的異步加載的 Chunk
  • 提取某個相似 jquery 或 react 的代碼庫「可是這個用得不多,使用用 dll 插件來打包會更好一些,一下篇介紹」

3、使用DllPlugin和DllReferencePlugin來提升打包速度

3.一、爲何使用DllPlugin和DllReferencePlugin

使用 CommonsChunkPlugin,設置 minChunks 爲 Infinity 可用於打包此類代碼,但缺點也是比較明顯的:git

  • 每次執行 webpack 時,都會去解析打包這些代碼,耗時也耗資源
  • 若是設置了文件名 hash,一次構建生成一個新的hash,那這些文件即便沒有變,文件名也會變,不利於緩存。 對於這些代碼我是用 Dll 插件單獨構建。

3.二、vue-cli中如何利用DllPlugin和DllReferencePlugin

  • 在build目錄下編寫webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
const AssetsPlugin = require('assets-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
  entry: {
    libs: [
      'vue/dist/vue.esm.js',
      'vue-router',
      'vuex',
      'element-ui'
    ]
  },
  output: {
    path: path.resolve(__dirname, '../static'),
    filename: '[name].[chunkhash:7].js',
    library: '[name]_library'
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.resolve(__dirname, '../static/[name]-manifest.json'),
      name: '[name]_library',
      context: __dirname
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new AssetsPlugin({
      filename: 'bundle-config.json',
      path: './static'
    }),
    new CleanWebpackPlugin(['static'], {
      root: path.join(__dirname, '../'),
      verbose: true,
      dry: false
    })
  ]
}

複製代碼
  • 在build目錄下編寫buildDll.js
const path = require('path')
const webpack = require('webpack')
const webpackDll = require('./webpack.dll.conf')
const chalk = require('chalk')
const ora = require('ora')
const rm = require('rimraf')
const spinner = ora({
  color: 'green',
  text: 'Dll生產中'
})

spinner.start()

rm(path.resolve(__dirname, '../static'), err => {
  if(err) throw err
  webpack(webpackDll, (err, status) => {
    spinner.stop()
    if(err) throw err
    process.stdout.write(status.toString({
      colors: true,
      modules: false,
      children: false,
      chunks: false,
      chunkModules: false
    }) + '\n\n')
  })
  console.log(chalk.cyan('dll success'))
})

複製代碼
  • 修改webpack.base.conf.js
// 添加plugins
plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('../static/libs-manifest.json')
    })
  ]
複製代碼
  • 修改webpack.dev.conf.js
const bundleConfig = require("../static/bundle-config.json")//調入生成的的路徑json
new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true,
      libJsName: bundleConfig.libs.js
}),
複製代碼
  • 修改webpack.prod.conf.js
const bundleConfig = require("../static/bundle-config.json")//調入生成的的路徑json
 new HtmlWebpackPlugin({
      ...省略號...
      libJsName: bundleConfig.libs.js
      ...省略號...
    })
複製代碼
  • 修改index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vue-multipage</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script src="./static/<%= htmlWebpackPlugin.options.libJsName %>"></script>
  </body>
</html>
複製代碼

參考文章:github

相關文章
相關標籤/搜索