Module Providers for Lightning Web Runtime on Node.js

Module providers locate and serve modules for your web app. Your project's LWR server contains a module registry, which maintains a list of available module providers and helps match module requests to a valid module provider.

All Lightning Web Runtime on Node.js (LWR-JS) apps automatically include default module providers that support common module types, like static file system modules and packaged Lightning web components (LWCs). If you want to use ECMAScript (ES) modules from other sources, you can import a module provider or create a custom module provider.

This flexibility ensures that your runtime is small for simple use cases, but LWR-JSS can support more complex applications if needed.

You project automatically includes these module providers.

This module provider generates only the Application Bootstrap Module. You need it for your website to load correctly.

The Router Module Provider generates a router based on a static JSON file.

The LWC Module Provider locates and serves Lightning Web Components (LWC) modules for your app. LWCs are special instances of ES modules that extend the LightningElement class. They have to be processed by the LWC compiler before a module provider can serve them.

This module provider locates and serves all of the Node Package Manager (npm) ES modules from your project's node_modules directories.

The LWR-JS Externals Module Provider creates module definitions based on the externals in your project's bundle configuration (bundleConfig).

With LWR-JS, you can add an existing module provider to your project. For example, the LWR Label Module Provider exposes capabilities for scoped module label support (@salesforce/label/*). You can add this tooling to your application via the @lwrjs/label-module-provider npm package.

To add an optional module provider to your project, first install the package using npm on the command line interface (CLI). For example, this code installs the Label Module Provider.

Then, add the module provider plugin to your lwr.config.json file. Remember to include the default module providers in the moduleProviders array. Here's how to add the Label Module Provider to your app's config file.

The moduleProviders array overwrites the default LWR array. You have to list all the module providers needed by your app, including the default LWR ones listed in Default Module Providers.

That configuration lets your application components statically import labels sourced from JSON files in your project’s $rootDir/src/labels directory, like this:

You can add these module providers to your LWR-JS project.

If you want your app to use a custom module that can't be served by one of the default module providers, add a custom module provider to your project. You can create a custom ES provider or a custom LWC provider.

In this section, we'll walk through how to create and implement a custom ES provider. We can boil this process down into three steps.

  1. Create the module provider.
  2. Configure getModuleEntry() and getModule().
  3. Register the module provider.

To create an ES module provider, implement the ModuleProvider LWR interface. You have to give the module provider a name, but the version property is optional.

Save this file in your app's src folder. For example, the sample module provider es-custom-provider is nested in src/services.

Module providers rely on getModuleEntry() and getModule() to match module requests to module providers and help compile modules. You should customize these functions for your custom module provider.

When your LWR server receives a request for a module – like someone loading a webpage – the module registry calls getModuleEntry() on all of its module providers. The first module provider to correctly handle this request is assigned to serve the requested module.

The module registry passes these two arguments into getModuleEntry().

  • A module ID, which contains the module's specifier (a unique ID value).
  • RuntimeParams, a map of unique requirements for the requested page. For example, it could include a requirement for a specific locale.

The function returns a ModuleEntry object that contains information from a valid module provider and the module request.

You should customize the information in ModuleEntry based on your custom module provider and the module it serves.

  • id - At a minimum, include the module's specifier and the module provider's version. If the moduule is locale-specific, include the locale value from RuntimeParams.
  • virtual - If module code from your provider is generated from scratch, set this to true. If it's read off of a file system or another source, set this to false.
  • entry - Set this to the module's filepath. If the module is virtual, ensure the path includes the specifier.
  • version - Set this to the module provider's version.

Here's an example of a ModuleEntry object returned by a custom module provider.

When the module registry validates that a module provider can fulfill a module request, the registry calls getModule(). getModule() takes the same arguments as getModuleEntry(). It returns a ModuleCompiled object.

To register a custom module provider, add it to your project's lwr.config.json file. Make sure that TypeScript has been transpiled into JavaScript.

The moduleProviders array overwrites the default LWR array. You have to list all the module providers needed by your app, including the default LWR ones listed in Default Module Providers.

Alternatively, you can pass your configuration from lwr.config.json to a module provider constructor. The configuration can be any JSON object or primitive type.

The configuration and ProviderContext (from the LWR server) are passed into the module provider constructor.

LWCs are special instances of ES modules that extend the LightningElement class. Before a module provider serves LWCs, they have to be processed by the LWC compiler.

The easiest way to create a custom LWC module provider is to extend the LwcModuleProvider class from the package @lwrjs/lwc-module-provider.

To adapt the LWC module provider for your LWR app, override getModuleEntry() and getModuleSource(). The getModule() function of the superclass handles compilation of the LWC.