@lwrjs/loader v0.14.4
Lightning Web Runtime :: Module Loader
This package contains the client-side AMD (Async Module Definition) module loader for Lightning Web Runtime (LWR).
The LWR loader is inspired and borrows from the algorithms and native browser principles of https://github.com/systemjs/systemjs
Basic Example
import Loader from 'lwr/loader';
const loader = new Loader();
// Set the define on the global scope, matching the module define call from the server
globalThis.LWR.define = loader.define;
// load a module by URL -- assume fetched module is AMD
loader.load('/path/to/foo/bar').then((module) => {
console.log(module.default);
});
// define/preload a module then load it
loader.define('foo/baz', [], function () {
return 'foo/baz';
});
loader.load('foo/baz').then((module) => {
console.log(module.default); // foo.baz
});
API
class Loader
class Loader {
constructor(baseUrl? string){...}
}
A class used to construct a loader instance.
Parameters
baseUrl
(string - optional) Set the base URL for all resolved URLs. By default the loader will attempt to parse the baseUrl from the document (if there is a document).
loader.define()
interface Define {
(name: string, dependencies: string[], exporter: Function, signatures: ModuleDefinitionSignatures): void;
}
type ModuleDefinitionSignatures = {
ownHash: string;
hashes: {
[key: string]: string;
};
};
LWR's AMD-like module format support. Unlike generic AMD, all modules in LWR must be named.
parameters
name
- The module namedependencies
- A list of module dependencies (module imports)execute
- The function containing the module code.signatures
- An argument unique to LWR's AMD loader. The object containing the "signature" of the module and the signatures for each of its dependencies. Signatures are used to identify module changes from the server and is discussed at length in the Module API RFC.
```
In order to load modules from the server, you must set the define on the global scope matching the module define call from the server:
const loader = new Loader();
globalThis.LWR.define = loader.define;
Modules can now be defined globally:
LWR.define('foo/bar', ['exports'], (exports) => {
exports.foo = 'bar';
});
loader.load()
interface Load {
(id: string): Promise<Module>;
}
Retrieves/loads a module, returning it from the registry if it exists and fetching it if it doesn't. Note, this is functionality equivalent to an ESM dynamic import, returning a Promise
which resolves to the module.
parameters
id
- A module identifier or URL
loader.has()
interface Has {
(id: string): boolean;
}
Checks if a Module exists in the registry. Note, returns false even if the ModuleDefinition exists but the Module has not been instantiated yet (executed).
parameters
id
- A module identifier or URL
loader.resolve()
interface Resolve {
(id: string): Promise<string>;
}
Returns a promise resolving to the module identifier or URL. Returns the module identifier if the module has been defined, or the full resolved URL if a URL is given.
parameters
id
- A module identifier or URL
Loader ServiceAPI
interface ServiceAPI {
addLoaderPlugin: LoaderPluginSetter;
}
interface LoaderPluginSetter {
(plugin: LoaderPlugin): void;
}
interface LoaderPlugin {
resolveModule: ResolveModuleHook;
loadModule: LoadModuleHook;
}
loader.services.addLoaderPlugin()
The loader.services.addLoaderPlugin
method allows defining plugins (i.e. hooks) into the loader.
parameters
hooks
(Object) - Thehooks
object contains the available hooks available into the loader. Hooks can be defined multiple times (with subsequentaddLoaderPlugin
calls), and will be used by the loader in the order that they are defined.
Examples
loader.services.addLoaderPlugin({
resolveModule: (id, parentUrl) => {
if (id.startsWith('lightning')) {
return `/my/api/${id}`;
}
// defer back to default loader resolve
return null;
},
loadModule: async (url) => {
if (url.indexOf('/my/api/') >= 0) {
return fetch(url);
}
// defer back to default loader load
return null;
},
});
resolveModule
hook
interface ResolveModuleHook {
(id: string, parentUrl: string): ResolveResponse | Promise<ResolveResponse>;
}
type ResolveResponse = URLResponse | string | null;
type URLResponse = {
url: string;
};
The ResolveModuleHook allows hooking into the resolution phase of the module lifecycle. The hook can be synchronous or async (return a Promise
). If there are multiple ResolveModuleHooks
defined, each hook (in order) will be called until a URLResponse
is received.
parameters
id
- A module identifier or URLparentUrl
- thebaseUrl
of the loader
return value
Returning the following values from the hook will determine the next steps of the loader:
URLResponse
- The loader will call theload
phase with the givenurl
.string
- The loader will call the nextResolveModuleHook
or defer back to the default loader resolution with the returnedstring
.null
- The loader will call the nextResolveModuleHook
or defer back to the default loader resolution with the originalid
.
loadModule
hook
interface LoadModuleHook {
(url: string): Promise<LoadResponse> | LoadResponse;
}
type LoadResponse = Response | CustomResponse | null;
type CustomResponse = {
// the string response for the module request
data: string;
// the HTTP status code for the module request - a 200 or 201 value indicates success
status: number;
// the HTTP status message for the module request
statusText?: string;
};
The LoadModuleHook allows hooking into the load phase of the module lifecycle. The hook can be synchronous or async (return a Promise
). If there are multiple LoadModuleHooks
defined, each hook (in order) will be called until a CustomResponse
| Response
is received.
parameters
url
- The absolute URL of the module to load
return value
Returning the following values from the hook will determine the next steps of the loader:
CustomResponse | Response
- The loader will evaluate the module definition returned from the response.null
- The loader will call the nextLoadModuleHook
or defer back to the default loaderload
with the givenurl
Bundling Support
The LWR loader supports loading AMD bundles -- multiple modules concatenated in a single file:
note When a bundle is loaded & executed without a module name, the last module in the bundle (file) is executed. See examples below.
note Module bundlers such as Rollup also support "bundling" of AMD modules via import/export rewriting, instead of module concatenation.
// my/bundle.js
LWR.define('c', [], () => 'c');
LWR.define('b', ['c'], (c) => b + c);
LWR.define('a', ['b'], (b) => a + b);
"Preload" the bundle with a script, then execute the 'a' module
...
<script src="/path/to/my/bundle.js" type="text/javascript">
<script type="text/javascript">
// assume loader provided globally for this example
loader.load('a').then((module) => {
console.log(module.default); // 'abc'
});
</script>
Loads and executes the last module in a bundle:
const { default: result } = await loader.load('/path/to/my/bundle.js');
console.log(result); // 'abc'
Loader Shim
This package contains the Client Runtime Loader Shim for hosting a LWR application in AMD format. The AMD Loader Shim is responsible for:
- defining and executing the
@lwr/loader
- exposure of the loader's
define
API atglobalThis.LWR.define
- client-side orchestration for the generated application bootstrap module
LWR Application Document
A web client provides the following HTML document to bootstrap a LWR application:
<head>
<title>Lightning Web Application</title>
</head>
<body>
<x-example></x-example>
<!-- client bootstrap configuration for c/example app -->
<script>
globalThis.LWR = globalThis.LWR || {};
Object.assign(globalThis.LWR, {
autoBoot: true,
bootstrapModule: 'bootstrap/c%2fexample/v/0.0.1',
});
</script>
<!-- preloaded bootstrap modules: AMD Loader Shim and Loader Module -->
<script src="/1/resource/prod/l/en_US/amd-loader-shim.js/v/0_0_1"></script>
<script async src="/1/module/prod/l/en_US/lwr/loader/v/0_0_1"></script>
</body>
Read more in the bootstrap RFC.
Client Bootstrap Config
The LWR server provides configuration used by the loader shim:
globalThis.LWR: {
// true if there is no customInit hook
autoBoot: true,
// versioned application bootstrap module name
bootstrapModule: 'bootstrap/hello%2Fworld/v/0.0.1',
// (optional) modules which must be loaded before the application is mounted
// add all preloaded modules to this list
// the lwr/loader module is an implied member of this list
requiredModules: [
'bootstrap/lwr%2fexample/v/0.0.1',
// ...
],
// (optional) modules being preloaded outside the LWR loader
preloadModules: [
'lwr/example/v/0.0.1',
// ...
]
// (optional) versioned root application component name
rootComponent: 'hello/world/v/1'
}
Read more in the bootstrap RFC.
Custom Initialization
Some host environments may desire to defer or manage when the application is initialized. To do this, the customInit
bootstrap hook can be implemented by:
- setting
globalThis.LWR.autoBoot
tofalse
- adding a
globalThis.LWR.customInit
function:
type CustomInitFunction = (lwr: CustomInitAPI, config: ClientBootstrapConfig) => void;
// The API argument passed to the customInit hook
type CustomInitAPI = {
// called to trigger app initilization
initializeApp: InitializeApp;
// register bootstrap error state callback
onBootstrapError: RegisterBootstrapErrorHandler;
// A convenience pointer to the globally available LWR.define
define: Function;
};
type ClientBootstrapConfig = {
autoBoot: boolean;
bootstrapModule: string;
requiredModules?: string[];
preloadModules?: string[];
rootCompoonent?: string;
};
The loader shim calls the customInit
hook and will not start the application until it calls lwr.initializeApp()
. Triggering lwr.initializeApp()
before all requiredModules
are defined will result in an error.
<body>
<x-example></x-example>
<!-- client bootstrap configuration for c/example app -->
<script>
globalThis.LWR = globalThis.LWR || {};
Object.assign(globalThis.LWR, {
autoBoot: false,
bootstrapModule: 'bootstrap/c%2fexample/v/0.0.1',
customInit: (lwr, config) => {
// execute custom pre-initialization code
lwr.initializeApp();
},
});
</script>
<!-- ... -->
</body>
Read more in the bootstrap RFC.
Output
The AMD Loader Shim is pre-built provided as a static IIFE resource:
build/
└── assets
└── prod
└── lwr-loader-shim.js
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
9 months ago
9 months ago
8 months ago
9 months ago
8 months ago
8 months ago
8 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
11 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
10 months ago
10 months ago
1 year ago
12 months ago
10 months ago
10 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
11 months ago
11 months ago
11 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago