Vue SPA 打包優化實踐

本文是繼筆者上一篇文章<<Vue SPA 首屏加載優化實踐>>基礎上進一步優化的實踐經驗分享!css

隨着咱們的項目的增加,打包會愈來愈慢。每次打包都會將第三方的js打包一遍,可是這些第三方的不會常常變化,如何能將第三方的js只打包一次呢?html

異步組件

咱們先將路由組件改爲異步組件。官方文檔vue

// src/router/index.js

...
export default new VueRouter({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: resolve => require(['@/components/HelloWorld'], resolve)
    }
  ]
})
複製代碼

webpack DllPlugin

webpack提供了一個插件 DllPlugin ,用於將不常變更的js單獨打包。node

  1. 首先咱們在src目錄下新建 vendor.jsimport 第三方的js:
import 'babel-polyfill'
import Vue from 'vue'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import {sync} from 'vuex-router-sync'
import axios from 'axios'
import ElementUI from 'element-ui'
複製代碼

這裏只須要import進來就好了。webpack

  1. build目錄下新建 webpack.dll.conf.js 配置文件:
var path = require('path')
var webpack = require('webpack')

var context = path.join(__dirname, '..')

module.exports = {
  entry: {
    vendor: ['./src/vendor.js'] // entry 以項目根目錄爲起始路徑
  },
  output: {
    // 將打包後的 js 放到 static 目錄下,build的時候會copy到dist目錄
    path: path.join(context, 'static/js'),
    filename: '[name].dll.js',
    library: '[name]'
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(context, '[name].manifest.json'),
      name: '[name]',
      context: context
    }),
    // 壓縮js代碼
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      output: { // 刪除打包後的註釋
        comments: false
      }
    })
  ]
}
複製代碼

這裏的 context 很是關鍵,我這裏以項目的根路徑做爲context,manifest.json的位置可自由定義,name要和output裏面的library保持一致。resolve 裏將 webpack.base.conf.js 裏面的 vue$ copy過來,vue用的是vue.esm.js。須要注意的是 dllPlugin 只支持 Array 類型的 entryios

  1. package.json 裏面加上 script :build:dll
"scripts": {
  "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
  "start": "npm run dev",
  "lint": "eslint --ext .js,.vue src",
  "build": "node build/build.js",
  "build:dll": "webpack --config build/webpack.dll.conf.js --progress"
}
複製代碼

運行 npm run build:dll,會在 static/js 裏面生成 vendor.dll.jsnginx

到這裏咱們的第三方js就打包完了,那麼如何使用呢?git

webpack DllReferencePlugin

  1. webpack提供了DllReferencePlugin。修改 build/webpack.base.conf.js
const webpack = require('webpack')

module.exports = {
  ...
  plugins: [
    new webpack.DllReferencePlugin({
      // name參數和dllplugin裏面name一致,能夠不傳
      name: 'vendor',
      // dllplugin 打包輸出的manifest.json
      manifest: require('../vendor.manifest.json'),
      // 和dllplugin裏面的context一致
      context: path.join(__dirname, '..')
    })
  ]
  ...
}
複製代碼

注意:這裏的context必定要和dllplugin裏面的context保持一致github

  1. 修改 build/webpack.prod.js。刪除上一篇文章中配置的externals配置項:
module.exports = {
  ...
  // externals: {
  // 'vue': 'Vue',
  // 'vuex': 'Vuex',
  // 'vue-router': 'VueRouter',
  // 'element-ui': 'ELEMENT'
  // }
  ...
  plugins: [
    ...
    // 去掉這裏的CommonsChunkPlugin
    // new webpack.optimize.CommonsChunkPlugin({
    // name: 'vendor',
    // minChunks (module) {
    // // any required modules inside node_modules are extracted to vendor
    // return (
    // module.resource &&
    // /\.js$/.test(module.resource) &&
    // module.resource.indexOf(
    // path.join(__dirname, '../node_modules')
    // ) === 0
    // )
    // }
    // }),
    // 去掉這裏的CommonsChunkPlugin
    // new webpack.optimize.CommonsChunkPlugin({
    // name: 'manifest',
    // minChunks: Infinity
    // }),
    ...
  ]
}
複製代碼

去掉這兩個CommonsChunkPlugin,由於咱們已經經過dllplugin打包了,這裏就不須要了。web

  1. index.dev.htmlindex.prod.html 合併成一個文件 index.html,去掉CDN資源,引入 vendor.dll.js
<head>
  ...
  <link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.0.7/theme-chalk/index.css">
</head>

<body>
  <div id="app"></div>
  <!-- built files will be auto injected -->
  <script src="static/js/vendor.dll.js"></script>
</body>
複製代碼

這裏 element-ui 的樣式文件依然採用CDN加載,由於咱們沒有將樣式打包到vendor.dll.js裏面

  1. 修改 webpack.dev.conf.jswebpack.prod.conf.js 裏面的模板文件的配置:
...
plugins: [
  ...
  new HtmlWebpackPlugin({
    template: 'index.html'
  })
]
複製代碼
  1. 修改 src 裏面 vuexvue-router 的使用:
// src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
複製代碼

至此,咱們全部的準備工做就作完了。接下來運行npm run dev,啓動本地開發服務:

打包:npm run build,而後部署到nginx服務,啓動nginx服務:

總結

之因此將 vendor.dll.js 放在 static/js 目錄下,是爲了方便開發和發佈使用相同的路徑。爲了保持element-ui的js和樣式版本一致,能夠在項目中加入lessscss等,而後@import進來就能夠了,這樣打包的時候就會單獨打包到css裏面。

示例項目傳送門:vue-spa-starter-kit,歡迎你們吐槽和 star

相關文章
相關標籤/搜索