我們知道vue可以快速開發web單頁應用,而且官方為我們提供了自己的應用腳手架vue-cli,我們只需要下載腳手架,安裝依賴后就可以啟動vue應用雛形。
這得益與webpack的依賴追蹤,各種資源后綴的loader,以及相關webpack插件的強大功能。
然而有些時候,我們有多頁面的開發需求,在這種情況下,我們可以為多頁面構建相應的多個應用,比如通過vue-cli生成多個應用目錄,但是這樣一方面會多出很多重復的構建代碼和樣板代碼,另外也會破壞應用的統一性,不便於維護。我們可以在vue-cli的基礎上通過修改webpack配置來讓腳手架具備構建多頁應用的能力。
webpack在打包編譯vue文件時,最重要的是入口和輸出的配置、所以我們會主要修改這兩個部分的配置。
我的個人博客就是一個vue多頁應用,包含客戶端和后台管理兩個部分,下面就以它為例子來說明如何實現vue多頁應用,整個過程是基於vue-cli2的。
入口配置
入口配置比較簡單,打開webpack.base.conf.js,只需要修改entry配置就可以了,修改如下:
entry: {
client: ["babel-polyfill", "./src/Client/main.js"],
manager: ["babel-polyfill", "./src/Manager/main.js"],
},
增加babel-polyfill主要是兼容低版本瀏覽器,因為Babel默認只轉換新的JavaScript句法(syntax),而不轉換新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(比如Object.assign)都不會轉碼。
輸出配置
輸出配置要分別配置開發環境以及生產環境的輸出,我們先來配置開發環境。打開webpack.dev.conf.js,在plugin配置項中添加以下配置,並刪除原來的HtmlWebpackPlugin配置。
new HtmlWebpackPlugin({ filename: 'client.html', template: './tpl/index.html', inject: true, chunks: ['client'], }), new HtmlWebpackPlugin({ filename: 'manager.html', template: './tpl/index.html', inject: true, chunks: ['manager'], }),
可以看到,這里使用HtmlWebpackPlugin插件配置了兩份html輸出,fliename是編譯輸出的文件名,template是html模版,不同頁面可以使用相同的模版也可以使用不同的模版。
實際上,開發環境下我們訪問的頁面資源是被webpack管理在內存中的,webpack-dev-server作為本地服務根據url返回內存資源給瀏覽器從而呈現頁面。但是多頁面情況下如何去根據url返回對應的頁面呢,答案就是配置devServer下的historyApiFallback,該配置項會傳遞給 connect-history-api-fallback這個中間件,對request請求的url進行重定向,避免開發環境下頁面404,配置如下:
historyApiFallback: { rewrites: [ { from: 'index', to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, { from: /\/admin/, to: path.posix.join(config.dev.assetsPublicPath, 'admin.html') }, ], },
到這里開發環境的配置就完成了,npm start啟動項目后,使用localhost:8080可以看到客戶端頁面,使用localhost:8080/admin可以看到后台管理頁面。
接下來對生產環境進行配置,首先打開config/index.js, 在build配置項中增加目標html的輸出路徑及名稱。
index: path.resolve(__dirname, '../server/public/index.html'),
admin: path.resolve(__dirname, '../server/public/admin.html'),
接下來打開build/webpack.prod.conf.js,在pulgin中添加以下配置:
new HtmlWebpackPlugin({ filename: config.build.index, template: './tpl/index.html', inject: true, minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true }, chunksSortMode: 'dependency', chunks: ['manifest', 'vendor', 'client'] }), new HtmlWebpackPlugin({ filename: config.build.admin, template: './tpl/index.html', inject: true, minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true }, chunksSortMode: 'dependency', chunks: ['manifest', 'vendor', 'manager'] }),
這個地方要特別注意的是一定要配置chunks,否則所有打包后的文件將同時引入admin.html和index.html。
這樣,整個vue多頁面配置就完成了。我們可以看到,如果項目中每增加一個一級頁面,就需要多處修改webpack配置,很繁瑣。為此,更好的方式是基於vue-cli2進行一層封裝,這是我寫的一個擴展示例multiPage-vue-cli。
history模式
有的時候出於強迫症,不能忍受hash模式下的url上存在#符號,或者是出於業務需求,url不能帶#號。這個時候要考慮采用vue-router的history模式,history模式的前端配置與上文大同小異,但是由於history模式下url路徑的跳轉是vue-router利用h5的history API動態添加的,而手動刷新頁面會導致找不到路由從而產生404錯誤,因此還需要對服務端進行配置,將路由重定向到一級頁面。比如可以對nginx作如下配置:
server { listen 80; location ^~ /api { proxy_pass http://127.0.0.1:3000; } location /admin { root /home/silentport.github.io/nginx/blog/; index admin.html; try_files $uri $uri/ /admin.html; } location / { root /home/silentport.github.io/nginx/blog; index index.html; try_files $uri $uri/ /index.html; } }
其中,
第一個配置是將所有的以/api開頭的請求轉發到node服務器處理;
第二個配置是將所有/admin開頭的請求重定向到admin.html;
第三個配置是將所有的不是以api和admin開頭的請求重定向到index.html,root的配置還可以響應頁面的靜態文件;
這樣一來客戶端訪問就沒什么問題了,刷新頁面也不會404,一切正常,但是管理端訪問依然存在問題,問題是出在當在admin.html中做路由切換,並手動刷新的時候,url中的admin消失,這樣一來nginx會將它重定向到客戶端的頁面。針對這個問題,還需要在admin的頁面中對vue-router增加一個base配置項,讓路由跳轉的時候url始終攜帶這個base,配置如下:
export default new Router({ mode: 'history', base: '/admin', routes: [ ] })
經過上述所有的配置以后,history模式就可以正常使用了。
