Webpack5.0 新特性嚐鮮實戰 ??

前端先鋒發表於2019-03-12

在老袁寫這篇文章的時候,v5版本仍然處於早期階段,可能仍然有問題。而且作為一個major版本,其中有一些breaking changes,可能會導致一些配置和外掛不工作。但這並無妨礙我們去開始對changelog上的新特性進行嚐鮮實戰。大家如果遇到什麼問題可以移步到這進行反饋。另外有關於Webpack4的配置和Compiler->Compilation->Chunk->Module->Template整體執行原理國內外有很多優秀的文章我這裡就不一一展開了。接下來天也不早了人也不少了,讓我們一起幹點正事。

Webpack5.0 新特性嚐鮮實戰 ??
(本圖截自twitter列出了接下來v5版本的改進,嗯…感覺螢幕還是小了一點)

Webpack5.0 新特性嚐鮮實戰 ??
(本圖截自github,截圖時間為3月12日。我們看到目前開發進度到了57%)

一頓操作猛如虎指南

  • 升級你的Node到8(V5將Node.js版本從6升級到了8)
  • npm install webpack@next —save-dev
  • npm install webpack-cli —save-dev
  • package.json新增 "dev": "webpack --mode development"
  • package.json 新增 "prod": "webpack --mode production"

開始Webpack V5嚐鮮之旅

新建src資料夾,然後新建index.js。簡單的寫了一句 console.log("Hello Webpack5")

1. dist打包檔案測評

#激動的心 顫抖的手
npm run dev
複製程式碼

Webpack5.0 新特性嚐鮮實戰 ??

我的內心毫無波瀾…...卒?…好了,到這裡結束了。散了吧~

3個小時以後…我依舊心不死 發現了這個issues解決。讓我們一起看看執行成功之後V5和V4的對比圖

V5打包到dist的main.js

Webpack5.0 新特性嚐鮮實戰 ??
V4打包到dist的main.js

Webpack5.0 新特性嚐鮮實戰 ??
V5打包過程

Webpack5.0 新特性嚐鮮實戰 ??

V4打包過程

Webpack5.0 新特性嚐鮮實戰 ??

沒有文化的我只能說一句,哎呀我去!!體積小了一半之多,而且那個startup函式簡直騷氣的一批?

2. 讓人揪心的按需載入

以前當我們想在index.js內部 import(./async.js").then(...)的時候,如果我們什麼也不加。V4會預設對這些檔案生成一堆0.js,1.js,2.js…是多麼的整齊.所以我們需要使用 import(/* webpackChunkName: "name" */ "module") 才能化解這份尷尬。今天V5可以在開發模式中啟用了一個新命名的塊 id 演算法,該演算法提供塊(以及檔名)可讀的引用。 模組 ID 由其相對於上下文的路徑確定。 塊 ID 是由塊的內容決定的,所以你不再需要使用Magic Comments。

//src資料夾index.js
import("./async.js").then((_)=>{
    console.log(_.data);
})
console.log("Hello Webpack5")
複製程式碼
//src資料夾async.js
const data = "非同步資料?";
export default data; 
複製程式碼

再次編譯之後src_async_js.js 就躺在了dist裡?。如果這個時候去執行 npm run prod 會在dist裡出現一個已數字開頭的js檔案。比如我的是61.js,你可能非常好奇,這是什麼鬼❓

3. moduleIds & chunkIds得已確定

首先我們改造一下上面的檔案。

//src資料夾index.js
import("./async.js").then((_) => {
    console.log(_.data);
})
import("./async2.js").then((_) => {
    console.log(_.data2);
})
console.log("Hello Webpack5")
複製程式碼
//src資料夾async2.js
import common from "./common.js"
console.log(common)
const data2 = "非同步資料?";
export default data2;
複製程式碼

在V4的版本中async.js、async2.js會被一次分配給一個chunkId。然後生成的main.js根據chunkId載入對應的檔案,但是悲劇的事如果此時我刪掉 import("./async.js").then(() => {console.log(.data);}) 這一行的話會導致async2進行上位,也就是原來的1變成了0,如下圖:

Webpack5.0 新特性嚐鮮實戰 ??

Webpack5.0 新特性嚐鮮實戰 ??

利用BeyondCompare我們也清晰的看到了main的變化。

Webpack5.0 新特性嚐鮮實戰 ??

有同學說這還不好辦,我又可以用Magic Comments、也可以用一些外掛就可以固定住他的 moduleIds & chunkIds。是的你說的沒錯,但是V5將不需要引入任何的外力,如上我們遇到prod陌生的帶數字的JS,就是為了增強long-term caching,增加了新的演算法,並在生產模式下使用以下配置開啟。這些演算法以確定性的方式為模組和資料塊分配非常短(3或4個字元)的數字 id。

//Webpack4生產環境的預設配置
module.exports = {
    optimization:{
     	chunkIds: "deterministic”,
		moduleIds: "deterministic"   
    }
}
//Webpack4生產環境的預設配置
module.exports = {
    optimization:{
     	chunkIds: "natural”,
		moduleIds: "size"   
    }
}
複製程式碼

如果你覺得這些新特性讓你不爽,你依舊可以設定 optimization: { chunkIds: 'named' } 它是相容的,這一點還是值得點讚的。

4. 飽受詬病的編譯速度

Webpack的編譯速度相信是很多同學比較頭痛的問題,當然我們也有很多優化的辦法。比如HappyPack、Cache-loader、排除node_modules、多執行緒壓縮甚至可以採用分散式編譯等等。其實Webpack編譯慢還跟他的loder機制有一定關係,比如string->ast->string這一點跟Parcel確實有些差距 ?。那在V5的版本中都帶來些哪些改變呢?其實你只要在配置檔案中加上這樣一句:

module.exports = {
    cache: {
        type: "filesystem"
    }
}
複製程式碼

其實cache在V4版本中就有cache,不過如上這個配置官網上也在說是一個實驗性的,也說如果當使用持久快取時,不再需要cache-loader。 對於 babel cacheDirectory 等也是如此。老袁太忙也沒有時間詳細的翻所有的pr和原始碼,不過大致執行了下貌似有的效果?如果哪位大神這裡有空翻過了原始碼也歡迎在評論區討論?

Webpack5.0 新特性嚐鮮實戰 ??
(開啟快取之後的編譯速度)

Webpack5.0 新特性嚐鮮實戰 ??

5. minSize&maxSize 更好的方式表達

在V4版本中預設情況下,僅能處理javascript的大小?

module.exports = {
    optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    chunks: "all",
                    name: "commons",
                    minChunks: 1,
                    minSize: "數值",
                    maxSize: "數值"
                }
            }
        }
    }
}
複製程式碼

V5版本的變更,這個變更簡直是太皮了? 老袁已經試過了,效果還是蠻不錯的。

module.exports = {
    optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    chunks: "all",
                    name: "commons",
                }
            },
            //最小的檔案大小 超過之後將不予打包
            minSize: {
                javascript: 0,
                style: 0,
            },
            //最大的檔案 超過之後繼續拆分
            maxSize: {
                javascript: 1, //故意寫小的效果更明顯
                style: 3000,
            }
        }
    }
}
複製程式碼

7.編譯器的優化

如果大家讀過Webpack的原始碼一定知道Compiler的重要性,在Webpack中充斥著大量的鉤子和觸發事件。

Webpack5.0 新特性嚐鮮實戰 ??

在新的版本中,編譯器在使用完畢後應該被關閉,因為它們在進入或退出空閒狀態時,擁有這些狀態的 hook。 外掛可以用這些 hook 來執行不太重要的工作(比如:永續性快取把快取慢慢地儲存到磁碟上)。同時外掛的作者應該預見到某些使用者可能會忘記關閉編譯器,所以 當編譯器關閉所有剩下的工作時應儘快完成。 然後回撥將會通知已徹底完成。 當你升級到 v5 時,請確保在完成工作後使用 Node.js API 呼叫 Compiler.close。

8. Node.js polyfills 自動被移除

過去,Webpack 4版本附帶了大多數 Node.js 核心模組的 polyfills,一旦前端使用了任何核心模組,這些模組就會自動應用,但是其實有些是不必要的。 V5中的嘗試是自動停止 polyfilling 這些核心模組,並側重於前端相容的模組。當遷移到 v5時,最好儘可能使用前端相容的模組,並儘可能手動新增核心模組的polyfills。 Webpack鼓勵大家多提交自己的意見,因為這個更改可能會也可能不會進入最終的 v5版本。現在微前端已經在很多國內的團隊大量應用,老袁個人覺得這個改動對於前端更專注開發模組更有益處。


在本文開頭的時候,我們列出了一張作者演講的圖有關於Webpack的改動。大家可以點選這裡看到全部。新的版本變動必將引起很多外掛會出問題,但是V5的效能改進是我們更加期待的。最後我想說天下武功出少林,天下技術出基礎。大家夯實基礎多悟原理才能跟的上變化如此快的前端娛樂圈。

前端人的福利

老袁從業8年,幾年前僥倖進入百度和騰訊,後來在阿里offer和創業之間選擇了創業,更僥倖在27歲那年拿到了月薪30K+。

3年時間,我在騰訊課堂講了近200節直播課,我精選了50節,現免費送給想提升的同學,感興趣的可以掃碼免費領取,先到先得>>

Webpack5.0 新特性嚐鮮實戰 ??

Webpack5.0 新特性嚐鮮實戰 ??
掃描二維碼,新增大鵬老師領取。

作者 志佳老師

2019 年 03月 12日

相關文章