solidjs / solid-router

A universal router for Solid inspired by Ember and React Router
MIT License
1.13k stars 143 forks source link

Using Router with ssr and hydrate, click event not working #473

Closed bakkar1989 closed 3 weeks ago

bakkar1989 commented 3 weeks ago

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 ( <>

  <main>{props.children}</main>
</>

); };

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 (

); };

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.ts import { 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>

SSR with SolidJS
${html}
${script}
`;
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

Additional context

No response

bakkar1989 commented 3 weeks ago

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

from

Layout.tsx ` return ( <>

  <main>{props.children}</main>
</>

);`

to

` return (

{props.children}

);`

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