Parcel 2 RC

Parcel 團隊非常興奮地宣布第一個 Parcel 2 發行候選版本!此版本包含許多改進,包括新功能、更好的效能、API 一致性,以及許多錯誤修正和穩定性改進。

透過原生 ES 模組進行自動差異化組合

#

Parcel 2 現在會自動產生原生 ES 模組以供現代瀏覽器使用,以及傳統腳本作為舊瀏覽器的後備。透過傳送現代語法,而不是轉譯成 ES5,這會大幅減少大多數使用者的組合大小。

傳統腳本與 ES 模組

#

Parcel 的基本設計目標之一一直是像網路一樣運作。我們試著避免鎖定,方法是遵循網路標準,並盡可能不發明 Parcel 特定的語法或功能。在 Parcel v1 中,這一點不成立的地方之一是 Parcel 處理 HTML 中的 <script> 標籤的方式。以前,Parcel 會將所有腳本視為模組,包括支援 importexport 陳述式,並將每個檔案的頂層範圍與其他模組隔離。儘管很方便,但這實際上並非 <script> 標籤在瀏覽器中的運作方式。

沒有 type="module" 的傳統腳本,實際上會將頂層範圍中的變數視為全域變數,且無法有匯入或匯出,因此現在 Parcel 也符合這種行為。這也修正了 jQuery 等舊式函式庫的一些問題,這些函式庫預期在全域腳本環境中執行,而不是在孤立的模組中執行。

當你從 Parcel 的舊版本升級時,你需要將 type="module" 屬性新增到你的腳本標籤。你會看到像下面這樣的診斷,指出你需要修改的位置。

Screenshot of an error message showing "Browser scripts cannot have imports or exports. Add the type='module' attribute to the script tag."

差異化組合

#

差異化套件化是針對不同目標發送多個版本程式碼,並允許瀏覽器選擇最理想版本下載的概念。現代瀏覽器支援 <script type="module">,除了支援匯入和匯出語法外,也支援其他現代語法,例如類別、箭頭函式、非同步/等待等。發送現代語法,而不是將此語法轉譯為較舊的 JavaScript 版本,可以大幅減少套件大小並改善載入時間。不過,如果您仍需要支援較舊的瀏覽器,<script nomodule> 可用於傳送程式碼的轉譯版本,此版本只會載入到較舊的瀏覽器中。這讓您能同時享有兩全其美的優點,也就是為大多數使用者提供較小的套件,但不會犧牲較舊瀏覽器的使用者。

使用 module/nomodule 模式的差異化套件化現在已在 Parcel 2 中完全自動化。只要在 HTML 檔案中使用指向原始程式碼的 <script type="module"> 標籤,Parcel 就會自動產生 nomodule 版本(如果需要的話)。

<script type="module" src="app.js"></script>

會變成

<script type="module" src="app.c9a6fe.js"></script>
<script nomodule src="app.f7d631.js"></script>

這會根據您的瀏覽器目標自動發生,這些目標在 package.json 檔案的 "browserslist" 鍵中宣告。如果您的某些目標不原生支援 ES 模組,將會自動編譯 nomodule 版本。

改善 JSX 支援

#

Parcel 一直支援 JSX,甚至會自動偵測您使用的函式庫(例如 React、Preact 等),並相應地進行編譯。在此版本中,Parcel 現在支援 React 17 中新增的 新的 JSX 執行時期。這完全是自動化的,Parcel 會偵測您的程式碼使用的 React 版本,並相應地選擇正確的 JSX 執行時期。新的 JSX 執行時期應會產生較小的套件,並改善效能。您也不再需要在每個檔案中手動匯入 React 才能使用 JSX。請閱讀 React 團隊的 部落格文章,以取得更多資訊。

此外,Parcel 現在會讀取專案中的 tsconfig.jsonjsconfig.json 檔案,讓您設定 JSX 編譯的幾個面向。您可以使用此設定來覆寫 JSX 執行時期、函式庫和其他屬性,以及啟用其他實驗性的 JavaScript 功能,例如裝飾器。請參閱 TypeScript 團隊的 TSConfig 參考 以取得更多資訊。

改善的 Worker 支援

#

Parcel 長期以來支援 Web Worker 和 Service Worker,在此版本中,我們進行了一些重大的改善。類似於 HTML 中的 <script> 標籤,瀏覽器中實際上支援兩種 Worker:傳統指令碼 Worker 和 ES 模組 Worker。Parcel 過去一直將所有 Worker 視為模組,但在這個版本中,我們現在比照原生瀏覽器行為,並將它們視為不同的東西。

若要建立使用 ES 模組語法的 Worker,例如 importexport,現在在建構 Worker 時需要 type: 'module' 選項。此外,現在需要使用 URL 建構函數來建立 Worker,而不是傳遞字串文字。這些變更改善了 Parcel 與原生瀏覽器行為以及生態系統中其他工具的相容性。

new Worker(
new URL('worker.js', import.meta.url),
{type: 'module'}
);

此外,在模組 Worker 中,不再支援 importScripts,應改用 import 陳述式或動態 import() 取代。

Parcel 會顯示診斷訊息,協助您將現有程式碼移轉到新的模式。

Screenshot of an error message showing "Constructing a worker with a string literal is not supported"

Worklet 支援

#

除了 Web Worker 和 Service Worker 之外,Parcel 現在也支援 Worklet,包括 CSS Houdini paint worklet 以及 Web Audio worklet

使用下列語法自動偵測 Paint worklet

CSS.paintWorklet.addModule(new URL('worklet.js', import.meta.url));

Web audio worklet 無法靜態分析,因此你可以使用 worklet: 名稱的管道取得為正確環境編譯的 worklet 檔案 URL。

import workletUrl from 'worklet:./worklet.js';

context.audioWorklet.addModule(workletUrl);

改善函式庫建置

#

在此版本中,Parcel 對建置函式庫的支援已獲得改善。

Parcel 現在支援 Node.js 使用的 .mjs.cjs 檔案副檔名,用來表示模組是 ESM 或 CommonJS。此外,也支援 package.json 中的 "type": "module" 欄位。這些提示可協助 Parcel 在編譯原始碼時自動判斷要使用的輸出格式。如果你嘗試在 package.json 欄位中使用不支援的檔案副檔名,你還會收到診斷訊息。

Screenshot of an error message showing "Unexpected output file type .html in target 'main'"

此外,當你在程式碼中使用工作執行緒或 URL 相依項時,Parcel 現在會在建置函式庫時產生可靜態分析的輸出。這讓你的函式庫可以在稍後於應用程式中使用時,由 Parcel 或其他套件管理工具打包。URL 相依項會編譯成 URL 建構函式,該建構函式在 Node 和瀏覽器中都得到原生支援,且也受到許多套件管理工具支援。

new URL('some-code.js', import.meta.url)

最後,我們改善了與函式庫相關的許多案例的診斷。例如,當函式庫建置的範圍提升已停用,或使用了不支援的輸出格式時,你會收到診斷訊息。我們新增的另一個有用的診斷訊息會在你的程式碼中有未在 package.json 中宣告的外部相依項時通知你。這有助於防止在你的函式庫被下游使用者使用時發生會中斷的程式碼。

Screenshot of an error message showing "External dependency 'lodash-es' is not declared in package.json."

其他 JavaScript 改進

#

同一個檔案中的多個相依項類型

#

以前,無法在同一個檔案中對同一個規格符使用多種類型的相依項。例如,一個檔案無法同時使用靜態匯入和動態匯入同一個規格符。現在已正確支援此功能。

import something from './foo';

import('./foo');

解構 process.env

#

現在可以使用解構語法對 process.env 進行解構。

let {NODE_ENV, API_TOKEN} = process.env;

支援獨立的 import.meta

#

Parcel 現在更全面地支援 import.meta。當單獨參照 import.meta 時,現在會取得包含 url 屬性的物件。import.meta.url 會直接編譯成相同的 URL,沒有中間物件。URL 是 file:// URL,其中包含從專案根目錄到包含 import.meta.url 參照之檔案的相對路徑。

console.log(import.meta);
// => {url: 'file:///src/App.js'}

console.log(import.meta.url);
// => 'file:///src/App.js'

此外,在建立工作執行緒時,import.meta.url 可用作自我參照,在這種情況下,啟動工作執行緒的檔案也將是工作執行緒本身。

new Worker(import.meta.url, {type: 'module'});

Glob 解析器外掛程式

#

Parcel 2 現在有一個 Glob 解析器外掛程式,其運作方式類似於 Parcel 1 中的 Glob 匯入支援。這可讓您一次匯入多個檔案,並取得包含對應於檔案的鍵值之物件。

import * as files from './files/*.js';

console.log(files.foo);

等同於

import * as foo from './files/foo.js';
import * as bar from './files/bar.js';

let files = {
foo,
bar
};

這也適用於 url: 等管線,以及動態匯入。

let files = import('./files/*.js');

async function doSomething() {
let foo = await files.foo();
let bar = await files.bar();
return foo + bar;
}

由於 Glob 匯入是非標準的,因此未包含在預設的 Parcel 設定檔中。若要啟用它們,請將 @parcel/resolver-glob 新增至 .parcelrc

{
"extends": "@parcel/config-default",
"resolvers": ["@parcel/resolver-glob", "..."]
}

效能改善

#

在上一個版本中,我們 宣布 以 Rust 編寫的新 JavaScript 編譯器,可將效能提升多達 10 倍。此版本持續改善效能,整體而言比前一個測試版快了 ~38%。有許多小變更加總起來,但下面說明了一些重點。

LMDB

#

Parcel 會將所有執行的工作快取到檔案系統中。這可透過避免重複工作來改善重新啟動 Parcel 時的效能。此外,檔案系統會在建置期間用作暫時儲存區域,以在工作執行緒之間進行通訊。這也讓 Parcel 建置可擴充到超過可用記憶體容量的非常大型專案。因此,讀寫檔案系統的效能對 Parcel 建置的整體效能非常重要。

在此版本中,我們已將檔案系統快取實作替換為由 LMDB 支援的儲存體。LMDB 是一個以 C 編寫的極快速嵌入式鍵值儲存體。特別是,我們使用絕佳的 lmdb-store 模組給 Node。它使用單一記憶體映射檔案,並在非同步背景執行緒中自動處理寫入。

使用 LMDB 取代檔案系統作為快取,可將效能提升約 20%!

xxHash

#

Parcel 廣泛使用雜湊處理許多事項,包括快取金鑰、內容雜湊等。我們之前大多依賴內建的 Node md5 函式進行雜湊,但在這個版本中,我們已將其替換為 xxHash。xxHash 是一種極快的雜湊函式,以 RAM 速度限制運作。我們在 xxHash 的 Rust 實作周圍建構了一個自訂的 Node 封裝,速度比 md5 快約 7 倍。整體而言,這可將 Parcel 建置效能提升約 5%。

原始碼對應表改進

#

Parcel 使用 我們自己的程式庫(以 Rust 編寫)來處理原始碼對應表。從快取序列化和反序列化大型原始碼對應表可能需要花費大量時間。在此版本中,我們已將 SerdeBincode 替換為 rkyv,這是一個極快的零複製反序列化架構,適用於 Rust。這在讀取快取的原始碼對應表時快了約 2.5 倍,相當於整體 Parcel 建置快了約 5%。

快取改進

#

可靠的快取一直是 Parcel 2 的重點領域,如我們之前的部落格文章所述。在此版本中,我們已持續進行這項工作,並完成將 Parcel 2 的所有部分移轉到我們的基於要求的快取架構。

特別是,封裝和最佳化套件是 Parcel 中最後一個尚未完全可靠的階段。現在,當封裝器和最佳化外掛程式設定變更時,我們會適當地使快取失效。此外,只有實際變更的套件會重新封裝並寫入磁碟,這可提升效能。如果 dist 目錄被刪除或套件被手動修改,Parcel 會偵測到此情況,並自動將先前封裝的套件從快取複製回 dist 目錄。

最後,快取現在能適應位置和平台的變更。例如,如果專案移至檔案系統中的不同位置,或在不同機器上複製,現在就能重複使用快取。所有參考的檔案路徑現在都儲存在相對於專案根目錄的位置,而不是絕對路徑。它們也儲存在與平台無關的分隔符號中,這表示快取可以在 POSIX 和 Windows 機器之間共用。

API 變更

#

在此版本中,我們對外掛程式 API 做了重大變更。如果你有任何現有的外掛程式,你可能需要更新它們。由於這是一個候選版本,我們承諾在此版本之後避免中斷 API 變更。

這些變更主要是為了改善 API 的一致性、可讀性、類型安全性,以及可理解性。例如,所有外掛程式類型都支援的 loadConfig API 現在已完全類型化。此外,Asset 和 Bundle API 已減少對布林旗標的依賴,並已將這些旗標替換為較小的列舉集,用來指出哪些選項實際上是互斥的。變更很多,請查看 此處 的 API diff。

最後,我們現在會發布 TypeScript 定義,以及我們所有公開的套件。這包括外掛程式 API,以及 Parcel 核心程式 API。這應有助於使用 TypeScript 編寫外掛程式,以及在像 VSCode 這樣的編輯器中使用純 JavaScript。

其他

#

此版本包含許多其他小改進和錯誤修正。以下是一些重點。請參閱 提交 diff 以取得變更的完整清單,或 GitHub 里程碑 中已修正錯誤的清單。

SVG 優化器

#

Parcel 現在包含一個基於 SVGO 的 SVG 優化器外掛程式。這會自動縮小建置中引用的獨立 .svg 檔案大小。它可以使用 svgo.config.jsonsvgo.config.js 檔案進行設定。

此外,SVGO 也用於 HTML 檔案中的內嵌 SVG。此版本中也修復了幾個相關的錯誤。

影像參考

#

Parcel 2 在參考影像檔案時不再需要 url: 前置詞。這些檔案可以在 JavaScript 中匯入或從 HTML 或 CSS 參考,並會產生一個轉換後的 URL,其中包含一個內容雜湊,以進行長期快取。

Parcel 還包含一個影像轉換器,你可以使用查詢參數來啟用它。這允許你自動調整來源檔案中影像的大小或轉換影像。例如,在 HTML 中,你可以使用不同的查詢參數多次參考同一張影像,以產生不同格式的多個不同表示。

<picture>
<source src="snow.jpg?as=webp&width=400" type="image/webp" />
<source src="snow.jpg?as=jpg&width=400" type="image/jpeg" />
<img src="snow.jpg?as=jpg&width=400" alt="snow" />
</picture>

網路清單

#

Parcel 支援 網路清單 檔案,這使 PWA 能夠安裝在使用者的裝置上。這些檔案使用 <link rel=“manifest”> 標籤從 HTML 檔案參考。Parcel 會自動處理這些檔案中的 URL 參考,就像處理任何其他依賴項一樣。在此版本中,你現在可以使用 .json 檔案,而不是許多開發人員偏好的 .webmanifest 檔案。

試試看!

#

請試用候選版本,並在 GitHub 上提供意見回饋。我們將在正式版本發布前的一個多月內修復錯誤並改善文件。你也可以捐款給我們的 開放集體,這有助於支持我們的貢獻者。謝謝!