MelbJS March 2023 notes
Raw notes from the MelbJS meetup held at Culture Amp in Richmond on 8 March, 2023.
Fundamentals of Module Federation, Mathew ByrnePermalink to Fundamentals of Module Federation, Mathew Byrne
Microfrontends are an architectural pattern to split up large codebases into small apps that are stitched together into a single page at runtime.
Problems of a single build (monolith):
- Scaling build times
- Dependency versioning: Team A wants to upgrade React, Team B isn’t ready
- Deployments: slow builds means deploys back up
- In general, bottlenecks!
Multiple apps: a new bundle per “page”. New problems:
- Compromised user experience
- Hard to maintain client state across apps
- Scaling challenges still exist within each app
- Duplicate dependencies
Webpack externals: shared dependencies are loaded separately. New problems:
- No on-demand loading of code. All dependencies must be available first.
- Manual juggling of those dependencies.
Native ES Modules: trust the browser to load your dependencies for you. New problems:
- Performance: round-tripping of cascading requests for dependencies.
- Limited client support.
- Can’t use non-ESM dependencies.
Module federation: a run-time method of sharing modules between independent builds.
- Host: The first webpack runtime to boot on the client
- Remote: A bundle that the host can dynamically load in when requested.
- These are not mutually exclusive.
Redundancy, self-healing and versioning come built-in. Already-loaded modules get used. Missing modules get auto-loaded.
Doesn’t interfere with a familiar developer experience.
Works in the browser and in Node.
Remote loads are “hoisted”: an entire tree of missing dependencies will be loaded in parallel.
Demo: Two independent webpack apps in a monorepo. Both dev servers running. App1 loads App2 as a remote! App2 is lazy-loaded, but it doesn’t have to be. App1’s webpack config has a
ModuleFederationPlugin that declares a remote for
App2. App2’s webpack config has a
ModuleFederationPlugin that declares that App2 is remote that can be loaded by a host. When App1 loads App2, App2 gets its react, etc. from App1.
A bundle can be both a host and a remote, which enables some interesting configurations. The module federation project repo has dozens of examples. E.g. Bidirectional, two modules that can each act as a host, but load the other on demand. App Shell, a single host designed to load multiple remotes.
MF first shipped with Webpack 5 in Oct 2020. Next 13, SSR support are now there. Delegate modules, a new feature like middleware for loading remotes (e.g. dynamic host selection, etc.), just landed.
- Follow Zack Jackson, @ScriptedAlchemy.
Standard Promises. Promise Standards, FrankyPermalink to Standard Promises. Promise Standards, Franky
Promises are a combination of two specifications: ECMAScript and HTML.
The browser maintains an event loop, background micro-task queues, etc. to make this all work.
A tour of the relevant specs, using a simple promise example:
How it works (according to the spec):
- Check that the
Promiseconstructor was passed a function as an executor.
- Create an internal promise object, using the Promise prototype, which includes all the promise features we’re used to (
then, etc.). Creates some internal “slots” for information about the promise.
- Create the
rejectfunctions, which are passed into the executor later.
- Call the executor function. If it completes successfully, it’s a normal completion. If it throws and exception, it’s an abrupt completion.
- Return the promise!
How the resolving functions (
reject) work internally: Depending which is called, the promise will be fulfilled or rejected. If
resolve is called with another promise, that promise is used in turn to continue resolving. Otherwise, the promise is resolved straight away.
How a promise is fulfilled:
Once a promise is fulfilled, it needs to be handled. That’s where we move into the
then method. The specification for this function is really, really long! For brevity, we’ll ignore all the parts that have to do with rejecting. This is where the HTML spec starts to come in.
then method creates another promise, which operates just like the one we’ve been talking about. It’s a bit hidden, but it’s what lets us chain promises.
then takes a callback, which gets passed to
The Event loop processing model:
- Event loop
- Task queue
- Microtask queue
There are entire talks on this stuff, so we’re only going to cover it briefly.
The microtask queue is a priority queue. Being in the task queue is like boarding a plane in Economy Class.
So, back in the world of the promises standard,
HostEnqueuePromiseJob schedules tasks on the high-priority microtask queue (defined in the HTML spec).
Another example of how these two standards operate together:
Not covered for time (but equally interesting!): stuff like what happens if
resolve is passed another promise. Opens up another can of worms. Also interesting, how browser APIs like
fetch work under the surface.
Pyodide and JS: The One Language to Rule Them All, Hon Weng ChongPermalink to Pyodide and JS: The One Language to Rule Them All, Hon Weng Chong
Pyodide: compile Python to WebAssembly.
Cortical Labs: we grow neurons (live brain cells) and program them to play video games like Pong!
Python was the most popular language when we looked, so that’s where we started!
We built a web-stack IDE (Monaco text editor engine).
Load the Pyodide JS bundle, then write a little bootstrap script and pass it Python source code to run. Just like that, Python running in the browser! No backend, no installation.
Take the value returned by Pyodide and call its
Can also use
Demo: a game of Pong implemented in Python, rendering its current state to a Canvas with JS.
Pyodide is important because it will bring all of the machine learning and AI technologies (implemented in Python) into the Web, where we can give them a UI.