天天看點

webpack打包jquery多頁_webpack多頁面打包實踐

前不久從零開始寫了一個webpack多頁面打包boilerplate(webpack4-boilerplate),友善以後工作可以開箱即用,特此記錄下開發過程中的要點。

注意:本文不會詳細介紹webpack的基礎知識,如果完全不會,建議看下我之前寫過的基礎文章

多頁打包的原因

首先發出一個直擊靈魂的拷問:為什麼要多頁面打包?

習慣了React,Vue全家桶的同學,可能覺得寫代碼不就是:npm run dev npm run build一把梭嗎?

然而現實是骨感的,很多場景下,單頁應用的開發模式并不适用。比如公司經常開發一些活動頁:

https://www.demo.com/activity/activity1.html

https://www.demo.com/activity/activity2.html

https://www.demo.com/activity/activity3.html

上述三個頁面是完全不相幹的活動頁,頁面之間并沒有共享的資料。然而每個頁面都使用了React架構,并且三個頁面都使用了通用的彈框元件。在這種場景下,就需要使用webpack多頁面打包的方案了:

保留了傳統單頁應用的開發模式:使用Vue,React等前端架構(當然也可以使用jQuery),支援子產品化打包,你可以把每個頁面看成是一個單獨的單頁應用

獨立部署:每個頁面互相獨立,可以單獨部署,解耦項目的複雜性,你甚至可以在不同的頁面選擇不同的技術棧

是以,我們可以把多頁應用看成是乞丐版的前端微服務。

多頁面打包的原理

首先我們約定:

src/pages目錄下,每個檔案夾為單獨的一個頁面。每個頁面至少有兩個檔案配置:

app.js: 頁面的邏輯入口

index.html: 頁面的html打包模闆

src/pages

├── page1

│ ├── app.js

│ ├── index.html

│ ├── index.scss

└── page2

├── app.js

├── index.html

└── index.scss

前面我們說過:每個頁面可以看成是個獨立的單頁應用。

單頁應用怎麼打包的?單頁應用是通過配置webpack的的entry

module.exports = {

entry: './src/main.js', // 項目的入口檔案,webpack會從main.js開始,把所有依賴的js都加載打包

output: {

path: path.resolve(__dirname, './dist'), // 項目的打封包件路徑

filename: 'build.js' // 打包後的檔案名

}

};

是以,多頁應用隻需配置多個entry即可

module.exports = {

entry: {

'page1': './src/pages/page1/app.js', // 頁面1

'page2': './src/pages/page2/app.js', // 頁面2

},

output: {

path: path.resolve(__dirname, './dist'),

filename: 'js/[name]/[name]-bundle.js', // filename不能寫死,隻能通過[name]擷取bundle的名字

}

}

同時,因為多頁面的index.html模闆各不相同,是以需要配置多個HtmlWebpackPlugin。

注意:HtmlWebpackPlugin一定要配chunks,否則所有頁面的js都會被注入到目前html裡

module.exports = {

plugins: [

new HtmlWebpackPlugin(

{

template: './src/pages/page1/index.html',

chunks: ['page1'],

}

),

new HtmlWebpackPlugin(

{

template: './src/pages/page2/index.html',

chunks: ['page2'],

}

),

]

}

多頁面打包的原理就是:配置多個entry和多個HtmlWebpackPlugin

多頁打包的細節

代碼分割

把多個頁面共用的第三方庫(比如React,Fastclick)單獨打包出一個vendor.js

把多個頁面共用的邏輯代碼和共用的全局css(比如css-reset,icon字型圖示)單獨打包出common.js和common.css

把運作時代碼單獨提取出來manifest.js

把每個頁面自己的業務代碼打包出page1.js和page1.css

前3項是每個頁面都會引入的公共檔案,第4項才是每個頁面自己單獨的檔案。

實作方式也很簡單,配置optimization即可:

module.exports = {

optimization: {

splitChunks: {

cacheGroups: {

// 打包業務中公共代碼

common: {

name: "common",

chunks: "initial",

minSize: 1,

priority: 0,

minChunks: 2, // 同時引用了2次才打包

},

// 打包第三方庫的檔案

vendor: {

name: "vendor",

test: /[\\/]node_modules[\\/]/,

chunks: "initial",

priority: 10,

minChunks: 2, // 同時引用了2次才打包

}

}

},

runtimeChunk: { name: 'manifest' } // 運作時代碼

}

}

hash

最後打包出來的檔案,我們希望帶上hash值,這樣可以充分利用浏覽器緩存。webpack中有hash,chuckhash,contenthash:生産環境時,我們一般使用contenthash,而開發環境其實可以不指定hash。

// dev開發環境

module.exports = {

output: {

filename: 'js/[name]/[name]-bundle.js',

chunkFilename: 'js/[name]/[name]-bundle.js',

},

}

// prod生産環境

module.exports = {

output: {

filename: 'js/[name]/[name]-bundle.[contenthash:8].js',

chunkFilename: 'js/[name]/[name]-bundle.[contenthash:8].js',

},

}

mock和proxy

開發環境,通常需要mock資料,還需要代理api到伺服器。我們可以通過devServer配合mocker-api第三方庫實作。

const apiMocker = require('mocker-api');

// dev開發環境

module.exports = {

devServer: {

before(app) { // 本地mock資料

apiMocker(app, path.resolve(__dirname, '../mock/index.js'))

},

proxy: { // 代理接口

'/api': {

target: 'https://anata.me', // 後端聯調位址

changeOrigin: true,

secure: false,

},

}

},

}

拆分webpack配置

為了通用配置,把webpack的配置檔案分成3份。

build

├── webpack.base.js // 共用部分

├── webpack.dev.js // dev

└── webpack.prod.js // 生産

dev和prod配置的主要差別:

dev配置devServer,友善本地調試開發

prod打包壓縮檔案,單獨提取css (dev不提取是為了css熱更新),生成靜态資源清單manifest.json

關于為什麼要生成一份manifest.json,以及打包後的代碼如何部署,我将會在下一篇文章詳情介紹。

總結

webpack的學習始終是前端繞不過去的一道坎。通過這次從零搭建多頁面打包模闆,也算是鞏固了一下基礎知識,離webpack配置工程師又近了一步。

作者:深紅