Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lazy-hook

lazy-hook lazily loads Phoenix LiveView hooks with dynamic import(). It keeps app.js smaller by moving hook code into split chunks and loading each hook only when LiveView mounts it.

Because LiveView expects hooks to be registered synchronously at startup, lazy-hook installs a lightweight proxy hook and forwards lifecycle callbacks after the real hook finishes loading.

Install

npm install @jump-app/lazy-hook

Quick start

  1. Enable ES modules and code splitting in esbuild. Example config.exs:
default: [
  args:
-    ~w(js/app.js --bundle --outdir=../priv/static/assets ...),
+    ~w(js/app.js --bundle --format=esm --splitting --chunk-names=chunks/[name]-[hash] --outdir=../priv/static/assets ...),
  cd: Path.expand("../assets", __DIR__),
  env: %{"NODE_PATH" => esbuild_node_path}
],
  1. Load app.js as an ES module. Example root.html.heex:
- <script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
+ <script defer phx-track-static type="module" src={~p"/assets/app.js"}>
  1. Wrap hook imports with lazyHook.

For a default export:

+ import { lazyHook } from "@jump-app/lazy-hook";
- import ExampleHook from "./hooks/example";

+ const ExampleHook = lazyHook(() => import("./hooks/example"));

const liveSocket = new LiveSocket("/live", Socket, {
  // ...
  hooks: { ...colocatedHooks, ExampleHook },
});

liveSocket.connect();

For a named export, pass the export name as the second argument:

+ import { lazyHook } from "@jump-app/lazy-hook";
- import { ExampleNamedHook } from "./hooks/example";

+ const ExampleNamedHook = lazyHook(() => import("./hooks/example"), "ExampleNamedHook");

const liveSocket = new LiveSocket("/live", Socket, {
  // ...
  hooks: { ...colocatedHooks, ExampleNamedHook },
});

liveSocket.connect();

You do not need to change the hook implementation itself.

Tip

Lazy-load hooks that pull in large dependencies or are only used on a small part of the app. Keep small, widely used hooks in the main app.js bundle.

Example loading waterfall

These traces show the effect of moving heavy hooks out of the initial bundle, on an actual user-facing page in Jump's Phoenix application. Network and CPU throttling are enabled here to make the difference easier to see.

Before

Screenshot of Chrome DevTools performance tab with a single app.js bundle

After

Screenshot of Chrome DevTools performance tab with LiveView hooks split into chunks via lazy-hook

About

Asynchronous loading of LiveView JavaScript hooks for Phoenix applications

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages