Linaria通过Babel插件在构建时静态解析css模板字符串和styled调用,提取为独立CSS文件,运行时无样式逻辑、无insertRule或useEffect;所有表达式须编译期可求值,不支持运行时动态插值。

Linaria 是怎么做到“零运行时”的?
Linaria 在构建时通过 Babel 插件解析 css 模板字符串和 styled 调用,把样式提取成独立的 CSS 文件,运行时完全不注入或操作 document.styleSheets。这意味着打包后 JS 里没有样式逻辑,也没有 useEffect 或 insertRule 调用。
- 构建阶段必须启用
@linaria/babel-preset或手动配置@linaria/babel-plugin -
css和styled必须是顶层字面量(不能是变量拼接、动态模板),否则会被跳过 - 所有表达式必须能在编译期求值(比如不能含
Math.random()、process.env.NODE_ENV以外的环境变量)
如何正确配置 Babel 以支持 Linaria?
Babel 配置错误是本地能跑、CI 报错或样式丢失的最常见原因。
- 在
.babelrc或babel.config.js中,@linaria/babel-preset必须放在其他 preset(如@babel/preset-react)之前 - 如果使用自定义插件链,确保
@linaria/babel-plugin的sourceMap选项与项目一致(开发建议开,生产可关) - Next.js 用户需额外安装
@linaria/next并在next.config.js中启用,否则getStaticProps里的styled会被忽略
示例片段(babel.config.js):
module.exports = {
presets: [
'@linaria/babel-preset',
'@babel/preset-react',
],
};
为什么 styled 组件在 SSR 下 class 名不一致?
这不是 bug,而是 Linaria 默认使用内容哈希生成 class 名,但服务端和客户端若构建环境不一致(比如 NODE_ENV 不同、fs 缓存路径不同),哈希结果就会不同,导致 hydrate 失败。
立即学习“前端免费学习笔记(深入)”;
- 开发时设
classNameSlug: '[name]__[local]___[hash:base64:5]'有助于调试,但不要用于生产 - 生产务必统一构建环境:服务端渲染的代码必须和静态构建用同一份输出 CSS,不能分别构建
- 若用 Webpack,确认
@linaria/webpack-loader的sourceMap和preprocessor选项两端一致;Vite 用户注意linaria/vite插件默认禁用缓存,需显式配cacheDir
动态主题切换为何不生效?
Linaria 的零运行时特性决定了它不支持运行时计算样式值。所有传入 css 或 styled 的参数必须是编译期常量。
- 不能写
styled.div`color: \${props => props.theme.color}`—— 这会直接报错:“Expression is not allowed in css tag” - 替代方案只有两个:
• 提前为每种主题生成独立 CSS 文件(例如theme-dark.css+theme-light.css),运行时切换<link rel="stylesheet">
• 改用 CSS 自定义属性(--primary-color),在css中硬编码引用,再由 JS 控制根节点的style属性
后者更轻量,例如:
const Button = styled.button\` color: var(--button-color, #007bff); \`;
class 名生成和主题适配这两块,最容易被当成“功能缺失”去折腾,其实只是对“零运行时”的边界理解不到位。


















