宣布 Parcel CSS:一個用 Rust 編寫的新 CSS 解析器、編譯器和壓縮器!

我很興奮地宣布 @parcel/css,一個用 Rust 編寫的新 CSS 解析器、編譯器和壓縮器!在 GitHub 上查看它,或在您的瀏覽器中嘗試 線上示範

Parcel CSS 的效能顯著優於現有的工具,同時也提升了壓縮品質。除了壓縮之外,Parcel CSS 處理編譯 CSS 模組、tree shaking、自動為您的瀏覽器目標加入和移除供應商前綴,以及轉譯巢狀、邏輯屬性、4 級顏色語法等現代 CSS 功能,還有更多。

它可以用於 Parcel,作為 JavaScript 或 Rust 的獨立函式庫,或包裝為任何其他工具中的外掛程式。Rust 函式庫被設計為 CSS 工具的平台,可以存取所有 CSS 規則、選取器、屬性和值的完整解析資料結構。

效能

#

Parcel CSS 非常快。它的壓縮速度比 CSSNano 快 100 倍,比 ESBuild 快 3 倍以上。它可以在單一執行緒上每秒壓縮超過 270 萬行程式碼。此範例顯示一個基準測試,它壓縮了大約 10,000 行的 Bootstrap 4。

Performance CSSNano ESBuild Parcel CSS 0ms 150ms 300ms 450ms 600ms 4.6ms 17.41ms 542.96ms

儘管速度非常快,但 Parcel CSS 沒有在大小上妥協。在許多情況下,它可以產生比其他工具更小的輸出,這要歸功於它將許多函式庫中使用的舊版 CSS 語法轉換為更小的現代語法,以及它對每個個別 CSS 屬性的完全理解。

Size CSSNano ESBuild Parcel CSS 0 KB 40 KB 80 KB 120 KB 160 KB 139.8 KB 156.57 KB 155.89 KB

Parcel CSS 不僅因為是用原生語言撰寫而快速,還因為它從一開始就以效能為考量進行設計。它在記憶體使用方式上經過最佳化,例如使用單位元組旗標來表示供應商前綴,以及將所有 CSS 屬性解析為結構化資料,而不是將它們表示為每次使用時都需要重新解析的字串。

架構

#

Parcel CSS 以 cssparser Rust 箱子為基礎,這是 Mozilla 建立並用於 Firefox 的瀏覽器等級 CSS 分詞器。這提供了穩固的基礎,包括分詞和基本解析。但它不會詮釋任何 CSS 屬性或規則。這就是 Parcel CSS 發揮作用的地方。它會處理解析每個個別規則和屬性值,以及縮小、編譯和列印回 CSS。

許多其他 CSS 處理器將屬性值視為字串,或未分型的代幣系列。這表示每個想要使用這些值的轉換器都必須自行解析和詮釋它們,導致重複工作和不一致。例如,PostCSS 解析的 CSS 屬性 AST 如下所示

{
"type": "decl",
"prop": "background",
"value": "url(img.png) 20px 10px / 50px 100px"
}

即使您使用許多 PostCSS 外掛程式用來對屬性值進行分詞的獨立函式庫 postcss-value-parser,每個代幣的意義仍然未被詮釋。上述值會解析如下

[
{
type: 'function',
value: 'url',
nodes: [ { type: 'word', value: 'img.png' } ]
},
{ type: 'space', value: ' ' },
{ type: 'word', value: '20px' },
{ type: 'space', value: ' ' },
{ type: 'word', value: '10px' },
{ type: 'div', value: '/' },
{ type: 'word', value: '50px' },
{ type: 'space', value: ' ' },
{ type: 'word', value: '100px' }
]

雖然比字串更具結構化且更容易處理,但並不清楚 20pxbackground-position-x 的值,而 50px 是背景寬度的值。這必須由使用者詮釋。

Parcel CSS 使用 CSS 規格中的語法解析所有值,並為每個屬性公開特定的值類型。例如,Parcel CSS 會將上述屬性表示如下

Background([Background {
image: Url(Url { url: "img.png" }),
color: CssColor(RGBA(RGBA { red: 0, green: 0, blue: 0, alpha: 0 })),
position: Position {
x: Length(Dimension(Px(20.0))),
y: Length(Dimension(Px(10.0))),
},
repeat: BackgroundRepeat {
x: Repeat,
y: Repeat,
},
size: Explicit {
width: LengthPercentage(Dimension(Px(50.0))),
height: LengthPercentage(Dimension(Px(100.0))),
},
attachment: Scroll,
origin: PaddingBox,
clip: BorderBox,
}])

這正是瀏覽器解析 CSS 的方式。值會被詮釋,並填入背景附加等隱含的預設值。這會改善效能,因為每當轉換器想要對屬性做些什麼時,它不需要重新解析、轉換和再次字串化它。這也會改善可靠性,因為每個轉換器不會以稍微不同的方式解析值,或使用正規表示法或字串替換等捷徑,這可能會導致錯誤。

由於屬性值是個別詮釋的,因此這種方法也能夠進行更好的縮小化。例如,隱含的預設值可以自動移除,不需要的空白可以移除,長寫屬性可以在可能的情況下合併為簡寫等。

這個架構提供了 CSS 工具的基礎,這些工具可以專注於以有趣的方式使用屬性,而不是解析和詮釋它們。

試試看

#

如果您使用 Parcel,您可以嘗試使用 Parcel CSS 作為您的 CSS 轉換器、縮小器,或兩者。我們希望很快就能取代預設的 CSS 轉換器和縮小器,但想先取得回饋。現在,只要將以下內容新增到您的 .parcelrc 檔案中

{
"extends": "@parcel/config-default",
"transformers": {
"*.css": ["@parcel/transformer-css-experimental"]
},
"optimizers": {
"*.css": ["@parcel/optimizer-css"]
}
}

您也應該將 browserslist 屬性新增到您的 package.json,這會定義您的 CSS 將編譯的目標瀏覽器。

雖然 Parcel CSS 處理了最常用的 PostCSS 外掛程式,例如 autoprefixerpostcss-preset-env 和 CSS 模組,但您可能仍然需要 PostCSS 來使用更多自訂外掛程式,例如 TailwindCSS。如果是這樣,只要在 @parcel/transformer-css-experimental 之前新增 @parcel/transformer-postcss,您的 PostCSS 設定就會自動選取。您可以從您的 PostCSS 設定中移除上面列出的外掛程式,它們會由 Parcel CSS 處理。

如果您沒有使用 Parcel,您仍然可以嘗試 Parcel CSS。您可以使用 JavaScript API 獨立使用它,或為您最喜愛的建置工具建立外掛程式。我們希望 Parcel CSS 能被許多工具採用,而不仅仅是 Parcel,這樣我們就能推動整個 CSS 工具生態系統向前發展。

您也可以試試 parcel_css Rust 箱子,它讓您可以完全存取已剖析的 AST,並允許您建置自訂工具。更多 API 文件即將推出,但目前,您需要從 StyleSheet API 開始。請注意,儘管 JavaScript API 是穩定的,但 Rust API 仍處於 alpha 階段,而且隨著我們持續改進 Parcel CSS,結構可能會在不同版本之間變更。

請讓我們知道進展如何!您可以在 GitHub 上提交錯誤或功能要求。