@dotglitch/ngx-lazy-loader
Version:
A hackable lazy loader for Angular components
662 lines (652 loc) • 31.6 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, Injectable, Inject, EventEmitter, isDevMode, ViewContainerRef, Component, Optional, ViewChild, Input, Output, NgModule } from '@angular/core';
import { __awaiter } from 'tslib';
import { NgIf, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { debounceTime } from 'rxjs';
import * as i2 from '@angular/cdk/dialog';
var ComponentResolveStrategy;
(function (ComponentResolveStrategy) {
/**
* Match the fist component we find
* (best used for standalone components)
* @default
*/
ComponentResolveStrategy[ComponentResolveStrategy["PickFirst"] = 0] = "PickFirst";
/**
* Perform an Exact ID to Classname of the Component
* case sensitive, zero tolerance.
*/
ComponentResolveStrategy[ComponentResolveStrategy["MatchIdToClassName"] = 1] = "MatchIdToClassName";
/**
* Perform a fuzzy ID to classname match
* case insensitive, mutes symbols
* ignores "Component" and "Module" postfixes on class
* names
*/
ComponentResolveStrategy[ComponentResolveStrategy["FuzzyIdClassName"] = 2] = "FuzzyIdClassName";
/**
* Use a user-provided component match function
*/
ComponentResolveStrategy[ComponentResolveStrategy["Custom"] = 3] = "Custom";
})(ComponentResolveStrategy || (ComponentResolveStrategy = {}));
/**
* Convert a string `fooBAR baz_160054''"1]"` into a slug: `foobar-baz-1600541`
*/
const stringToSlug = (text) => (text || '')
.trim()
.toLowerCase()
.replace(/[\-_+ ]/g, '-')
.replace(/[^a-z0-9\-]/g, '');
const Logger = (context, contextColor, textColor = "#03a9f4") => ({
log: (message, ...args) => {
console.log(`%c[${context}] %c${message}`, 'color: ' + contextColor, 'color: ' + textColor, ...args);
},
warn: (message, ...args) => {
console.warn(`%c[${context}] %c${message}`, 'color: ' + contextColor, 'color: ' + textColor, ...args);
},
err: (message, ...args) => {
console.error(`%c[${context}] %c${message}`, 'color: ' + contextColor, 'color: ' + textColor, ...args);
},
error: (message, ...args) => {
console.error(`%c[${context}] %c${message}`, 'color: ' + contextColor, 'color: ' + textColor, ...args);
}
});
// Monkey-patch the type of these symbols.
const $id = Symbol("id");
const $group = Symbol("group");
const NGX_LAZY_LOADER_CONFIG = new InjectionToken('config');
class NgxLazyLoaderService {
get err() { return NgxLazyLoaderService.config.logger.err; }
get log() { return NgxLazyLoaderService.config.logger.log; }
get warn() { return NgxLazyLoaderService.config.logger.warn; }
constructor(config = {}) {
// Ensure this is singleton and works regardless of special instancing requirements.
NgxLazyLoaderService.configure(config);
}
static configure(config) {
var _a;
const { log, warn, err } = Logger("ngx-lazy-loader", "#009688");
this.config = Object.assign({ componentResolveStrategy: ComponentResolveStrategy.PickFirst, logger: {
log,
warn,
err
} }, config);
(_a = config.entries) === null || _a === void 0 ? void 0 : _a.forEach(e => this.addComponentToRegistry(e));
// If a custom resolution strategy is provided but no resolution function is passed,
// we throw an error
if (this.config.componentResolveStrategy == ComponentResolveStrategy.Custom &&
!this.config.customResolver) {
throw new Error("Cannot initialize. Configuration specifies a custom resolve matcher but none was provided");
}
if (this.config.loaderDistractorComponent && this.config.loaderDistractorTemplate)
throw new Error("Cannot have both a Component and Template for Distractor view.");
if (this.config.errorComponent && this.config.errorTemplate)
throw new Error("Cannot have both a Component and Template for Error view.");
if (this.config.notFoundComponent && this.config.notFoundTemplate)
throw new Error("Cannot have both a Component and Template for NotFound view.");
}
static addComponentToRegistry(registration) {
var _a;
if (!registration)
throw new Error("Cannot add <undefined> component into registry.");
// Clone the object into our repository and transfer the id into a standardized slug format
const id = stringToSlug((_a = registration.id) !== null && _a !== void 0 ? _a : Date.now().toString()); // purge non-basic ASCII chars
const group = registration.group || "default";
registration[$id] = id;
registration[$group] = id;
if (!this.registry[group])
this.registry[group] = [];
// Check if we already have a registration for the component
// if (this.registry[group] && typeof this.registry[group]['load'] == "function") {
// // Warn the developer that the state is problematic
// this.config.logger.warn(
// `A previous entry already exists for ${id}! The old registration will be overridden.` +
// `Please ensure you use groups if you intend to have duplicate component ids. ` +
// `If this was intentional, first remove the old component from the registry before adding a new instance`
// );
// // If we're in dev mode, break the loader surface
// if (isDevMode())
// return;
// }
this.registry[group].push(registration);
}
/**
* Register an Angular component
* @param id identifier that is used to resolve the component
* @param group
* @param component Angular Component Class constructor
*/
registerComponent(args) {
if (this.isComponentRegistered(args.id, args.group)) {
this.log(`Will not re-register component '${args.id}' in group '${args.group || 'default'}' `);
return;
}
NgxLazyLoaderService.addComponentToRegistry({
id: stringToSlug(args.id),
matcher: args.matcher,
group: stringToSlug(args.group || "default"),
load: args.load || (() => args.component)
});
}
/**
*
* @param id
* @param group
*/
unregisterComponent(id, group = "default") {
const _id = stringToSlug(id);
const _group = stringToSlug(group);
if (!this.resolveRegistrationEntry(id, group))
throw new Error("Cannot unregister component ${}! Component is not present in registry");
// TODO: handle clearing running instances
delete NgxLazyLoaderService.registry[_group][_id];
}
/**
* Get the registration entry for a component.
* Returns null if component is not in the registry.
*/
resolveRegistrationEntry(value, group = "default") {
const _id = stringToSlug(value);
const _group = stringToSlug(group);
const targetGroup = (NgxLazyLoaderService.registry[_group] || []);
let items = targetGroup.filter(t => {
if (!t)
return false;
// No matcher, check id
if (!t.matcher)
return t[$id] == _id;
// Matcher is regex
if (t.matcher instanceof RegExp)
return t.matcher.test(_id) || t.matcher.test(value);
// Matcher is string => regex
if (typeof t.matcher == 'string') {
const rx = new RegExp(t.matcher, 'ui');
return rx.test(_id) || rx.test(value);
}
// Matcher is array
if (Array.isArray(t.matcher)) {
return !!t.matcher.find(e => stringToSlug(e) == _id);
}
// Custom matcher function
if (typeof t.matcher == "function")
return t.matcher(_id);
return false;
});
if (items.length > 1) {
this.warn("Resolved multiple components for the provided `[component]` binding. This may cause UI conflicts.");
}
if (items.length == 0) {
return null;
}
const out = items[0];
if (out.matcher instanceof RegExp) {
const result = _id.match(out.matcher) || value.match(out.matcher);
return {
entry: out,
matchGroups: result === null || result === void 0 ? void 0 : result.groups
};
}
return { entry: out };
}
/**
* Check if a component is currently registered
* Can be used to validate regex matchers and aliases.
*/
isComponentRegistered(value, group = "default") {
return !!this.resolveRegistrationEntry(value, group);
}
/**
*
* @param bundle
* @returns The component `Object` if a component was resolved, `null` if no component was found
* `false` if the specified strategy was an invalid selection
*/
resolveComponent(id, group, modules) {
switch (NgxLazyLoaderService.config.componentResolveStrategy) {
case ComponentResolveStrategy.PickFirst: {
return modules[0];
}
// Exact id -> classname match
case ComponentResolveStrategy.MatchIdToClassName: {
const matches = modules
.filter(k => k.name == id);
if (matches.length == 0)
return null;
return matches[0];
}
// Fuzzy id -> classname match
case ComponentResolveStrategy.FuzzyIdClassName: {
const _id = id.replace(/[^a-z0-9_\-]/ig, '');
if (_id.length == 0) {
NgxLazyLoaderService.config.logger.err("Fuzzy classname matching stripped all symbols from the ID specified!");
return false;
}
const rx = new RegExp(`^${id}(component|module)?$`, "i");
const matches = modules
.filter(mod => {
let kid = mod.name.replace(/[^a-z0-9_\-]/ig, '');
return rx.test(kid);
});
if (matches.length > 1) {
NgxLazyLoaderService.config.logger.err("Fuzzy classname matching resolved multiple targets!");
return false;
}
if (matches.length == 0) {
NgxLazyLoaderService.config.logger.err("Fuzzy classname matching resolved no targets!");
return null;
}
return matches[0];
}
case ComponentResolveStrategy.Custom: {
return NgxLazyLoaderService.config.customResolver(modules);
}
default: {
return false;
}
}
}
}
// A proxied registry that mutates reference keys
NgxLazyLoaderService.registry = {};
/** @nocollapse */ NgxLazyLoaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderService, deps: [{ token: NGX_LAZY_LOADER_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ NgxLazyLoaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () {
return [{ type: undefined, decorators: [{
type: Inject,
args: [NGX_LAZY_LOADER_CONFIG]
}] }];
} });
class NgxLazyLoaderComponent {
/**
* The id of the component that will be lazy loaded
*/
set id(data) {
const id = stringToSlug(data);
// Check if there is a change to the loaded component's id
// if it's updated, we destroy and rehydrate the entire container
if (this.initialized && this._id != id) {
this._id = id;
this.ngAfterViewInit();
}
else {
this._id = id;
}
}
;
set group(data) {
const group = stringToSlug(data);
if (typeof group != "string" || !group)
return;
// If the group was updated, retry to bootstrap something into the container.
if (this.initialized && this._group != group) {
this._group = group;
this.ngAfterViewInit();
return;
}
this._group = group;
}
get group() { return this._group; }
/**
* A map of inputs to bind to the child.
* Supports change detection. (May fail on deep JSON changes)
*
* ```html
* <lazy-loader component="MyLazyComponent"
* [inputs]="{
* prop1: true,
* prop2: false,
* complex: {
* a: true,
* b: 0
* }
* }"
* >
* </lazy-loader>
* ```
*/
set inputs(data) {
if (data == undefined)
return;
let previous = this._inputs;
this._inputs = data;
if (data == undefined)
console.trace(data);
if (this.targetComponentFactory) {
const { inputs } = this.targetComponentFactory.ɵcmp;
const currentKeys = Object.keys(inputs);
const oldKeys = Object.keys(previous).filter(key => currentKeys.includes(key));
const newKeys = Object.keys(data).filter(key => currentKeys.includes(key));
const removed = oldKeys.filter(key => !newKeys.includes(key));
// ? perhaps set to null or undefined instead
removed.forEach(k => this.targetComponentInstance[k] = null);
this.bindInputs();
}
}
/**
* A map of outputs to bind from the child.
* Should support change detection.
* ```html
* <lazy-loader component="MyLazyComponent"
* [outputs]="{
* prop3: onOutputFire
* }"
* >
* </lazy-loader>
* ```
*/
set outputs(data) {
let previous = this._outputs;
this._outputs = data;
if (this.targetComponentFactory) {
const { inputs } = this.targetComponentFactory.ɵcmp;
const currentKeys = Object.keys(inputs);
const removed = Object.keys(previous).filter(key => !currentKeys.includes(key));
removed.forEach(k => {
var _a;
// Unsubscribe from observable
(_a = this.outputSubscriptions[k]) === null || _a === void 0 ? void 0 : _a.unsubscribe();
delete this.targetComponentInstance[k];
});
this.bindOutputs();
}
}
constructor(service, viewContainerRef, dialog, dialogArguments) {
this.service = service;
this.viewContainerRef = viewContainerRef;
this.dialog = dialog;
this.dialogArguments = dialogArguments;
this._group = "default";
this.outputSubscriptions = {};
/**
* Emits errors encountered when loading components
*/
this.componentLoadError = new EventEmitter();
/**
* Emits when the component is fully constructed
* and had it's inputs and outputs bound
* > before `OnInit`
*
* Returns the active class instance of the lazy-loaded component
*/
this.componentLoaded = new EventEmitter();
// Force 500ms delay before revealing the spinner
this.loaderEmitter = new EventEmitter();
this.clearLoader$ = this.loaderEmitter.pipe(debounceTime(300));
this.showLoader = true; // whether we render the DOM for the spinner
this.isClearingLoader = false; // should the spinner start fading out
this.initialized = false;
this.config = NgxLazyLoaderService.config;
this.err = NgxLazyLoaderService.config.logger.err;
this.warn = NgxLazyLoaderService.config.logger.warn;
this.log = NgxLazyLoaderService.config.logger.log;
// First, check for dialog arguments
if (this.dialogArguments) {
this.inputs = this.dialogArguments.inputs || this.dialogArguments.data;
this.outputs = this.dialogArguments.outputs;
this.id = this.dialogArguments.id;
this.group = this.dialogArguments.group;
}
this.loaderSub = this.clearLoader$.subscribe(() => {
this.showLoader = false;
});
}
ngAfterViewInit() {
return __awaiter(this, void 0, void 0, function* () {
this.ngOnDestroy(false);
this.isClearingLoader = false;
this.showLoader = true;
this.initialized = true;
if (!this._id) {
this.warn("No component was specified!");
return this.loadDefault();
}
try {
const _entry = this.service.resolveRegistrationEntry(this._id, this._group);
if (!_entry || !_entry.entry) {
this.err(`Failed to find Component '${this._id}' in group '${this._group}' in registry!`);
return this.loadDefault();
}
const { entry, matchGroups } = _entry;
this._matchGroups = matchGroups;
// Download the "module" (the standalone component)
const bundle = this.targetModule = yield entry.load();
// Check if there is some corruption on the bundle.
if (!bundle || typeof bundle != 'object' || bundle['__esModule'] !== true || bundle.toString() != "[object Module]") {
this.err(`Failed to load component/module for '${this._id}'! Parsed resource is invalid.`);
return this.loadError();
}
const modules = Object.keys(bundle)
.map(k => {
const entry = bundle[k];
// Strictly check for exported modules or standalone components
if (typeof entry == "function" && typeof entry["ɵfac"] == "function")
return entry;
return null;
})
.filter(e => e != null)
.filter(entry => {
entry['_isModule'] = !!entry['ɵmod']; // module
entry['_isComponent'] = !!entry['ɵcmp']; // component
return (entry['_isModule'] || entry['_isComponent']);
});
if (modules.length == 0) {
this.err(`Component/Module loaded for '${this._id}' has no exported components or modules!`);
return this.loadError();
}
const component = this.targetComponentFactory = this.service.resolveComponent(this._id, "default", modules);
if (!component) {
this.err(`Component '${this._id}' is invalid or corrupted!`);
return this.loadError();
}
// Bootstrap the component into the container
const componentRef = this.targetComponentContainerRef = this.targetContainer.createComponent(component);
this.targetRef = this.targetContainer.insert(this.targetComponentContainerRef.hostView);
const instance = this.targetComponentInstance = componentRef['instance'];
this.bindInputs();
this.bindOutputs();
this.componentLoaded.next(instance);
this.instance = instance;
// Look for an observable called isLoading$ that will make us show/hide
// the same distractor that is used on basic loading
const isLoading$ = instance['ngxShowDistractor$'];
if (isLoading$ && typeof isLoading$.subscribe == "function") {
this.distractorSubscription = isLoading$.subscribe(loading => {
if (!loading) {
this.isClearingLoader = true;
this.loaderEmitter.emit();
}
else {
this.showLoader = true;
this.isClearingLoader = false;
}
});
}
else {
this.isClearingLoader = true;
}
const name = Object.keys(bundle)[0];
this.log(`Loaded '${name}'`);
this.loaderEmitter.emit();
return componentRef;
}
catch (ex) {
if (isDevMode()) {
console.warn("Component " + this._id + " threw an error on mount!");
console.warn("This will cause you to see a 404 panel.");
console.error(ex);
}
// Network errors throw a toast and return an error component
if (ex && !isDevMode()) {
console.error("Uncaught error when loading component");
throw ex;
}
return this.loadDefault();
}
});
}
ngOnDestroy(clearAll = true) {
var _a, _b, _c, _d, _e;
// unsubscribe from all subscriptions
Object.entries(this.outputSubscriptions).forEach(([key, sub]) => {
sub.unsubscribe();
});
this.outputSubscriptions = {};
// Clear all things
if (clearAll) {
(_a = this.loaderSub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
}
(_b = this.distractorSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
// Clear target container
(_c = this.targetRef) === null || _c === void 0 ? void 0 : _c.destroy();
(_d = this.targetComponentContainerRef) === null || _d === void 0 ? void 0 : _d.destroy();
(_e = this.targetContainer) === null || _e === void 0 ? void 0 : _e.clear();
// Wipe the rest of the state clean
this.targetRef = null;
this.targetComponentContainerRef = null;
}
/**
* Bind the input values to the child component.
*/
bindInputs() {
if (!this._inputs || !this.targetComponentInstance)
return;
// Merge match groups
if (typeof this._matchGroups == "object") {
Object.entries(this._matchGroups).forEach(([key, val]) => {
if (typeof this._inputs[key] == 'undefined')
this._inputs[key] = val;
});
}
// forward-bind inputs
const { inputs } = this.targetComponentFactory.ɵcmp;
// Returns a list of entries that need to be set
// This makes it so that unnecessary setters are not invoked.
const updated = Object.entries(inputs).filter(([parentKey, childKey]) => {
return this.targetComponentInstance[childKey] != this._inputs[parentKey];
});
updated.forEach(([parentKey, childKey]) => {
if (this._inputs.hasOwnProperty(parentKey))
this.targetComponentInstance[childKey] = this._inputs[parentKey];
});
}
/**
* Bind the output handlers to the loaded child component
*/
bindOutputs() {
if (!this._outputs || !this.targetComponentInstance)
return;
const { outputs } = this.targetComponentFactory.ɵcmp;
// Get a list of unregistered outputs
const newOutputs = Object.entries(outputs).filter(([parentKey, childKey]) => {
return !this.outputSubscriptions[parentKey];
});
// Reverse bind via subscription
newOutputs.forEach(([parentKey, childKey]) => {
if (this._outputs.hasOwnProperty(parentKey)) {
const target = this.targetComponentInstance[childKey];
const outputs = this._outputs;
// Angular folks, stop making this so difficult.
const ctx = this.viewContainerRef['_hostLView'][8];
const sub = target.subscribe(outputs[parentKey].bind(ctx)); // Subscription
this.outputSubscriptions[parentKey] = sub;
}
});
}
/**
* Load the "Default" component (404) screen normally.
* This is shown when the component id isn't in the
* registry or otherwise doesn't match
*
* This
*/
loadDefault() {
if (this.config.notFoundComponent)
this.targetContainer.createComponent(this.config.notFoundComponent);
this.showLoader = false;
}
/**
* Load the "Error" component.
* This is shown when we are able to resolve the component
* in the registry, but have some issue boostrapping the
* component into the viewContainer
*/
loadError() {
if (this.config.errorComponent)
this.targetContainer.createComponent(this.config.errorComponent);
this.showLoader = false;
}
}
/** @nocollapse */ NgxLazyLoaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderComponent, deps: [{ token: NgxLazyLoaderService }, { token: i0.ViewContainerRef, optional: true }, { token: i2.DialogRef, optional: true }, { token: MAT_DIALOG_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ NgxLazyLoaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.0", type: NgxLazyLoaderComponent, isStandalone: true, selector: "ngx-lazy-loader", inputs: { id: ["component", "id"], group: "group", inputs: "inputs", outputs: "outputs" }, outputs: { componentLoadError: "componentLoadError", componentLoaded: "componentLoaded" }, viewQueries: [{ propertyName: "targetContainer", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "<ng-container #content></ng-container>\n\n<div class=\"ngx-lazy-loader-distractor\" [class.destroying]=\"isClearingLoader\">\n <ng-container *ngIf=\"config.loaderDistractorComponent\" [ngComponentOutlet]=\"config.loaderDistractorComponent\"></ng-container>\n <ng-container *ngIf=\"config.loaderDistractorTemplate\" [ngTemplateOutlet]=\"config.loaderDistractorTemplate\" [ngTemplateOutletContext]=\"{ '$implicit': inputs }\"></ng-container>\n</div>\n", styles: [":host{display:contents;contain:content;z-index:1;position:relative}.ngx-lazy-loader-distractor{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;background-color:var(--background-color, #212121);opacity:1;transition:opacity .3s ease;z-index:999999}.ngx-lazy-loader-distractor.destroying{opacity:0;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-lazy-loader', imports: [NgIf, NgComponentOutlet, NgTemplateOutlet], standalone: true, template: "<ng-container #content></ng-container>\n\n<div class=\"ngx-lazy-loader-distractor\" [class.destroying]=\"isClearingLoader\">\n <ng-container *ngIf=\"config.loaderDistractorComponent\" [ngComponentOutlet]=\"config.loaderDistractorComponent\"></ng-container>\n <ng-container *ngIf=\"config.loaderDistractorTemplate\" [ngTemplateOutlet]=\"config.loaderDistractorTemplate\" [ngTemplateOutletContext]=\"{ '$implicit': inputs }\"></ng-container>\n</div>\n", styles: [":host{display:contents;contain:content;z-index:1;position:relative}.ngx-lazy-loader-distractor{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;background-color:var(--background-color, #212121);opacity:1;transition:opacity .3s ease;z-index:999999}.ngx-lazy-loader-distractor.destroying{opacity:0;pointer-events:none}\n"] }]
}], ctorParameters: function () {
return [{ type: NgxLazyLoaderService }, { type: i0.ViewContainerRef, decorators: [{
type: Optional
}] }, { type: i2.DialogRef, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [MAT_DIALOG_DATA]
}] }];
}, propDecorators: { targetContainer: [{
type: ViewChild,
args: ["content", { read: ViewContainerRef }]
}], id: [{
type: Input,
args: ["component"]
}], group: [{
type: Input,
args: ["group"]
}], inputs: [{
type: Input,
args: ["inputs"]
}], outputs: [{
type: Input,
args: ["outputs"]
}], componentLoadError: [{
type: Output
}], componentLoaded: [{
type: Output
}] } });
class NgxLazyLoaderModule {
static forRoot(config) {
return ({
ngModule: NgxLazyLoaderModule,
providers: [
NgxLazyLoaderService,
{
provide: NGX_LAZY_LOADER_CONFIG,
useValue: config
}
]
});
}
}
/** @nocollapse */ NgxLazyLoaderModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
/** @nocollapse */ NgxLazyLoaderModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderModule, imports: [NgxLazyLoaderComponent], exports: [NgxLazyLoaderComponent] });
/** @nocollapse */ NgxLazyLoaderModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderModule, imports: [NgxLazyLoaderComponent] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: NgxLazyLoaderModule, decorators: [{
type: NgModule,
args: [{
imports: [NgxLazyLoaderComponent],
exports: [NgxLazyLoaderComponent]
}]
}] });
/*
* Public API Surface of ngx-lazy-loader
*/
/**
* Generated bundle index. Do not edit.
*/
export { ComponentResolveStrategy, NGX_LAZY_LOADER_CONFIG, NgxLazyLoaderComponent, NgxLazyLoaderModule, NgxLazyLoaderService };
//# sourceMappingURL=dotglitch-ngx-lazy-loader.mjs.map