Skip to content

遅延モード

デフォルトでは、EffCSSはCSSを積極的に生成します。ユーティリティを呼び出すとすぐに、スタイルシートのルールがCSSOMに書き込まれます。遅延モードでは、実際の生成は遅延されます。生成されたリゾルバーが実際に使用される(呼び出されるか、文字列変換される)まで、CSSはスタイルシートに書き込まれません。

遅延モードには2つの種類があり、必要な制御レベルを選択できます。

種類トリガースコープ
制御lazy*ユーティリティをオプトインユーティリティごと、常に遅延
ライブラリレベルconfigure({ lazy: true })リゾルバーを返すすべての生成ユーティリティ

1. 制御対象 — lazy* ユーティリティ

これらのユーティリティは、グローバル設定に関わらず、常に遅延評価されます。各呼び出しは関数リゾルバを返します。以下の操作を行うまで、何も生成されません。

  • リゾルバを呼び出す — fn() (または fn(...args))、
  • 文字列に変換する — `${fn}` または String(fn)

ルールの内容は、オブジェクトとして、またはオブジェクトを返す関数として渡すことができます。関数は、最初のウォームアップ時に遅延評価されます。

ユーティリティ戻り値生成
lazyClassName(rule) (または className.lazy(rule))() => string (クラス名)匿名クラスルール 1 つ
lazyAttribute(rule) (または attribute.lazy(rule))() => object ({ 'data-…': '' })匿名属性ルール 1 つ
lazyClassNames(gen) (または classNames.lazy(gen))セレクタリゾルバークラスセレクタスタイルシート
lazyAttributes(gen) (または attributes.lazy(gen))セレクタリゾルバー属性セレクタスタイルシート
lazyCustomStyles(gen) (または customStyles.lazy(gen))セレクタリゾルバーカスタムスタイルシート

前に - すぐに

ts
import { className, attribute, classNames } from 'effcss';

// CSS is written into the shared stylesheet right here
const centerCls = className({ margin: 'auto' });
const markerAttr = attribute({ fontWeight: 'bold' });
const utils = classNames<Utils>((selectors) => {
    const { w } = selectors;
    return {
        [w.s]: { width: '12px' },
        [w.m]: { width: '16px' }
    };
});

すべての呼び出しは、結果がページ上で使用されなくても、即座にルールを生成します。

After — 制御された遅延評価

ts
import { lazyClassName, lazyAttribute, lazyClassNames } from 'effcss';

// nothing is generated at creation time
const centerCls = className.lazy({ margin: 'auto' });
const markerAttr = attribute.lazy({ fontWeight: 'bold' });
const utils = classNames.lazy<Utils>((selectors) => {
    const { w } = selectors;
    return {
        [w.s]: { width: '12px' },
        [w.m]: { width: '16px' }
    };
});

// ... later, where the value is actually consumed:
<div className={centerCls()} {...markerAttr()}>   // generates the anonymous rules
<div className={utils({ w: 'm' })} />             // generates the stylesheet

lazyClassName (className.lazy) や lazyAttribute (attribute.lazy) を含むすべての遅延ハンドラは関数を返すことに注意してください。個々のルールの遅延リゾルバの場合、これによりさらに利点が得られます。このようなリゾルバを文字列にキャストすると、他のスタイルで使用できる正しいセレクタが返されます。

ts
const divider = className.lazy({
    width: '100%',
    height: '1px'
});

const layout = classNames.lazy<Layout>((selectors) => ({
    [selectors.row]: {
        display: 'flex'
    },
    // `divider` coerce to its real `.class` selector
    // when `layout` will be used at the first time
    [`& ${divider}`]: {
        background: 'red'
    }
}));

さらに、これらの関数はオブジェクトだけでなくジェネレータも受け入れることができます。

ts
const divider = className.lazy(() => {
    // you can create other global rules inside
    // so that they are created the first time className is used
    const width = variable('100%');
    return {
        width: width(),
        height: '1px',
        '&:hover': {
            [width]: '50%'
        }
    };
});

重要: className / attribute は関数以外の値 (string / オブジェクト) を返します。これらは遅延評価ではなく、ここでは関係ありません。

2. ライブラリレベル — configure({ lazy: true })

configure({ lazy: true }) は、関数リゾルバーを返すすべての生成ユーティリティを、実行時に遅延バージョンに切り替えます。対象となるユーティリティは以下のとおりです。

variablevariablesanimationanimationslayerlayersfontfontsclassNamesattributescustomStyles

API はこれまでと変わらず、lazy* という名前を使う必要はありません。これらのユーティリティは、結果が使用されるまで生成を遅延します。

classNameattribute は影響を受けません。これらはリゾルバーではなく、プレーンな値(string またはオブジェクト)を返すため、すぐに生成されます。

以前 — デフォルト(熱心)

ts
import { variable, animation, classNames } from 'effcss';

const shadowColor = variable('#58666d');
const spin = animation({ to: { transform: 'rotate(360deg)' } });

const utils = classNames<Utils>((selectors) => {
    const { w } = selectors;
    return {
        [w.s]: { width: '12px' }
    };
});

configure({ lazy: true }) の後

ts
import { configure, variable, animation, classNames } from 'effcss';

configure({ lazy: true });

// same API, different timing
const shadowColor = variable('#58666d');
const spin = animation({ to: { transform: 'rotate(360deg)' } });
// nothing is written yet

const utils = classNames.lazy<Utils>((selectors) => {
    const { w } = selectors;
    return {
        [w.s]: { width: '12px' }
    };
});
// nothing is written yet

// CSS is produced only on first real use:
`${shadowColor()} or ${shadowColor}`
`${spin()} or ${spin}`
utils({ w: 's' })

複数のユーティリティ(variablesanimationslayersfontsなど)の場合、バッチ全体がまとめてウォームアップされます。つまり、いずれかのリゾルバを操作すると、セット全体が生成され、SSRハイドレーションの順序が決定論的に保たれます。

動作に関する注記

  • ウォームアップのトリガー — リゾルバは呼び出す文字列変換によってウォームアップされます。単に保持するだけ(または変数に対して.get() / .set()を呼び出すだけ)では、CSSは生成されません
  • variable().get() / .set() — ウォームアップ前は、get()''を返し、set()何もしないです。これらは、リゾルバがウォームアップされた後にのみ有効になります。
  • update() — 遅延モードでは、まだ作成されていない変数は変更されません。
  • SSRハイドレーション — 生成順序は決定論的(内部カウンターを共有)なので、サーバーとクライアントが同じ順序でリゾルバーをウォームアップする限り、同一のセレクターを生成します。
  • subscribeイベントEffCSSEventは、ユーティリティが最初に呼び出された時ではなく、実際の生成(リゾルバーのウォームアップ)の時点で発行されます。

2つの選択肢

  • 特定のルールのみに遅延処理を適用し、それ以外は即時処理にしたい場合は、制御されたlazy*ユーティリティを使用します。アプリケーション全体の設定とは独立して遅延処理を保証したい場合は、**configure({ lazy: true })**を使用します。
  • コードを変更せずにライブラリ全体で実際に使用されるもののみの動作を実現したい場合は、**configure({ lazy: true })**を使用します。例えば、vite-plugin-effcssと組み合わせて、実際にレンダリングされるCSSのみを配信する場合などです。

Apache License 2.0に基づいて公開されています。