createLinks without React dependency to generate links for backend
Closed this issue ยท 3 comments
Why it is needed?
Hey,
first of all, thanks for this amazing Router that help us keeps our routes type safe ๐ช We also love the simplicity in it's API and how it leverage existing solution such as ts-pattern.
For our use-case, we have a monorepo (manage by Nx) and we share some code (Domain) between frontend and backend. The list of app routes are shared and we would also be able to share the generated links functions that is build by the createRouter to be able to use it in backend.
Here is an example in our user.service.ts
import { Links } from '@company/shared/domain';
const confirmLink =
this.environmentContext.appBaseUrl() +
Links.ConfirmEmail({ token: `${timestamp}-${ident}-${token}` });
With this scaffolding, we have type safe links between our backend and frontend ๐.
The only issue is that createRouter
is coupled with React
and create a dependency to React
on our backend.
Possible implementation
A possible solution could be to publish a createLinks
function separately to be imported at it's own path without React dependency.
We could also publish another package to npm such as @swan-io/chicane-backend
or something else.
For now, as a workaround, we created a file create-links.ts
that reuse your code in our domain lib without the React dependency (no push, no useRoute hook) but we have the createURLFunctions
that generates all link functions.
Also could be a good use of a monorepo with 2 libs:
core
: contains all main functions and utils without React dependencyreact
: contains the binding with React framework and the hook useRoutes
Publish separately and @swan-io/chicane-react
depends on @swan-io/chicane-core
.
Happy to discuss possible solutions if you're interested in this feature :wink.
Code sample
Usage could be something like this.
import { createLinks } from '@swan-io/chicane-core';
// Search params constants
export const TOKEN_SEARCH_PARAMS = 'token';
export const routes = {
AppArea: '/*',
AppRoot: '/',
// Auth
Login: '/login?:redirect',
ForgetPassword: '/forget-password',
ResetPassword: `/reset-password?:${TOKEN_SEARCH_PARAMS}`,
Register: '/register?:redirect',
RedeemInvite: `/redeem-invite?:${TOKEN_SEARCH_PARAMS}`,
} as const;
export const Links = createLinks(routes);
I created a gist for a workaround (not really elegant but it works so far).
https://gist.github.com/Nightbr/c41a0390454ea36d0bd6caf96823396a
Hi! Instead of copying / embedding / updating a large part of this library codebase, I would simply recommend adding react
(react-dom
isn't needed) as a dependency on your backend.
It supports server-side, it's light and don't come with a lot of dependencies, so no big deal.
After that, declare a router file:
import { createRouter } from "@swan-io/chicane";
// Search params constants
export const TOKEN_SEARCH_PARAMS = "token";
export const routes = {
AppArea: "/*",
AppRoot: "/",
// Auth
Login: "/login?:redirect",
ForgetPassword: "/forget-password",
ResetPassword: `/reset-password?:${TOKEN_SEARCH_PARAMS}`,
Register: "/register?:redirect",
RedeemInvite: `/redeem-invite?:${TOKEN_SEARCH_PARAMS}`,
} as const;
const { useRoute, push, replace, ...createLinkFns } = createRouter(routes);
export const Links = createLinkFns; // only export links creation functions
Hey, for sure this is a solution and the workaround is clearly nor ideal or elegant. We have different backend services some on k8s other on Lambda services, ... I need to investigate what impact this could have.
IMO the best solution still is to have a core lib that is framework agnostic and binding libs. This could also enable the creation of bindings for other framework (Such as Svelte).