-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make your own TEA #1
Open
eeue56
wants to merge
14
commits into
main
Choose a base branch
from
make-your-own-tea-post
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The Elm archiceture, otherwise known as TEA, is a model for handling interactive user interfaces. This concept was popularized in the frontend world by Redux, though Elm got there first. The idea is simple: every program has state, known as the model, a way of modifying the model, known as update, and finally a way to represent the model and allow for interactions known as the view. The model should be immutable - the update function should return a modified copy of the model. There are two many user-provided types: model, and message. The model type is state. The messages are triggered by interactions - for example, ClickOnSubmit. This pattern is best applied to single page applications, where it makes sense to have a runtime that can render different content based on the model. In this initial commit, only the structure is provided. Later commits will introduce the flow that enables this pattern to be used.
To render content into the DOM, it's handy to have an Abstract Syntax Tree (AST) which represents the content to be rendered. In Elm, this is provided via the Html package. In React, JSX provides a user-familiar syntax while still turning into Reacty type stuff. In this example, we create our AST with 3 constructor functions that users can call - instead of using another templating language, make-your-own-tea focuses on everything being a function. Once we have our AST, we can use that the render and fill the DOM with actual elements.
Now it's time to introduce event handlers to our AST. Each node can have events attached to it. An event is composed of a name of an event to listen for, and the callback that will take event data then produce a <message> that can be fed into the update loop. In order to modify the event handlers attached to the DOM elements, we store the event handlers with their IDs on the nodes. This allows us to remove the event handler. Patching is used in order to avoid fully rerendering the existing DOM, and instead only apply changes between the currently rendered version and the next.
We move the valid tag types out into a seperate union, and reduce code repetition by using a helper to construct nodes. This refactor helps us prepare for adding support for more tags.
In order to get text from a user, we add an input node that contains user-input.
Attributes allow the DOM elements to change their settings. Attributes fall into two groups: attributes set via =, and properties set by modifying the properties of the DOM node in JavaScript. For now we just add support for attributes that have string values. Different tags support different attributes, but we'll leave that as an exercise for the reader.
To give a more realistic of example of how to use the framework, we move the code out from being one giant view function into several smaller functions.
Boolean attributes are those that are either true or false. A great example is a checkbox.
To send a message asynchronously to the update loop, we add a callback that can be given a message.
To prevent unnecessary re-renders or re-draws, we add better support for diffing between previous and current attributes.
In order to either server-side render content, or to do a simple one time render without an update loop, we add a way to render Html as a string.
In order to add an event loop to a statically rendered DOM, we provide a hydration function which will attach events and take over the drawing loop.
To provide functions outside of the update loop with model changes and messages, we expose a subscription function.
There are a number of tags which cannot have children. We represent these in our AST with VoidNode.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This pull request demonstrates how to build an Elm-style event loop in TypeScript, as is used in Derw. The Elm Architecture was implemented by other JavaScript libraries such as Redux. This PR approaches the core loop behind the idea, along with examples on how to limit the API so only valid elements can be created. It also has support for hydration, with an example, and async event handling. There is also a way to subscribe to state changes inside the update loop.
The way to consume this PR is to go through commit by commit, where there is a long message in the commit, along with lots of inline comments explaining the different parts of the code.
To run it locally, clone the repo then use
esbuild --bundle src/index.ts --outfile=build/index.js
For more info see the blog post: https://derw.substack.com/p/make-your-own-tea-the-elm-architecture?sd=pf