Tree-shaking
Tree-shaking is an optimization technique used in JavaScript bundlers (like esbuild, Webpack or Rollup) to remove unused or dead code from the final bundle. Needle DI has been designed with this in mind.
Tree-shaking: how does it work?
It works by analyzing the import
and export
statements of modules and ensuring that only the parts of code actually used in the application are included. By "shaking off" unused code, tree-shaking reduces the bundle size, improves load times, and enhances overall performance of the application.
Tree-shakeable injection tokens
Let's imagine a library with a class SomeHeavyClass
that depends on a lot of code, resulting in a larger bundle size.
Since we cannot decorate this class, the alternative is to bind it using an injection token:
import { InjectionToken } from "@needle-di/core";
const MY_TOKEN = new InjectionToken<SomeHeavyClass>("MY_TOKEN");
const container = new Container();
container.bind({
provide: MY_TOKEN,
useFactory: () => new SomeHeavyClass()
});
However, if there is an entry point in which there are no other references to MY_TOKEN
and SomeHeavyClass
, it will NOT be tree-shaken.
This is because it is still referred by the container itself.
However, there also an option to provide a factory
function in your InjectionToken
, which will remove the need to bind it to your container:
import { InjectionToken } from "@needle-di/core";
const MY_TOKEN = new InjectionToken<SomeHeavyClass>(
"MY_TOKEN",
{
factory: () => new SomeHeavyClass(),
}
);
const container = new Container();
container.bind({
provide: MY_TOKEN,
useFactory: () => new SomeHeavyClass()
});
This basically enables auto-binding: there is no need anymore to manually register this token in your container. Since it holds a factory function, the container can automatically construct it when you obtain it for the first time.
But more importantly, this will make your token tree-shakeable: when there are no references to your injection token, everything associated with your token will be removed from your bundle.
When to use?
This is mainly relevant if you have multiple entry points in the same codebase, and you create separate bundles for each of them. Or, if you use code splitting (e.g. lazy loaded modules/chunks) for dynamic imports.
However, using factory functions in injection tokens can also help you to organize your code in a more modular way.