I am experimenting with the isomorphic approach for Solidjs. I followed the documentation quite faithfull: https://www.solidjs.com/guides/server.
Visually, everything seems to be working: my html is rendered in the browser as expected. However, if the hydration would be successful, I would see a log in the browser. Instead I see an error log.
The server:
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>
`;
}
The HelloWorld component:
import {createEffect} from "solid-js";
const HelloWorld = () => {
createEffect(() => {
console.log('lel!')
})
return <div>
<h1>Hello</h1>
</div>
}
export default HelloWorld
The hydrate.js-script (this script is pulled in at the client-side):
import {hydrate} from "solid-js/web";
import HelloWorld from "../hybrid/components/HelloWorld";
hydrate(() => <HelloWorld/>, document)
I get the following error in the browser's console:
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
The webpack config for compiling the script:
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')
}
}
Finally, the relevant part of the bundled 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
})();
Did I miss something?
I tried playing around with different webpack configs
eg: "generate"; "ssr" instead of "dom"
I also triple checked possible syntax mistakes and the documentation.
I also tried other domNodes instead of document, eg:
hydrate(() => <HelloWorld/>, helloWorldWrapper)
with the same result.
After a few days I found the solution:
First I was having an webpack configuration error:
const configClient = {
...configServer,
entry: './src/client/hydrate.tsx',
module: {
rules: [tsAndTsxRuleClient]
},
output: {
filename: 'hydrate.js',
path: path.resolve(__dirname, 'dist-client')
}
}
configServer contained: {target: node}
while it should be: {target: web}
Probably you should avoid merging server & client config like this because of this exact reason.
The other problem was my hydration-script tag: <script defer src="hydrate.js"/>
should have the async attribute: <script async src="hydrate.js"/>
.
I suggested to improve the documentation. (https://github.com/solidjs/solid/discussions/1857)