Announcing: AshTypescript
What if you had full stack types for SPAs built with tech like React, Inertia, Vue, Svelte... but all of the power of Ash Framework and Elixir on the backend? Well, you can now. π.
https://hexdocs.pm/ash_typescript/readme.html
This is just 0.1.0, but it is the beginning of something big, and frankly something that we've been missing for a long time. Can't wait to see what you all do with it, and a huge shoutout to our newest core team member @Torkan for all of his amazing work!
58 Replies
Super awesome! I see Zod is coming soon. Is some form of subscription support planned as well?
Zod is actually already up and running, I just forgot to update that part of the readme file π
It would be kinda cool if, instead of running a mix task, one could leverage a custom compiler to automatically keep the generated file up to date. The same way that Phoenix LV does it with the new colocated hooks:
https://github.com/phoenixframework/phoenix_live_view/blob/main/lib/mix/tasks/compile/phoenix_live_view.ex
That is on the short term roadmap, itβll probably be hooked into the same functionality that also detects that you need to run ash.codegen βdev etc π
Hi @Torkan , it includes the open api (ash json api) or just actions and we need still create like this
Thank you
It is unrelated to open api π
This uses its own json-based communication protocol and controller, and generates types for those.
Sorry
Yes. My main question is that the frontend is currently using HTTP , we can convert the OpenAPI spec to types. But where exactly can this library help me? Since it's working at the resource and domain level, while my frontend interacts via HTTP!
It produces a typescript client library and a controller that the client library uses that routes to the relevant action
So calling it makes a
fetch
request to your controller that we provideAHhhaaa :))) I just found out. Thank you, so I need react query and axios instead of fetchπ
We plan to extend it to support that kind of thing π
If you want to try it out and see how they can be connected that would be cool π
Yeeh sure!
Thank you for your all efforts, it is the good one
I'm so stupid I didn't even see RPC. π
I might be missing something: what do I need to do in my router to declare the /rpc/validate and /rpc/run endpoints?
Yeah I think the steps are missing
@Torkan ^
we need to tell them to create their RPC controller
Ooops, yup, those are indeed missing from the readme π
Add this in
rpc_controller.ex
:
Replace the module namespace and :ash_events_demo
with your actual app name
And in router.ex:
If you're already assigning the actor in a plug earlier in your pipeline, then you can skip the calls to Ash.PlugHelpers.set_actor
@Torkan can you add that to the setup guide? Ill republish docs after
Replace
AshEventsDemo
with MyApp
Yup, working on it now
There, just pushed a full overhaul of the readme, usage-rules & the internal docs
Will publish later
I should probably also clean up the repo I used for the live demo on Saturday a little, and then we can reference that as an example implementation
Thank you β€οΈ
Np, and pls let me know if you run into any issues!
I'll also shortly add support for overriding the currently hardcoded usage of the native
fetch
function, and that you can specify any fetch options if needed@Torkan I think the big win there would be one mega dumb example using none of the fancy stuff, and then your integrated inertia-backed example could be the upgraded version etc.
100% agreed!
Also @Torkan I'm pretty sure just
mix ash.codegen --dev
works and we should encourage people to do that?
Or maybe it doesn't matter?
But ideally we have basically a single loop
just "make some changes -> mix ash.codegen --dev
-> repeat -> when done, mix ash.codegen make_feature_x
"Yup, it's just not hooked up atm π
(PRs welcome)
(nvm, fixed)
Oh I thought I added it but maybe it was on that branch I threw away
Ah yes, you did setup a PR that included that change way back, I just never merged it, so my bad really π
Custom HTTP client support incoming btw
There, just pushed it
another amazing tool in the ever growing Ash toolkit, kudos to the team!
quick question, my current project uses
AshPostgres.LTree
type and works fine for JSON API generation.
But with ash_typescript
, mix ash_typescript.codegen --dry_run
throws an error.
I tried a custom wrapper and that did not take.
Any pointers on how to use ash_typescript
with non-standard types?Hmm...how did you try it?
**try to wrap it
This is a very promising. It opens up a whole plethora of possibilities, like using LiveSvelte in Ash with fully typed client, a thing that I was missing so bad in my project. Not anymore! Just wow!. Also, it reminds me of SvelteKit's remote functions. But having BEAM as foundations with Ashes declarative approach its just a blessing
Did you follow the instructions in README.md for custom types?
Yeah, using it with LiveSvelte, LiveVue etc should be fairly straight-forward, typed queries would be the main thing to use in those settings I think, since you usually want to run everything through the event handlers of your liveviews
thanks @Torkan , @Zach generation worked after
1. I cloned this as a custom type in the project: https://github.com/ash-project/ash_postgres/blob/v2.6.15/lib/types/ltree.ex
2. followed these steps: https://hexdocs.pm/ash_typescript/readme.html#custom-types, specifically added this:
3. and added this snippet in
config.exs
:
GitHub
ash_postgres/lib/types/ltree.ex at v2.6.15 Β· ash-project/ash_postgres
The PostgreSQL data layer for Ash Framework. Contribute to ash-project/ash_postgres development by creating an account on GitHub.
Awesome! I'm currently adding native support for it in ash_typescript now as well, so soon you won't have to create that wrapper π
Just pushed an update to main with ltree support @DonkeyKong, if you could try it out and confirm it works as needed that would be great π
It works with TanStack Query / Table!
(super) quick demo video:
https://www.youtube.com/watch?v=brqbxS2vpzY
Nice! π₯ If that demo is from a public repo that could work as a reference example it would be awesome if we could reference it, then I won't have to build one myself π
I'm tidying it up, will have something shareable Wednesday evening!
Excellent! Thanks for making the effort!
Thank you for doing the hard part!
amazing work @Torkan , much better DX, thank you π
Released 0.1.2 now, which contains the LTree support and makes the typescript codegen hook into
ash.codegen --dev
@Torkan so I think the next awesome milestone would be to make the igniter installer set everything up and create a basic
index.ts
file that is all hooked up, perhaps with a page that tells users what to do when they open it. Like "go create some resources and hook them up X way" etc.
Maybe behind a flag like mix igniter.install ash_typescript --setup
and then on the ash-hq.org installer we can add a React SPA preset that does thatYup, agreed!
The updated README is brilliant, thank you
this is INSANE
Would it be a lot of work to perform the RPC over a websocket?
Yes and no (it depends on what you want/need) π
With http/2, there is very little to be gained in terms of performance/overhead though. Are there other reasons why you'd prefer/need to do it over WS instead HTTP?
Technically, there is nothing stopping you from setting up a channel and just call AshTypeScript.Rpc.run_action with the incoming payloads really, but you'd have to manually ensure that you set the types for the various action results yourself though on the client
Assuming you already have a socket, why perform more requests? The, albeit minimal, overhead per request from fetching the user/tenant/w/e can also be avoided. Perhaps it's more about separating the transport from the actions/types.
Well, mainly because there are no huge benefits in avoiding performing more requests π
It's totally possible to use the building blocks provided by ash_typescript yourself to do it though, it's just not very straightforward/currently possible to make a "ready for use" setup using WS as the transport protocol
So it's a little outside of the scope of the extension itself currently in terms of what is supported out of the box.. We are however looking into implementing the concept of a typed phoenix channel at some point π
I wouldn't worry too much about the performance hit of validating the actor & tenant etc, I don't think I've ever heard something along the lines of "We tried using a http api for our backend, but it couldn't handle the load so we had to move over to websockets instead" π
I think it's perfectly reasonable to want to do this over a web socket and I think we could provide some tools to do it
But maybe something lower level that requires rigging etc
Yeah, it's totally doable with what's provided as-is, but you'd have to plug it all together yourself
Regarding what is provided, I'm thinking of types for the expected payload for an action, types for inferring the result of an action (based on the fields requested in the payload), and functionality on the backend to run the action
It's hard to make a more generalized approach that could be automatically setup for you and be used straight after installing though, but it's definitely something that should be taken into consideration for typed channels
But it currently involves a lot of scaffolding/boilerplate, so not something I would recommend π
Hm, I might have thought of a sort of abstraction that might remove the need for a lot of that boilerplate now though, Iβll try implementing it later tonight hopefully
@Randall Released 0.2.0 last night, that also adds generated functions that can be used with a channel.. see the project readme for setup
Cool, nice that it's possible. I do wonder about the API a bit. Couple things at first glance:
1. The channel is definitely a required parameter. Perhaps it should be the first positional arg then? E.g.
createTodoChannel(channel, { ... })
.
2. Why callbacks, rather than a promise?
Generating additional functions like this is fine, I imagine the bundler takes care of tree shaking here.
Sorry if you felt pressured by my question earlier, I didn't mean for this to feel like a priority of some sort; it was mostly a question out of curiousity.Well, phoenix channels are callback-based, so it's hard to get around that fact π
Yeah, it's a bit rough there. I know LiveView also does a bit of work to "Promise"-ify stuff like
pushEventTo
By the looks of it they something similar to this:
In assets/js/phoenix_live_view/view.js:pushWithReply/3
How so? LV only uses addEventListener & no-reply events AFAIK
Ah right, didn't see the last part there π
It does in hooks. See
view_hook.ts
:
Right, I'll take it into consideration π
As promised, a demonstration of AshTypescript using Tanstack table and Tanstack query (plus a LiveView for comparison): https://github.com/ChristianAlexander/ash_typescript_demo
GitHub
GitHub - ChristianAlexander/ash_typescript_demo: A demonstration of...
A demonstration of the Ash Typescript package, showing React and LiveView access to the same resources - ChristianAlexander/ash_typescript_demo
Awesome work, thanks for sharing! π₯³ I think this repo is a perfect example of how low the barrier of entry can be in terms of utilizing ash_typescript in a regular Phoenix/LiveView application, where you just need to mount a few pages using React (or another front-end framework). Is it okay if I reference it in ash_typescript's readme?
Use it in whatever way youβd like!