I’ve spend a bit of time playing around with NextJS’s experimental app/ directory setup which introduces React’s new server components (RSC), but it seems like it’s not possible use the new features with Rescript.
How it currently works is that you add a 'use client'; directive at the top of the file in which you define client components. I can’t figure out how/if this can be done in Rescript. Using %%raw() does not seem to work since it appears after the imports even if you use it on line 1. Is there any other way I can get around this?
Also, it seems like colocating pages (always named page.<ext>), and layouts (always named layout.<ext>) with components is the convention that is being advocated for when it comes to the app/ directory in NextJS 13+. Since it’s not possible to have the pages and layouts in Rescript anymore because the naming convention means code duplication, following this would mean mixing .res and .js files in the same directory. I understand that the no-duplicate-filenames is very intentional, but could it make sense to have some kind of escape hatch for this, given that you’re fine with the contents of these files not being possible to import elsewhere?
What it does - as soon as it spots use client string - it will remove it from the file and add on top of it (before imports);
So %%raw("use client") would work as intended.
Regardless file naming.
You can use the same approach with js-post-build - for example, you have CartPage.res, CartPage_Layout.res and CartPage_Error.res - you will create files via fs.writeFileSync and have /cart/page.mjs, /cart/layout.mjs, /cart/error.mjs.
Or you can simply create those js files by hand and import compiled from rescript file.
Something like /cart/page.mjs:
import { make as Component } from 'src/pages/cart/CartPage.mjs;
export default Component;
We use this approach at my company, and I think it’s actually the best way of working with Next.js routing as of now.
Also, you can write it a little bit shorter:
export { make as default } from 'src/pages/cart/CartPage.mjs;
If I have time in the next year, I think of writing a small code-gen tool to generate the /pages directory with reexports. It’ll reduce manual labor and make the solution a little bit more typesafe.
I can’t use it either, not with 10.1.3. nor with 11.x and even the example code from the compiler tests does not give me the same results (i.e. it does not generate the first two lines as advertised).
Some time passed in the thread, so just to note my best practice here:
In client code, in particular on the threshold when I switch from server component to client component, I use
@@directive("'use client';")
In RSC code I don’t add this or any other directive.
Note that there is a use server; but disturbing as it is, that is not the counterpart of use client, but it has to do with Server Actions which is an entirely different concept (and which I don’t currently use).
I also have the following that I sometimes add to code that I only want to use from RSC:
@@directive("require('server-only');")
This is just a safeguard that makes sure that this code cannot accidentally “become” a client component.
It also has a client-only counterpart. This would error when a module designated for client only would accidentally be used from a RSC. But I have no use case where this would be useful.
That’s it… I’d prefer a more consistent pattern, but the inconsistency originates from nextjs, thus it cannot be resolved from Rescript.
yes, i definitely like this idea better than pure ‘use client’/‘use server’ directives. Especially, since they are implementation dependent. I’ve seen $dollarprefix, i’ve seen dollarsuffix$, i’ve seen ‘use server’, who knows what’s coming next. I strongly feel like ‘use client/server’ would be a mistake for ReScript.