vue-cli是Vue.js官方推出的腳手架,它功能豐富、擴展性強,爲Vue應用開發帶來了極大的便捷,它提供了多種開發範式,詮釋了開箱即用。vue-cli@3版本經歷了alpha、beta、rc版本近7個月的迭代開發,在最近幾天正式版終於發佈,本文主要講解如何使用vue-cli建立一個多入口工程,若要近一步瞭解vue-cli,請訪問官方文檔。css
單頁應用(SPA)每每只含有包含一個主入口文件與index.html,頁面間切換經過局部刷新資源來完成。而在多頁應用中,咱們會爲每一個HTML文檔文件都指定好一個JS入口,這樣一來當頁面跳轉時用戶會得到一個新的HTML文檔,整個頁面會從新加載。html
單頁應用、多頁應用的優劣勢在此就不進行分析了,總而言之,多頁架構模式暫時是沒法取代的,若是嘗試把幾十個不關聯的頁面作成一個,那麼開發成本會很是大的,Not every app has to be an SPA。vue
首先咱們安裝好vue-cli腳手架,並初始化一個默認工程. 修改項目目錄:webpack
.
├── assets
│ └── logo.png
├── components
│ ├── About.vue
│ ├── HelloWorld.vue
│ └── Home.vue
├── pages
│ ├── page1
│ │ ├── page1.html
│ │ ├── page1.js
│ │ └── page1.vue
│ └── page2
│ ├── page2.html
│ ├── page2.js
│ └── page2.vue
└── style
├── common.css
└── common.less
複製代碼
vue.config.js是一個可選文件,用戶須要自行建立,它會被@vue/cli-service
讀取。當正確添加配置後,重啓一下項目,測試一下項目在改變目錄結構後可否正常運行。試想一下,若照着這個思路進行配置多入口,那麼首先須要刪除或修改掉原有webpack配置項,而後還需添加多入口的一些插件,雖然經過腳手架對外提供的API能夠實現,但是這種修改方式還不是直接修改原生構建配置更快,那麼還有其餘解決方法嗎?web
let path = require('path')
let glob = require('glob')
//配置pages多頁面獲取當前文件夾下的html和js
function getEntry(globPath) {
let entries = {},
basename, tmp, pathname, appname;
glob.sync(globPath).forEach(function(entry) {
basename = path.basename(entry, path.extname(entry));
// console.log(entry)
tmp = entry.split('/').splice(-3);
console.log(tmp)
pathname = basename; // 正確輸出js和html的路徑
// console.log(pathname)
entries[pathname] = {
entry: 'src/' + tmp[0] + '/' + tmp[1] + '/' + tmp[1] + '.js',
template: 'src/' + tmp[0] + '/' + tmp[1] + '/' + tmp[2],
title: tmp[2],
filename: tmp[2]
};
});
return entries;
}
let pages = getEntry('./src/pages/**?/*.html');
console.log(pages)
//配置end
module.exports = {
lintOnSave: false, //禁用eslint
baseUrl:process.env.NODE_ENV === "production"?'https://www.mycdn.com/':'/',
productionSourceMap: false,
pages,
devServer: {
index: 'page1.html', //默認啓動serve 打開page1頁面
open: process.platform === 'darwin',
host: '',
port: 8088,
https: false,
hotOnly: false,
proxy: {
'/xrf/': {
target: 'http://reg.tool.hexun.com/',
changeOrigin: true,
pathRewrite: {
'^/xrf': ''
}
},
'/wa/': {
target: 'http://api.match.hexun.com/',
changeOrigin: true,
pathRewrite: {
'^/wa': ''
}
}
}, // 設置代理
before: app => {}
},
chainWebpack: config => {
config.module
.rule('images')
.use('url-loader')
.loader('url-loader')
.tap(options => {
// 修改它的選項...
options.limit = 100
return options
})
Object.keys(pages).forEach(entryName => {
config.plugins.delete(`prefetch-${entryName}`);
});
if(process.env.NODE_ENV === "production") {
config.plugin("extract-css").tap(() => [{
path: path.join(__dirname, "./dist"),
filename: "css/[name].[contenthash:8].css"
}]);
}
},
configureWebpack: config => {
if(process.env.NODE_ENV === "production") {
config.output = {
path: path.join(__dirname, "./dist"),
filename: "js/[name].[contenthash:8].js"
};
}
}
}
複製代碼
├── css
│ ├── page1.9951d5a1.css
│ └── page2.009d0d6f.css
├── img
│ └── logo.82b9c7a5.png
├── js
│ ├── chunk-vendors.f061f10e.js
│ ├── page1.5a5322e0.js
│ └── page2.db57562b.js
├── page1.html
└── page2.html
複製代碼
@vue/cli-service經過判斷是否傳入pages參數來生成對應Webpack配置文件,讓咱們先來看看沒有傳入時的處理函數:vue-cli
if (!multiPageConfig) {
// default, single page setup.
htmlOptions.template = fs.existsSync(htmlPath)
? htmlPath
: defaultHtmlPath
webpackConfig
.plugin('html')
.use(HTMLPlugin, [htmlOptions])
if (!isLegacyBundle) {
// inject preload/prefetch to HTML
...
}
}
複製代碼
由源碼可知,pages參數可用於生成三個插件:preload-plugin、prefetch-plugin、html-plugin,若不傳html文件則會使用一個只空的默認html文件,而在多入口模式下,代碼的邏輯也很簡單,在此就不貼源碼了,它會執行如下步驟:api
因爲本人並不喜歡爲未來作打算,所以並不但願預加載一些可能會用到的asyncChunk,由於會浪費掉一些帶寬,並且在多頁面中並不見得預加載其餘入口的文件是一件好事情,因而咱們經過chainWebpack進行刪除:瀏覽器
modules.exports = {
// ...
chainWebpack: config => {
Object.keys(pages).forEach(entryName => {
config.plugins.delete(`prefetch-${entryName}`);
});
}
}
複製代碼
關閉以後不只能加快生產環境的打包速度,也能避免源碼暴露在瀏覽器端:bash
modules.exports = {
// ...
productionSourceMap: false,
}
複製代碼
首先回顧一下dist中的部分文件夾:架構
├── css
│ ├── page1.9951d5a1.css
│ └── page2.009d0d6f.css
├── img
│ └── logo.82b9c7a5.png
├── js
│ ├── chunk-vendors.f061f10e.js
│ ├── page1.5a5322e0.js
│ └── page2.db57562b.js
├── page1.html
└── page2.html
複製代碼