solidjs/solid-router

Using Router with ssr and hydrate, click event not working

Closed this issue · 1 comments

Describe the bug

I have set up a simple TypeScript solidjs.
The application generates ssr and hydrate files.
When I do not use Router the click event works but when using Router the click event does not work.

I put the full sample project at https://stackblitz.com/edit/stackblitz-starters-5rgwrj?file=package.json

Am I missing a config on Router?

Please note this is a sample that I got the part not working, my project makes use of <A> etc.

Layout.tsx
`import type { Component } from 'solid-js';

const Layout: Component = (props: any) => {
const showAlert = () => {
console.log('Alert button clicked!'); // Debugging log
alert('Button clicked!');
};

return (
<>


click me from layout

{props.children}
</>
);
};

export default Layout;
`

App.tsx
`
import type { Component } from 'solid-js';

const App: Component = () => {
const showAlert = () => {
console.log('Alert button clicked!'); // Debugging log
alert('Button clicked!');
};

return (


click me

);
};

export default App;
index.tsx/* @refresh reload */
import { hydrate } from 'solid-js/web';
import { Router } from '@solidjs/router';
import Layout from './Layout';

import App from './App';

const root = document.getElementById('root');

if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
throw new Error(
'Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?'
);
}
const routes = {
path: '/',
component: App,
};

// works
// hydrate(() => , root!);

// does not work
hydrate(
() => (

{routes}

),
root!
);

`

index_server.tsx

`/* @refresh reload */
import { generateHydrationScript, renderToStringAsync } from 'solid-js/web';
import { Router } from '@solidjs/router';

import App from './App';
import Layout from './Layout';

const routes = {
path: '/',
component: App,
};

export default async function render() {
//work
//const rendered = await renderToStringAsync(() => );
// does not work
const rendered = await renderToStringAsync(() => (

{routes}

));
const hydration = generateHydrationScript();
return [rendered, hydration];
}

vite.config.tsimport { defineConfig } from 'vite';
import solidPlugin from 'vite-plugin-solid';
// import devtools from 'solid-devtools/vite';

export default defineConfig(({ command, mode }) => {
const isSSR = mode == "ssr";
return {
plugins: [
/*
Uncomment the following line to enable solid-devtools.
For more info see https://github.com/thetarnav/solid-devtools/tree/main/packages/extension#readme
*/
// devtools(),
solidPlugin({
solid: {
generate: isSSR ? 'ssr' : 'dom', // Conditionally set generate based on SSR build
},
}),
],
server: {
port: 3000,
},
build: {
target: 'esnext',
ssr: isSSR,
rollupOptions: {
input: isSSR
? src/index_server.tsx
: src/index.tsx,
output: {
format: 'esm', // Output format differs for server and client
entryFileNames: isSSR ? 'server.js' : 'client.js',
assetFileNames: (assetInfo) => {
// by default it comes with a random hash... this was removed by removign -[hash] field
//return 'assets/[name]-[hash][extname]';
return 'assets/[name][extname]';
}
},
},
outDir: isSSR ? dist/server : dist/client
},
}});
package.json
{
"name": "vite-template-solid",
"version": "0.0.0",
"description": "",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build && vite build --mode ssr ",
"serve": "vite preview"
},
"license": "MIT",
"devDependencies": {
"solid-devtools": "^0.29.2",
"typescript": "^5.3.3",
"vite": "^5.0.11",
"vite-plugin-solid": "^2.8.2"
},
"dependencies": {
"@solidjs/router": "^0.14.3",
"express": "^4.19.2",
"solid-js": "^1.8.11"
},
"type": "module"
}

`
the following command i use to generate both client.js and server.js: npm run build

server.js to host

`
import express from "express";
const app = express();
app.use(express.static('dist'));
app.use(express.json());

app.get('/*', async (req, res) => {
const renderFunc = (await import(./dist/server/server.js)).default;
const [html, script] = await renderFunc();
const output = <!DOCTYPE html> <html> <head> <title>SSR with SolidJS</title> <link rel="shortcut icon" href="/templates/backoffice/app/assets/favicon.png"> </head> <body> <div id="root">${html}</div>${script}<script type="module" src="/client/client.js"></script> </body> </html>;
res.send(output);
});
var port = 9001;
app.listen(port, () => {
console.log('ready');
console.log("http://localhost:" + port);
});

`

Your Example Website or App

https://stackblitz.com/edit/stackblitz-starters-5rgwrj?file=package.json

Steps to Reproduce the Bug or Issue

If you run the server node server.js, the opened pages will show "click me" button and does not work.
If you change the content in index.tsx and index_server.tsx to use App component directly and npm run build to build the js files then node server.js to host the application, the "click me" button will work

Expected behavior

"click me" button shows an alert when using Router

Screenshots or Videos

No response

Platform

  • OS: Windows
  • Browser: Brave
  • Version: 1.69.153

Additional context

No response

for some reason I had to add a <div></div> instead of empty tag <></> in the Layout and started working.

from

Layout.tsx
return ( <> <header> <button onclick={showAlert}>click me from layout</button> </header> <main>{props.children}</main> </> );

to

return ( <div> <header> <button onclick={showAlert}>click me from layout</button> </header> <main>{props.children}</main> </div> );

I used <></> because it was in the documentation: https://docs.solidjs.com/solid-router/concepts/layouts