Skip to content(if available)orjump to list(if available)

Show HN: libmodulor – An opinionated TS library to build multi-platform apps

Show HN: libmodulor – An opinionated TS library to build multi-platform apps

17 comments

·January 23, 2025

Initially I started building this for my own projects. The main goal was to define a unified "blueprint" allowing me to develop multi-platform apps using the same code, without code generation. I wanted to be able to develop the same functionality on web, desktop, cli, server, mobile, whatever...

I've been able to achieve this by relying on TypeScript, a 4-layer architecture (UseCase => App => Product => Target) and dependency injection.

This mechanism allows me to use whatever tech stack I want, provided the good adapters are developed. For instance, I have pre-built ones : node express (server), next.js (server), node hono (server in alpha), node parseArgs (CLI), node stricli (CLI), react-web-pure (web with no CSS), react-native (mobile), node mcp server (anthropic MCP in alpha), etc.

The same goes with data storage : Postgres, SQLite, a txt file, whatever.

It also comes with auto testing and auto documentation.

Did I reinvent the wheel ? Probably on some aspects. Is it too much abstraction ? Probably as well. But I like the idea of modularity and portability.

That's why it's not made for everyone, nor all types of projects.

If you like testing new stuff, give it a try and feel free to ping me if needed, I'd love to help.

I'm aware the documentation is not state of the art yet. I wanted to focus on the "Getting Started" Guide to give a quick overview instead of going to deeply into the details.

Best,

null

[deleted]

gr4vityWall

Congrats on your project.

I feel like you could describe the abstractions you built in more detail. When I read the explanation for what the 'UseCase', 'App', 'Product' and 'Target' were, it wasn't clear how each of those translates to TypeScript. My guess is that 'UseCase' and 'App' would be like Classes, if you're modeling your program in an OOP way? The 'Product' seems like it would be the TypeScript project itself, with the package.json, source code and all of that.

I would rethink how you named the 'App' layer. The examples given ('auth', 'accounting', etc.) are not necessarily what I would call an 'app'.

As you introduce names and concepts for things in your library, I recommend trying to keep the cognitive load as low as possible. It seems like there are a very high amount of high-level concepts and implementation details like types, functions, etc. that 1. are specific/unique to libmodulor and 2. you need to learn before you can start actually building your application, from looking at the examples. The barrier to give it a try in a side project seems really high.

Building things is cool regardless :) I'm happy that you built something it's useful to you and that you got to share here.

tomhallett

I enjoy your 4 types on the architecture.

But I’m still a bit confused on what the project actually “is”. I see you have an architecture and I’m using ts to define the interface between those 4 types of components. But let’s say I have a react-native target: what am I expressing in that interface? A cli which can build/deploy that interface? Each ui screen in that rn app (rn login, rn add contact)? Or all of the api endpoints in the web target which gets called by the rn target?

In the readme, I would focus a bit less on the UML part, and a bit more on the “if I have a webapp and a mobile app, with auth and crud for contacts, here’s what you’d need”

pmdfgy

Thank you for your feedback, I really appreciate.

Let's say you want to create a product with auth and crud for contacts. You'll have a SignInUCD, a CreateContactUCD, a AddPhoneNumberToContactUCD, etc.

As you said, your react-native target will define the UI screens. You are free to design them the way you want as the library does not make any assumptions about the UI/UX. In every screen where you want to "inject" a use case, you'll use the `useUC` hook and `<UCPanel uc={uc} />` (see https://github.com/c100k/libmodulor/tree/master/dist/esm/tar...). See also https://github.com/c100k/libmodulor/blob/master/docs/getting.... It explains for web, but the mechanics are the same.

Since react-native expects `<View>`, `<Text>` and not `<div>`, etc. you'll also need to define your "design system", like it's been done here for example : https://github.com/c100k/libmodulor/tree/master/dist/esm/tar.... Basically, you need to define how you want a use case form to be displayed, etc. When in web we rely on `<input>`, in react-native we'll rely on `<TextInput>`. And of course, according to the data type, you can display a specific form control.

I realize it's super hard to explain and I'm not clear enough but hopefully I'll find the best way to express it.

tomhallett

Let's say I'm using shadcn's Dialog [1] on my web target, which has many subcomponents (Dialog, DialogTrigger, DialogHeader, etc). How many of those am i representing with a 1-to-1 `UC`? Is it just the parts that are on the IO seam, like a UC for opening the dialog, UC for closing a dialog, and UC for submitting a dialog? Or is it also for things the user sees like UC for header, UC for content, UC for buttons panel?

There is obviously some cost to expressing the interface between the product/target/usecase. What exact benefit is that cost getting me? do i know that if i expose a certain use case in one target then i have to explicitly decide if i'm going to expose (or not expose) it in a different target, which helps me get consistency/governance between my app as it grows? does it help me "integration test" by application in isolation, in a "similar" way that pact [2] helps with integration testing microservices? (ex: the mobile app relies on X input, but from the ts interfaces, the tool can detect that the web-api is no longer defining an output for that api. if so, is this on the /api/v1/resource level? the openapi schema for a json body response level?). do i get a mono-build-system, where everything flows together and i just say "libmodulor build" and "libmodulor deploy" and I'm good to go?

said in another way: many of the people on HN have a backend api, a react SPA, and a mobile app. what types of problems do i have now which libmodulor solves?

[1] https://ui.shadcn.com/docs/components/dialog [2] https://pact.io/

joshmarinacci

Ah. Thank you. Having examples up front really helps me understand it better.

bjacobso

You should check out https://effect.website/

It might help you implement some of these ideas

yasserf

Looks great!

I build something similar (vramework.dev), actually on my way now to give a talk on it

Got a presentation for it at presentation.vramework.dev if anyone is interested

gervwyk

interesting, when you say websocket support on aws, does this mean ws using lambda? and ws on nextjs (would be a game changer if someone made this happen)

pmdfgy

Looks great, will have a look at it.

sramam

vramework looks really well thought out. Is it in use by anyone yet?

0x20cowboy

I find most often people who are opinionated have very little knowledge on the subject. They are opinionated in an effort to try to keep discussions in a realm they feel they have some sort of expertise, but by definition their limited view makes them look silly to those with deeper understanding.

I apologise for being off topic, but I really want “an opinionated X” to stop having some kind of positive connotation to junior devs.

popalchemist

Limited is not intrinsically bad. Even if someone makes questionable decisions, the act of limiting the scope by defining specific interfaces/patterns has value in and of itself.

0x20cowboy

I agree, but limited isn’t the same as opinionated. In these types of usage, people seem to think they are opinionated because they are right.

I think it’s misunderstanding the angst of knowledgeable people’s frustration with the world, by trying to emulate the frustration without having the actual knowledge or experience.

johnny22

I'm a big fan of opinionated software. This world is full of software that tries to do everything. A lot of the times I just want it to do the one thing really well.

mystified5016

I always read "opinionated program" as "I'm immature, don't understand my own opinions, and would rather force my opinions on you than examine my beliefs in any capacity"

Extremely immature and "I'm an asshole and I'm making it your problem" behavior

null

[deleted]