Lazy Decorator

When working on a big scaled application, sometimes you want to load and asynchronously instantiate part of it. If you worked on a big client-side application with a bundler like Webpack or Vite, you probably know how code-splitting works.

If you read about Injex's Webpack Runtime, you noticed that we use require.context() and with Vite Runtime we use import.meta.glob() to load the files inside the project. The problem with this approach is that we're bundling all the code together.

With the @lazy() decorator you create a class that implements the ILazyModule interface. The import method should load and return a Constructor inside a Promise, then the constructor is called with args you pass in. You can use the import method for lazy-loading the code.

Usage

To use the @lazy() decorator, put it above an exported class that implements the ILazyModule interface. Lines 9 and 11 will create a chunk using Webpack's/Vite's code-splitting feature.

import { define, lazy, ILazyModule, IConstructor } from "@injex/core";
@define()
@lazy()
export class CreatePage implements ILazyModule<IPage> {
public async import(pageType: "home" | "profile"): Promise<IConstructor<IPage>> {
switch(pageType) {
case "home":
return (await import("./pages/home")).HomePage;
case "profile":
return (await import("./pages/profile")).ProfilePage;
}
}
}
home.lazy.ts
import { define, inject } from "@injex/core";
/**
* This file will be lazy loaded
*/
@define()
export class HomePage implements IPage {
@inject() private env;
public render(): string {
return `<H1>Home Page</H1>`;
}
}

And finally, use the CreatePage lazy module from anyware

import { define, singleton, inject } from "@injex/core";
@define()
@singleton()
export class PageRenderer {
@inject() privatge createPage: () => Promise<IPage>;
public async render() {
// calling `this.createPage("home")` will load the HomePage module chunk asynchronously.
const home = await this.createPage("home");
document.getElementById('root').innerHTML = home.render();
}
}

Prevent lazy modules from beeing bundled

When using the @lazy() feature, we tell Injex that some modules will be loaded later in our application lifecycle. These modules are excluded when Injex loads and initializes our container.
To do so, when creating the container using Injex.create(), we can decide which files should be loaded into the container upon initialization and which be avoided.

We can create files with a specific extension to be avoided, for example:

myModule.lazy.ts

To skip the files with the *.lazy.ts extension, we can create the Injex container like so:

Using Webpack runtime:

import { Injex } from "@injex/webpack";
Injex.create({
resolveContext: () => require.context(__dirname, true, /^.*[^\.lazy]\.ts$/)
});

Using Vite runtime:

import { Injex } from "@injex/vite";
Injex.create({
glob: () => import.meta.glob('./**/*[!.lazy].ts', { eager: true })
});