The current bootstrap process for Ionic2, whether via the @App
decorator or through direct use of the ionicProviders
function in https://github.com/driftyco/ionic/blob/2.0/ionic/config/bootstrap.ts makes it really difficult to run it in a web worker. They make direct use of the window
and document
objects which are not available in a web worker.
Suggest the creation of an ionicProviders
equivalent that uses abstracted ng2 primitives (e.g DomAdapter, MessageBus, etc) to obtain the needed information when running in a worker app.
Might need a message bus bridge internally to retrieve the necessary information from the render thread. FYI: https://github.com/angular/angular/blob/master/modules/angular2/docs/web_workers/web_workers.md
Steps to reproduce:
export function ionicProviders(args: any={}) {
let platform = new Platform();
let navRegistry = new NavRegistry(args.pages);
var config = args.config;
if (!(config instanceof Config)) {
config = new Config(config);
}
platform.setUrl(window.location.href);
platform.setUserAgent(window.navigator.userAgent);
platform.setNavigatorPlatform(window.navigator.platform);
platform.load();
config.setPlatform(platform);
let clickBlock = new ClickBlock();
let events = new Events();
let featureDetect = new FeatureDetect();
setupDom(window, document, config, platform, clickBlock, featureDetect);
bindEvents(window, document, platform, events);
// prepare the ready promise to fire....when ready
platform.prepareReady(config);
return [
IonicApp,
provide(ClickBlock, {useValue: clickBlock}),
provide(Config, {useValue: config}),
provide(Platform, {useValue: platform}),
provide(FeatureDetect, {useValue: featureDetect}),
provide(Events, {useValue: events}),
provide(NavRegistry, {useValue: navRegistry}),
TapClick,
Form,
Keyboard,
MenuController,
Translate,
ROUTER_PROVIDERS,
provide(LocationStrategy, {useClass: HashLocationStrategy}),
HTTP_PROVIDERS,
];
}
function setupDom(window, document, config, platform, clickBlock, featureDetect) {
let bodyEle = document.body;
let mode = config.get('mode');
// if dynamic mode links have been added the fire up the correct one
let modeLinkAttr = mode + '-href';
let linkEle = document.head.querySelector('link[' + modeLinkAttr + ']');
if (linkEle) {
let href = linkEle.getAttribute(modeLinkAttr);
linkEle.removeAttribute(modeLinkAttr);
linkEle.href = href;
}
// set the mode class name
// ios/md/wp
bodyEle.classList.add(mode);
// language and direction
platform.setDir(document.documentElement.dir, false);
platform.setLang(document.documentElement.lang, false);
let versions = platform.versions();
platform.platforms().forEach(platformName => {
// platform-ios
let platformClass = 'platform-' + platformName;
bodyEle.classList.add(platformClass);
let platformVersion = versions[platformName];
if (platformVersion) {
// platform-ios9
platformClass += platformVersion.major;
bodyEle.classList.add(platformClass);
// platform-ios9_3
bodyEle.classList.add(platformClass + '_' + platformVersion.minor);
}
});
// touch devices should not use :hover CSS pseudo
// enable :hover CSS when the "hoverCSS" setting is not false
if (config.get('hoverCSS') !== false) {
bodyEle.classList.add('enable-hover');
}
if (config.get('clickBlock')) {
clickBlock.enable();
}
// run feature detection tests
featureDetect.run(window, document);
}
/**
* Bind some global events and publish on the 'app' channel
*/
function bindEvents(window, document, platform, events) {
window.addEventListener('online', (ev) => {
events.publish('app:online', ev);
}, false);
window.addEventListener('offline', (ev) => {
events.publish('app:offline', ev);
}, false);
window.addEventListener('orientationchange', (ev) => {
events.publish('app:rotated', ev);
});
// When that status taps, we respond
window.addEventListener('statusTap', (ev) => {
// TODO: Make this more better
var el = document.elementFromPoint(platform.width() / 2, platform.height() / 2);
if (!el) { return; }
var content = closest(el, 'scroll-content');
if (content) {
var scrollTo = new ScrollTo(content);
scrollTo.start(0, 0, 300, 0);
}
});
// start listening for resizes XXms after the app starts
setTimeout(function() {
window.addEventListener('resize', function() {
platform.windowResize();
});
}, 2000);
}
Ionic Version: 2.x
Browser & Operating System: Android / Chrome
Run ionic info
from terminal/cmd prompt:
Your system information:
Cordova CLI: 6.0.0
Gulp version: CLI version 3.9.1
Gulp local: Local version 3.9.1
Ionic Version: 2.0.0-beta.2
Ionic CLI Version: 2.0.0-beta.19
Ionic App Lib Version: 2.0.0-beta.9
OS:
Node Version: v5.6.0
Ideally this would be baked into the underlying angular2 framework's DomAdapter which is currently Parse5DomAdapter, but as you can see the current implementation does not do that.
Maybe what could be done is to extend Parse5DomAdapter
and override the methods needed for ionic2 (e.g getUserAgent
) to get the relevant information via the message bus from the render thread which in turn could get it from the DOM.
Alternatively you could have the bootstrapper on the render thread get all the relevant platform info then send it to the ionic app as one json object during initialization.
Either way there's code that will have to run on the UI thread, which is where all of our dom setup will have to be fired from. It's the config setup that can run on the UI thread, and all of that can run before ng2 even needs to be bootstrapped. From the config we need to figure out what to add to the body class and a few other things. We'll have to make sure that all of that is separated. Thanks for all the info!
You're welcome. Looks like alot of messy marshalling either way. I suspect send all necessary information in bulk from UI thread to worker app may be the most efficient, rather than multiple worker-to-ui thread requests.
I would also like to run ionic in a web worker as it brings fairly big performance improvements. Is this planned for the final release of v2?
@adamdbradley ?
+1 I find webworkers to be a pivotal implementation for ionic and absolutely would like to hear more about it.
Now that there is the new ionicBootstrap
function would it be possible to also provide two functions ionicBootstrapRender
and ionicBootstrapWorker
?
The setup part for the platform and DOM could be executed in the former and the results could be send via the postMessage
mechanism to the application. The application would then be bootstrapped as a result of this setup message.
Is there any update on this? Has anyone successfully used web workers on an Ionic2 app? Would also love to know what are IonicTeam's plans for web worker support?
Was able to implement webworker by copying the JS file into the www/build folder. anyone care to write a wrapper/hook to pull worker js files?
How did you manage to bootstrap the ionic app in a web worker? They are accessing the Dom when bootstrapping which is not possible in a worker.
+1 to let ionic run in a web worker
+1
Is there any update on this?
Hello everyone! Thanks for the feature request. I'm going to move this issue over to our internal list of feature requests for evaluation. We are continually prioritizing all requests that we receive with outstanding issues. We are extremely grateful for your feedback, but it may not always be our next priority. I'll copy the issue back to this repository when we have begun implementation. Thanks!
This issue was moved to driftyco/ionic-feature-requests#24
Hello!
Is there any chance to get any updates on this feature request? Is it accepted and planned to be released as part of a known milestone?
Thanks.
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Most helpful comment
I would also like to run ionic in a web worker as it brings fairly big performance improvements. Is this planned for the final release of v2?
@adamdbradley ?