亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

詳解多頁應用 Webpack4 配置優化與踩坑記錄

2024-05-06 16:46:28
字體:
來源:轉載
供稿:網友

前言

最近新起了一個多頁項目,之前都未使用 webpack4,于是準備上手實踐一下。這篇文章主要就是一些配置介紹,對于正準備使用 webpack4 的同學,可以做一些參考。

webpack4 相比之前的 2 與 3,改變很大。最主要的一點是很多配置已經內置,使得 webpack 能“開箱即用”。當然這個開箱即用不可能滿足所有情況,但是很多以往的配置,其實可以不用了。比如在之前,壓縮混淆代碼,需要增加uglify插件,作用域提升(scope hosting)需要增加ModuleConcatenationPlugin。而在 webpack4 中,只需要設置 mode 為 production即可。當然,如果再強行增加這些插件也不會報錯。

所以我建議,如果大家想遷移到 webpack4,還是從 0 開始做加法,參考歷史,重新做一個配置。而不是從歷史的配置里刪刪減減,再升級為 webpack4。這樣 webpack4 的配置會顯得更精簡。

打包優化

打包優化主要就是多頁應用構建時,對所有頁面加載的依賴進行合理打包。這個目前業界都已經有了很多實踐,包括 webpack4,也有很多文章介紹。我再補充幾個不容易注意的小細節。有些點我不詳細介紹,不熟悉 webpack 配置的同學可能會不明白,可以搜索對應關鍵詞,網上肯定有非常詳細的文章介紹。

首先,構建多頁應用,往往會抽離如下幾個 chunk 包:

  • common:將被多個頁面同時引用的依賴包打到一個 common chunk 中。網上大部分教程是被引入兩次即打入 common。我建議可以根據自己頁面數量來調整,在我的工程中,我設置引入次數超過頁面數量的 1/3 時,才會打入 common 包。
  • dll: 將每個頁面都會引用的且基本不會改變的依賴包,如 react/react-dom 等再抽離出來,不讓其他模塊的變化污染 dll 庫的 hash 緩存。
  • manifest: webpack 運行時(runtime)代碼。每當依賴包變化,webpack 的運行時代碼也會發生變化,如若不將這部分抽離開來,增加了 common 包 hash 值變化的可能性。
  • 頁面入口文件對應的page.js

然后我們會給打出的 chunk 包名,注入 contentHash,以實現最大緩存效果。在我們分 chunk 的過程中,最關鍵的一個思想就是,每次迭代發布,盡量減少 chunk hash 值的改變。這個在業界也有很多非常多的實踐,比如這篇文章:https://github.com/pigcan/blog/issues/9

不過在 webpack4 中,我們不用再增加這么多插件啦,一個 optimization 配置完全就能搞定。

我先貼上我的 webpack 的 optimization 配置,然后我再對其做一些介紹,加深大家印象

const commonOptions = { chunks: 'all', reuseExistingChunk: true}export default { namedChunks: true, moduleIds: 'hashed', runtimeChunk: {  name: 'manifest' }, splitChunks: {  maxInitialRequests: 5,  cacheGroups: {   polyfill: {    test: /[///]node_modules[///](core-js|raf|@babel|babel)[///]/,    name: 'polyfill',    priority: 2,    ...commonOptions   },   dll: {    test: /[///]node_modules[///](react|react-dom)[///]/,    name: 'dll',    priority: 1,    ...commonOptions   },   commons: {    name: 'commons',    minChunks: Math.ceil(pages.length / 3), // 至少被1/3頁面的引入才打入common包    ...commonOptions   }  } }}

runtimeChunk

在 webpack4 之前,抽離 manifest,需要使用 CommonsChunkPlugin,配置一個指定 name 屬性為'manifest'的 chunk。在 webpack4 中,無需手動引入插件,配置 runtimeChunk 即可。

splitChunks

這個配置能讓我們以一定規則抽離想要的包,我們可能會抽好幾個包,如 verdor + common,所以 splitChunks 中提供 cacheGroups 字段,cacheGroups 每增加一個 key,就相當于多一個抽包規則。

在網上很多教程中,dll 往往是專門再加一個 webpack 配置,使用 DllPlugin 來構建 dll 庫,再在自己項目工程的 webpack 中利用 DllReferencePlugin 來映射 dll 庫。雖然這樣構建速度會快不少,但是,哎,是真 TM 煩.....

我是一個很怕煩的人,我情愿在 webpack4 中利用 splitChunks,配好規則,再抽離對應的 dll 包。當然這個大家可以自己根據實際情況選擇方案。

除了 dll 與 common 兩個 chunk,我還加了一個 polyfill。這是因為我們用的某些新的庫或者使用某些 ES6+語法(如 async/await)需要 runtime 墊片。比如我工程中使用了 react16,需要增加Map/Set/requestAnimationFrame (https://reactjs.org/docs/javascript-environment-requirements.html)那我必須在 dll 庫加載之前增加 polyfill,因此我將所有 core-js 與 babel 引入的包專門打進 polyfill,保證后續加載的 chunk 能執行。priority字段用來配置 chunk 的引入優先級,一般的項目應該都是 polyfill > dll > common > page。

splitChunks 中配置項maxInitialRequests表示在一個入口(entry)中,最大初始請求 chunk 數(不包含按需加載的,即 dom 中 script 引入的 chunk),默認值是 3。我現在 cacheGroups 中已經有三個,又因為配置了 runtimeChunk,會打出 manifest,故而總共有 4 個 chunk 包,超出了默認 3 個,因此需要重新配置值。

moduleIds

稍微了解過 webpack 運行機制的同學會知道,項目工程中加載的 module,webpack 會為其分配一個 moduleId,映射對應的模塊。這樣產生的問題是一旦工程中模塊有增刪或者順序變化,moduleId 就會發生變化,進而可能影響所有 chunk 的 content hash 值。只是因為 moduleId 變化就導致緩存失效,這肯定不是我們想要的結果。

在 webpack4 以前,通過 HashedModuleIdsPlugin 插件,我們可以將模塊的路徑映射成 hash 值,來替代 moduleId,因為模塊路徑是基本不變的,故而 hash 值也基本不變。

但在 webpack4 中,只需要optimization的配置項中設置 moduleIds 為 hashed 即可。

namedChunks

除了 moduleId,我們知道分離出的 chunk 也有其 chunkId。同樣的,chunkId 也有因其 chunkId 發生變化而導致緩存失效的問題。由于manifest與打出的 chunk 包中有chunkId相關數據,所以一旦如“增刪頁面”這樣的操作導致 chunkId 發生變化,可能會影響很多的 chunk 緩存失效。

在 webpack4 以前,通過增加NamedChunksPlugin,使用 chunkName 來替換 chunkId,實現固化 chunkId,保持緩存的能力。在 webpack4 中,只需在optimization的配置項中設置 namedChunks 為 true 即可。

css 相關

在 webpack4 以前,使用 extract-text-webpack-plugin 插件將 css 從 js 包中分離出來單獨打包。在 webpack 中則需要換成 MiniCssExtractPlugin。并且在生產環境或者需要 HMR(模塊熱替換)時,要用 MiniCssExtractPlugin.loader 替換 style-loader。

注意,這里有個坑。由于開發環境我們會配置熱更新,css 的熱更新目前MiniCssExtractPlugin.loader自身還待支持,故而還需要增加 css-hot-loader。 切記,css-hot-loader一定不能在生產環境下使用。否則每次構建過程所有 js chunk 包的 contentHash 值都會不一致,進而導致所有 js 緩存失效。 因為生產環境增加這個配置不會有任何報錯,頁面也能正常構建,故而容易忽視。

簡化多頁應用的入口文件

使用react/vue等框架的同學知道,我們一般需要一個入口index.js,如這樣:

import React from 'react'import ReactDOM from 'react-dom'import App from './app'ReactDOM.render(<App />, document.getElementById('root'))

如果你還需要使用dva,或者給所有 react 頁面增加一個 layout 功能的話,可能就會變成這樣:

import React from 'react'import dva from 'dva'import Model from './model'import Layout from '~@/layout'import App from './app'const app = dva()app.router(() => ( <Layout>  <App /> </Layout>))app.model(Model)app.start(document.getElementById('root'))

如果每個頁面都這樣,略略有點兒難受,因為程序員最怕寫重復的東西了。但是它又必須要有,沒辦法抽離成一個單獨文件。因為這個是入口文件,而多頁工程,每個頁面必須要有自己的入口文件,即使他們長得一模一樣。于是,我們的資源目錄就會是這樣:

- src - layout.js - pages  - pageA   - index.js   - app.js   - model.js  - pageB   - index.js   - app.js   - model.js

因為所有的 index 都一樣,我理想中的頁面的入口文件僅僅需要app.js就好,像這樣:

- src - layout.js - pages  - pageA   - app.js   - model.js  - pageB   - app.js   - model.js

作為一名前端開發工程師,Node 對于我們來說,應該是熟練運用的工具,而不是僅僅拿別人已經封裝好的各類工具。

在這個問題中,我們大可以在 webpack 構建前,通過Node的文件系統(File System),對應我們的每個頁面,通過同一個入口文件模板,創建一些臨時入口文件:

- src - .entires  - pageA.js  - pageB.js - layout.js - pages

然后將這些臨時文件,作為 webpack 的 entry 配置。代碼如下:

const path = require('path')const fs = require('fs')const glob = require('glob')const rimraf = require('rimraf')const entriesDir = path.resolve(process.cwd(), './src/.entries')const srcDir = path.resolve(process.cwd(), './src')// 返回webpack entry配置module.exports = function() { if (fs.existsSync(entriesDir)) {  rimraf.sync(entriesDir) } fs.mkdirSync(entriesDir) return buildEntries(srcDir)}function buildEntries(srcDir) { return getPages(srcDir).reduce((acc, current) => {  acc[current.pageName] = buildEntry(current)  return acc }, {})}// 獲取頁面數據,只考慮一級目錄function getPages(srcDir) { const pagesDir = `${srcDir}/pages` const pages = glob.sync(`${pagesDir}/**/app.js`) return pages.map(pagePath => {  return {   pageName: path.relative(pagesDir, p).replace('/app.js', ''), // 取出page文件夾名   pagePath: pagePath  } })}// 構建臨時入口文件function buildEntry({ pageName, pagePath }) { const fileContent = buildFileContent(pagePath) const entryPath = `${entriesDir}/${pageName}.js` fs.writeFileSync(entryPath, fileContent) return entryPath}// 替換模板中的 App 模塊地址,返回臨時入口文件內容function buildFileContent(pagePath) { return `  import React from 'react'  import dva from 'dva'  import Model from './model'  import Layout from '~@/layout'  import App from 'PAGE_APP_PATH'  const app = dva()  app.router(() => (   <Layout>    <App />   </Layout>  ))  app.model(Model)  app.start(document.getElementById('root')) `.replace(PAGE_APP_PATH, pagePath)}

這樣一來,我們就簡單的去掉了重復的入口文件,還增加了一個 layout 的功能。這只是簡單的代碼,實際項目可能還有多級目錄,多個 model 等等,需要自己再定制啦。

webpack4出來已經挺久了,文章寫的有點兒滯后了,所以很多我覺得應該大家都明白的地方就沒詳細寫了。如果還有什么疑問的話,歡迎評論~~

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲欧美日韩直播| 4438全国成人免费| www.亚洲免费视频| 久久精品国产成人| 在线成人激情视频| 性欧美暴力猛交69hd| 久久这里只有精品视频首页| 九九热这里只有精品6| 久久久久久久999精品视频| 亚洲精品黄网在线观看| 亚洲免费av片| 亚洲第五色综合网| 成人黄色短视频在线观看| 日韩欧美亚洲范冰冰与中字| 亚洲资源在线看| 日韩成人激情影院| 久久精品国产久精国产一老狼| 一区二区三区无码高清视频| 中文在线不卡视频| 欧美大胆a视频| 国产精品电影久久久久电影网| 热门国产精品亚洲第一区在线| 亚洲天堂男人天堂| 欧美日韩中文在线| 日本精品久久中文字幕佐佐木| 亚洲午夜激情免费视频| 亚洲毛片在线看| 美日韩精品免费视频| 中文字幕日韩在线视频| 日韩欧美国产高清91| 亚洲xxxxx性| 精品美女久久久久久免费| 欧美日本啪啪无遮挡网站| 一个人www欧美| 成人h视频在线观看播放| 欧美成人免费全部观看天天性色| 久久综合国产精品台湾中文娱乐网| 亚洲成人三级在线| 综合国产在线观看| 欧美激情在线观看视频| 欧美国产在线电影| 久久国产精品99国产精| 欧美激情性做爰免费视频| 精品无码久久久久久国产| 成人国产在线激情| 欧洲成人在线观看| 成人黄色在线观看| 国产精品嫩草影院一区二区| 亚洲成年人在线| 夜色77av精品影院| 久久综合久久美利坚合众国| 国产精品偷伦一区二区| 最近2019年手机中文字幕| 日韩电影免费观看中文字幕| 欧洲中文字幕国产精品| 欧美一级淫片videoshd| 日韩美女在线看| 不卡av电影在线观看| 国产婷婷色综合av蜜臀av| 亚洲精品成人免费| 日韩国产在线播放| 国产啪精品视频| 国产精品视频成人| 欧美美最猛性xxxxxx| 日韩欧美一区二区三区久久| 久久亚洲精品成人| 亚洲成人xxx| 欧美激情一区二区三级高清视频| www.xxxx精品| 日韩经典一区二区三区| 亚洲美女av在线| 日韩av第一页| 亚洲精品一二区| 久久久精品在线观看| 中文字幕日韩av综合精品| 国产精品一区专区欧美日韩| 国产+成+人+亚洲欧洲| 欧美黑人视频一区| 91麻豆国产精品| 国产在线播放91| 国产一区二区三区直播精品电影| 日韩二区三区在线| 国内自拍欧美激情| 亚洲综合社区网| 亚洲成人久久电影| 黑人精品xxx一区| 97在线看免费观看视频在线观看| 一区二区三区视频免费在线观看| 亚洲精品日韩激情在线电影| 欧美韩日一区二区| 亚洲一区二区三区四区视频| 清纯唯美亚洲激情| 97视频免费在线观看| 久久国产精品久久久久久| 欧美精品福利在线| 国产精品嫩草影院一区二区| www.日韩视频| 国产日韩在线看| 亚洲国产精品久久久久久| 免费av一区二区| 日韩精品日韩在线观看| 亚洲视频一区二区| 日韩中文字幕在线看| 亚洲午夜精品久久久久久性色| 九九热最新视频//这里只有精品| 亚洲精品欧美极品| 国产v综合v亚洲欧美久久| 91九色蝌蚪国产| 日本不卡高字幕在线2019| 亚洲第一精品夜夜躁人人躁| 亚洲成人久久电影| 亚洲精品99久久久久中文字幕| 日韩成人在线电影网| 91精品久久久久久久久久久久久| 在线视频精品一| 国产玖玖精品视频| 国产精品成人免费视频| 精品福利樱桃av导航| 国产日韩欧美中文| 在线性视频日韩欧美| 激情久久av一区av二区av三区| 国产精品日韩欧美| 国产精品免费一区二区三区都可以| 国语自产精品视频在线看| 日韩黄色在线免费观看| 国产日韩在线免费| 久久久久久久久久久久久久久久久久av| 97久久久免费福利网址| 色偷偷噜噜噜亚洲男人| 国产精品第一区| 亚洲精品mp4| 最新的欧美黄色| 一本色道久久综合狠狠躁篇怎么玩| 国产精品丝袜白浆摸在线| 亚洲男人天堂久| 97热精品视频官网| 亚洲黄色在线看| 亚洲欧美另类中文字幕| 国产精品大陆在线观看| 日韩免费观看av| 亚洲丝袜在线视频| 亚洲一区二区三区四区视频| 亚洲欧美另类人妖| 91免费综合在线| 国产亚洲人成a一在线v站| 久久91精品国产91久久久| 国产91在线播放九色快色| 成人亚洲欧美一区二区三区| 日韩欧美在线第一页| 日韩欧中文字幕| 国产精品专区h在线观看| 在线日韩中文字幕| 亚洲欧美日韩爽爽影院| 欧美激情中文字幕乱码免费| 精品国产乱码久久久久久婷婷| 91成人免费观看网站| 欧美一级视频免费在线观看| 亚洲精品电影网在线观看| 国产亚洲精品成人av久久ww| 成人美女免费网站视频| 日本国产高清不卡| 26uuu亚洲伊人春色| 欧美插天视频在线播放| 日韩国产高清视频在线|