Fifthtry

Realm: Build Bundling

Currently we are generating a single bundle that contains all Elm apps. This approach was a makeshift arrangement, to quickly get started and is problematic for medium to large websites: basically build size will keep going up as amount of elm code goes up.

In realm, every “page” (that is something that implements realm::Page trait, or every Elm file in frontend/Pages folder, both of them are same, they have one to one mapping), is a “realm app”.

Each realm app is an Elm app, with something extra: basically Realm.js and Realm.elm files. Realm.elm uses the elm file corresponding to the realm page, and manages it, loads it, unloads it and so on.

When compiling, currently we pass all the “realm app” elm files to elm make, and then merge the Realm.js to it to create our build.

Loader vs Independent Bundles

One design consideration when we start bundling is, should we have some sort of bundle loader, which loads the appropriate bundle, or should each bundles act as completely independent bundles?

Each bundle is a collection of one or more realm apps (eg Pages.Index elm module can be a whole bundle or part of a bundle along with Pages.SignUp and Pages.SignIn).

When a loader, we can do somethings extra, eg “delta download”, eg if I already have say a base bundle, say we demarcated one of our bundles as base bundle, the other bundles may need something from base bundle, and we do a “delta download”, only download the diff from other bundle to base bundle, thus saving on download size slightly.

Each bundle will still be built by elm make, and every elm has a bunch of common dependencies, eg Json.Encoder, or VirtualDom and so on, all the stuff that comes with elm, all the common libraries. These will be included in each output js generated by elm make.

If we do not do some sort of “delta”, we will be downloading all those things multiple times.

Consider a website that has four pages, Pages.Index, Pages.SignIn, Pages.SignUp and Pages.Editor. Say we want to create two bundles, one with Pages.{Index, SignIn, SignUp}, called “base bundle”, and other with just Pages.Editor, called “editor bundle”.

One option is we say that base bundle will also act as a loader, and every time you need editor bundle you will also download base bundle first, and then editor bundle (orchestrated by the loader portion of base bundle).

So if you go to / or /sign-in/ etc, you only download base bundle, but if you go to /editor/, you download both base bundle and editor bundle. This is the loader scenario.

Other scenario, we call “independent bundles” is that what you download purely depends on what page you are visiting, if you visit /editor/ you will download editor bundle, and if you visit /, then the base bundle.

Independent bundles are simpler, but they download more than minimally needed.

But on the other hand browsers start parsing JS in a streaming fashion. So if we are doing delta patching in javascript, we will have to serve it as non-js content type, as the javascript is not complete, it has missing portions, which will be supplied during patch phases after downloading the JS, which means browsers can’t do streaming JS parsing.

For now I am thinking of going with simpler approach: independent bundles, we will see if it becomes a big problem then will consider delta.

How Are Bundles Specified?

We have to ways to specify bundling, i.e. deciding how many bundled are there, and which elm files belong to which bundles, we can do it bases elm module path, or as a json config file.

In elm module path approach, say we create a folder structure, Pages.Base.Index and Pages.Base.SignIn, will go to “base: (Base lowercased) bundle”, and Pages.Editor.Editor will go to “editor bundle”.

In json config approach we will have a json file:

{
    "base": ["*"],
    "editor": ["Editor"]
}

Here “*” will evaluate to everything (but “Editor”, we will ensure this semantics: can only work if each pattern is exclusive).

One advantage of json approach is we can re-bundle without changing code, and we can even use “intelligent techniques” like doing a statistical analysis of traffic, or even do a “user category” wise bundling, eg logged in users get different bundle configuration and so on (to implement this, Page trait may get another hinting function .with_bundle()).

In Elm file path approach, everything is too rigid and can’t move around easily.

The Switch

So we have a bundle map, for each elm file we know the js file name that is to be included.

For first page load (realm_mode=HTML), our server will look at response, find the elm file mentioned, and ensure right js file is made part of html rendered.

On subsequent requests (realm_mode=JSON), our Realm.js will look at Elm file name in response, and Realm.js too has access to bundle map, and will know if current bundle (each bundle will have its own Realm.js) has the elm file, and if not, what bundle has the code for requested Elm file, and attach the script node to page after setting the current config in some place globally. The new bundle js file will be downloaded (or loaded from browser cache), look at the global config, and proceed (like how our elm does on page load).

In case we are switching between Elm files from two bundles back and forth, we do not want to keep adding script after script to page, ideally we should add as many scripts as unique bundles needed so far, we can have some js global record of what all bundles are loaded, along with init function for each bundle, so if the bundle is already loaded, instead of storing things globally, we will call the init of the bundle with the config.

Table Of Content

What is Realm?

A Bit On Motivation

Routing is Hard

What does Realm do?

Backend Data And Type Safety

Tutorial

Quick Start Realm Tutorial

In Depth Tutorial (not ready)

Nix
Shell
Doit
Hello Rust
Hello Elm
Hello Static Files
Hello Server Side Rendering
Pre-Commit Hooks

Routing, Request And Response

Frontend, Data, Navigation, And APIs

How To Guides

File Upload

Backend: S3 File Upload
Authenticated File Serving
Frontend: Uploading Files From Elm

How to use storybook?

How to implement “loading..”?

Docs

Realm.In

Realm.Storybook.Story

realm::In

realm::Context

realm::Result

realm.magicSlice

realm::RequestConfig

Environment Variables

Internals - Only for Realm Developers, not Users

“Realm DATA”
iFrame Controller
Shutdown Routine
Testing Internals

Change Log

Get Realm Starter Working

Transparent Offline Feature

How to make http requests in Realm?

Development

Tutorial: ToDo App

Realm Testing

Enhance Realm Starter

Double Load Issue

Deploy To Heroku Button

End failure

Realm-Starter Github Template

Proposal: Tracker And Visit

Proposal: Activity Store

Proposal: Bundling

Proposal: Retry On Network Error

Storybook: Editable JSON

Storybook: Notes

Storybook: Reference

Backlog

Readings

Change Log

How to Publish

Testing

Code Snippets

Skip rustfmt For Some Section

Close Modal Dialog When Clicked Outside

Ignoring Lints In Python

Ignoring Lints (clippy and rustc warnings) In Rust

Handle DateTime in Rust & Elm

Handle CiText value read in Rust

Transport Enum Type to and fro Rust/Elm through JSON