css-loader 的 exportonlylocals 必须设为 false,否则 ssr 无法获取 css 字符串;禁用 mini-css-extract-plugin,改用 css-loader + string-loader 或 extract-css-chunks-webpack-plugin;样式需按组件渲染顺序动态收集并注入 head。

css-loader 的 exportOnlyLocals 必须设为 false
Less 文件经 less-loader 编译后,最终交由 css-loader 处理。默认配置下 css-loader 的 exportOnlyLocals: true 会丢弃原始 CSS 内容,只保留类名映射对象(如 { button: 'Button_button_abc' })。服务端没 document,style-loader 完全无效,你根本拿不到 CSS 字符串。
必须显式关闭这个开关:
-
css-loader配置中加{ exportOnlyLocals: false } - 否则
module.exports或__webpack_module__.exports里没有toString()方法可用 - Vue/React SSR 中调用
css.toString()或读取css.locals都会失败或返回空字符串
别用 mini-css-extract-plugin 处理 SSR 构建的 Less
这个插件专为浏览器端构建设计:它把 CSS 提取成独立文件,然后靠 link 标签加载。但在 Node.js 环境里,你没法自动读取生成的哈希文件路径(比如 main.1a2b3c.css),也无法可靠判断 chunk 对应关系。
SSR 构建阶段应该让 Less/CSS 内容保留在模块导出中,而不是写文件:
- Webpack 配置中对
.less规则禁用mini-css-extract-plugin - 改用
css-loader+string-loader(或自定义 loader)输出纯字符串 - 或者用
extract-css-chunks-webpack-plugin,它提供getCssString()API,可在服务端调用
服务端收集样式时要按组件渲染顺序执行
你不能在入口处一次性 require 所有 Less 模块拼接 CSS —— 这会导致注入顺序错乱。客户端 hydration 后,style 标签被重插,优先级可能低于外部 link,样式被覆盖,出现闪动。
正确做法是结合渲染上下文动态收集:
- 在
renderToString前创建隔离上下文(如createServerContext()) - 每个组件渲染时,通过
useEffect(React)或onServerPrefetch(Vue)触发样式注册 - 服务端收集器按实际渲染顺序 push CSS 字符串,最后统一注入
Less 变量和 @import 在 SSR 中的路径问题
Less 的 @import 默认基于当前文件路径解析,但 Webpack 构建时路径已扁平化。服务端运行时若直接 require Less 文件,Node 不认识 @import 语法,会报错或静默失败。
关键点在于:SSR 不该直接 require Less 源文件,而应依赖 Webpack 构建产物:
- 确保所有
@import路径在构建时能被less-loader正确解析(推荐用~别名或相对路径) - 不要在 Node 环境里用
less.render()动态编译 —— 缺少浏览器环境变量、函数(如contrast())可能失效 - 变量作用域以 Webpack module graph 为准,不是运行时文件系统层级
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











