前端模块化与SSR可兼容,但需注意执行环境差异、生命周期时机、模块导出方式;应避免浏览器API、统一ESM或兼容CommonJS、组件需无副作用、动态导入须await、环境标识要明确。

前端模块化与服务端渲染(SSR)可以良好兼容,但需注意执行环境差异、生命周期时机和模块导出方式等关键问题。
模块语法需兼顾 Node.js 与浏览器
ES Module(import/export)在现代 Node.js(v14+)中已原生支持,但 SSR 环境(如 Next.js、Nuxt 或自建 Express + React-SSR)通常依赖打包器(Webpack/Vite)或运行时处理。若直接在 Node 中 import 浏览器专属模块(如含 window、document 的代码),会抛错。
- 服务端应避免使用仅限浏览器的 API,或用条件判断隔离:例如
if (typeof window !== 'undefined') { ... } - 推荐统一使用 ESM,但需确保
package.json中设置"type": "module",或使用.mjs后缀;否则 CommonJS(require)更稳妥兼容旧版 Node - 第三方库若未提供 ESM 入口,可通过打包器配置
resolve.alias或externals控制加载行为
组件/模块导出需适配 SSR 生命周期
React/Vue 等框架的 SSR 要求组件是纯函数式、无副作用、可多次同步执行。若模块在顶层执行中访问全局对象、发起请求或修改状态,服务端渲染将失败或产生不一致结果。
- 数据获取逻辑应放在
getServerSideProps(Next.js)、asyncData(Nuxt)或useEffect的客户端侧分支中,而非模块顶层 - 自定义 Hook 或工具模块应设计为“惰性执行”,例如导出函数而非立即执行的对象:
export const createApiClient = (baseUrl) => ({ get() { ... } });,而非const client = new ApiClient(...) - 样式模块(如 CSS-in-JS)需支持服务端样式收集,例如 Emotion 提供
CacheProvider+renderStylesToString,Styled-components 需配合ServerStyleSheet
动态导入(import())在 SSR 中需谨慎使用
import() 是异步操作,在服务端同步渲染流程中若未 await,会导致内容缺失或 hydration 不匹配。
- Next.js 的
dynamic(..., { ssr: false })可禁用某组件 SSR,适合广告、评论等非核心内容 - 若需服务端加载,应使用
await import('./module')并确保该模块本身不含浏览器 API;Vite/webpack 会自动将其转为 Promise,Node 环境需支持顶层 await(ESM 模块中可用) - 路由级代码分割(如
React.lazy)默认不支持 SSR,必须搭配服务端预加载方案(如getInitialProps中手动import)
构建与运行时环境标识要明确
同一份模块可能被服务端和客户端同时引用,需清晰区分执行上下文,避免“hydration mismatch”或重复初始化。
- 通过打包器定义常量(如
process.env.NODE_ENV、typeof window === 'undefined')做环境判断,但避免在顶层写死逻辑 - 状态管理库(如 Zustand、Pinia)需支持服务端 store 实例创建与序列化,例如将初始 state 注入 HTML 模板,并在客户端 rehydrate
- 使用
__dirname、require.resolve等 Node 特有 API 的模块,不可直接在浏览器中运行,应单独封装或通过条件导出分离
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











