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

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
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

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 4
  • Comments: 16 (4 by maintainers)

Most upvoted comments

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.

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.

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?

+1 to let ionic run in a web worker