使用前端開發的webpack4註解
現在,web開發變得愈發複雜,因此須要引入其餘工具協助咱們開發網站。下面介紹一個現實開發中關於webpack4配置的完整例子。
開發一個現代化的網站已經成爲流行的開發方式。也指望網站提供更多的功能,而不只僅是具備市場的宣傳效果,由於它還具備傳統APP的功能。
一旦系統功能變複雜了,就須要把功能分解成組件,使用工具自動編譯打包。不管是造車,起草法律文件仍是建網站,都是如此。
像webpack這樣的工具已經成爲現代前端開發的首選,緣由如前面描述的:構建複雜的程序。
正如webpack4大加宣揚的幾個特性,最吸引個人恐怕就是更加快速的構建。因此我決定使用它。
打起精神,由於這不只是篇文章,並且幹活慢慢。
試用webpack
幾年前,我發佈過一篇文件《試用Gulp構建前端自動化》,文章詳細介紹了試用Gulp達到這一效果。然而,在開發期間,我對Vuejs還有GraphQL作了大量的研究,在文章《Vuejs和GraphQL實戰》有詳細描述。
我發現webpack使用流行的工具鏈輕易地構建出各類類型的網站和應用。
其餘的選擇:
- Laravel Mix,在webpack基礎上抽象出的層,簡潔易用:快速上手、構建快速,而且能支持客戶近90%的需求。剩下的10%你不管如何都是要詳細研究webpack了。不足的就是還不支持webpack4。
- vue-cli,若是你是vue前端開發者,那麼應該足夠吸引你。這個也是在webpack基礎上的抽象,多數場景下都能工做的很好。可是若是想分離它內置的功能也只能深刻研究webpack了。我不是一直使用Vuejs的。
- Neutino,這是一個構建在webpack基礎的頗有意思的一個抽象,在博文《Neutrino: How I Learned to Stop Worrying and Love Webpack》有詳細的描述。設計理念很不錯,經過將預置的組件平湊在一塊兒來構建webpack配置。
你選擇上面的任何一個(或者是其餘的)我都不會指責你,可是請謹記,他們都有一個共同的特性:webpack的抽象層。
理解在開發系統中各層是如何工做的、效果如何複製代碼
最終,你只須要決定你但願在前端技術金字塔中的位置。有時候,咱們須要理解像webpack這樣重要的工具是如何工做是頗有意義的。
剛纔,我和Sean Larkin(webpack的核心團隊成員)關於webpack像一個「黑盒子」有過爭論,他的回答雖然簡練可是卻直中要害:
他說的很對。如今咱們開始打開這個盒子。
這篇文章不是教你學習webpack或者是怎麼安裝。這已經有不少教程了:
還有不少。這篇文章意在介紹一個至關複雜的webpack4的完整配置。你也可能都用得上;也可能只用一點。仍是但願你們能從中學習一二。
在學習webpack的過程當中,我發現了不少視頻教程,不少知識簡單的安裝和一些基本配置,不是完整的從實際項目出發的webpack 配置項。因此咱們會和盤托出。
從webpack盒子裏咱們能獲得什麼
當我開始打開這個盒子學習webpack時,我列舉了它所依賴的技術列表,我想這能夠成爲構建的一部分。我也曾花時間環顧四周,看看有什麼使用的工具。
像在《A Pretty Website Isn't Enough》討論過的,網站性能是一個常常被關注的核心指標,因此咱們將注意力放到webpack的配置上也是很天然的事情。
從我本身對webpack的需求出發,列舉了一下在構建過程當中使用的技術點:
- Development/Production, 本地開發環境,我指望使用webpack-dev-server在內存中快速構建。發佈構建(一般在Docker容器內完成),我又指望全部可能的優化。所以,須要把dev和prod配置分開。
- Hot Module Replacement,一旦我更改了javascript,css 或者template文件,我但願web頁面能「悄悄」刷新。這種開發速度是驚人的:不須要刷新按鈕。
- Dynamic Code Splitting,我不想在配置文件中定義chunk,但願webpack能替我梳理處理。
- Lazy Loading,又叫異步動態模塊加載。只加載須要的代碼或資源,加載資源不阻塞render。
- Modern& Legacy JS Bundles, 我但願部署支持75%以上瀏覽器的ES2015 module,同時優雅地爲舊版瀏覽器提供後備舊版bundle包(編譯後的代碼和墊片)
- Cache Busting via manifest.json, 支持給靜態資源設置超長的過時時間,即便資源發生改變也能自動緩存。
- Critical CSS,詳細的見《Implement Critical CSS on your website》,使初始頁的加載速度顯著提升。
- Workbox Service Worker,咱們能夠利用Google的Workbox項目生成一個ServiceWorker,以瞭解咱們的靜態資源。PWA,咱們來了。
- PostCSS,能夠當作「Bable of CSS」,在這個基礎上構建出SASS和SCSS,支持即將發佈的CSS特性。
- Image Optimization,在多數的web頁面中圖片佔了最大的一部分,因此使用自動化的工具如mozjpeg,optipng,svgo仍是頗有意義的。
- Automatic.webp Creation,Chrome,Edge和Firefox都已經支持.webp,這是一種比JPEG更加高效的格式。
- Vuejs,vuejs是我前端框架的備選項,我但願可以使用單個文件.vue組件做爲我開發過程的無縫部分。
- Tailwind CSS,Tailwind是一個實用爲先的工具集,本地能快速開發。使用PurgeCSS編譯上線包,並顯著減小包的大小。
看,這是一個多麼有雄心的列表。
還有更多,像自動JavaScript壓縮,CSS壓縮和前端構建系統須要咱們須要的標準工具。
我還但願它與開發團隊合做,開發團隊能夠爲他們的本地開發環境使用不一樣的工具,並使配置易於維護和項目之間的重用。
你的前端框架/技術堆棧可能與個人不一樣,但應用的原則是相同的。 因此請繼續閱讀,不管你使用什麼!
項目目錄樹和代碼組織
咱們先看概覽一下生成的目錄骨架結構:
就核心配置文件而言,咱們有以下配置:
.env
,webpack-dev-server指定的環境配置項,該項不該提交到git庫。
webpack.setting.js
, 一個JSON風格配置文件,這是項目之間惟一須要修改的地方。
webpack.common.js
,兩個環境相同的配置項。
webpack.dev.js
,本地開發環境配置腳本。
webpack.prod.js
,上線環境打包配置腳本
如今用圖片描述下這些都是怎麼配合工做的;
目標就是在項目中應用,你只須要修改黃色圓角矩形部分(.env和webpack.settings.js)。
以這種方式分離出來,使得配置文件的使用變得更加容易。 即便您最終更改了我在此處提供的各類webpack配置文件,保持這種配置方法也有助於長期維護。
不要擔憂,稍後咱們會詳細介紹各個文件。
package.json註解
下面咱們經過分解package.json的方式開始這一過程:
這裏沒有什麼特殊關注的,僅僅是些package.json規範約定的元信息項。
配置兩個腳本,意味着爲咱們的項目支持兩個構建步驟。
- dev,本地什麼時候候運行,都會拉起webpack-dev-server,並之內存方式支持熱模塊替換(HMR)及其餘的特性 。
- build,該命令在生產部署時使用,它完成了生產部署須要完成的全部花哨和耗時的事情,如Critical CSS,JavaScript的壓縮等。
在開發環境中,若是你使用yarn,能夠在Cli命令行執行 yarn dev或者yarn build。若是使用npm,能夠執行npm run dev或npm run build。這僅是兩條運行腳本的命令。
注意到使用 --config 參數,傳遞到多個配置文件中,這使咱們能夠將webpack配置分解爲單獨的邏輯文件,由於與生產版本相比,咱們將爲開發構建作不少不一樣的事情。
下面咱們看browserslist:
這是一個基於人類可讀配置的特定瀏覽器的表。 PostCSS autoprefixer默認使用咱們的生產設置。 咱們將legacyBrowsers和modernBrowsers傳遞給Babel來處理遺留和現代JavaScript包的構建。 稍後會詳細介紹!
下面看devDependencies,這裏指定了構建系統須要的全部的npm包:
這裏有至關多的包,構建過程也確實複雜。
最後,咱們使用denpendencies指定在網站前端要使用的包:
很顯然,一個真實的網站或APP,這個字段中會有不少的依賴包;可是咱們如今只關注構建過程。
webpack.setting.js註解
我曾經用過相同的方法在《A Better package.json for the Frontend artical》,這是爲了鎖定從項目到項目的配置變爲單獨的webpack.settings.js,並保持webpack配置自己不變。
關鍵理念是咱們須要在項目之間編輯的惟一文件是webpack.settings.js複製代碼
由於大部分的項目都具備類似的配置,因此咱們能夠爲多數項目建立一套webpack配置。須要修改的無非就是怎麼操做數據。
所以,咱們的webpack.settings.js文件(項目之間的數據變動)和咱們的webpack配置中的內容(如何操做數據以產生最終結果)之間的關注點分離。
咱們將在webpack配置部分介紹全部這些內容。 這裏須要注意的重要一點是,咱們已經採起了從項目到項目的更改,並將它們從webpack配置中分離出來,並轉換爲單獨的webpack.settings.js文件
這意味着咱們能夠在webpack.settings.js文件中定義每一個項目的不一樣之處,而沒必要對webpack配置頻繁改動。
即便webpack.settings.js文件只是JavaScript,也儘可能將其保留爲JSON風格,因此咱們只是更改其中的簡單設置。 我沒有使用JSON文件格式,也容許添加註釋。
連接常見的WEBPACK配置約定
我爲全部webpack配置文件(webpack.common.js,webpack.dev.js和webpack.prod.js)採用了一些約定,以使配置更加一致。
每一個config文件有兩個內部配置項:
- legacyConfig,該配置項會應用到遺留的ES5構建。
- modernConfig,該配置會應用到現代的ES2015+構建。
咱們這樣作是由於有單獨的配置來建立遺留和現代的構建。 這使它們在邏輯上分開,webpack.common.js也有一個baseConfig; 這純粹是代碼組織要求的。
能夠把它想象成OOP,當多個配置繼承時,baseConfig就是那個基類。
我爲保持配置清晰和可讀而採用的另外一個約定是爲各類webpack插件和須要配置的其餘webpack片斷配置configure()函數,而不是所有內聯。
我這樣作是由於來自webpack.settings.js的一些數據須要在webpack使用以前進行轉換,而且因爲雙重遺留/現代構建系統,咱們須要根據構建類型返回不一樣的配置。
它還使配置文件更具可讀性。
做爲通常的webpack概念,要了解webpack自己只知道如何加載JavaScript和JSON。 要加載其餘任何東西,須要使用加載器。 咱們將在webpack配置中使用許多不一樣的加載器。
webpack.common.js註解
如今讓咱們看一下webpack.common.js配置文件,它包含dev和prod構建類型共享的全部設置。
在前面,咱們引入了須要的Node包,以及咱們使用的webpack插件。 而後咱們將webpack.settings.js導入爲settings,以便訪問定義的設置,並將package.json做爲pkg導入,以便訪問那裏的一些設置。
配置函數
configureBabelLoader()函數以下:
configureBabelLoader函數配置babel-loader處理加載的全部的js文件。使用@babel/preset-env代替.babelrc文件,因此咱們能夠將全部內容保留在咱們的webpack配置中。
Babel能夠編譯現代ES2015+ JavaScript文件(還支持其餘文件如:TypeScript或coffeeScript),編譯成目標瀏覽器能夠識別的代碼。
咱們將browserList做爲參數傳入,這樣咱們就能夠爲舊版瀏覽器構建現代ES2015 +模塊和帶polyfill的傳統ES5 JavaScript。
在HTML文件中,僅僅添加以下:
沒有墊片,沒有小題大作。老款瀏覽器會忽略type="module",加載main-legacy.js。現代瀏覽器加載main.js,會忽略nomudule。這是很是明智的,在vue-cli3中已經採起了這種策略。
@babel/plugin-syntax-dynamic-import插件容許咱們在Web瀏覽器實現ECMAScript動態導入提議以前進行動態導入,這使咱們能夠異步加載JavaScript模塊,並根據須要動態加載。
這個是什麼意思呢?意味着咱們能夠像下面這麼作:
主要作了兩個主要事情:
一、經過/* webpackChunkName: "vue" */ 註釋,已經告訴webpack咱們但願這個動態代碼拆分塊被命名。
二、由於咱們在async main方法中使用import函數,await函數等待動態加載的JavaScript導入的結果,而其他的代碼繼續以其原來的方式執行。
咱們已經告訴webpack但願代碼塊經過代碼分割,而不是經過配置。 經過@ babel / plugin-syntax-dynamic-import的神奇功能,能夠根據須要異步加載此JavaScript塊。
請注意,咱們也使用.vue單個文件組件作了一樣的事情。
除了使用await,咱們還能夠在import後返回的Promise中執行咱們的代碼:
在這裏,咱們使用了Promise,而不是使用await,所以咱們知道動態導入已經生效,能夠愉快地使用Vue了。
若是你關注過相似的問題,就能夠看到咱們經過Promises有效地解決了JavaScript依賴關係。太好了!
咱們甚至能夠在用戶點擊某些內容,滾動到某個位置或知足其餘條件後加載某些JavaScript塊等有趣的事情。 查看
模塊方法import()瞭解更多信息。
接下來咱們看下configureEntries():
在這裏,咱們經過settings.entries從webpack.settings.js中提取webpack入口點。 對於單頁應用程序(SPA),只有一個入口點。 對於更傳統的網站,可能有幾個入口點(每頁模板可能有一個入口點)。
不管哪一種方式,由於咱們已經在webpack.settings.js中定義了咱們的入口點,因此很容易配置。 入口點實際上只是一個<script src =「app.js」> </ script>標籤,咱們將在HTML中加入該標記以啓動JavaScript。
既然咱們使用動態導入模塊,因此在頁面中僅有一個script標籤;剩下的JavaScript按需加載。
下面看下configureFontLoader函數:
dev和prod構建的字體加載是相同的,因此咱們在這裏定義。 對於咱們正在使用的任何本地字體,咱們能夠告訴webpack在JavaScript中加載它們:
import comicsans from '../fonts/ComicSans.woff2';
下面是configureManifest函數:
這會爲基於文件名的緩存清除配置webpack-manifest-plugin。 簡而言之,webpack知道咱們須要的全部JavaScript,CSS和其餘資源,所以它能夠生成一個指向資源的內容哈希名稱的清單
咱們傳入一個文件名,由於咱們建立了一個現代的manifest.json和一個遺留的manifest-legacy.json,它們分別具備現代ES2015 +模塊和傳統ES5模塊的入口點。 對於爲現代和遺留構建而構建的資源,兩個清單中的鍵都是相同的。
接下來看下標準的configureVueLoader:
這只是讓咱們輕鬆加載
Vue單文件組件。 webpack負責爲您提取適當的HTML,CSS和JavaScript。
基本配置
baseConfig與modernConfig和legacyConfig合併:
這裏的全部內容都是很是標準的webpack配置,但請注意咱們將vue $別名爲vue/dist/vue.esm.js,以便咱們能夠得到Vue的ES2015模塊版本。
咱們使用WebpackNotifierPlugin以友好的方式告訴咱們構建的狀態。
遺留瀏覽器配置
legacyConfig用於使用適當的polyfill構建ES5遺留JavaScript:
請注意,咱們把pkg.browserslist.legacyBrowsers傳遞給configureBabel Loader(),而後將'manifest-legacy.json'傳遞給configureManifest()。
在此次編譯中還使用到了CopyWebpackPlugin,因此咱們只須要在settings.copyWebpackConfig中定義一次拷貝文件。
現代瀏覽器配置
modernConfig用來構建現代ES2015 js模塊。
請注意,咱們把pkg.browserslist.modernBrowsers傳遞給configureBabelLoader(),而後把mainfest.json傳遞到configureManifest方法
module.exports
最後,module.exports使用webpack-merge合併配置文件,返回一個對象,能夠在webpack.dev.js和webpack.prod.js中使用。
註釋webpack.dev.js
如今,讓咱們看下webpack.dev.js,該配置文件包含了全部在開發階段須要的build包,它與webpack.common.js中的設置合併,造成一個完整的webpack配置。
在前面,咱們再次引入了須要的Node包,以及使用的webpack插件。 而後咱們將webpack.settings.js導入爲setting,以便咱們能夠訪問那裏的設置,並將package.json做爲pkg導入,以便訪問那裏的一些設置。
咱們還導入webpack.common.js經常使用webpack配置,將合併開發設置。
配置函數
下面是configureDevServer函數實現
進行生產構建時,webpack會捆綁全部各類資源並將它們保存到文件系統中。 相比之下,在本地開發時,經過webpack-dev-server使用開發構建:
- 爲咱們的靜態資源提供服務的本地Express Web服務器
- 爲了提升速度,在內存而不是文件系統中構建咱們的靜態資源
- 將從新構建像JavaScript,CSS,Vue組件等資源,由於咱們更改它們並經過熱模塊替換(HMR)將它們注入網頁而無需從新加載頁面
- 在更改模板時會從新加載頁面
這相似於更復雜的Browsersync變體,並大大加快了開發速度。
惟一有點不經常使用的事情是使用
Sane監視未經過webpack運行的文件(在本例中爲咱們的模板),以便在其中一個更改時執行整頁從新加載。
所以,不要在webpack.settings.js文件中對本地開發環境進行硬編碼(由於它可能因團隊中的人而異),webpack.settings.js能夠從一個可選的.env文件中讀取 擁有特定的devServer配置:
你有可能使用不一樣的配置,所以根據須要在.env文件中根據須要更改設置。 .env背後的思想是在.env文件中放置了一個特定環境配置,咱們不會將它提交到git 庫。 若是.env文件不存在,那很好,它只使用默認值:
咱們還使用PUBLIC_PATH .env變量(若是存在)來容許生成構建的每一個環境。 這樣咱們就能夠進行構建本地生產版本,或者在Docker容器中進行內容分發時構建,該容器使用可經過CDN分發URL構建。
下面看下configureImageLoader方法:
參數傳入buildType,能夠返回不一樣的結果,具體取決於它是遺留構建仍是現代構建。 在這種狀況下,返回相同的配置,但能夠想象到這些可能會改變。
重要的是要注意,這僅適用於webpack構建中包含的圖像; 許多其餘圖像未來自其餘地方(CMS系統,資產管理系統等)。
要讓webpack識別圖像,應先將其導入:
import Icon from './icon.png';
下面看下configurePostcssLoader部分:
咱們使用PostCSS來處理全部CSS,包括Tailwind CSS。 我認爲它是CSS版的Babel,由於它將各類高級CSS功能編譯成瀏覽器能夠解析爲普通CSS。
重要的是要注意,對於webpack加載器,它們按照定義的相反順序進行處理:
請記住,由於這是咱們在本地開發中所作的事情,因此咱們不須要作任何花哨的事情就將全部CSS提取到最小化文件中。 相反,咱們只是讓樣式加載器在html文檔中內聯注入。
webpack-dev-server爲css加載使用Hot Module Replacement(HMR),所以每當更改內容時,它都會從新編譯CSS並自動從新注入。 這有點神奇。
以一下方式導入CSS:
import styles from '../css/app.pcss';
從App.js入口點開始; 將此視爲PostCSS的切入點。 app.pcss文件@imports項目使用的全部CSS; 稍後將詳細介紹。
module.exports
最後,module.exports使用webpack-merge包將webpack.common.js中的common.legacyConfig與開發遺留配置合併,並將common.modernConfig與開發現代配置合併:
module.exports返回一個數組,這就告訴webpack咱們須要完成多個編譯:一個用於遺留構建,另外一個用於現代構建。
須要注意的是遺留構建,輸出的JavaScript文件格式爲[name]-legacy.[hash].js,現代構架的輸出格式爲[name].[hash].js。
經過將mode設置爲「development」,咱們告訴webpack這是一個開發版本。
經過將devtool設置爲'inline-source-map',咱們將CSS / JavaScript的.maps
內聯到文件中。文件雖然變得龐大,但便於調試。
webpack.HotModuleReplacementPlugin支持的熱模塊替換(HMR)。
我發現DashboardPlugin開發HUD比默認的webpack進度滾動更有用。
就是這樣,咱們如今爲項目提供了一個很好的開發構建; 查看熱模塊替換視頻,瞭解此操做的示例:
註解WEBPACK.PROD.JS
如今讓咱們看看webpack.prod.js配置文件,它包含了項目用於生產構建的全部設置。 它與webpack.common.js中的設置合併,造成一個完整的webpack配置。
再次引入了咱們須要的Node包,以及用到的webpack插件。 而後咱們將webpack.settings.js導入爲setting,以即可以訪問裏面的設置,並將package.json做爲pkg導入,以便訪問一些設置。
咱們還導入咱們的webpack.common.js經常使用webpack配置,將合併成開發設置。
Tailwind 提取器
此類是Tailwind CSS的自定義PurgeCSS提取器,容許在類名中使用特殊字符。
這取自Tailwind CSS文檔中刪除未使用的CSS with PurgeCSS部分。 請參閱下文,瞭解此提取器如何與PurgeCSS配合使用,從而神奇地使CSS變得更加整潔。
配置函數
咱們看下configureBanner方法
這只是爲咱們構建的每一個文件添加的含有項目名稱,文件名,做者和git信息的banner。
如今看下configureBundleAnalyzer方法
使用WebpackBundleAnalyzer插件爲咱們的現代和舊版bundle構建生成報告,生成一個自包含的交互式HTML頁面,詳細瞭解由webpack生成的bundle包中的確切內容。
【圖片省略】
我發現幫助保持bundle包大小很是有用,而且確切地瞭解webpack正在構建什麼,因此我已經將它做爲生產構建過程的一部分。
如今看下configureCriticalCss方法:
這裏使用CriticalCssPlugin經過咱們的webpack.settings.js中的settings.criticalCssConfig.pages進行分塊,生成CriticalCSS。
請注意,若是傳入的頁面在其名稱中的任何位置都有settings.criticalCssConfig.ampPrefix,則會經過傳入很是大的高度爲整個網頁(而不只僅是上面的摺疊內容)生成CriticalCSS。
我不會在這裏詳細介紹CriticalCSS; 有關CriticalCSS的更多信息,請查看您網站上的關鍵CSS文章。
下面看下configureCleanWebpack函數
使用CleanWebpackPlugin從webpack.settings.js中刪除settings.paths.dist.base中的構建目錄。
下面是configureHtml函數:
這將HtmlWebpackPlugin與WebappWebpackPlugin(見下文)結合使用,爲咱們的favicons生成HTML。 請注意,咱們在templateContent中傳入一個空字符串,以便輸出只是WebappWebpackPlugin的原始輸出。
下面看configureImageLoader
傳入buildType參數,返回不一樣的結果,具體取決於它是遺留構建仍是現代構建。 這種狀況下,咱們可使用各類圖像優化手段,而後經過img-loader進行構建。
咱們只對現代版本執行此操做,由於花費時間來優化現代版本和舊版本的圖像是沒有意義的(圖像對於二者都是相同的)。
重要的是要注意,這僅適用於咱們的webpack構建中包含的圖像; 許多其餘圖像未來自其餘地方(CMS系統,資產管理系統等)。
以以下方式在JavaScript中導入圖片:
import Icon from './icon.png';
能夠檢出webpack文檔的Loading Image部分進行詳細查看。
如今看configureOptimization方法:
這是咱們配置webpack生產版本優化的地方。 對於遺留構建(兩次沒有任何意義),咱們使用MiniCssExtractPlugin將項目範圍內使用的全部CSS提取到單個文件中。 若是之前使用過webpack,那麼過去是使用了ExtractTextPlugin來執行此操做。
而後,咱們還使用OptimizeCSSAssetsPlugin經過刪除重複規則來優化生成的CSS,並經過cssnano壓縮CSS。
最後,咱們將JavaScript最小化器設置爲TerserPlugin; 這是由於UglifyJsPlugin再也不支持最小化ES2015 + JavaScript。 因爲咱們正在生成ES2015 + bundle包,因此咱們須要它。
看下configurePostcssLoader方法:
這看起來很是相似於configurePostcssLoader()的dev版本,除了最後的加載器,使用MiniCssExtractPlugin.loader將全部的CSS提取到一個文件中。
只對遺留構建執行此操做,由於對每一個構建執行它沒有任何意義(CSS是相同的)。 使用ignore-loader進行現代構建,所以咱們的.css和.pcss文件存在一個加載器,但它什麼也沒作。
如前所述,使用PostCSS處理全部CSS,包括Tailwind CSS。 我認爲它是CSS的Babel,由於它將各類高級CSS功能編譯成瀏覽器能夠識別的普通CSS。
一樣,重要的是要注意,對於webpack加載器,它們按照它們列出的相反順序進行處理:
因爲這是一個生產版本,咱們使用MiniCssExtractPlugin.loader提取全部使用的CSS,並將其保存到單個.css文件中。 CSS也被壓縮的,針對生產進行了優化。
能夠按以下方式導入pcss文件:
import styles from '../css/app.pcss';
這在webpack文檔的Loading CSS部分中有詳細討論。
咱們以App.js入口點開始; 將此視爲PostCSS的切入點。 app.pcss文件@imports咱們項目使用的全部CSS; 稍後將詳細介紹。
下面看下configurePurgeCss函數:
Tailwind CSS是一個出色的實用優先的CSS框架,容許快速原型設計,由於在本地開發中,不多須要實際編寫任何CSS。 相反,只需使用提供的實用程序CSS類。
缺點是生成的CSS可能有點大。 這就是PurgeCSS的用武之地。它將解析全部HTML /模板/ Vue /任何文件,並刪除任何未使用的CSS。
節省的費用可能很大; Tailwind CSS和PurgeCSS是天做之合。 在Tailwind CSS實用程序 - Adam Wathan播客的第一個CSS上深刻探討了這個問題。
它遍歷settings.purgeCssConfig.paths中的全部路徑globs,尋找要保留的CSS規則; 未找到的任何CSS規則都會從咱們生成的CSS構建中刪除。
咱們還使用WhitelisterPlugin,當咱們知道咱們不但願某些CSS被剝離時,能夠輕鬆地將整個文件或全局列入白名單。 與咱們的settings.purgeCssConfig.whitelist匹配的全部文件中的CSS規則都列入白名單,而且永遠不會從生成的構建中剝離。
如今看下configureTerser函數:
這只是配置TerserPlugin使用的一些設置,能夠最小化咱們的遺留和現代JavaScript代碼。
看下configureWebApp函數:
這使用WebappWebpackPlugin以無數種格式生成咱們全部的網站favicon,以及咱們的webapp manifest.json和其餘PWA細節。
它與HtmlWebpackPlugin結合使用,還能夠輸出一個webapp.html文件,其中包含指向全部生成的favicons和相關文件的連接,以包含在咱們的HTML頁面的<head> </ head>中。
下面看下configureWorkbox函數:
Module.exports
最後,module.exports使用webpack-merge將webpack.common.js中的common.legacyConfig與生產遺留配置合併,並將common.modernConfig與生產現代配置合併:
經過在module.exports中返回一個數組,告訴webpack須要完成多個編譯:一個用於咱們的遺留構建,另外一個用於咱們的現代構建。
請注意,對於遺留構建,將處理後的JavaScript輸出爲[name]-legacy.[hash] .js,而現代構建將其輸出爲[name].[hash].js。
經過將mode設置爲'production',告訴webpack這是一個生產版本。 這樣能夠實現適合生產構建的許多設置。
經過將devtool設置爲'source-map',咱們要求將CSS / JavaScript的.maps生成爲單獨的.map文件。 更容易調試實時生產,而無需添加靜態資源的文件大小。
這裏使用了幾個咱們還沒有涉及的webpack插件:
就是這樣,咱們如今爲項目提供了一個很好的生產構建,包括全部的花裏胡哨。
Tailwind css 和PostCSs配置
爲了使webpack正確構建Tailwind CSS和其餘CSS,還須要作一些設置。 感謝個人夥伴Jonathan Melville在構建這方面的工做。 首先咱們須要一個postcss.config.js文件:
這能夠存儲在項目根目錄中; PostCSS將在構建過程當中自動查找它,並應用指定的PostCSS插件。 請注意,這是咱們包含tailwind.config.js文件的位置,以使其成爲構建過程的一部分。
最後,CSS入口點app.pcss看起來像這樣:
顯然,包含了自定義CSS的任意組件/頁面。
生成的項目代碼樹
在html頁面注入script和css標籤
略
總結
嗯,這是一個頗有潛力的工具! 當我第一次開始學習webpack時,就我很快意識到它是一個很是強大的工具,具備很是強大的功能。 你走多遠取決於你想要潛水多遠。
但願這對你有所幫助,享受你的旅程,並作一些使人驚歎的東西!