Skip to content

零副作用

PikaCSS 產生零執行期副作用。建置時期編譯完成後,你的 JavaScript 中不含任何樣式引擎、CSS 產生邏輯,也沒有用於樣式的 DOM 操作。唯一的產物是程式碼中的純字串字面值,以及一個靜態 CSS 檔案。

「零副作用」的意涵

在傳統的 CSS-in-JS 函式庫中,樣式引擎會被打包至瀏覽器並在執行期運作——它在執行期解析樣式物件、產生 CSS、對 class 名稱進行雜湊,並將 <style> 標籤注入 DOM。這些步驟的每一項都是副作用,會消耗 CPU 週期並延遲渲染。

PikaCSS 透過在建置期間執行每個步驟,消除了所有這些執行期副作用:

步驟傳統 CSS-in-JSPikaCSS
樣式解析執行期建置時期
Class 名稱產生執行期建置時期
CSS 產生執行期建置時期
DOM 注入執行期 <style> 標籤靜態 CSS 檔案
打包中的樣式引擎有(10–50 KB+)無(0 KB)

編譯輸出:純字串字面值

建置插件轉換程式碼後,pika() 呼叫會變成純字串字面值。pika 函式呼叫被完全移除——它們在執行期不存在。

原始碼:

ts
// Source code — uses pika() to define styles
// pika() is available as a global function — no import needed

const cardClass = pika({
	padding: '1.5rem',
	borderRadius: '0.75rem',
	boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
})

const titleClass = pika({
	fontSize: '1.25rem',
	fontWeight: '700',
	color: '#1a1a1a',
})

export function createCard(title: string, content: string) {
	return `
    <div class="${cardClass}">
      <h2 class="${titleClass}">${title}</h2>
      <p>${content}</p>
    </div>
  `
}

編譯後:

ts
// After compilation — no pika import, no function calls
// Only plain string literals remain

const cardClass = 'a b c'

const titleClass = 'd e f'

export function createCard(title: string, content: string) {
	return `
    <div class="${cardClass}">
      <h2 class="${titleClass}">${title}</h2>
      <p>${content}</p>
    </div>
  `
}

注意:

  • pika() 呼叫變成像 'a b c' 這樣的字串常數
  • 編譯輸出中不存在任何函式呼叫——只有純字串字面值
  • 匯出的函式是純粹的——沒有隱藏的執行期依賴

唯一的執行期產物

PikaCSS 新增至執行期打包中的唯一產物是一個靜態 CSS 檔案(預設為 pika.gen.css)。此檔案透過虛擬模組 pika.css 匯入,unplugin 會將其解析至產生的 CSS 檔案:

css
/* Auto-generated by @pikacss/unplugin-pikacss */

/* The ONLY runtime artifact — a static CSS file */
.a { padding: 1.5rem; }
.b { border-radius: 0.75rem; }
.c { box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.d { font-size: 1.25rem; }
.e { font-weight: 700; }
.f { color: #1a1a1a; }

此 CSS 檔案:

  • 在建置時期產生一次
  • 包含整個應用程式中使用的所有原子化樣式 class
  • 作為一般靜態資源提供——像任何其他樣式表一樣被瀏覽器快取
  • 不向執行期打包新增任何 JavaScript

Tree-shaking 支援

由於編譯後的 pika() 呼叫只是字串字面值,它們本質上是可 tree-shake 的。若持有已編譯樣式字串的變數從未被使用,打包器的無用程式碼消除功能會將其完全移除。

包含未使用樣式的原始碼:

ts
// Source code — buttonStyles is used, but unusedStyles is never referenced

const buttonStyles = pika({
	color: 'white',
	backgroundColor: '#0ea5e9',
})

// This variable is never used anywhere
const unusedStyles = pika({
	padding: '2rem',
	margin: '1rem',
})

document.querySelector('#btn')!.className = buttonStyles
// unusedStyles is never referenced — tree-shaking removes it

編譯並 tree-shaking 後:

ts
// After compilation and tree-shaking by the bundler:
// - pika() calls become string literals (build-time transform)
// - Unused string variables are eliminated (bundler tree-shaking)

const buttonStyles = 'a b'

// `unusedStyles` was a plain string 'c d' — the bundler
// detects it has no side effects and removes it entirely.

document.querySelector('#btn')!.className = buttonStyles

unusedStyles 變數被編譯為純字串 'c d',打包器將其識別為未使用並予以消除。零副作用意味著打包器可以安全地將其移除。

INFO

pika() 呼叫在建置期間存在於被掃描的檔案中,未使用樣式的 CSS 可能仍會出現在 pika.gen.css 中。然而,未使用的 CSS class 不會讓你的 JavaScript 打包變大,未來的 PikaCSS 版本也可能支援 CSS 層級的剪枝。

與傳統 CSS-in-JS 的比較

ts
// Traditional CSS-in-JS (runtime cost)
// ❌ Ships a style engine to the browser
// ❌ Generates CSS at runtime via JavaScript
// ❌ Blocks rendering while computing styles
import { css } from 'some-runtime-css-in-js'

const className = css({
	color: 'red', // Evaluated at runtime
	fontSize: '16px', // Hashed at runtime
}) // Injected into DOM at runtime

// PikaCSS (zero runtime cost)
// ✅ No style engine in the bundle
// ✅ CSS is pre-generated at build time
// ✅ No rendering delay from style computation
const className = 'a b' // Just a string literal — nothing to compute

執行期成本分析

  • 傳統 CSS-in-JS:打包一個樣式引擎(通常 gzip 後 10–50 KB+),在每次渲染時解析樣式物件,在執行期產生並注入 CSS,可能導致版面配置抖動。
  • PikaCSS:不新增任何額外 JavaScript。樣式是預先計算的靜態字串。CSS 是一次性載入的靜態檔案。樣式計算不造成任何渲染延遲。

對你的應用程式的影響

  1. 更快的初始載入:無需下載、解析或執行樣式引擎 JavaScript
  2. 無執行期開銷:樣式解析在建置時期完成,而非每次渲染時
  3. 更好的快取:產生的 CSS 檔案是可被積極快取的靜態資源
  4. 更小的打包大小:樣式無需執行期依賴——只有字串字面值
  5. 無未樣式化內容閃爍:CSS 從一開始就以靜態檔案的形式提供,不需等到 JavaScript 執行後才產生

下一步