從零學腳手架(四)---babel


如果此篇對您有所幫助,在此求一個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提供了擴展支持。

🐋🐋 ES6ES2015+所有版本統稱 有的文章會寫成ES7ES8。但其實都是ES6

🐋 上面代碼使用到了ES6Promise類型塊級聲明(const)箭頭函數for-of語法數組APIawait屬性,不了解ES6的朋友可以學習阮一峰老師的ES6入門教程

babel

babel介紹

ES6來臨后,前端開啟了百花綻放的時代。從而也導致了ES6ES5的工作並不僅僅局限於JS語言的原始特性。

例如:TypescriptJSX語法等等。

這些都可以使用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-loaderwebpack執行時攔截需要轉換文件,將文件先交給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/corebabel-core

🐋后面會陸續加入其它文件執行babel-loader。例如:.ts.jsx

但是目前依然無法轉換ES6(ES2015+)代碼。因為只添加了引擎(@babel/core),並沒有添加具體轉換庫。

@babel/preset-env

先來介紹一下@babel/preset-env庫,來完成部分轉換功能。

@babel/preset-envbabel 預設的一個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配置可以設置短名稱,

  1. preset庫名稱以 babel-preset- 前綴,可以省去前綴。 例如:babel-preset-my-custom,可以直接設置為:custom
  2. 短名稱也適用於冠名,例如:@org/preset-env,可以設置為:@org/env

此時執行yarn build操作后生成的代碼就會處理部分ES6(ES2015+)

生成代碼中可以看到:awaitfor-ofconst 這些ES6代碼被轉換了。

🐋 代碼中的那堆 case 語句,是await ES5的寫法。await 本質只是一個 將異步同步化狀態機。不熟悉 await 機制的朋友可以忽略,只需知道代碼為await語法ES5寫法即可。

但細心的朋友可以發現,並不是所有的ES6特性被轉換了。

還有部分ES6特性並沒有被轉換(promiseincludesfilter),並且代碼被一個箭頭函數包裹着。

代碼被箭頭函數包裹這個問題稍后在解決。

先來了解下為什么有的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(類型、函數)進行替換。

🐋 JSSyntax(語法)錯誤提示是:Uncaught SyntaxErrorAPI(類型、函數)錯誤提示是:Uncaught ReferenceError

@babel/preset-env只是babel提供處理Syntax(語法)預設插件(preset)

至於API(類型、函數)的處理,則是由其它插件處理,這個插件俗稱:墊片、膩子

babel配置形式

在處理API(類型、函數)之前,先介紹下babel配置文件。

剛才在配置@babel/preset-env時,直接配置在了babel-loaderpresets屬性。

除了babel-loaderbabel還支持其它方式配置

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瀏覽器版本一般都為IE11IE瀏覽器支持對版本進行修改IE瀏覽器

F12-開發者模式--仿真--文檔模式 可以修改IE瀏覽器版本,在這里使用的版本為IE9

處理箭頭函數包裹

在剛才打包編譯時,發現生成的代碼使用了一個箭頭函數包裹。

這個箭頭函數函數懷疑是打包時webpack搞得鬼,具體原因沒排查,在這里只介紹下處理方案。

package.json文件中添加browserslist屬性,設置打包代碼支持IE9瀏覽器。

"browserslist": [
 "ie 9"
]

🐋 browserslist屬性是browserslist庫提供的一個屬性,browserslist是提供瀏覽器版本支持的庫。多個庫中都依賴了browserslistbrowserslist庫詳情在下一篇介紹。

此時使用yarn build執行打包編譯,生成代碼就不再由箭頭函數包裹

regenerator-runtime和core-js
regenerator-runtime

介紹下關於之前打包代碼缺少 regeneratorRuntime() 問題。

regeneratorRuntime() 是由regenerator-runtime庫提供的,

regenerator-runtime庫是一個轉換ES6generator函數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庫其實就是babelcore-jsregenerator-runtime的封裝庫。

不過在babel官網,這個庫已經被棄用了。babel@7.4.0版本之后就建議直接使用core-jsregenerator-runtime

上面那段話的大致意思為:@babel@7.4.0開始,@babel/polyfill會被棄用,直接使用core-jsregenerator-runtime

下面那段話的大致意思為:babel具有一個polyfill包含了core-jsregenerator-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-jsregenerator-runtime需要在代碼中手動引用。babel當然也支持配置,慢慢來

index.js文件引用。

🐋🐋

  1. 導入core-js庫時,導入方式為:"core-js/stable",是為了只導入穩定版本特性, 關於stage請參考:[ECMAScript] TC39 process
  2. 導入regenerator-runtime時,導入方式為:regenerator-runtime/runtime,為了節省文件大小

此時執行yarn build打包 編譯生成代碼中會看到好多引用代碼。這些都是core-js處理ES6 API(類型、函數)墊片

例如promise類型,就可以在編譯生成后的代碼中找到core-js自定義的實現方式。

這時候使用IE9運行代碼可以運行成功,也就是說ES6 API(類型、函數)被成功替代了。

@babel/preset-env 屬性設置

按需加載

剛才加入core-jsregenerator-runtime后打包運行,可以知道ES6 API(類型、函數)被成功替代了。

但其實這里還具有一個非常嚴重的問題,那就是文件大小。

可以看到打包生成的文件現在高達428K。雖然打包代碼壓縮,但也不應該這個大小

在代碼中僅寫了兩個函數。那么原因大概是引入core-jsregenerator-runtime導致。

core-jsES6 API(類型、函數)的墊片。

core-js本身並不知道你使用哪些ES6 API(類型、函數),而babel默認情況會將所有的墊片引入,

也就造成了這個恐怖的文件大小

前端對於文件大小非常敏感,文件大小直接影響到網站的加載速度。所以必須要做到按需加載墊片 (僅加載需要使用的墊片)

不同項目對瀏覽器支持版本需求不一樣。

babel處理ES6 API(類型、函數)墊片時的按需加載墊片具有三種含義

  1. 按照瀏覽器版本加載墊片
  2. 按照代碼中使用加載墊片
  3. 按照瀏覽器版本+代碼中使用加載墊片

🐋瀏覽器支持版本需求 取決於項目的使用用戶,例如有的項目只是公司管理項目,無須兼容老版本瀏覽器

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屬性類型為 StringObject;支持browserslist格式規則。

targets屬性的優先級高於browserslist

{
    "presets": [
        ["@babel/preset-env",{
            "targets": "chrome > 75",
        }]
    ],
    "plugins": [
    ]
}
{
    "presets": [
        ["@babel/preset-env",{
            "targets": {
                "chrome": "58",
                "ie": "11"
            }]
            ],
        "plugins": [
    ]
}

推薦使用browserslist設置,也就是package.jsonbrowserslist屬性。

因為browserslist庫已經被社區高度認可。好多庫都依賴了browserslist,使用browserslist庫可以做到:配置統一管理,利於項目維護

🐋:🐋🐋 瀏覽器版本設置也會影響Syntax(語法)的轉換。 指定的瀏覽器版本支持的Syntax(語法)不會被轉換ES5

corejs

在介紹按需加載墊片之前再說一個@babel/preset-env屬性:corejs

corejs屬性是babel@7.4.0時加入的,用於設置加載core-js版本。

corejs設置的類型為: StringObject

{
    "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設置為entryusage才有效。

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-jsregenerator-runtime庫了

babel會自動加載。

此時哪怕設置ie 9。打包文件大小也不會像entry時那么大了。

"browserslist": [
    "ie 9"
]

而在Chrome > 75的情況下,代碼都不需要進行處理了

"browserslist": [
    "Chrome > 75"
]

entry、usage有話說

  1. babel在處理entry屬性值時,直接將按需加載處理邏輯做到了入口。而在處理usage時,則在用到時進行了單獨引用,並且保證每一個API(類型、函數)只引用一次

  2. 在兩者選擇使用時,不要一味的追求usage,因為usage使用起來更為棘手

modules

@babel/preset-env配置項中有一個modules

modules屬性表示是否將ES modules轉換為指定模塊類型處理。

modules屬性值具有:amdsystemjsumdcommonjscjsautofalse

默認屬性值為auto:默認情況下,使用ES modules來進行處理,但是會受到其它pluginmodules屬性影響。

推薦使用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-runtimeusage屬性值一樣:按照瀏覽器版本+代碼中使用加載墊片

開發第三方庫,強烈建議使用@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-corejs3babel提供的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-jsregenerator-runtime@babel/runtime-corejs3中會依賴這兩個庫

.babelrc文件中使用@babel/plugin-transform-runtime配置替代@babel/preset-env中配置。

不過注意的是@babel/plugin-transform-runtime屬性中corejs.version不再是字符串,而是23。 因為加載的是@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庫時,發現有兩種類型:

  1. preset@babel/preset-env
  2. plugin@babel/plugin-transform-runtime

配置時也是不同屬性:

{
  "presets": [
    
  ],
  "plugins": [
  ]
}

preset的中文翻譯為:預置。其實也就是babel提供的預置插件庫,其本質也都是plugin

總結

🐋🐋🐋

  • babel來用來處理ES6特性的庫
  • babel也是核心引擎 + 插件化的設計模式
  • babel-loaderbabel的適配器,將babel提供webpack使用
  • babel使用不同的插件分別處理Syntax(語法)API(類型、函數)
  • babel提供不少的預設插件,配置在presets屬性中。
  • @babel/preset-envuseBuiltIns屬性用來設置按需加載墊片
  • @babel/plugin-transform-runtime提供了一種不污染全局情況下使用墊片方式。

本文參考

本文依賴

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
        }
      }
    ]
  ]
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM