Skip to content

Commit

Permalink
Merge pull request oskariorg#2792 from ZakarFin/bundle-lazy-loader
Browse files Browse the repository at this point in the history
Oskari 3.0 bundle lazy-loader
  • Loading branch information
ZakarFin authored Feb 19, 2025
2 parents acf94f9 + 304852e commit ad44d85
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 98 deletions.
26 changes: 26 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,32 @@ Removed bundles:
- `catalogue/metadatacatalogue` replaced by `catalogue/metadatasearch`
- `catalogue/metadataflyout` replaced by `catalogue/metadata`

### Changes for bundle registrations

In preparation of removing the packages-folder from oskari-frontend and migrating any bundle.js files under it to bundles-folder as index.js files.


New loaders for application main.js usage:
- `oskari-bundle` replaces oskari-loader and supports more streamlined bundle registrations
- `oskari-lazy-bundle` replaces oskari-lazy-loader for adding support to lazy-load bundles with the streamlined bundle registration

This allows linking bundles like this:
```
import 'oskari-bundle!oskari-frontend/bundles/admin/admin';
```
instead of:
```
import 'oskari-loader!oskari-frontend/packages/admin/bundle/admin/bundle.js';
```
and removes the unnecessary complication that comes with the packages-folder.

These changes shouldn't really affect your app, but things that have changed inside the "engine":

- New core component `src/BundleRegister` for managing bundles and exposes Oskari.bundle() (previously part of src/loader.js) and Oskari.lazyBundle() functions.
- Oskari.bundle_manager functions removed:
- registerDynamic() - replaced by BundleRegister.lazyBundle() that is exposed as Oskari.lazyBundle()
- loadDynamic() - moved to src/loader.js as private function as it doesn't need to be exposed

## 2.14.2

For a full list of changes see:
Expand Down
34 changes: 34 additions & 0 deletions src/BundleRegister.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const _bundleRegistry = {};
const _availableLazyBundles = {};

export const BundleRegister = {
/**
* @method bundle
* Register bundle that is loaded and available for starting
*
* @param {string} bundlename Bundle name
* @param {Function} factory function returns a bundle instance
*/
bundle: (bundleId, value) => {
if (value) {
_bundleRegistry[bundleId] = value;
}
return _bundleRegistry[bundleId];
},
/**
* @method lazyBundle
* Register bundle for lazy-loading/run-time loading with ES import()
*
* @param {string} bundlename Bundle name
* @param {Function} loader function that returns an promise that resolve to the module to be loaded
*/
lazyBundle: (bundleId, loader) => {
if (loader) {
if (!_availableLazyBundles[bundleId]) {
_availableLazyBundles[bundleId] = [];
}
_availableLazyBundles[bundleId].push(loader);
}
return _availableLazyBundles[bundleId];
}
};
68 changes: 19 additions & 49 deletions src/bundle_manager.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@

(function (o) {
if (!o || !o.clazz) {
// can't add loader if no Oskari ref
return;
}
var log = Oskari.log('Oskari.BundleManager');
const log = Oskari.log('Oskari.BundleManager');
/**
* singleton instance of the class system
*/
var cs = o.clazz;
const cs = o.clazz;

/* legacy Bundle_manager */

/**
* @singleton @class Oskari.Bundle_manager
*/
var BundleManager = function () {
const BundleManager = function () {
this.clazz = o.clazz;
var me = this;
const me = this;
me.serial = 0;
me.bundleDefinitions = {};
me.sources = {};
me.bundleInstances = {};
me.bundles = {};
me.dynamicLoaders = {};

/*
* CACHE for lookups state management
Expand Down Expand Up @@ -55,8 +53,8 @@
* @private @method _purge
*/
_purge: function () {
var p;
var me = this;
let p;
const me = this;

for (p in me.sources) {
if (me.sources.hasOwnProperty(p)) {
Expand Down Expand Up @@ -88,8 +86,8 @@
*
*/
_install: function (biid, bundleDefinition, srcFiles, bundleMetadata) {
var me = this;
var defState = me.bundleDefinitionStates[biid];
const me = this;
let defState = me.bundleDefinitionStates[biid];

if (defState) {
defState.state = 1;
Expand Down Expand Up @@ -120,11 +118,11 @@
*
*/
installBundleClass: function (biid, className) {
var clazz = Oskari.clazz.create(className);
const clazz = Oskari.clazz.create(className);
if (clazz) {
// Oskari.bundle is the new registry for requirejs loader
Oskari.bundle(biid, {
clazz: clazz,
clazz,
metadata: cs.getMetadata(className)
});
}
Expand All @@ -141,10 +139,10 @@
* @return {Object} Bundle
*/
createBundle: function (biid, bid) {
var bundle;
var bundleDefinition;
var me = this;
var bundleDefinitionState;
const me = this;
let bundle;
let bundleDefinition;
let bundleDefinitionState;

if (biid === null || biid === undefined) {
throw new TypeError('createBundle(): Missing biid');
Expand Down Expand Up @@ -193,10 +191,10 @@
// creates a bundle_instance
// any configuration and setup IS BUNDLE / BUNDLE INSTANCE specific
// create / config / start / process / stop / destroy ...
var me = this;
var bundle;
var bundleInstance;
var bundleInstanceId;
const me = this;
let bundle;
let bundleInstance;
let bundleInstanceId;

if (bid === null || bid === undefined) {
throw new TypeError('createInstance(): Missing bid');
Expand Down Expand Up @@ -244,7 +242,7 @@
* @return
*/
_destroyInstance: function (biid) {
var bundleInstance;
let bundleInstance;

if (biid === null || biid === undefined) {
throw new TypeError('_destroyInstance(): Missing biid');
Expand All @@ -255,34 +253,6 @@
bundleInstance = null;

return bundleInstance;
},
/**
* @method registerDynamic
* Register bundle for run-time loading with ES import()
*
* @param {string} bundlename Bundle name
* @param {Function} loader function that returns an promise that resolve to the module to be loaded
*/
registerDynamic: function(bundlename, loader) {
if (!this.dynamicLoaders[bundlename]) {
this.dynamicLoaders[bundlename] = [];
}
this.dynamicLoaders[bundlename].push(loader);
},
/**
* @method loadDynamic
* Called to start dynamic loading of a bundle
*
* @param {string} bundlename Bundle name
*
* @return Promise that resolves when all modules have loaded
*/
loadDynamic: function(bundlename) {
const loaders = this.dynamicLoaders[bundlename];
if (loaders) {
return Promise.all(loaders.map((l) => l.call()));
}
return null;
}
};

Expand Down
6 changes: 3 additions & 3 deletions src/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import './sandbox/sandbox-map-methods.js';
import './sandbox/sandbox-abstraction-methods.js';

// Oskari application helpers
import '../src/loader.js';
import '../src/oskari.app.js';
import '../src/BasicBundle.js';
import './loader.js';
import './oskari.app.js';
import './BasicBundle.js';

// deprecated functions
import './deprecated/deprecated.core.js';
Expand Down
68 changes: 27 additions & 41 deletions src/loader.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,8 @@
/**
* Bundle register.
* Usage:
*
* // get
* var bundledetails = Oskari.bundle('mybundle');
* // set
* Oskari.bundle('mybundle', bundledetails);
*
* Details contain an object with:
* {
* clazz : instance of class defined in packages/.../bundle.js,
* metadata : metadata for above bundle.js including scripts to load for the bundle
* }
*
*/
(function (o) {
if (!o) {
// can't add bundle if no Oskari ref
return;
}
var _bundleRegistry = {};
// Add the bundle method to Oskari
o.bundle = function (bundleId, value) {
if (value) {
_bundleRegistry[bundleId] = value;
}
return _bundleRegistry[bundleId];
};
}(Oskari));
/**
* Startupsequence processor for Oskari. Bundles have ether been bundled/minfied
* into the application JS file or separate chunks. In both cases bundles must be
* declared in miniferAppSetup.json
*
*
* Usage:
*
* var startupSequence = [...bundles to load/start... ];
Expand All @@ -52,16 +22,32 @@
if (o.loader) {
// loader already present, but we might want another?
}
var log = Oskari.log('Loader');
var linkFile = function (href, rel, type) {
var importParentElement = document.head || document.body;
var linkElement = document.createElement('link');
const log = Oskari.log('Loader');
const linkFile = function (href, rel, type) {
const importParentElement = document.head || document.body;
const linkElement = document.createElement('link');
linkElement.rel = rel || 'stylesheet';
linkElement.type = type || 'text/css';
linkElement.href = href;
importParentElement.appendChild(linkElement);
};

/**
* @method loadDynamic
* Called to start dynamic loading of a bundle
*
* @param {string} bundlename Bundle name
*
* @return Promise that resolves when all modules have loaded
*/
const loadDynamic = function (bundlename) {
const loaders = Oskari.lazyBundle(bundlename);
if (loaders) {
return Promise.all(loaders.map((l) => l.call()));
}
return null;
};

/**
* Loader
* @param {Object[]} startupSequence sequence of bundles to load/start
Expand Down Expand Up @@ -97,7 +83,7 @@
* @param {Function} done callback
*/
processSequence: function (done, suppressStartEvent = false) {
var me = this;
const me = this;
if (sequence.length === 0) {
// everything has been loaded
if (typeof done === 'function') {
Expand All @@ -108,7 +94,7 @@
}
return;
}
var seqToLoad = sequence.shift();
const seqToLoad = sequence.shift();
if (typeof seqToLoad !== 'object') {
// log warning: block not object
log.warn('StartupSequence item is a ' + typeof seqToLoad + ' instead of object. Skipping');
Expand All @@ -117,24 +103,24 @@
return;
}

var bundleToStart = seqToLoad.bundlename;
const bundleToStart = seqToLoad.bundlename;
if (!bundleToStart) {
log.warn('StartupSequence item doesn\'t contain bundlename. Skipping ', seqToLoad);
// iterate to next
this.processSequence(done, suppressStartEvent);
return;
}
// if bundleinstancename is missing, use bundlename for config key.
var configId = seqToLoad.bundleinstancename || bundleToStart;
var config = appConfig[configId] || {};
const configId = seqToLoad.bundleinstancename || bundleToStart;
const config = appConfig[configId] || {};

if (Oskari.bundle(bundleToStart)) {
log.debug('Bundle preloaded ' + bundleToStart);
me.startBundle(bundleToStart, config, configId);
this.processSequence(done, suppressStartEvent);
return;
}
let bundlePromise = Oskari.bundle_manager.loadDynamic(bundleToStart);
const bundlePromise = loadDynamic(bundleToStart);
if (!bundlePromise) {
log.warn('Bundle wasn\'t preloaded nor registered as dynamic. Skipping ', bundleToStart);
this.processSequence(done, suppressStartEvent);
Expand Down
12 changes: 8 additions & 4 deletions src/oskari.es6.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
*
* A set of methods to support loosely coupled classes and instances for the mapframework
*/
import Sequence from './counter.es6.js';
import Logger from './logger.es6.js';
import Sequence from './counter.es6';
import Logger from './logger.es6';
import pkg from '../package.json';
import { DOMHelper } from './oskari.dom.js';
import { Customization } from './oskari.customization.js';
import { DOMHelper } from './oskari.dom';
import { Customization } from './oskari.customization';
import { BundleRegister } from './BundleRegister';

const defaultSequence = new Sequence();
const sequences = {};
Expand Down Expand Up @@ -59,6 +60,9 @@ const Oskari = {
Oskari.log('Oskari').deprecated('getDefaultMarker', 'Use Oskari.custom.getMarker() instead');
return Customization.getMarker();
},
// from BundleRegister.js
bundle: BundleRegister.bundle,
lazyBundle: BundleRegister.lazyBundle,
// from oskari.customization.js
custom: Customization,
// from oskari.dom
Expand Down
1 change: 1 addition & 0 deletions webpack/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ const RESOLVE_LOADER = {
alias: {
'oskari-loader': path.resolve(__dirname, './oskariLoader.js'),
'oskari-bundle': path.resolve(__dirname, './oskariBundleLoader.js'),
'oskari-lazy-bundle': path.resolve(__dirname, './oskariBundleLazyLoader.js'),
'oskari-lazy-loader': path.resolve(__dirname, './oskariLazyLoader.js')
}
};
Expand Down
Loading

0 comments on commit ad44d85

Please sign in to comment.