import "./styles.css"不是静态引入,因webpack将其作为js模块处理,运行时通过style-loader注入,导致ssr无样式、css混入js bundle、fouc及js失效则样式丢失;真正静态化需在gatsby-ssr.js中读取构建产物的独立css文件并注入。

直接在组件里 import "./styles.css" 或在 gatsby-browser.js 中导入全局 CSS,都不是真正意义上的“静态引入”——样式仍被 webpack 打包进 JS bundle,首屏渲染必须等 JS 下载、解析、执行后才注入,存在 FOUC 和 JS 失败即无样式的风险。
为什么 import CSS 不是静态引入?
Webpack 把 import 的 CSS 当作模块处理,最终通过 style-loader 在运行时动态插入 <style></style> 标签。这意味着:
- 样式内容不参与 SSR,服务端生成的 HTML
里没有样式 - 构建产物中 CSS 通常混在
app-xxx.js里,而非独立.css文件 - 浏览器无法并行下载 CSS,JS 加载阻塞样式呈现
- 哪怕用了
gatsby-plugin-sass或gatsby-plugin-postcss,只要路径是 JSimport进来的,就仍是运行时链路
如何让 CSS 真正静态化(零运行时)?
核心是绕过 JS 模块系统,在构建阶段生成带 hash 的独立 CSS 文件,并在 gatsby-ssr.js 中同步读取、注入到 HTML 里。实操要点:
- 确保插件(如
gatsby-plugin-postcss)已配置,并将 CSS 输出到public/static/css/目录下(文件名含 hash,如app.123abc.css) - 在
gatsby-ssr.js中用fs.readFileSync同步读取该文件(仅限构建时,不可用于浏览器) - 用
onRenderBody钩子 +setHeadComponents注入为<style></style>或<link rel="stylesheet"> - 绝对不要在
gatsby-browser.js做任何样式注入——那是客户端行为,与静态目标冲突
更省心的零运行时方案:vanilla-extract 或 Linaria
它们不依赖 webpack 的 CSS loader,而是用 Babel 插件在构建时解析样式代码,直接输出标准 CSS 文件,并自动完成 SSR 注入:
-
vanilla-extract:需安装gatsby-plugin-vanilla-extract,样式写在.css.ts文件里,类型安全,构建即得.css文件 -
Linaria:写法接近styled-components(如const Button = styled.button`color: blue;`),但构建后无 JS 样式逻辑,需配gatsby-ssr.js的onRenderBody才能保证 SSR 有样式 - 二者都要求你在
gatsby-config.js中启用对应插件,且不能跳过gatsby-ssr.js配置——否则 SSR 阶段页面无样式
最容易被忽略的一点:无论选哪种方案,gatsby-ssr.js 中的 onRenderBody 是 SSR 样式注入的唯一入口;漏掉它,再“静态”的 CSS 也只在客户端生效,首屏照样白屏或闪动。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











