如果此篇對您有所幫助,在此求一個star。專案地址: OrcasTeam/my-cli
接下來介紹一個打包編譯過程中一個極為重要的工具--babel。
ES6的枷鎖
細心的朋友可以知道,在之前打包編譯測試都是使用簡單的ES5特性,
並沒有使用過ES6(ES2015+)特性(import除外)
這是因為webpack本身不會處理程式碼中的ES6(ES2015+)特性,所以也就沒有使用。
先來做一個測試
在 /src/index.js 檔案使用部分ES6(ES2015+),檢視打包編譯程式碼會發現webpack並沒有處理ES6(ES2015+)特性。
自從ES6(ES2015+)時代來臨後,前端才具有了飛速發展。ES6(ES2015+)各種特性也給開發人員帶來了便利。
毫不客氣的說,沒有人再想寫ES5程式碼了。
但是,前端程式碼的執行環境(瀏覽器)是由使用者決定的,如果使用者一直使用舊版本瀏覽器,那麼新特性就無法執行在使用者瀏覽器中。
這時候就需要一種工具:將程式碼使用的ES6(ES2015+)特性轉換為ES5特性
這個工具就叫做:babel
?? ? webpack作為一個打包器。為babel提供了擴充套件支援。
?? ES6是ES2015+所有版本統稱 有的文章會寫成ES7、ES8。但其實都是ES6。
? 上面程式碼使用到了ES6的 Promise型別、塊級宣告(const)、箭頭函式、for-of語法、陣列API、await屬性,不瞭解ES6的朋友可以學習阮一峰老師的ES6入門教程
babel
babel介紹
ES6來臨後,前端開啟了百花綻放的時代。從而也導致了ES6轉ES5的工作並不僅僅侷限於JS語言的原始特性。
例如:Typescript、JSX語法等等。
這些都可以使用babel進行處理。
babel的設計思想也與webpack一致:提供核心引擎 + 外掛化的模式管理
babel提供了一個核心引擎庫:@babel/core 和 擴充套件外掛庫配置。
@babel/cli
babel 其實並不是webpack一個擴充套件外掛,它是一個獨立的工具。可以進行單獨配置、執行。
babel提供了一個@babel/cli庫,與webpack-cli庫一樣,允許命令列直接執行babel
{
"scripts": {
"build": "babel src -d lib"
}
}
在此就不介紹@babel/cli這一塊的內容了,有興趣的朋友可以去官網學習
??? babel作為一個獨立工具,理論可以配置在所有打包器中。
babel-loader
babel作為一個獨立的工具,那麼肯定不能直接配置在webpack中。
那麼想要babel執行在webpack,就必須提供一個介面卡,來橋接兩個庫。
而這個介面卡就是babel-loader。
babel-loader在webpack執行時攔截需要轉換檔案,將檔案先交給babel進行轉換,然後再傳回webpack執行接下來的操作。
而babel-loader只是呼叫了@babel/core庫中的API。最後執行的還是@babel/core引擎
下面先安裝babel-loader和@babel/core
yarn add -D babel-loader@8.2.2 @babel/core@7.13.1
然後在webpack.config.js中配置所有的js檔案都使用babel-loader進行轉換。
{
module:{
rules:[
{
// 所有的.js檔案都走babel-loader
test:/\.js$/,
include: path.join(config.root,'src'),
loader: "babel-loader",
}
]
},
}
? babel@6.X版本時,核心引擎庫名為babel-core。從babel@7.X版本之後,官方對庫名稱做了統一的修改,官方提供的包都以@babel/冠名,所以babel-core和@babel/core實際上是一個庫 。有興趣朋友可以在NPM中對比下兩個包的版本 :@babel/core、babel-core
?後面會陸續加入其它檔案執行babel-loader。例如:.ts、.jsx
但是目前依然無法轉換ES6(ES2015+)程式碼。因為只新增了引擎(@babel/core),並沒有新增具體轉換庫。
@babel/preset-env
先來介紹一下@babel/preset-env庫,來完成部分轉換功能。
@babel/preset-env是babel 預設的一個plugin
yarn add -D @babel/preset-env@7.13.5
在配置loader時,可以設定當前loader使用的屬性和依賴庫。babel-loader具有一個presets屬性來依賴的預設外掛(preset)
{
module:{
rules:[
{
// 所有的.js檔案都走babel-loader
test:/\.js$/,
include: path.join(config.root,'src'),
loader: "babel-loader",
options: {
presets:[
"@babel/preset-env",
]
}
}
]
}
}
?? presets的執行是從後往前執行的,官方說為了確保向後相容
? presets配置可以設定短名稱,
- preset庫名稱以 babel-preset- 字首,可以省去字首。 例如:babel-preset-my-custom,可以直接設定為:custom
- 短名稱也適用於冠名,例如:@org/preset-env,可以設定為:@org/env
此時執行yarn build
操作後生成的程式碼就會處理部分ES6(ES2015+)
生成程式碼中可以看到:await、for-of、const 這些ES6程式碼被轉換了。
? 程式碼中的那堆 case 語句,是await ES5的寫法。await 本質只是一個 將非同步同步化的狀態機。不熟悉 await 機制的朋友可以忽略,只需知道程式碼為await語法ES5寫法即可。
但細心的朋友可以發現,並不是所有的ES6特性被轉換了。
還有部分ES6特性並沒有被轉換(promise、includes、filter),並且程式碼被一個箭頭函式包裹著。
程式碼被箭頭函式包裹這個問題稍後在解決。
先來了解下為什麼有的ES6特性沒有被轉換。
? @babel/preset-env取代了preset-es20系列的預設外掛(preset)
目前生成程式碼還無法在瀏覽器執行,缺少regeneratorRuntime,這個稍後再說
Syntax和API
思考一個問題:剛才被轉換的ES6特性與未被轉換的ES6特性有何不同。
答案是被轉換的ES6特性是Syntax(語法),而未被轉換的則是:API(型別、函式)
babel處理ES6特性時將Syntax(語法)和API(型別、函式)進行了分開處理。
為什麼要這樣做呢?
原因是兩者本質的不同:Syntax(語法)是一個語言本身客觀存在的事實,而API(型別、函式),則只是對一系列操作的封裝
當執行環境不支援某Syntax(語法)時,那麼就只能使用其它Syntax(語法)進行替換。
而執行環境中不存在某API(型別、函式)時,可以編寫自定義API(型別、函式)進行替換。
? JS中Syntax(語法)錯誤提示是:Uncaught SyntaxError;API(型別、函式)錯誤提示是:Uncaught ReferenceError。
@babel/preset-env只是babel提供處理Syntax(語法)的預設外掛(preset)
至於API(型別、函式)的處理,則是由其它外掛處理,這個外掛俗稱:墊片、膩子。
babel配置形式
在處理API(型別、函式)之前,先介紹下babel配置檔案。
剛才在配置@babel/preset-env時,直接配置在了babel-loader中presets屬性。
除了babel-loader,babel還支援其它方式配置
package.json
@babel/core支援在package.json檔案設定
package.json檔案babel屬性設定babel 外掛
@babel/core執行時會嘗試讀取此屬性。
"babel": {
"presets": [
"@babel/preset-env"
],
"plugins": [
]
}
配置檔案
babel支援使用配置檔案設定。
這種方式與webpack.config.js檔案一樣,使用.約定檔名稱設定。@babel/core執行時會嘗試讀取.約定檔案。
約定檔名稱 可以為 babel.config.js 或 .babelrc.json 。 較為常用的是 .babelrc.json 。不過一般都會省略字尾, 名稱叫做 .babelrc
package.json形式和配置檔案形式 只能選擇一種形式設定。如果同時存在會直接報錯。
babel-loader配置方式優先順序高於其他兩種方式
引數設定
在使用plugin/preset時,可以設定屬性。
不過引數形式有些奇葩。
plugin/preset與引數存在於一個陣列內,第一個為plugin/preset,第二個為屬性物件
{
"presets": [
["@babel/preset-env", {
"targets": "defaults"
}]
],
"plugins": [
]
}
??? 以下會使用配置檔案方式,所以一定要把babel-loader中的設定刪除掉。否則會因為優先順序問題而失效。:我就因為這個疏漏曾經被耽誤了一天
轉換API(型別、函式)
設定低版本瀏覽器
在轉換API(型別、函式)時要進行測試。
而開發人員基本上使用的都是新版瀏覽器,所以需要具有一個不支援ES6API(型別、函式)的瀏覽器。
一般ES6的新特性,都已經不再支援IE瀏覽器了。所以IE瀏覽器是一個天然的測試物件。
例如ES6Promise型別,就不再支援IE瀏覽器
win 10系統攜帶的IE瀏覽器版本一般都為IE11。IE瀏覽器支援對版本進行修改IE瀏覽器
F12-開發者模式--模擬--文件模式 可以修改IE瀏覽器版本,在這裡使用的版本為IE9
處理箭頭函式包裹
在剛才打包編譯時,發現生成的程式碼使用了一個箭頭函式包裹。
這個箭頭函式函式懷疑是打包時webpack搞得鬼,具體原因沒排查,在這裡只介紹下處理方案。
在package.json檔案中新增browserslist屬性,設定打包程式碼支援IE9瀏覽器。
"browserslist": [
"ie 9"
]
? browserslist屬性是browserslist庫提供的一個屬性,browserslist是提供瀏覽器版本支援的庫。多個庫中都依賴了browserslist。 browserslist庫詳情在下一篇介紹。
此時使用yarn build
執行打包編譯,生成程式碼就不再由箭頭函式包裹
regenerator-runtime和core-js
regenerator-runtime
介紹下關於之前打包程式碼缺少 regeneratorRuntime() 問題。
regeneratorRuntime() 是由regenerator-runtime庫提供的,
regenerator-runtime庫是一個轉換ES6中 generator函式、await函式 功能的庫。babel直接使用此庫處理兩種函式。
core-js
很多文章介紹時regenerator-runtime都與core-js一起介紹。所以在此也將這兩個庫放在一起介紹。
處理ES6 API(型別、函式)的解決方案在上面介紹過。
當執行環境中不存在某API(型別、函式)時,可以使用自定義API(型別、函式)進行替代。
而core-js庫就是一個自定義的API(型別、函式)庫。也就是俗稱的膩子
core-js是 個人開源專案,並不屬於任何公司。
babel直接使用了core-js進行處理API(型別、函式)
core-js截至到編寫文章時的最新版本為@3.9.0
core-js的@3.X與@2.X兩個大版本間具有巨大的差異性,以至於影響到了babel。不過目前基本都是使用core-js@3.X版本。
? core-js開發者目前在開發core-js@4.X版本。可能到時候配置又會具有大變化。
@babel/polyfill
關於babel的文章中,有很多都會介紹@babel/polyfill。
@babel/polyfill庫其實就是babel對core-js和regenerator-runtime的封裝庫。
不過在babel官網,這個庫已經被棄用了。babel@7.4.0版本之後就建議直接使用core-js和regenerator-runtime
上面那段話的大致意思為:@babel@7.4.0開始,@babel/polyfill會被棄用,直接使用core-js和regenerator-runtime。
下面那段話的大致意思為:babel具有一個polyfill包含了core-js和regenerator-runtime。
??? 關於@babel/polyfill庫被棄用的原因好像是因為:core-js@3.X版本和core-js@2.X版本的巨大差異 導致@babel/polyfill無法過渡適配。
core-js、regenerator-runtime使用
yarn add regenerator-runtime@0.13.7 core-js@3.9.0 // 安裝在dependencies
直接使用core-js和regenerator-runtime需要在程式碼中手動引用。babel當然也支援配置,慢慢來
index.js檔案引用。
??
- 匯入core-js庫時,匯入方式為:"core-js/stable",是為了只匯入穩定版本特性, 關於stage請參考:[ECMAScript] TC39 process
- 匯入regenerator-runtime時,匯入方式為:regenerator-runtime/runtime,為了節省檔案大小
此時執行yarn build
打包 編譯生成程式碼中會看到好多引用程式碼。這些都是core-js處理ES6 API(型別、函式)的墊片
例如promise型別,就可以在編譯生成後的程式碼中找到core-js自定義的實現方式。
這時候使用IE9執行程式碼可以執行成功,也就是說ES6 API(型別、函式)被成功替代了。
@babel/preset-env 屬性設定
按需載入
剛才加入core-js和regenerator-runtime後打包執行,可以知道ES6 API(型別、函式)被成功替代了。
但其實這裡還具有一個非常嚴重的問題,那就是檔案大小。
可以看到打包生成的檔案現在高達428K。雖然打包程式碼壓縮,但也不應該這個大小
在程式碼中僅寫了兩個函式。那麼原因大概是引入core-js和regenerator-runtime導致。
core-js是ES6 API(型別、函式)的墊片。
core-js本身並不知道你使用哪些ES6 API(型別、函式),而babel預設情況會將所有的墊片引入,
也就造成了這個恐怖的檔案大小
前端對於檔案大小非常敏感,檔案大小直接影響到網站的載入速度。所以必須要做到按需載入墊片 (僅載入需要使用的墊片)
不同專案對瀏覽器支援版本需求不一樣。
babel處理ES6 API(型別、函式)墊片時的按需載入墊片具有三種含義
- 按照瀏覽器版本載入墊片
- 按照程式碼中使用載入墊片
- 按照瀏覽器版本+程式碼中使用載入墊片
?瀏覽器支援版本需求 取決於專案的使用使用者,例如有的專案只是公司管理專案,無須相容老版本瀏覽器
babel中@babel/preset-env提供了兩種按需載入配置方案:按照瀏覽器版本載入(1)和按照瀏覽器版本+程式碼中使用載入(3)
@babel/preset-env 屬性配置
設定瀏覽器版本(browserslist、targets)
按需載入墊片中有一個瀏覽器版本載入的含義,想要實現瀏覽器版本載入那就必須設定瀏覽器版本,
babel提供了兩種設定瀏覽器版本的方案:
browserslist
browserslist方案在剛才處理函式包裹程式碼時使用到了,設定在package.json中的browserslist屬性
"browserslist": [
"ie 9"
]
browserslist是一個提供瀏覽器版本的一個庫,提供了多種配置規則,好多庫都使用到了browserslist,例如:babel。
browserslist屬性是Array,允許設定多個瀏覽器版本。例如ie 9,便是支援IE9瀏覽器。
還可以設定範圍版本,例如大於Chrome75版本。
"browserslist": [
"Chrome > 75"
]
在這裡只使用這兩種規則測試,browserslist會在下一篇介紹
targets
targets屬性是babel自身提供瀏覽器版本設定,配置在@babel/preset-env屬性中
targets屬性型別為 String、Object;支援browserslist格式規則。
targets屬性的優先順序高於browserslist。
{
"presets": [
["@babel/preset-env",{
"targets": "chrome > 75",
}]
],
"plugins": [
]
}
{
"presets": [
["@babel/preset-env",{
"targets": {
"chrome": "58",
"ie": "11"
}]
],
"plugins": [
]
}
推薦使用browserslist設定,也就是package.json中browserslist屬性。
因為browserslist庫已經被社群高度認可。好多庫都依賴了browserslist,使用browserslist庫可以做到:配置統一管理,利於專案維護
?:?? 瀏覽器版本設定也會影響Syntax(語法)的轉換。 指定的瀏覽器版本支援的Syntax(語法)不會被轉換ES5
corejs
在介紹按需載入墊片之前再說一個@babel/preset-env屬性:corejs
corejs屬性是babel@7.4.0時加入的,用於設定載入core-js版本。
corejs設定的型別為: String、Object。
{
"presets": [
["@babel/preset-env",{
"corejs": {
"version": "3.9",
"proposals":true
}
}]
],
"plugins": [
]
}
-
version:設定載入的core-js版本。
此屬性可以設定任何受支援的core-js
引數型別為 String
預設值為:2.0
-
proposals:是否載入core-js支援的 提議API
引數型別為:Boolean
預設值為:false
?? corejs屬性只有在啟用按需載入墊片(useBuiltIns設定為entry、usage才有效。
useBuiltIns
按需載入墊片是由@babel/preset-env庫提供的useBuiltIns屬性設定。
useBuiltIns屬性可以設定三個屬性值:
false
不啟用按需載入墊片功能,全部載入core-js墊片。此值為預設值。
entry
按照瀏覽器版本載入墊片。
{
"presets": [
["@babel/preset-env",{
"useBuiltIns": "entry",
"corejs": {
"version": "3.9",
"proposals":true
}
}]
],
"plugins": [
]
}
browserslist屬性為 Chrome > 75 時 打包出來的檔案大小就會小很多
"browserslist": [
"Chrome > 75"
]
可以看到,此時檔案大小與剛才是天壤之別。因為瀏覽器設定的為 Chrome > 75 ,幾乎支援全部新特性
可以看到打包生成程式碼中沒有提供filter墊片,並且 await 語法都沒有轉換。這些特性在新版Chrome都提供了。
如果將browserslist屬性設定為 ie 9
那麼檔案大小依然會很大。因為ES6 新特性都不支援IE 9
"browserslist": [
"ie 9"
]
usage
剛才使用entry屬性值實現了按照瀏覽器版本載入墊片的功能。
不過並不能算是我們需要的真正按需載入墊片。
useBuiltIns屬性的usage值提供了理論上真正的按需載入:瀏覽器版本+程式碼中使用
{
"presets": [
["@babel/preset-env",{
"useBuiltIns": "usage",
"corejs": {
"version": "3.9",
"proposals":true
}
}]
],
"plugins": [
]
}
在使用usage屬性值時,就不需要手動引用core-js和regenerator-runtime庫了
babel會自動載入。
此時哪怕設定ie 9。打包檔案大小也不會像entry時那麼大了。
"browserslist": [
"ie 9"
]
而在Chrome > 75的情況下,程式碼都不需要進行處理了
"browserslist": [
"Chrome > 75"
]
entry、usage有話說
-
babel在處理entry屬性值時,直接將按需載入處理邏輯做到了入口。而在處理usage時,則在用到時進行了單獨引用,並且保證每一個API(型別、函式)只引用一次
-
在兩者選擇使用時,不要一味的追求usage,因為usage使用起來更為棘手
modules
@babel/preset-env配置項中有一個modules。
modules屬性表示是否將ES modules轉換為指定模組型別處理。
modules屬性值具有:amd、systemjs、umd、commonjs、cjs、auto、false。
預設屬性值為auto:預設情況下,使用ES modules來進行處理,但是會受到其它plugin的modules屬性影響。
推薦使用ES modules,將屬性值設定為false
因為ES6 modules 可以進行tree-shaking優化
{
"presets": [
[
"@babel/preset-env",
{
"modules":false
}
]
]
}
@babel/preset-env還有一些別的屬性,在此就不贅述。有興趣的朋友可以查詢官網。
@babel/plugin-transform-runtime
babel處理ES6特性時,還提供了一個解決全域性汙染的墊片庫:@babel/plugin-transform-runtime
@babel/plugin-transform-runtime也是一個經常被使用到的庫。
在日常開發中都應該遵守的一個原則:避免全域性汙染。
全域性汙染是一件極為可怕的問題。在協同、程式碼執行時會出現不可預知的問題。
@babel/plugin-transform-runtime庫就是將程式碼使用到的ES6 API(型別、函式)名稱轉換為自定義名稱,從而避免汙染執行環境自身API。
? @babel/plugin-transform-runtime與usage屬性值一樣:按照瀏覽器版本+程式碼中使用載入墊片
開發第三方庫,強烈建議使用@babel/plugin-transform-runtime
@babel/runtime-corejs3
@babel/plugin-transform-runtime庫依賴了一個@babel/runtime-corejs3或@babel/runtime-corejs2庫。
???
@babel/runtime-corejs3對應的core-js@3.X
@babel/runtime-corejs2對應的core-js@2.X
@babel/runtime-corejs3是babel提供的core-js封裝庫,內部做了一些處理,具體可以參考這篇文章。不過此文章是基於@babel/runtime-corejs2版本,與@babel/runtime-corejs3具有一定差異。
yarn add -D @babel/plugin-transform-runtime@7.13.7 @babel/runtime-corejs3@7.13.7
?? 使用@babel/plugin-transform-runtime時,就不需要安裝core-js和regenerator-runtime ,@babel/runtime-corejs3中會依賴這兩個庫
.babelrc檔案中使用@babel/plugin-transform-runtime配置替代@babel/preset-env中配置。
不過注意的是@babel/plugin-transform-runtime屬性中corejs.version不再是字串,而是2、3。 因為載入的是@babel/runtime-corejs[3/2]
{
"presets": [
[
"@babel/preset-env",
{
// 移除useBuiltIns設定
// "targets": "chrome > 75",
// "useBuiltIns": "usage",
// "corejs": {
// "version": "3.9",
// "proposals":true
// }
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": {
"version": 3,
"proposals": true
}
}
]
]
}
配置完畢後,不再需要任何引用就可以進行打包生成。
"browserslist": [
"ie 9"
]
在IE9環境yarn build
。
可以看到使用的ES6-API已經被轉換為另外的API了,所以並不會再汙染全域性程式碼。至於打包的大小,並沒有多大
至於在Chrome > 75的打包結果,有興趣的朋友可以自行測試。
preset和plugin
在使用babel庫時,發現有兩種型別:
- preset:@babel/preset-env
- plugin:@babel/plugin-transform-runtime
配置時也是不同屬性:
{
"presets": [
],
"plugins": [
]
}
preset的中文翻譯為:預置。其實也就是babel提供的預置外掛庫,其本質也都是plugin
總結
???
- babel來用來處理ES6特性的庫
- babel也是核心引擎 + 外掛化的設計模式
- babel-loader是babel的介面卡,將babel提供webpack使用
- babel使用不同的外掛分別處理Syntax(語法)和API(型別、函式)
- babel提供不少的預設外掛,配置在presets屬性中。
- @babel/preset-env中useBuiltIns屬性用來設定按需載入墊片
- @babel/plugin-transform-runtime提供了一種不汙染全域性情況下使用墊片方式。
本文參考
本文依賴
- babel-loader@8.2.2
- @babel/core@7.13.1
- @babel/preset-env@7.13.5
- regenerator-runtime@0.13.7
- core-js@3.9.0
- @babel/plugin-transform-runtime@7.13.7
- @babel/runtime-corejs3@7.13.7
package.json
{
"name": "my-cli",
"version": "1.0.0",
"main": "index.js",
"author": "mowenjinzhao<yanzhangshuai@126.com>",
"license": "MIT",
"devDependencies": {
"@babel/core": "7.13.1",
"@babel/plugin-transform-runtime": "7.13.7",
"@babel/preset-env": "7.13.5",
"@babel/runtime-corejs3": "7.13.7",
"babel-loader": "8.2.2",
"clean-webpack-plugin": "3.0.0",
"html-webpack-plugin": "5.2.0",
"webpack": "5.24.0",
"webpack-cli": "4.5.0"
},
"dependencies": {
"jquery": "3.5.1",
},
"scripts": {
"start": "webpack --mode=development --config webpack.config.js",
"build": "webpack --mode=production --config webpack.config.js"
},
"browserslist": [
"ie 9",
"Chrome > 75"
]
}
webpack.config.js
const path = require('path')
const webpack = require("webpack");
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const config = {
root: path.join(__dirname, './'),
}
const modules = {
// 入口檔案
// 字串形式
entry: path.join(config.root, 'src/index.js'),
// 物件形式
// entry:{
// 'index': path.join(config.root, 'src/index.js'),
// },
// 輸出檔案
// 字串形式
// output:path.join(config.root, './dist/[name].js')
//物件形式
output: {
// 輸出檔案的目錄地址
path: path.join(config.root, 'dist'),
// 輸出檔名稱,contenthash代表一種快取,只有檔案更改才會更新hash值,重新打包
filename: '[name]_[contenthash].js'
},
//devtool:false, //'eval'
module:{
rules:[
{
// 所有的.js檔案都走babel-loader
test:/\.js$/,
include: path.join(config.root,'src'),
loader: "babel-loader"
}
]
},
optimization: {
minimize: false,
minimizer: [
new TerserPlugin({
// 指定壓縮的檔案
include: /\.js(\?.*)?$/i,
// 排除壓縮的檔案
// exclude:/\.js(\?.*)?$/i,
// 是否啟用多執行緒執行,預設為true,開啟,預設併發數量為os.cpus()-1
// 可以設定為false(不使用多執行緒)或者數值(併發數量)
parallel: true,
// 可以設定一個function,使用其它壓縮外掛覆蓋預設的壓縮外掛,預設為undefined,
minify: undefined,
// 是否將程式碼註釋提取到一個單獨的檔案。
// 屬性值:Boolean | String | RegExp | Function<(node, comment) -> Boolean|Object> | Object
// 預設為true, 只提取/^\**!|@preserve|@license|@cc_on/i註釋
// 感覺沒什麼特殊情況直接設定為false即可
extractComments: false,
// 壓縮時的選項設定
terserOptions: {
// 是否保留原始函式名稱,true代表保留,false即保留
// 此屬性對使用Function.prototype.name
// 預設為false
keep_fnames: false,
// 是否保留原始類名稱
keep_classnames: false,
// format和output是同一個屬性值,,名稱不一致,output不建議使用了,被放棄
// 指定壓縮格式。例如是否保留*註釋*,是否始終為*if*、*for*等設定大括號。
format: {
comments: false,
},
output: undefined,
// 是否支援IE8,預設不支援
ie8: false,
compress: {
// 是否使用預設配置項,這個屬性當只啟用指定某些選項時可以設定為false
defaults: false,
// 是否移除無法訪問的程式碼
dead_code: false,
// 是否優化只使用一次的變數
collapse_vars: true,
warnings: true,
// 是否刪除所有 console.*語句,預設為false,這個可以線上上設定為true
drop_console: false,
// 是否刪除所有debugger語句,預設為true
drop_debugger: true,
// 移除指定func,這個屬性假定函式沒有任何副作用,可以使用此屬性移除所有指定func
// pure_funcs: ['console.log'], //移除console
},
},
})
]
},
plugins: [
new HtmlWebpackPlugin({
// HTML的標題,
// template的title優先順序大於當前資料
title: 'my-cli',
// 輸出的html檔名稱
filename: 'index.html',
// 本地HTML模板檔案地址
template: path.join(config.root, 'src/index.html'),
// 引用JS檔案的目錄路徑
publicPath: './',
// 引用JS檔案的位置
// true或者body將打包後的js指令碼放入body元素下,head則將指令碼放到中
// 預設為true
inject: 'body',
// 載入js方式,值為defer/blocking
// 預設為blocking, 如果設定了defer,則在js引用標籤上加上此屬性,進行非同步載入
scriptLoading: 'blocking',
// 是否進行快取,預設為true,在開發環境可以設定成false
cache: false,
// 新增mate屬性
meta: {}
}),
new CleanWebpackPlugin({
// 是否假裝刪除檔案
// 如果為false則代表真實刪除,如果為true,則代表不刪除
dry: false,
// 是否將刪除日誌列印到控制檯 預設為false
verbose: true,
// 允許保留本次打包的檔案
// true為允許,false為不允許,保留本次打包結果,也就是會刪除本次打包的檔案
// 預設為true
protectWebpackAssets: true,
// 每次打包之前刪除匹配的檔案
cleanOnceBeforeBuildPatterns: ['**/*'],
// 每次打包之後刪除匹配的檔案
cleanAfterEveryBuildPatterns:["*.js"],
}),
new webpack.DefinePlugin({ "global_a": JSON.stringify("我是一個打包配置的全域性變數") }),
],
resolve: {
alias:{
// 設定路徑別名
'@': path.join(config.root, 'src') ,
'~': path.join(config.root, './src/assets') ,
},
// 可互忽略的字尾
extensions:['.js', '.json'],
// 預設讀取的檔名
mainFiles:['index', 'main'],
}
}
// 使用node.js的匯出,將配置進行匯出
module.exports = modules
.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules":false
// 移除useBuiltIns設定
// "targets": "chrome > 75",
// "useBuiltIns": "usage",
// "corejs": {
// "version": 3,
// "proposals":true
// }
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": {
"version": 3,
"proposals": true
}
}
]
]
}