S
SolidJSโ€ข2w ago
50BytesOfJohn

Missing SSR component after client side navigation (help with icons library SSR)

Hey all, I'm currently building a port of phosphor icons to solid, based on their react package. I wanted to also add SSR support, but I'm not very experienced in solid start. I was thinking about separate exports, like in their react package, and bundle it with babel-solid preset using ssr true. This kinda works, as I'm not getting any hydration errors, but after changing pages on client side (home -> about -> home) the icon disappears. I'm thinking that maybe in case of Solidjs it would be better to use isServer flag. Since I don't have much experience, wanted to ask for an advise, what would be the best way to export icons with good SSR support. In client side icons I'm using context for global theming of icons (like in react version). If anyone would like to share opinion or tip, I would be thankful! ๐Ÿ˜Š
13 Replies
50BytesOfJohn
50BytesOfJohnOPโ€ข2w ago
I'm not sure but maybe I figured it out, it seems that I can do 2 builds for SSR, one with ssr and one with dom. Then in package.json I can export dom version for browser and by default and ssr for node/deno etc. For now it works fine, not sure if this is best approach ๐Ÿ˜‰
Erik Demaine
Erik Demaineโ€ข2w ago
You can see how https://github.com/x64Bits/solid-icons did it. There's some special hackery with ssr built-in that I didn't know about...
Brendonovich
Brendonovichโ€ข2w ago
I'd suggest building your library on top of this: https://github.com/solidjs-community/solid-lib-starter When building Solid libraries you usually want to also provide the uncompiled JSX under the solid export condition, this lets the end user's bundler take care of the client/server differences. That template will setup the right exports for you automatically
GitHub
GitHub - solidjs-community/solid-lib-starter: SolidJS library start...
SolidJS library starter template. Use it to create your own solid package. - solidjs-community/solid-lib-starter
50BytesOfJohn
50BytesOfJohnOPโ€ข2w ago
Thanks both for the input, the solid-icons has some interesting approach. I've seen it before, but the approach is different than what I wanted to achieve, so I haven't use it like that. I haven't seen the solid lib starter before, it's good to know for the future. I think, that it would be best for me to try to push my changes and share a link to the repo. Maybe someone would be so kind to test it. But in short, I have 2 different exports for one icon. One is client-side only, that uses context and 2nd is from "<lib name>/ssr" that is not using context and supports ssr. For the ssr build, I'm building 2 versions from ssr input. 1 with generate for ssr, and one with generate for dom. Resulting in something like this in package.json:
"exports": {
".": {
"import": {
"types": "./dist/types/index.d.ts",
"default": "./dist/index/index.mjs"
}
},
"./ssr": {
"worker": {
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr.js"
}
},
"browser": {
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr-dom.js"
}
},
"deno": {
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr.js"
}
},
"node": {
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr.js"
}
},
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr-dom.js"
}
}
},
"exports": {
".": {
"import": {
"types": "./dist/types/index.d.ts",
"default": "./dist/index/index.mjs"
}
},
"./ssr": {
"worker": {
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr.js"
}
},
"browser": {
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr-dom.js"
}
},
"deno": {
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr.js"
}
},
"node": {
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr.js"
}
},
"import": {
"types": "./dist/ssr/types/ssr.d.ts",
"default": "./dist/ssr/ssr-dom.js"
}
}
},
Apparently, this works really well with solid-start. I mean, no hydration errors at least ๐Ÿ˜… For ssr, it generates a huge file, with content like this:
import{ssr as a,ssrHydrationKey as h,ssrElement as Z,mergeProps as A,escape as t,createComponent as H}from"solid-js/web";var l=["<path",' d="M232,104a56.06,56.06,0,0,0-56-56H136a24,24,0,0,1,24-24,8,8,0,0,0,0-16,40,40,0,0,0-40,40H80a56.06,56.06,0,0,0-56,56,16,16,0,0,0,8,13.83V128c0,35.53,33.12,62.12,59.74,83.49C103.66,221.07,120,234.18,120,240a8,8,0,0,0,16,0c0-5.82,16.34-18.93,28.26-28.51C190.88,190.12,224,163.53,224,128V117.83A16,16,0,0,0,232,104ZM80,64h96a40.06,40.06,0,0,1,40,40H40A40,40,0,0,1,80,64Zm74.25,135c-10.62,8.52-20,16-26.25,23.37-6.25-7.32-15.63-14.85-26.25-23.37C77.8,179.79,48,155.86,48,128v-8H208v8C208,155.86,178.2,179.79,154.25,199Z"></path>'];const V={regular:a(l,h()),duotone:[a(["<path",
import{ssr as a,ssrHydrationKey as h,ssrElement as Z,mergeProps as A,escape as t,createComponent as H}from"solid-js/web";var l=["<path",' d="M232,104a56.06,56.06,0,0,0-56-56H136a24,24,0,0,1,24-24,8,8,0,0,0,0-16,40,40,0,0,0-40,40H80a56.06,56.06,0,0,0-56,56,16,16,0,0,0,8,13.83V128c0,35.53,33.12,62.12,59.74,83.49C103.66,221.07,120,234.18,120,240a8,8,0,0,0,16,0c0-5.82,16.34-18.93,28.26-28.51C190.88,190.12,224,163.53,224,128V117.83A16,16,0,0,0,232,104ZM80,64h96a40.06,40.06,0,0,1,40,40H40A40,40,0,0,1,80,64Zm74.25,135c-10.62,8.52-20,16-26.25,23.37-6.25-7.32-15.63-14.85-26.25-23.37C77.8,179.79,48,155.86,48,128v-8H208v8C208,155.86,178.2,179.79,154.25,199Z"></path>'];const V={regular:a(l,h()),duotone:[a(["<path",
For ssr-dom:
import{getNextElement as a,template as Z,setAttribute as A,spread as v,insert as H,runHydrationEvents as h,createComponent as l,mergeProps as g}from"solid-js/web";var s=Z("<svg><path d=M232,104a56.06,56.06,0,0,0-56-56H136a24,24,0,0,1,24-24,8,8,0,0,0,0-16,40,40,0,0,0-40,40H80a56.06,56.06,0,0,0-56,56,16,16,0,0,0,8,13.83V128c0,35.53,33.12,62.12,59.74,83.49C103.66,221.07,120,234.
import{getNextElement as a,template as Z,setAttribute as A,spread as v,insert as H,runHydrationEvents as h,createComponent as l,mergeProps as g}from"solid-js/web";var s=Z("<svg><path d=M232,104a56.06,56.06,0,0,0-56-56H136a24,24,0,0,1,24-24,8,8,0,0,0,0-16,40,40,0,0,0-40,40H80a56.06,56.06,0,0,0-56,56,16,16,0,0,0,8,13.83V128c0,35.53,33.12,62.12,59.74,83.49C103.66,221.07,120,234.
For client side bundle, it generates an index with:
export{IconContext}from"./lib/context.mjs";export{AcornIcon}from"./csr/AcornIcon.mjs";
export{IconContext}from"./lib/context.mjs";export{AcornIcon}from"./csr/AcornIcon.mjs";
And icons like that:
import{createComponent as o,mergeProps as m}from"solid-js/web";import{weights as r}from"../icons/Acorn.mjs";import s from"../lib/CSRIconBase.mjs";const i=i=>o(s,m(i,{weights:r}));export{i as AcornIcon};
import{createComponent as o,mergeProps as m}from"solid-js/web";import{weights as r}from"../icons/Acorn.mjs";import s from"../lib/CSRIconBase.mjs";const i=i=>o(s,m(i,{weights:r}));export{i as AcornIcon};
@Brendonovich I need to look at the compiled fiels from the example repo. I wanted to avoid having one export, due to context usage, as in react version. I think that for SSR, it would be bad to start using context on client side, change of icon style. So wanted to be explicit and provide 2 options. Most libraries/examples covers just one export, so I had some troubles figuring it out. Will play around with it to see how it can work and look like with solid exports
Brendonovich
Brendonovichโ€ข2w ago
Solid doesn't have server components, so I don't think you'll need to worry about context not being available
Brendonovich
Brendonovichโ€ข2w ago
Also have you seen unplugin-icons ? I use it + autoimport to access all sorts of icons including phosphor, means you don't need a dedicated package for each icon set
GitHub
GitHub - unplugin/unplugin-icons: ๐Ÿคน Access thousands of icons as co...
๐Ÿคน Access thousands of icons as components on-demand universally. - unplugin/unplugin-icons
50BytesOfJohn
50BytesOfJohnOPโ€ข2w ago
Oh... That's cool, I haven't seen it. Thanks! Anyways, it fun to build the library, and probably will publish it anyways. Even if solid does not have server components. While using ssr rendering or pre-redenring or static rendering or whatever happens there the context is not available in this case I guess, cause I had some errors on solid start about using client side api on server. So I thought that this may cause some issues or at least inconsistency in initial render.
Brendonovich
Brendonovichโ€ข2w ago
Ah context is available on the server, I think that error you got is just a vite 6 comatability thing Upgrade vite + vinxi to latest and context during ssr should work fine
50BytesOfJohn
50BytesOfJohnOPโ€ข2w ago
๐Ÿ˜ฎ Gonna try it, thanks!
Erik Demaine
Erik Demaineโ€ข2w ago
Wow, that's really cool. Thanks for the link!
Brendonovich
Brendonovichโ€ข2w ago
best way to consume third party + custom icons imo
Erik Demaine
Erik Demaineโ€ข2w ago
I am impressed it even offers auto-import
50BytesOfJohn
50BytesOfJohnOPโ€ข2w ago
I think that the problem with this library may be that it's hard to find it, if you don't know about it. I was searching for solidjs phosphor icons, and I couldn't find this library. Only one outdated community package. Which means that many people may have the same issue. Also, this is personal opinion, but if I would need a single icon library, I would possibly prefer their official library than this one (based on simplicity and specific instructions, it feels easier, at least for me, if I read phosphor react docs and unplugin icons docs). On the other hand, I think that if I would start using unplugin icons now, I would probably use it in future in all the cases ๐Ÿ˜…
Want results from more Discord servers?
Add your server