Package Exports
- liveviewjs
Readme
LiveViewJS
Front-end framework for back-end developers
Credit π
This is a backend implementation of Phoenix LiveView in Typescript. What the Phoenix folks have built is phenominal and I wanted to use that paradigm in Typescript and make it available to others.
Quick Overview of LiveView Approach
How Phoenix desribes LiveView:
LiveView is an exciting new library which enables rich, real-time user experiences with server-rendered HTML. LiveView powered applications are stateful on the server with bidrectional communication via WebSockets, offering a vastly simplified programming model compared to JavaScript alternatives.
In other words, LiveView takes a very different approach than the popular SPA frameworks like React, Vuejs, and Svelt to building rich, highly interactive web applications. Instead of sending down a bundle of javascript, LiveView apps render an HTML page on the first request and then connect via a persistent socket over which client events are sent and updated received. These events may trigger a state update on the server and a re-calculation of what the page should look like. Instead of reloading the page, the client receives a "diff" of the page via the socket and the page's DOM is updated. See a detailed sequence diagram of the client/server lifecycle.
The programming paradigm is extremely powerful and productive!
Feedback is a π
Please feel free to open an issue with questions, bugs, etc.
Status - Ξ²
LiveViewJS is in Ξ²eta. The project is still young but the code is stable, tested, and well-documented.
Implemented Phoenix Bindings
The bindings below marked with β
are working and tested and most of them have example usage in the examples codebase. Those with ?, I have not gotten around to testing so not sure if they work. Those marked with β are not yet implemented and known not to work.
(See Phoenix Bindings Docs for more details)
| Binding | Attribute | Supported |
|---|---|---|
| Params | phx-value-* |
β |
| Click Events | phx-click |
β |
| Click Events | phx-click-away |
β |
| Form Events | phx-change |
β |
| Form Events | phx-submit |
β |
| Form Events | phx-feedback-for |
β |
| Form Events | phx-disable-with |
β |
| Form Events | phx-trigger-action |
οΉ |
| Form Events | phx-auto-recover |
οΉ |
| Focus Events | phx-blur |
β |
| Focus Events | phx-focus |
β |
| Focus Events | phx-window-blur |
β |
| Focus Events | phx-window-focus |
β |
| Key Events | phx-keydown |
β |
| Key Events | phx-keyup |
β |
| Key Events | phx-window-keydown |
β |
| Key Events | phx-window-keyup |
β |
| Key Events | phx-key |
β |
| DOM Patching | phx-update |
β |
| DOM Patching | phx-remove |
οΉ |
| JS Interop | phx-hook |
β |
| Rate Limiting | phx-debounce |
β |
| Rate Limiting | phx-throttle |
β |
| Static Tracking | phx-track-static |
β |
LiveViewJS Changesets
Phoenix's Ecto ORM library and Phoenix LiveView rely on Ecto Changesets to allow filtering, validation, and other logic to be applied to the data. Changesets are a powerful way to apply logic to data and are used in Phoenix's ORM and LiveView. LiveViewJS uses Changesets to provide a similar API to Phoenix's though it is NOT a full-blown ORM.
Detailed documentation on LiveViewJS Changesets.
Usage - Show me some code! β¨οΈ
Step 0 Install LiveViewJS
npm i liveviewjs
Step 1 Implement a LiveViewComponent
import { SessionData } from "express-session";
import { BaseLiveView, html, LiveViewContext, LiveViewExternalEventListener, LiveViewMeta, LiveViewMountParams, LiveViewSocket, LiveViewTemplate } from "liveviewjs";
// describe the context (i.e. state of the view)
interface ClickDemoContext extends LiveViewContext{
count: number;
}
type MyEvent = "user-clicked";
// implement the LiveView
export class ClickDemo extends BaseLiveView<ClickDemoContext, never> implements
// add listener for external events
LiveViewExternalEventListener<ClickDemoContext, MyEvent, never>{
// mount only called once per http request and per socket connection
mount(params: LiveViewMountParams, session: Partial<SessionData>, socket: LiveViewSocket<ClickDemoContext>){
socket.assign({count: 0}); // set initial count to 0
}
// render the LiveView content (called each time an event is received)
render(context: ClickDemoContext, meta: LiveViewMeta): LiveViewTemplate | Promise<LiveViewTemplate> {
const { count } = context;
return html`
<h2>Click Demo</h2>
<button phx-click="${MyEvent}" type="button">Click to Increment</button>
<p><strong>Count:</strong>${count}</p>
`
}
// handle user interactions from client
handleEvent(event: MyEvent, params: never, socket: LiveViewSocket<ClickDemoContext>): void | Promise<void> {
socket.assign({count: socket.context.count + 1}); // increment count
}
}Step 2 - Register your LiveViewComponents and start the server with LiveViewServer
// import package
import {LiveViewServer} from "liveviewjs";
// create new LiveViewServer
const server = new LiveViewServer();
// define your routes by mapping paths to LiveViewComponents
const router: LiveViewRouter = {
"/clickdemo": new ClickDemo();
}
// AND then passing the router to the server
server.registerLiveViewRoutes(router);
// OR register your route with the server directly
// server.registerLiveViewRoute("/clickdemo", new ClickDemo());
// then start the server
server.start();Additional Feature Documentation
Other features to be implemented:
- LiveView Helpers - Vote for Issue 17
Build in Flash Message Supportv0.2.3- File Uploads - Vote for Issue 20
NPM Commands
npm i - install the deps
npm run build - builds the framework, client, and examples (server)
npm run watch - continually rebuilds the codebase when files are updated
npm run examples - runs the examples [See src/examples]
npm run test - runs the (few) tests
Run and Browse Examples
Credit: These examples are adapted from an amazing Phoenix Video / Code Course authored by the folks at Pragmatic Studio.
Navigate to src/examples to see the example code.
Run npm run examples then point your browser to:
http://localhost:4444/- Shows the index of all the examples
There is also a standalone TodoMVC example application written in LiveViewJS.
More Details on the Approach to Building LiveViewJS π
Reuse Phoenix Client Libraries and app.js code - The Phoenix team has done a ton of heavy lifting on the client that we can just use. We also benefit from fixes and improvements in the future. [See
src/client/liveview.tsfor client code.]Reuse Phoenix socket message protocol - The Phoenix team already figured out a great protocol to send events to/from the server. We just implemented a different backend.
Follow component API design (i.e.
mount,renderetc), reimplemented with Typescript (so even more type-safe) - Components in LiveViewJS follow themount,render,handleEvent, andhandleInfoAPI defined in Phoenix. Again, no need to invent a new API.
Gratitude π
Thanks to @ogrodnek for the early support, feedback, and the idea to reuse the Phoenix client code instead of reinventing!
Thanks to @blimmer for the awesome feedback, documentation suggests, and support!