solid-start
solid-start copied to clipboard
Documentation for separate imports for client/server bundle
Obviously this package is a WIP, but as an eventual documentation (or maybe feature) request:
Having some guidance on how to load different code on the server vs on the client would be helpful. Vite has a generic mechanism for adding conditional SSR logic, but that method won't work for switching out static imports on the client vs the server (e.g. providing a client version of a service on the client and a server version of a service on the server). Angular CLI handles this by allowing the user to specify file replacements per build environment (e.g. dev vs prod vs test).
Vite has instructions for creating a conditional config based on the build settings, unfortunately this doesn't appear to help (in development at least) because the config is only called once with the following environment object: { mode: 'development', command: 'serve' }. As such, it doesn't appear possible to use this feature to provide a file replacement pattern just for the server build.
It seems possible that this is a feature request for the solid-start plugin.
It doesn't work on static imports? I guess I should try again with Vite specifically. I mean technically solid-js/web has isServer that I've been using. Rollup is smart enough to treeshake out ESM modules.
So I was relying on this mechanism working.
Well the conditional config option doesn't work for the reasons described above, and the method for adding server/client conditional logic won't work for static imports for several reasons
1)
You might be thinking that this would work
import { ServerPkg } from 'server-pkg';
import { ClientPkg } from 'client-pkg';
const service = import.meta.env.SSR ? new ServerPkg() : new ClientPkg();
because tree shaking would turn it into something like
import { ClientPkg } from 'client-pkg';
const service = new ClientPkg();
Except I don't think tree shaking will happen if server-pkg / client-pkg has side effects
2)
You can't make an explicitly side effecting import work (so far as I know)
import "server-pkg"
// or
import "client-pkg"
3)
Relying on something like option (1) would also mean that development code vs production code would be slightly different because, theoretically, tree shaking wouldn't be happening in development. Maybe this wouldn't be a problem though.
For these reasons, while having import.meta.env.SSR is very useful, I don't think it's a replacement for being able to do file replacements based on build target. Personally, I also just find the file replacement method of producing different builds easier to work with (it generally creates cleaner, more readable files). Obviously this last bit is just one person's opinion though.
It does introduce potential for client and server not to match. I have an idea though for separate server data components/files that hopefully achieve similar goal. But I'd if possible encourage the view code to be the same file client/server.
I should also mention you can brute force it for the few places you have libs with side effects. You can tell Rollup to mark them as external and then there is a treeshaking option that completely removes external modules. I haven't done this through vite yet but it worked fine in pure rollup to remove the stream lib from a build I was doing where CJS version was getting pulled in (so couldn't be treeshaken). A bit manual but the idea is very few libraries would fall under this category.
First of all: @ryansolid solid start is unbelievably awesome. The concepts are so easy to understand and it's so intuitive to use for an Angular dev like me :D It's way easier to use than next.js imo.
Now to my problem: I have a concern that I think plays into this here. I want to implement a very basic authentication system in a solid start app and want to use argon2 for password hashing. The problem is, that I get an error in the server console but it works nevertheless. I guess this is just the client build failing. The error message is:
[vite] error while updating dependencies:
Error: Build failed with 1 error:
node_modules/.pnpm/[email protected]/node_modules/argon2/argon2.js:6:32: ERROR: No loader is configured for ".node" files
I tried putting the logic that uses argon2 in an api route instead of a server action but still the same error appears.
I suppose this is only the client build having fits with the imported package and the server build is fine with it. I'd love to be able to completely exclude certain imports from the client build so i can be sure nothing is sent to the client that doesn't belong there.
Is this possible currently? And where would logic like hashing passwords be placed ideally, is a serverAction sufficient?
@ChristofFritz You can use optimizeDeps.exclude to exclude any dependency that is incompatible with vite.
I've also personally opted for the following convention: any dependencies under dependencies in package.json gets externalized. The logic for that is that if it can be bundled it won't be needed in node_modules and can therefore be put under devDependencies. So only vite incompatible dependencies are left under dependencies.
const pkgJSON = JSON.parse(readFileSync("package.json", "utf-8"))
export default defineConfig(() => ({
plugins: [solid()],
optimizeDeps: {
exclude: Object.keys(pkgJSON.dependencies ?? []),
},
}))
Edit: I should clarify also that this happens because the server also gets bundled, it's not because it's getting included in the client bundle.
@ghalle Thank you for your blazingly fast reply ^^ and thank you for the working solution. You resolved my problem.
In setting up for SolidStarts next Beta Phase built on Nitro and Vinxi we are closing all PRs/Issues that will not be merged due to the system changing. If you feel your issue was closed by mistake. Feel free to re-open it after updating/testing against 0.4.x release. Thank you for your patience. See https://github.com/solidjs/solid-start/pull/1139 for more details.