如果此篇對您有所幫助,在此求一個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
}
}
]
]
}