SolidJS SSR 水化脚本编译错误排查求助
关于SolidJS同构开发水化失败的问题排查与解决
我正在尝试SolidJS的同构开发方案,严格遵循官方文档操作。页面视觉渲染正常,但水化成功本该出现的浏览器日志未出现,反而报错。
相关代码
服务器代码
app.get('/', (req, res) => { return res.send(getBasicHTMLSkeleton()) })
getBasicHTMLSkeleton函数
import {renderToString, generateHydrationScript, Dynamic} from "solid-js/web"; import HelloWorld from "../../hybrid/components/HelloWorld"; export const getBasicHTMLSkeleton = () => { const hello = renderToString(() => <HelloWorld />) return ` <html lang="en"> <head> <title>🔥 Solid SSR 🔥</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="/_index.min.css" /> <script src="hydrate.js" /> ${generateHydrationScript()} </head> <body>${hello}</body> </html> `; }
HelloWorld组件
import {createEffect} from "solid-js"; const HelloWorld = () => { createEffect(() => { console.log('lel!') }) return <div> <h1>Hello</h1> </div> } export default HelloWorld
客户端hydrate.js脚本
import {hydrate} from "solid-js/web"; import HelloWorld from "../hybrid/components/HelloWorld"; hydrate(() => <HelloWorld/>, document)
浏览器控制台报错
Uncaught TypeError: (0 , solid_js_web__WEBPACK_IMPORTED_MODULE_0__.template) is not a function at ./src/hybrid/components/HelloWorld.tsx (hydrate.js:25:83) at __webpack_require__ (bootstrap:19:1) at publicPath:1:1 at hydrate.js:3421:3 at hydrate.js:3423:12
Webpack客户端编译配置
const tsAndTsxRuleClient = { test: /\.(ts|tsx)$/i, exclude: ['/node_modules/'], use: [ { loader: 'babel-loader', options: { presets: [["solid", {"generate": "dom", "hydratable": true}]], }, }, { loader: 'ts-loader', }, ] } const configClient = { ...configServer, entry: './src/client/hydrate.tsx', module: { rules: [tsAndTsxRuleClient] }, output: { filename: 'hydrate.js', path: path.resolve(__dirname, 'dist-client') } }
打包后hydrate.js相关代码
(() => { console.log('HYDRATING?'); (0,solid_js_web__WEBPACK_IMPORTED_MODULE_1__.hydrate)(() => (0,solid_js_web__WEBPACK_IMPORTED_MODULE_2__.createComponent)(_hybrid_components_HelloWorld__WEBPACK_IMPORTED_MODULE_0__["default"], {}), document); // this code breaks everything })();
我尝试过调整Webpack配置(如将generate设为ssr)、检查语法、更换水化目标节点,但问题依旧。请问我遗漏了什么?
问题原因及解决方案
这个错误核心是客户端与服务端的组件编译格式不兼容,或Webpack配置存在加载顺序、预设冲突。以下是针对性修复方案:
1. 调整Babel与ts-loader的执行顺序
当前规则先执行babel-loader再执行ts-loader,会导致SolidJS的Babel预设无法正确处理TypeScript代码。需将ts-loader前置,先转译TS为JS,再让Babel处理SolidJS编译逻辑:
const tsAndTsxRuleClient = { test: /\.(ts|tsx)$/i, exclude: ['/node_modules/'], use: [ { loader: 'ts-loader', options: { transpileOnly: true, // 仅做类型检查,转译交给Babel compilerOptions: { jsx: 'preserve' // 保留JSX让Babel处理 } }, }, { loader: 'babel-loader', options: { presets: [["solid", {"generate": "dom", "hydratable": true}]], }, }, ] }
2. 确保服务端与客户端编译目标一致
- 服务端编译时,SolidJS预设的
generate需设为ssr;客户端保持generate: "dom"且hydratable: true,避免组件被编译为两种不兼容格式。 - 检查
configServer中的TS/TSX规则,确认服务端Babel预设为["solid", {"generate": "ssr"}]。
3. 修正HTML脚本加载顺序
generateHydrationScript()会输出SolidJS初始化脚本,必须在你的客户端水化代码之前加载,调整HTML模板中的顺序:
${generateHydrationScript()} <script src="hydrate.js"></script>
4. 验证TS配置与Webpack解析
- 确保
tsconfig.json中的jsx设为preserve,让Babel负责JSX编译,避免与ts-loader冲突。 - 在Webpack客户端配置中添加解析规则,确保正确识别SolidJS模块:
resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'], alias: { 'solid-js/web': require.resolve('solid-js/web'), 'solid-js': require.resolve('solid-js') } }
内容的提问来源于stack exchange,提问作者Thomas Opdebeeck
相关产品推荐
相关产品推荐

