vue-cli3.0 多頁面配置

舞動乾坤發表於2018-08-16

前言

vue-cli是Vue.js官方推出的腳手架,它功能豐富、擴充套件性強,為Vue應用開發帶來了極大的便捷,它提供了多種開發正規化,詮釋了開箱即用。vue-cli@3版本經歷了alpha、beta、rc版本近7個月的迭代開發,在最近幾天正式版終於釋出,本文主要講解如何使用vue-cli建立一個多入口工程,若要近一步瞭解vue-cli,請訪問官方文件

什麼是多頁應用

單頁應用(SPA)往往只含有包含一個主入口檔案與index.html,頁面間切換通過區域性重新整理資源來完成。而在多頁應用中,我們會為每個HTML文件檔案都指定好一個JS入口,這樣一來當頁面跳轉時使用者會獲得一個新的HTML文件,整個頁面會重新載入。

單頁應用、多頁應用的優劣勢在此就不進行分析了,總而言之,多頁架構模式暫時是無法取代的,如果嘗試把幾十個不關聯的頁面做成一個,那麼開發成本會非常大的,Not every app has to be an SPA

初始化專案

首先我們安裝好vue-cli腳手架,並初始化一個預設工程. 修改專案目錄:

.
├── 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可以實現,可是這種修改方式還不是直接修改原生構建配置更快,那麼還有其他解決方法嗎?

vue.config.js 配置

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"			
			};
		}
	}
}
複製程式碼

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


複製程式碼

原始碼部分

@vue/cli-service通過判斷是否傳入pages引數來生成對應Webpack配置檔案,讓我們先來看看沒有傳入時的處理函式:

   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檔案,而在多入口模式下,程式碼的邏輯也很簡單,在此就不貼原始碼了,它會執行以下步驟:

  1. 清除原有entry
  2. 對pages欄位的每個key做迴圈,解析每個入口物件的引數entry(必填)、title、template、filename、chunks
  3. 通過entry欄位生成webpack的entry入口
  4. 通過其餘引數生成對應的html-webpack-plugin,若不為傳統模式,也會生成對應入口的preload外掛與prefetch外掛

區域性優化

移除prefetch

由於本人並不喜歡為將來做打算,因此並不希望預載入一些可能會用到的asyncChunk,因為會浪費掉一些頻寬,而且在多頁面中並不見得預載入其他入口的檔案是一件好事情,於是我們通過chainWebpack進行刪除:

modules.exports = {
	// ...
  chainWebpack: config => {
    Object.keys(pages).forEach(entryName => {
      config.plugins.delete(`prefetch-${entryName}`);
    });
  }
}
複製程式碼

關閉SourceMap

關閉之後不僅能加快生產環境的打包速度,也能避免原始碼暴露在瀏覽器端:

modules.exports = {
	// ...
    productionSourceMap: false,
}
複製程式碼

打包分類(強迫症患者福音)

首先回顧一下dist中的部分資料夾:

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


複製程式碼

相關文章