原文地址javascript
Webpack是開發Vue.js單頁應用程序的重要工具。經過管理複雜的構建步驟,您能夠更輕鬆地開發工做流程,並優化應用程序的大小和性能。html
在本文中,我將解釋Webpack能夠加強您的Vue應用程序的四種方式,其中包括:vue
單文件組件java
優化Vue構建node
瀏覽器緩存管理webpack
代碼分割(code splitting)web
若是您使用的模板是從vue-cli構建應用程序,則會提供預製的Webpack配置。他們被很好的優化而且我沒有任何能夠改建的建議!vue-router
可是由於他們的工做很好,你可能不太清楚他們真正在作什麼,對嗎?考慮這篇文章對vue-cli模板中使用的Webpack配置的概述,就像它們包含我在這裏討論的相同的優化。vue-cli
Vue的特殊功能之一是使用HTML做爲組件模板。儘管如此,它們還有一個內在的問題:您的HTML標記須要是一個尷尬的JavaScript字符串,不然您的模板和組件定義將須要在單獨的文件中,使其難以使用。Vue有一個優雅的解決方案,稱爲單文件組件(SFC),其中包括模板,組件定義和CSS所有在一個整齊的.vue文件中:瀏覽器
MyComponent.vue
<template> <div id="my-component">...</div> </template> <script> export default {...} </script> <style> #my-component {...} </style>
SFC經過vue-loader Webpack插件實現。該加載器將SFC的語言塊和管道分紅適當的加載程序,例如腳本塊進入babel-loader,而模板塊則轉到Vue本身的vue-template-loader,將模板轉換爲JavaScript render
函數。
vue-loader的最終輸出是一個能夠包含在Webpack包中的JavaScript模塊。
典型配置vue-loader
以下:
module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { loaders: { // Override the default loaders } } }, ] }
若是您僅在Vue應用程序中使用渲染功能,而且沒有HTML模板,則不須要Vue的模板編譯器。您能夠經過從Webpack構建中省略編譯器來減小捆綁包大小。
注意,單個文件組件模板是在開發中預編譯的,以渲染功能!
Vue.js庫中只有一個運行時版本的構建,其中包含Vue.js除了模板編譯器(稱爲vue.runtime.js)以外的全部功能。它比完整版小約20KB,若是能夠的話值得使用。
默認狀況下使用運行時版本,所以每次import vue from 'vue';
在項目中使用這些都是您將得到的。您能夠經過使用alias
配置選項更改成不一樣的構建:
resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' // Use the full build } }
減小Vue.js構建大小的另外一種方法是刪除生產中的任何錯誤消息和警告。這些輸出包的大小與沒必要要的代碼有關可是仍是須要避免增長運行時的構建成本。
若是您檢查Vue源代碼,您將看到警告塊以環境變量的值爲條件,process.env.NODE_ENV
例如:
if (process.env.NODE_ENV !== 'production') { warn(("Error in " + info + ": \"" + (err.toString()) + "\""), vm); }
若是將process.env.NODE_ENV設置爲:production
則在構建過程當中,這些警告塊能夠經過分段器自動從代碼中刪除。
您可使用DefinePlugin設置process.env.NODE_ENV的值,並使用UglifyJsPlugin來縮小代碼並將未使用的塊刪除:
if (process.env.NODE_ENV === 'production') { module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new webpack.optimize.UglifyJsPlugin() ]) }
用戶的瀏覽器將緩存您的站點的文件,只有在瀏覽器尚未本地副本或本地副本已過時時纔會下載。
若是全部的代碼都在一個文件中,那麼一個微小的變化將意味着整個文件將須要從新下載。理想狀況下,您但願用戶儘量少的下載,所以將您的應用程序不多更改的代碼與其頻繁更改的代碼分開是很是明智的。
CommonsChunkPlugin插件能夠將公用的代碼塊分離出來(如依賴像Vue.js庫,不可能常常改變)。
您能夠配置插件以檢查依賴項是否來自該node_modules
文件夾,若是是,則將其輸出到單獨的文件中vendor.js
:
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: function (module) { return module.context && module.context.indexOf('node_modules') !== -1; } })
若是這樣作,您將在構建輸出中有兩個單獨的文件,這些文件將由瀏覽器獨立緩存:
<script src="vendor.js" charset="utf-8"></script> <script src="app.js" charset="utf-8"></script>
當構建文件發生更改的時候,咱們怎麼來更改瀏覽器的緩存?
默認狀況下,只有當緩存文件過時的時候,或者是用戶手動的清除了緩存文件的時候,瀏覽器纔會再次向服務器請求文件。若是服務器代表這些文件被更改過了則文件將被從新下載(不然服務器返回HTTP 304未修改)。
爲了保存沒必要要的服務器請求,咱們能夠在每次內容更改時更改文件的名稱,以強制瀏覽器從新下載。一個簡單的方法是經過附加一個哈希來爲文件名添加一個「指紋」,例如:
Common Chunks插件發出一個「chunkhash」,若是文件的內容已經更改,它將被更新。當它們輸出時,Webpack能夠將這個哈希追加到文件名中:
output: { filename: '[name].[chunkhash].js' },
當您這樣作時,您會看到您輸出的文件將具備像app.3b80b7c17398c31e4705.js這樣的名稱。
固然,若是你添加一個哈希,你必須更新索引文件中的文件的引用,不然瀏覽器將不會知道它:
<script src="app.3b80b7c17398c31e4705.js"></script>
這將是一個很是繁瑣的工做,手動執行,因此使用HTML Webpack Plugin幫您作。該插件能夠在捆綁過程當中自動將構建文件的引用注入到HTML文件中。
首先刪除對構建文件的引用:
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>test-6</title> </head> <body> <div id="app"></div> <!-- built files should go here, but will be auto injected --> </body> </html>
把HTML Webpack Plugin 添加到webpack配置中:
new HtmlWebpackPlugin({ filename: 'index.html' template: 'index.html', inject: true, chunksSortMode: 'dependency' }),
如今您的構建文件與哈希值將自動添加到您的索引文件。此外,您的index.html文件如今將包含在您的包輸出中,所以您可能須要告知Web服務器文件已更改。
默認狀況下,Webpack會將您的全部應用程序代碼輸出到一個整合的js文件中。可是,若是您的應用程序有多個頁面,則分割代碼將更有效,所以每一個單獨的頁面代碼都在單獨的文件中,而且僅在須要時加載。
Webpack有一個名爲「code splitting」的功能,正是這樣。在Vue.js中實現這一點也須要異步組件,而且經過Vue Router變得更加容易。
異步組件不是將定義對象做爲其第二個參數,而是具備解析定義對象的Promise函數,例如:
Vue.component('async-component', function (resolve, reject) { setTimeout(() => { resolve({ // Component definition including props, methods etc. }); }, 1000) })
當組件須要呈現時,Vue將調用該函數。它還將緩存將來從新渲染的結果。
若是咱們構建咱們的應用程序,所以每一個「頁面」都是一個組件,而且咱們將定義存儲在咱們的服務器上,那麼咱們就有一些方法來實現代碼的分割。
要從服務器加載異步組件的代碼,請使用Webpack require
語法。這將指示Webpack async-component
在構建時捆綁在一個單獨的包中,而更好的是,Webpack將處理使用AJAX加載該包,所以您的代碼能夠像如下同樣簡單:
Vue.component('async-component', function (resolve) { require(['./AsyncComponent.vue'], resolve) })
Vue.js應用程序vue-router一般是用於將SPA組織到多個頁面的模塊。Lazy加載是使用Vue和Webpack實現代碼分割的一種形式化方式。
const HomePage = resolve => require(['./HomePage.vue'], resolve); const rounter = new VueRouter({ routes: [ { path: '/', name: 'HomePage', component: HomePage } ] })
譯註:部分翻譯可能不太恰當,但願能有人指出相互提升。thanks