在服务器渲染应用中配置 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 流程。
#安装
#安装 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.0import { 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]' } } }})#添加构建脚本
将这些脚本合并到
package.json。启动或发布宿主系统前先构建;开发时请让监听进程与宿主服务器一起运行。{ "scripts": { "build:assets": "vite build", "watch:assets": "vite build --watch" }}#加载样式表
运行
npm run build:assets,按对应章节的方式从宿主布局链接构建后的master.css,再将段落加入会渲染的模板。
检查已安装的样式
<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 内边距。宿主与 npm run watch:assets 都在运行时,将 p-md 改为 p-lg:CSS 重新构建并重新加载页面后,内边距应增加到 1.5rem。检查后将类名恢复原值。
如果页面没有样式,请按顺序追查三个连接:
- **模板到扫描器:**将宿主的
@source行追加到src/master.css。路径相对于此样式表解析。添加时请保留@import。 - **构建到公开目录:**确认宿主提供文件前,
npm run build:assets已将master.css写入配置的outDir。 - **公开 URL 到页面:**确认布局的样式表请求返回 CSS,而非 404 或 HTML 回退页面,再检查段落的匹配规则。
静态生成需要完整类名字符串。请将数据库或编辑器值映射到完整类名,或通过 @safelist 添加范围有限的候选项。bg-${color} 这样的字符串拼接不会告诉扫描器应生成哪些类名。
请将 master.css 及其导入的所有 CSS 文件一并部署,保留名称和相对路径。如果宿主会提供 HTML,请禁用 JavaScript 检查部署后的页面;独立 Blazor WebAssembly 仍需要 JavaScript 渲染页面。固定资源文件名也需要宿主的缓存版本策略,下方 Rails、WordPress 和 ASP.NET Core 示例有所演示。
#加载构建后的资源
| 宿主系统 | outDir | 模板来源 |
|---|---|---|
| PHP | public/assets | .php 文件 |
| Rails | public/assets | ERB 视图 |
| WordPress | 主题中的 assets | 主题 .php 模板 |
| Shopify | 主题中的 assets | Liquid 文件和模板 JSON |
| ASP.NET Core | wwwroot/assets | Razor Pages 和 MVC 视图 |
| Blazor | wwwroot/assets | .razor、.cshtml 和宿主 HTML |
| Express | public/assets | 模板引擎视图 |
#PHP
扫描 PHP 模板,并从页面 head 链接样式表。CodeIgniter 请扫描 app/Views/**/*.php,并使用普通资源辅助函数加载 /assets/master.css。
@source "../app/**/*.php";@source "../public/**/*.php";<link rel="stylesheet" href="/assets/master.css">纯 PHP 项目假设以 public 为网站根目录,构建后运行 php -S localhost:8000 -t public。
#Rails
扫描 ERB 视图,并从应用布局引用样式表:
@source "../app/views/**/*.erb";<%= stylesheet_link_tag "/assets/master.css", "data-turbo-track": "reload" %>让路由和控制器能访问的视图渲染此段落,再启动 bin/rails server。这些 URL 会直接提供 public/assets 下的文件。发布新版本时,请为 URL 加上版本,例如 /assets/master.css?v=2:Turbo 的资源跟踪会比较标签,因此仅覆盖相同 URL 的文件不会触发重新加载。
#WordPress
在已启用的主题或子主题目录中工作,并设置 outDir: 'assets'。扫描主题 PHP 模板,包括 woocommerce/**/*.php 等覆盖文件,但不要扫描插件内部实现:
@source "../**/*.php";@source not "../vendor/**";@source not "../node_modules/**";从 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() 能读取文件;并在主题中保留 wp_head() 和 wp_footer(),让 WordPress 输出队列中的资源。
#Shopify
在本地主题目录中工作,并设置 outDir: 'assets'。扫描主题的 Liquid 模板、分区、区块和代码片段:
@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 和主题的其他资源:
{{ 'master.css' | asset_url | stylesheet_tag }}将段落放入当前模板会渲染的分区,并让 Vite 监听进程与 shopify theme dev 一起运行;预览更新不会重新构建 CSS。预设包含全局基础样式,因此请检查现有店面组件,并使用层叠层决定保留哪些主题样式。没有资源构建流程的主题可以使用 CLI 扫描相同来源。
#ASP.NET Core
设置 outDir: 'wwwroot/assets',扫描 Razor Pages 和 MVC 视图,并从共享布局引用样式表:
@source "../Pages/**/*.cshtml";@source "../Views/**/*.cshtml";@source not "../bin/**";@source not "../obj/**";<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',并扫描组件和宿主页面:
@source "../**/*.{razor,cshtml,html}";@source not "../bin/**";@source not "../obj/**";@source not "../node_modules/**";@source not "../wwwroot/assets/**";将样式表加入所用 Blazor 模型的宿主文档的 <head>,例如 Components/App.razor、wwwroot/index.html 或 Pages/_Host.cshtml。保留 <base>、<HeadOutlet />、路由和 Blazor 启动脚本;相对路径会根据 <base> 解析。
<link rel="stylesheet" href="assets/master.css">服务器渲染组件在禁用 JavaScript 时仍具有样式。仅使用 WebAssembly 的应用仍需要框架 JavaScript 才能渲染组件。
#Express
扫描模板引擎的视图,提供公开目录,并从渲染页面的布局链接样式表:
@source "../views/**/*.{ejs,hbs,pug}";app.use(express.static('public'))<link rel="stylesheet" href="/assets/master.css">在 Network 面板中,/assets/master.css 必须返回 CSS,而非 HTML 回退页面。
#Laravel
Laravel 已通过 Vite 构建资源,因此请跳过上方步骤。在现有的 Laravel 项目中运行安装程序;它会将 Master CSS 加入 resources/css/app.css,并在 laravel-vite-plugin 旁注册插件:
npm create @master/css@2.0.0 -- --framework laravel --mode static --yes从 CSS 入口扫描 Blade 视图,并将该入口保留在 Laravel 插件的 input 列表中。现有应用请保留 JavaScript 入口和其他插件:
@import '@master/css';@source '../views/**/*.blade.php';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' }) ]})使用 @vite 加载入口,它会从 Laravel 构建 manifest 解析带版本的文件;再运行 npm run build,通过 Laravel 加载页面:
<head> @vite('resources/css/app.css')</head>如果应用改由 JavaScript 入口导入 CSS,请保留该入口,避免通过两条路径加载相同 CSS。参阅 Laravel 的 Vite 集成。
#选择其他渲染模式
默认使用静态模式。切换模式时,请保留资源入口:
| 模式 | 宿主系统 | 变更内容 |
|---|---|---|
| 静态 | 所有宿主 | 运行时无额外动作 |
| 运行时 | PHP、Rails、WordPress、ASP.NET Core、Blazor、Express | mode: 'runtime'、运行时入口和模块脚本 |
| 渐进式 | Express | 服务器渲染首次响应 CSS;运行时处理后续类名 |
在浏览器中生成新类名
安装运行时,在 vite.config.ts 中设置 masterCSS({ mode: 'runtime' }),并从资源入口启动它。运行时生成不需要 @source 行:
npm install @master/css-runtime@2.0.0/// <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> |
| Blazor | 在 Blazor 启动脚本后加入 <script type="module" src="assets/master.js"></script> |
WordPress 6.5 及以上版本使用相同钩子中的 wp_enqueue_script_module() 加载模块:
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 宿主使用上方入口即可。
/// <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 或 shadow root 内的内容需要自己的 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' }),让入口延迟加载程序;已完整覆盖的页面便能延后加载引擎,直到新类名需要它:
/// <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":
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 和小型水合记录;服务器 manifest 留在服务器上。本示例使用默认预设 manifest 渲染,与 src/master.css 的预设一致。如果加入项目令牌或工具类,也必须为服务器编译项目 manifest,否则初始 CSS 将与浏览器定义不一致。
禁用 JavaScript 时,段落应已经具有样式。重新启用 JavaScript、重新加载,再从控制台加入 underline;它应直接应用,无需新的服务器响应。

