ナビゲーション

連携

サーバーレンダリングのアプリで Master CSS を設定する

Vite で Master CSS をビルドし、PHP、Laravel、Rails、WordPress、Shopify、ASP.NET Core、Blazor、Express のテンプレートから読み込みます。

このページの内容

サーバーや CMS が HTML をレンダリングする場合、Vite が Master CSS のアセットをビルドし、ホスト側がそのファイルを読み込みます。対象は PHP、Rails、WordPress、Shopify、ASP.NET Core、Blazor、Express です。Laravel は独自の Vite パイプラインを使います。ページ、ルート、ほかのアセットは引き続きホスト側が配信します。共通手順を適用する前にホスト別の節を選んでください。テンプレートのパスと公開ディレクトリーが走査対象とスタイルシートの配信先を決めます。Laravel は既存の Vite パイプラインに直接進めます。

#インストール

  1. #Vite と Master CSS をインストールする

    既存プロジェクトのルートまたはテーマのディレクトリーで、Vite と Master CSS の Vite インテグレーションをインストールします。package.json がなければ、先に npm init -y を実行してください。

    npm install @master/css@2.0.0npm install -D vite @master/css-vite@2.0.0
  2. #Vite を設定する

    アセットのエントリーをホスト側の公開アセットディレクトリーへビルドします。ホストの表に合わせて outDir を設定してください。emptyOutDir: false はホスト側のほかのファイルを保持します。

    vite.config.ts
    import { defineConfig } from 'vite'import masterCSS from '@master/css-vite'export default defineConfig({  base: './',  plugins: [    masterCSS({ mode: 'static' })  ],  build: {    outDir: 'public/assets',    emptyOutDir: false,    rollupOptions: {      input: 'src/master.ts',      output: {        entryFileNames: '[name].js',        assetFileNames: '[name][extname]'      }    }  }})
  3. #アセットのエントリーを作成する

    エントリーから Master CSS をインポートします。テンプレートは Vite のモジュールグラフに含まれないため、ホスト別の節の @source 行をスタイルシートに追加してください。

    src/master.ts
    import './master.css'
    src/master.css
    @import "@master/css";
  4. #ビルドスクリプトを追加する

    次のスクリプトを package.json に統合します。ホストの起動や公開前にビルドし、開発中は監視プロセスとホストのサーバーを並行して動かしてください。

    package.json
    {  "scripts": {    "build:assets": "vite build",    "watch:assets": "vite build --watch"  }}
  5. #スタイルシートを読み込む

    npm run build:assets を実行し、ホスト別の節に従ってレイアウトからビルド済み master.css にリンクし、レンダリングされるテンプレートに段落を追加します。

  6. 導入したスタイルを確認する

    <p id="master-check" class="w-fit m(0) p-md b-solid b(1) b-line-divider r-md text-sm font-regular bg-surface-raised fg-text-strong">  Hello World</p>
    ニュートラルなサーフェス、細い枠線、小さな角丸、各辺に 1rem の内側余白を持つ例です。

#アセットの接続を確認する

ホストのサーバーを動かし、例のテンプレートを実際にレンダリングするページを開きます。段落には浮き上がった面、角丸、1rem のパディングがあるはずです。ホストと npm run watch:assets の両方が動く状態で p-md を p-lg に変えてください。CSS の再ビルドとページ再読み込みの後、パディングが 1.5rem に増えます。確認後はクラスを元に戻します。

スタイルが付かない場合は、三つの接続を順に確認します:

  • **テンプレートからスキャナーへ:**ホストの @source 行を src/master.css に追加します。パスはそのスタイルシートからの相対です。追加時に @import を残してください。
  • **ビルドから公開ディレクトリーへ:**ホストが配信する前に、npm run build:assets が設定済み outDir へ master.css を書き出すか確認します。
  • **公開 URL からページへ:**レイアウトのスタイルシートリクエストが 404 や代替 HTML ではなく CSS を返すか確認し、段落に一致するルールを調べます。

静的生成には完全なクラス文字列が必要です。データベースやエディターの値を完全なクラス名に対応付けるか、@safelist で有限の候補を追加してください。bg-${color} のような文字列連結では、生成するクラスをスキャナーに伝えられません。

master.css と、それがインポートするすべての CSS ファイルを、名前と相対パスを保持して一緒にデプロイします。ホストが HTML を供給する場合は JavaScript を無効にしてデプロイ先のページを確認してください。単独の Blazor WebAssembly は、ページのレンダリングに引き続き JavaScript が必要です。固定アセット名には、以下の Rails、WordPress、ASP.NET Core で示すような、ホスト側のキャッシュバージョン管理も必要です。

#ビルドしたアセットを読み込む

ホストoutDirテンプレートのソース
PHPpublic/assets.php ファイル
Railspublic/assetsERB ビュー
WordPressテーマ内の assetsテーマの .php テンプレート
Shopifyテーマ内の assetsLiquid ファイルとテンプレート JSON
ASP.NET Corewwwroot/assetsRazor Pages と MVC ビュー
Blazorwwwroot/assets.razor、.cshtml、ホスト HTML
Expresspublic/assetsテンプレートエンジンのビュー

#PHP

PHP テンプレートを走査し、ページの head からスタイルシートにリンクします。CodeIgniter では app/Views/**/*.php を走査し、通常のアセットヘルパーで /assets/master.css を読み込みます。

src/master.css
@source "../app/**/*.php";@source "../public/**/*.php";
public/index.php
<link rel="stylesheet" href="/assets/master.css">

プレーン PHP プロジェクトでは、public を Web ルートとする場合、ビルド後に php -S localhost:8000 -t public を実行します。

#Rails

ERB ビューを走査し、アプリのレイアウトからスタイルシートを参照します:

src/master.css
@source "../app/views/**/*.erb";
app/views/layouts/application.html.erb
<%= stylesheet_link_tag "/assets/master.css", "data-turbo-track": "reload" %>

ルートとコントローラーから到達するビューで段落をレンダリングし、bin/rails server を起動します。これらの URL は public/assets 内のファイルを直接配信します。新しいリリースでは /assets/master.css?v=2 のように URL をバージョン付けしてください。Turbo のアセット追跡はタグを比較するため、同じ URL のファイルを上書きしても再読み込みは起きません。

#WordPress

有効なテーマまたは子テーマのディレクトリーで作業し、outDir: 'assets' を設定します。woocommerce/**/*.php などの上書きも含むテーマの PHP テンプレートを走査し、プラグインの内部は走査しません:

src/master.css
@source "../**/*.php";@source not "../vendor/**";@source not "../node_modules/**";

既存の設定を保持し、functions.php からスタイルシートをエンキューします。子テーマが有効なら、スタイルシートディレクトリーのヘルパーは子テーマを指します:

functions.php
add_action('wp_enqueue_scripts', function () {  wp_enqueue_style(    'master-css',    get_stylesheet_directory_uri() . '/assets/master.css',    [],    filemtime(get_stylesheet_directory() . '/assets/master.css')  );});

ページを読み込む前にビルドし、filemtime() がファイルを読めるようにします。WordPress がエンキューしたアセットを出力できるよう、テーマの wp_head() と wp_footer() を保持してください。

#Shopify

ローカルのテーマディレクトリーで作業し、outDir: 'assets' を設定します。テーマの Liquid テンプレート、セクション、ブロック、スニペットを走査します:

src/master.css
@source "../layout/**/*.liquid";@source "../sections/**/*.liquid";@source "../blocks/**/*.liquid";@source "../snippets/**/*.liquid";@source "../templates/**/*.liquid";@source "../templates/**/*.json";

テーマレイアウトの <head> 内にタグを追加し、content_for_header、content_for_layout、テーマのほかのアセットを保持します:

layout/theme.liquid
{{ 'master.css' | asset_url | stylesheet_tag }}

現在のテンプレートがレンダリングするセクションに段落を置き、Vite の監視を shopify theme dev と並行して動かします。プレビューの更新は CSS を再ビルドしません。プリセットにはグローバルなベーススタイルがあるため、既存のストアフロントコンポーネントを確認し、カスケードレイヤーで残すテーマスタイルを判断してください。アセットビルドのないテーマでは、同じソースに CLI を使えます。

#ASP.NET Core

outDir: 'wwwroot/assets' を設定し、Razor Pages と MVC ビューを走査して、共通レイアウトからスタイルシートを参照します:

src/master.css
@source "../Pages/**/*.cshtml";@source "../Views/**/*.cshtml";@source not "../bin/**";@source not "../obj/**";
Pages/Shared/_Layout.cshtml
<link rel="stylesheet" href="~/assets/master.css" asp-append-version="true">

dotnet build または dotnet publish の前に Vite のアセットをビルドし、.NET の静的アセット出力に含めます。新しい .NET テンプレートには Bootstrap が含まれる場合があり、レイヤーに属さない宣言が、レイヤー内の Master CSS ユーティリティを上書きする場合があります。カスケードレイヤーを参照してください。

#Blazor

Blazor は ASP.NET Core の設定に従い、outDir: 'wwwroot/assets' を使ってコンポーネントとホストページを走査します:

src/master.css
@source "../**/*.{razor,cshtml,html}";@source not "../bin/**";@source not "../obj/**";@source not "../node_modules/**";@source not "../wwwroot/assets/**";

Components/App.razor、wwwroot/index.html、Pages/_Host.cshtml など、使用する Blazor モデルのホストドキュメントの <head> にスタイルシートを追加します。<base>、<HeadOutlet />、ルート、Blazor の起動スクリプトは保持してください。相対パスは <base> に対して解決されます。

Components/App.razor
<link rel="stylesheet" href="assets/master.css">

サーバーレンダリングしたコンポーネントは、JavaScript を無効にしてもスタイルを保ちます。WebAssembly 専用のアプリは、コンポーネントのレンダリングにフレームワークの JavaScript が引き続き必要です。

#Express

テンプレートエンジンのビューを走査し、公開ディレクトリーを配信して、ページをレンダリングするレイアウトからスタイルシートにリンクします:

src/master.css
@source "../views/**/*.{ejs,hbs,pug}";
app.js
app.use(express.static('public'))
views/layout.ejs
<link rel="stylesheet" href="/assets/master.css">

Network パネルで、/assets/master.css が代替 HTML ページではなく CSS を返すことを確認してください。

#Laravel

Laravel はすでに Vite でアセットをビルドするため、上記の手順は省きます。既存の Laravel プロジェクトでインストーラーを実行してください。resources/css/app.css に Master CSS を追加し、laravel-vite-plugin とともにプラグインを登録します:

npm create @master/css@2.0.0 -- --framework laravel --mode static --yes

CSS エントリーから Blade ビューを走査し、そのエントリーを Laravel プラグインの input リストに保持します。既存アプリの JavaScript エントリーとほかのプラグインは残してください:

resources/css/app.css
@import '@master/css';@source '../views/**/*.blade.php';
vite.config.js
import { defineConfig } from 'vite'import laravel from 'laravel-vite-plugin'import masterCSS from '@master/css-vite'export default defineConfig({  plugins: [    laravel({ input: ['resources/css/app.css'], refresh: true }),    masterCSS({ mode: 'static' })  ]})

Laravel のビルドマニフェストからバージョン付きファイルを解決する @vite でエントリーを読み込み、npm run build を実行して Laravel 経由でページを開きます:

resources/views/app.blade.php
<head>  @vite('resources/css/app.css')</head>

アプリが JavaScript エントリーから CSS をインポートする場合は、そのエントリーを保持し、二つの経路で同じ CSS を読み込まないでください。Laravel の Vite インテグレーションを参照できます。


#別のレンダリングモードを選ぶ

既定は静的モードです。モードを変えてもアセットのエントリーを保持してください:

モードホスト変更点
静的すべて実行時の変更なし
ランタイムPHP、Rails、WordPress、ASP.NET Core、Blazor、Expressmode: 'runtime'、ランタイムエントリー、モジュールスクリプト
プログレッシブExpressサーバーが初回レスポンスの CSS をレンダリングし、後からのクラスはランタイムが処理
ブラウザーで新しいクラスを生成する

ランタイムをインストールし、vite.config.ts に masterCSS({ mode: 'runtime' }) を設定して、アセットのエントリーから起動します。ランタイム生成では @source 行は不要です:

npm install @master/css-runtime@2.0.0
src/master.ts
/// <reference types="@master/css/client" />import { MasterCSSRuntime } from '@master/css-runtime'import program from 'virtual:master-css-program'import emittedGlobals from 'virtual:master-css-emitted-globals'import './master.css'const runtime = await MasterCSSRuntime.start({ program, emittedGlobals })runtime.observe()

スタイルシートとともに master.js をモジュールとして読み込み、レイアウトのほかのタグは保持します:

ホストモジュールスクリプト
PHP、Express</body> の前に <script type="module" src="/assets/master.js"></script>
Rails<%= javascript_include_tag "/assets/master.js", type: "module", "data-turbo-track": "reload" %>
ASP.NET Core<script type="module" src="~/assets/master.js" asp-append-version="true"></script>
BlazorBlazor の起動スクリプトの後に <script type="module" src="assets/master.js"></script>

WordPress 6.5 以降では、同じフック内の wp_enqueue_script_module() でモジュールを読み込みます:

functions.php
wp_enqueue_script_module(  'master-css-runtime',  get_stylesheet_directory_uri() . '/assets/master.js',  [],  filemtime(get_stylesheet_directory() . '/assets/master.js'));

Blazor Web Apps は拡張ナビゲーション中に DOM を更新し、ランタイムのスタイルシートを削除する場合があります。各 enhancedload の後でランタイムを再起動し、ストリームの更新を直列に処理してください。単独の WebAssembly と古い Blazor Server のホストでは、上記のエントリーを使います。

src/master.ts
/// <reference types="@master/css/client" />import { MasterCSSRuntime } from '@master/css-runtime'import program from 'virtual:master-css-program'import emittedGlobals from 'virtual:master-css-emitted-globals'import './master.css'declare const Blazor: {  addEventListener(name: 'enhancedload', listener: () => void): void}async function startRuntime() {  const runtime = await MasterCSSRuntime.start({ program, emittedGlobals })  runtime.observe()  return runtime}let runtime = await startRuntime()let navigation = Promise.resolve()Blazor.addEventListener('enhancedload', () => {  navigation = navigation.then(async () => {    runtime.dispose()    runtime = await startRuntime()  }).catch(console.error)})

生成したすべてのスタイルシート、インポート、プログラムのアセットを一緒にデプロイします。ランタイムのスタイル適用は JavaScript の読み込み後に始まります。スクリプトが使えない場合も、レンダリングモードの説明どおりドキュメントを表示したままにしてください。起動後にブラウザーのコンソールで次を実行すると、再ビルドせずに段落に下線が付くはずです:

document.querySelector('#master-check').classList.add('underline')

ランタイムはページのドキュメントを監視します。独立した iframe やシャドウルート内の内容には、個別の CSS 配信が必要です。

Express でサーバーレンダリングしたスタイルを含める

プログレッシブレンダリングでは、Express がテンプレートをレンダリングし、@master/css-server が初回レスポンスの CSS を挿入し、ランタイムがそれを取り込んで後からのクラスを処理します。ランタイムに加えてサーバーレンダラーとプリセットをインストールします:

npm install @master/css-runtime@2.0.0 @master/css-server@2.0.0 @master/css-preset@2.0.0

masterCSS({ mode: 'runtime' }) を保持し、エントリーからプログラムを遅延読み込みします。これにより、すべてのクラスがカバー済みのページは、新しいクラスが必要になるまでエンジンを遅らせられます:

src/master.ts
/// <reference types="@master/css/client" />import { MasterCSSRuntime } from '@master/css-runtime'import emittedGlobals from 'virtual:master-css-emitted-globals'import './master.css'const runtime = await MasterCSSRuntime.start({  program: () => import('virtual:master-css-program').then(module => module.default),  emittedGlobals})runtime.observe()

まずテンプレートをレンダリングしてから、ドキュメント全体をレンダラーに渡します。ES モジュールのサーバーには、package.json の "type": "module" が必要です:

app.js
import express from 'express'import ejs from 'ejs'import { createServerRenderer } from '@master/css-server'import manifest from '@master/css-preset/default-manifest.json' with { type: 'json' }const app = express()const renderer = createServerRenderer({ manifest })app.use('/assets', express.static('public/assets'))app.get('/', async (_request, response) => {  const body = await ejs.renderFile('views/index.ejs')  const document = `<!doctype html><html lang="en"><head>  <meta charset="utf-8">  <meta name="viewport" content="width=device-width, initial-scale=1">  <link rel="stylesheet" href="/assets/master.css"></head><body>  ${body}  <script type="module" src="/assets/master.js"></script></body></html>`  const rendered = renderer.renderHTML(document, {    hydrationManifest: 'inject'  })  response.send(rendered.html)})const server = app.listen(3000)server.on('close', () => renderer.dispose())

初回レスポンスには style#master-css と小さなハイドレーションレコードが含まれ、サーバーマニフェストはサーバーに残ります。この例は src/master.css のプリセットと一致する、既定のプリセットマニフェストでレンダリングします。プロジェクトのトークンやユーティリティを追加する場合は、サーバー用のプロジェクトマニフェストもコンパイルしてください。そうしなければ、初期 CSS がブラウザーの定義と一致しません。

JavaScript を無効にしても、段落には最初からスタイルが付くはずです。JavaScript を再び有効にして読み込み直し、コンソールから underline を追加すると、新しいサーバーレスポンスなしに適用されるはずです。