(Lazy) load routes from other chunks at runtime
Heya,
I have an application that I've split into several layers (depending on the features available to the user) which I've told Vite to bundle into chunks and then lazy-load them when required (
lazy(() => import('./layer-1'))). Because of regulations, I need to keep those chunks separate, what goes on in layer-1 must only be inside layer-1 and not leak out.
This includes route data, too. I could lazy load the components but the information about the route/the loaders it uses would still be bundled in the initial bundle if I got it right, which I'm not allowed to do. I've looked into code splitting but it seems like it's more about distributing the route data and less about putting it in different independent bundles.
Is it possible to lazy load routes at runtime (e.g. signal based)? It doesn't matter if the routes can't be removed later on, the requirement is just to suppress the initial load. What I would like to do is something like
It would be nice if static typing works, but I could also live without, because the links between layers are very sparse and could just be a typeless hack if needs be. Currently with solid-router apparently this kind of works with something like <Show when={hasAccess()}>{lazy(() => import...)}</Show>, but I kinda need to migrate away from solid-router.8 Replies
typical-coral•2mo ago
does autoCodeSplitting not solve this for you?
https://tanstack.com/router/v1/docs/framework/react/guide/automatic-code-splitting
Automatic Code Splitting | TanStack Router React Docs
The automatic code splitting feature in TanStack Router allows you to optimize your application's bundle size by lazily loading route components and their associated data. This is particularly useful...
extended-salmonOP•2mo ago
It might, I haven't used file-based routing so far but rather went with the coded config approach instead (because my current setup wasn't made with that in mind and so I've organized the files in a more logical rather than route based way). I've ruled it out so far, but if it solves my chunking issues I'll give it a go.
I'm going to run some experiments and report back. Thank you so far!
I've tried it but I don't think it's working.
import { routeTree } from './routeTree.gen'; will include all route data, including components, because the .gen file imports all the routes (which in turn contain al the components). This means that my entrypoint bundle already contains all the other bundles, and nothing is really lazy loaded at all - it's all pulled in and loaded in one go:
at the very least, the route information becomes available this way, which is what I want to prevent, but seeing as it's importing the acp js too, it means it'll load that immediately on app start as well - so it's in separate files, but still all loaded at the same time, which makes it kinda pointless for metypical-coral•2mo ago
did you enable autoCodeSplitting ?
extended-salmonOP•2mo ago
typical-coral•2mo ago
this will still result in all routes being "available"
however the components are split off
check the actual chunks
extended-salmonOP•2mo ago
the acp.js which is included contains the component code
hm, maybe I need to split this up
let me try moving the components somewhere else
actually I can't do that because it's using just the RouteComponent function, is it?
what I mean is: I do the chunking by telling rollup to create manual chunks based on filenames - i.e. everything inside
/acp/ gets thrown into the acp-X.js
since that contains the route information and the component, it means that both are bundled in the same file, so even if tanstack just loads the route information, the component gets inevitably pulled in, too
let me see if I can defuse this by checking for ?tsr-split=component
okay, yeah, that worked - had to tell rollup to treat those queries differently
not super happy that the routes are still available on the client, but at least the components themselves would be separate nowtypical-coral•2mo ago
isnt hiding the routes on the client rather "security through obscurity"?
why do you need manual chunking?
extended-salmonOP•2mo ago
it kind of is, but security through obscurity isn't bad if it's an additional, and not the only, layer.
if you don't know how an application works, and what it can do, it becomes harder to exploit/copy it. at the end of the day, most of the stuff we do in that regard is always just raising the bar high enough so your average adversary gets fed up/runs out of time and goes somewhere else.
in my case, if the logic or functionality of the app were easily known by just going to the url and looking at the JS, it could be rather bad. there are actors that would love to know how e.g. the backend is configured, because this could help them game the system that I'm making
the backend filters access to chunks. if I use automatic chunks, vite throws them into random-ish named chunks, usually by the file name, which means I lose all information about where the chunk originally was.
by manually chunking it, I can say that all stuff from inside /acp/ goes into acp.js, and can then tell the backend accordingly that acp.js is to be served only to members in the admin group
in a way, it's about limiting the potential attack & information surface
the ideal way to deal with this problem, of course, would be to just have a separate app for e.g. the acp and whatever else, but then you have to split up the application, and then there's duplicate parts that need to be shared, and it becomes rather complicated in my opinion, especially if the functionality of the normal app is usually also needed to do the acp stuff