Ionic-framework: Unable to bootstrap an Ionic2 app in a web worker

Created on 5 Mar 2016  路  16Comments  路  Source: ionic-team/ionic-framework

Short description of the problem:

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.

What behavior are you expecting?

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:

  1. Try to boot an Ionic2 app in a web worker


    1. 3.
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

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 ?

All 16 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vswarte picture vswarte  路  3Comments

danbucholtz picture danbucholtz  路  3Comments

brandyscarney picture brandyscarney  路  3Comments

manucorporat picture manucorporat  路  3Comments

daveshirman picture daveshirman  路  3Comments