如何使用webpack構建多頁面應用,這是一個我一直在想和解決的問題。網上也給出了不少的例子,不少想法。猛一看,以爲有那麼點兒意思,但仔細看也就那樣。css
使用webpack這個構建工具,可使咱們少考慮不少的問題。html
咱們常見的單頁面應用只有一個頁面,它考慮問題,解決問題圍繞着中心化
去解決,所以不少麻煩都迎刃而解。若是你使用過vue.js,那麼想必你必定用過vue-router,vuex,它們就是典型的中心化管理模式,固然還有不少,這裏不一一列舉了。vue
而多頁面應用,咱們不能再按照中心化
模式的路走了,由於行不通,這也是不少人認爲多頁面應用很差作,或者乾脆認爲webapck只能作單頁面應用,而不能作多頁面應用的緣由。webpack
因此,我要說明的第一點兒是:不要用作單頁面應用的思惟來作多頁面應用。git
因此,第一個要解決的問題是:不一樣頁面的代碼塊共享如何實現?github
因此,第二個要解決的問題是:所頁面應用的導航該如何作?web
因此,第三個要解決的問題是:多頁面應用的狀態管理如何作?vue-router
注:這個問題問的其實有點兒傻,若是你作的是dom操做的多頁面兒應用,就不用作狀態管理了。若是你仍是使用想vue.js這樣的庫,你就須要考慮要不要再用作多頁面的狀態管理了,由於此法兒就是爲單頁面應用作的,多頁面兒行不通。vuex
入口(entry):json
webpack對入口不只能夠定義單個文件,也能夠定義多個文件。
熟悉當頁面應用開發的對於下面的代碼應該不會陌生吧?
module.exports = { entry: './src/index.js', ··· }
我第一次接觸真正的單頁面應用項目使用的就是angualrjs,使用的構建工具使webapck+gulp
,其中的webpack.config.js
中的看到的入口文件代碼就是它。
後來,接觸到的是數組形式,代碼以下:
module.exports = { entry: ['./src/index.js', 'bootstrap'] ··· }
這樣,將bootstrap和入口文件一塊兒引用,就能夠在任何一個代碼塊中使用boostrap。
再後來,接觸到的是對象形式,代碼以下:
module.exports = { main: './src/index.js' ··· }
這樣作的目的是爲了給輸出的文件指定特定的名字。
再後來,就是作多頁面應用,就須要用到以下的代碼:
module.exports = { entry: { index: './src/index.js', aboutUs: './src/aboutus.js', contactUs: './src/contactus.js' } }
爲了引入第三方庫,咱們能夠像以下這樣作:
module.exports = { entry: { index: ['./src/index.js', 'loadsh'], aboutUs: './src/aboutus.js', contactUs: ['./src/contactus.js', 'lodash'] } }
但爲了共享模塊代碼,咱們須要像下面這這樣作:
const CommonsChunkPlugin = require('webpack').optimization.CommonsChunkPlugin module.exports = { entry: { index: ['./src/index.js', './src/utils/load.js', 'loadsh'], aboutUs: ['./src/aboutus.js', 'loadsh'], contactUs: ['./src/contactus.js','./src/utils/load.js', 'lodash'] }, plugins: [ new CommonsChunkPlugin({ name: "commons", filename: "commons.js", chunks: ["index", "aboutUs", "contactUs"] }) ] }
這樣型就會造成以下所示的項目目錄結構:
├── src
│ ├── common // 公用的模塊
│ │ ├── a.js
│ │ ├── b.js
│ │ ├── c.js
│ │ ├── d.js
│ ├── uttils // 工具
│ │ ├── load.js // 工具代碼load.js
│ ├── index.js // 主模塊index.js (包含a.js, b.js, c.js, d.js)
│ ├── aboutUs.js // 主模塊aboutus.js (包含a.js, b.js)
│ ├── contactUs.js // 主模塊contactus.js (包含a.js, c.js)
├── webpack.config.js // css js 和圖片資源
├── package.json
├── yarn.lock
可是這個內置插件的侷限性比較大。正如上面所使用的那樣,它只會提取chunks
選項所匹配的模塊共有的代碼塊。就如同上面代碼表示的那樣,它只會提取pindex, aboutUs, contactUs
共有的代碼塊loadsh
,而不會提取index, contactUs
共有的代碼塊load.js
。
固然,通常的第三方庫,咱們也不這樣使用,而是像下面這樣使用:
const CommonsChunkPlugin = require('webpack').optimization.CommonsChunkPlugin module.exports = { entry: { index: ['./src/index.js', './src/utils/load.js'], aboutUs: ['./src/aboutus.js'], contactUs: ['./src/contactus.js','./src/utils/load.js'], vendors: ['lodash'] }, externals: { commonjs: "lodash", root: "_" }, plugins: [ new CommonsChunkPlugin({ name: "commons", filename: "commons.js", chunks: ["index", "aboutUs", "contactUs"] }) ] }
對於web應用最終的目的是:匹配生成不一樣的html頁面。
這裏咱們要使用的就是html-webpack-plugin
。
首先,須要安裝html-webpack-plugin
:
yarn add --dev html-webpack-plugin
而後引入插件,並配置以下:
... const HtmlWebapckPlugin = require('html-webpack-plugin'); ... plugins: [ ... new HtmlWebapckPlugin({ filename: 'index.html', chunks: ['vendors', 'commons', 'index'] }), new HtmlWebapckPlugin({ filename: 'aboutUs.html', chunks: ['vendors', 'commons', 'aboutUs'] }), new HtmlWebapckPlugin({ filename: 'contactUs.html', chunks: ['commons', 'contactUs'] }) ], ...
這樣一個基於webpack3.x的多頁面框架就有了基本的樣子。
而使用webpack4.x則徹底不一樣,它移除了內置的CommonsChunkPlugin
插件,引入了SplitChunksPlugin
插件,這個插件知足了咱們的須要,彌補了CommonsChunkPlugin
的不足。
若是你想要解決以前的不足,去提取index, contacUs
共有的模塊,操做起來會很簡單。正如上面的所列舉的那樣,咱們有三個入口點index, aboutUs, contactUs
,SplitChunksPlugin
插件會首先獲取這三個入口點共有的代碼塊,而後創建一個文件,緊接着獲取每兩個入口點的共有代碼塊,而後將每一個入口點獨有的代碼塊單獨造成一個文件。若是你使用了第三方庫,就像上面咱們使用的loadsh
,它會將第三方入口代碼塊單獨打包爲一個文件。
配置文件webpack.config.js
須要增長以下的代碼:
··· optimization: { splitChunks: { chunks: 'all', maxInitialRequests: 20, maxAsyncRequests: 20, minSize: 40 } } ···
由於SplitChunksPlugin
能夠提取任意的入口點之間的共同代碼,因此,咱們就不須要使用vendors
入口節點了。那麼,爲匹配生成不一樣的頁面代碼能夠修改爲以下:
const HtmlWebapckPlugin = require('html-webpack-plugin') ··· plugins: [ new HtmlWebapckPlugin({ filename: 'index.html', chunks: ['index'] }), new HtmlWebapckPlugin({ filename: 'aboutUs.html', chunks: ['aboutUs'] }), new HtmlWebapckPlugin({ filename: 'contactUs.html', chunks: ['contactUs'] }), ] ···
能夠發現結果愈來愈接近咱們所想。可是這裏仍是存在一個問題,第三方庫loadsh
由於在入口點index, aboutUs
中被分別引入,可是構建的結果卻輸出了兩個第三方庫文件,這不是咱們想要的。這個問題怎麼解決呢,由於html-webpack-plugin
插件的chunks
選項,支持多入口節點,因此,咱們能夠再單首創建一個第三方庫的入口節點vendors
。配置代碼修改以下:
... entry: { index: ['./src/index.js', './src/utils/load.js'], aboutUs: ['./src/aboutUs.js'], contactUs: ['./src/contactUs.js','./src/utils/load.js'], vendors: ['loadsh'] }, ... plugins: [ new HtmlWebapckPlugin({ filename: 'index.html', chunks: ['index', 'vendors'] }), new HtmlWebapckPlugin({ filename: 'aboutUs.html', chunks: ['aboutUs', 'vendors'] }), new HtmlWebapckPlugin({ filename: 'contactUs.html', chunks: ['contactUs'] }), ], ...
注意:若是不一樣的入口點兒之間有依賴關係,如上面的index
和vendors
之間,由於index
依賴於vendors
,因此vendors
要置於index
以前。
這篇文章,說到這裏基本上已經結束了。固然,webpack多頁面應用的知識點尚未講完,這些內容會放在後續的文章中詳解。