aurelia / bundler

A library for bundling JavaScript, HTML and CSS for use with SystemJS.
MIT License
37 stars 25 forks source link

Support bundles built with systemjs/builder's "buildStatic" rather than "bundle" due to severe mobile performance issues. #147

Closed insidewhy closed 6 years ago

insidewhy commented 7 years ago

There are bugs all over github about how slow systemjs bundles are... the mobile performance is simply unacceptable.

For bundles built with buildStatic rather than bundle the performance is just fine.

Would it be possible for aurelia bundler to hook into bundles built this way? If not I think there should be a huge warning about the extremely long delay times on mobile loads via systemjs bundles. I think many people would never use systemjs at all after discovering how poor the mobile load times are of bundled applications, a warning would go well to prevent annoyance.

insidewhy commented 7 years ago

Here's an angular 2 issue about the slowness of systemjs builds: https://github.com/angular/angular/issues/5198

Note the last comment: "SystemJS has problems and probably is not the way to go for production deployments."

If you check out the recent angular 2 presentations they are using systemjs for development and completely avoiding it for bundles. For very good reason.

MaximBalaganskiy commented 7 years ago

@ohjames I've got a gut feeling that it is quite easy to fix. I tried creating an SFX bundle and encountered 2 issues:

I tried loading requirejs before aurelia starts but this results in known mismatched definition

May be with a little bit of core team input we could figure out how to patch the loader.

MaximBalaganskiy commented 7 years ago

So, spent little bit more time on this... I create the bundle using jspm build. Basically, the main issue is that it scrambles module names - e.g. in my case aurelia-framework becomes "6". If we manage somehow to map those scrambled names with real ones and teach aurelia-loader to access this map it will work :)

MaximBalaganskiy commented 7 years ago

--skip-encode-names option leaves names intact, but they are full names similar to npm:aurelia-framework@1.0.7/aurelia-framework.js

MaximBalaganskiy commented 7 years ago

I've hacked aurelia-loader slightly and it successfully loads js modules. The issue I have at the moment is with html in the bundle... The template "module" loads fine but lacks template field which causes issue with the templating engine. If I set this field manually - all works :)

MaximBalaganskiy commented 7 years ago

Hopefully, someone will be able to pick up these hacks and make a loader out of them.

So, this is what I did to make SFX work

  var map = {
    "aurelia-binding": "npm:aurelia-binding@1.0.9/aurelia-binding.js",
    "aurelia-bootstrapper": "npm:aurelia-bootstrapper@1.0.1/aurelia-bootstrapper.js",
    "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.2.0/aurelia-dependency-injection.js",
    "aurelia-event-aggregator": "npm:aurelia-event-aggregator@1.0.0/aurelia-event-aggregator.js",
    "aurelia-framework": "npm:aurelia-framework@1.0.7/aurelia-framework.js",
    "aurelia-history": "npm:aurelia-history@1.0.0/aurelia-history.js",
    "aurelia-history-browser": "npm:aurelia-history-browser@1.0.0/aurelia-history-browser.js",
    "aurelia-loader": "npm:aurelia-loader@1.0.0/aurelia-loader.js",
    "aurelia-loader-default": "npm:aurelia-loader-default@1.0.0/aurelia-loader-default.js",
    "aurelia-logging": "npm:aurelia-logging@1.1.1/aurelia-logging.js",
    "aurelia-logging-console": "npm:aurelia-logging-console@1.0.0/aurelia-logging-console.js",
    "aurelia-metadata": "npm:aurelia-metadata@1.0.2/aurelia-metadata.js",
    "aurelia-pal": "npm:aurelia-pal@1.0.0/aurelia-pal.js",
    "aurelia-pal-browser": "npm:aurelia-pal-browser@1.0.0/aurelia-pal-browser.js",
    "aurelia-path": "npm:aurelia-path@1.1.1/aurelia-path.js",
    "aurelia-polyfills": "npm:aurelia-polyfills@1.1.1/aurelia-polyfills.js",
    "aurelia-route-recognizer": "npm:aurelia-route-recognizer@1.1.0/aurelia-route-recognizer.js",
    "aurelia-router": "npm:aurelia-router@1.0.7/aurelia-router.js",
    "aurelia-task-queue": "npm:aurelia-task-queue@1.1.0/aurelia-task-queue.js",
    "aurelia-templating": "npm:aurelia-templating@1.1.2/aurelia-templating.js",
    "aurelia-templating-binding": "npm:aurelia-templating-binding@1.0.0/aurelia-templating-binding.js",
    "aurelia-templating-resources": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/compose": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/with": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/if": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/show": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/hide": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/replaceable": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/attr-binding-behavior": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/update-trigger-binding-behavior": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/signal-binding-behavior": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/debounce-binding-behavior": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/throttle-binding-behavior": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/binding-mode-behaviors": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/focus": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/sanitize-html": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-resources/repeat": "npm:aurelia-templating-resources@1.1.1/aurelia-templating-resources.js",
    "aurelia-templating-router": "npm:aurelia-templating-router@1.0.0/aurelia-templating-router.js",
    "aurelia-templating-router/route-href": "npm:aurelia-templating-router@1.0.0/route-href.js",
    "aurelia-templating-router/route-loader": "npm:aurelia-templating-router@1.0.0/route-loader.js",
    "aurelia-templating-router/router-view": "npm:aurelia-templating-router@1.0.0/router-view.js",
    "css": "github:systemjs/plugin-css@0.1.32/css.js",
    "text": "github:systemjs/plugin-text@0.0.9/text.js",
    "app/main": "app/main.js",
    "app/configure": "app/configure.js",
    "template-registry-entry!app/main.html":"app/main.html!github:systemjs/plugin-text@0.0.9/text.js"
  };
    DefaultLoader.prototype._import = function(moduleId) {
      return new Promise(function(resolve, reject) {
        var m = window.$__System.get(map[moduleId]);
        m.template = m.default;
        resolve(m);
      });
    };

    DefaultLoader.prototype.loadModule = function(id) {
      var _this2 = this;
      var existing = this.moduleRegistry[id];
      if (existing !== undefined) {
        return Promise.resolve(existing);
      }
      return new Promise(function(resolve, reject) {
        resolve(ensureOriginOnExports(window.$__System.get(map[id]), id));

        /*require([id], function(m) {
          _this2.moduleRegistry[id] = m;
          resolve(ensureOriginOnExports(m, id));
        }, reject);*/
      });
    };
      if (!dependencies || dependencies.length === 0 && !compileInstruction.associatedModuleId) {
      //if (dependencies.length === 0 && !compileInstruction.associatedModuleId) {
jspm build app/**/*.js + app/**/*.html!text + aurelia-bootstrapper + aurelia-loader-default + aurelia-logging-console + aurelia-templating-binding + aurelia-history-browser + aurelia-templating-router + aurelia-polyfills + aurelia-framework + text + aurelia-templating-resources + aurelia-event-aggregator dist/bundle.js --skip-encode-names --format global
EisenbergEffect commented 7 years ago

Ping @ahmedshuhel

ahmedshuhel commented 7 years ago

On Nov 15, 2016 10:50 AM, Rob Eisenberg notifications@github.com wrote:

Ping @ahmedshuhel

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread. Looking into it.

MaximBalaganskiy commented 7 years ago

Any luck on this one?

thomas-darling commented 7 years ago

We really need this too - the performance on Android devices is just horrible, and switching loader is unfortunately not an option for us right now. Based on the investigation done by @MaximBalaganskiy, this seems like something that could be supported relatively easily - any chance you could take a look at it, @EisenbergEffect, @ahmedshuhel?

MaximBalaganskiy commented 7 years ago

@thomas-darling I've almost finished the aurelia-sfx-loader which is able to use jspm sfx bundles. There is just one issue to solve - auto generation of module mappings mentioned above.

MaximBalaganskiy commented 7 years ago

So, I've got a new loader and a simple gulp task which automates the mapping. All seems to be working in a bare project. I'll test it on our main app tomorrow and if there is a performance gain will try to put it on github.

MaximBalaganskiy commented 7 years ago

https://github.com/MaximBalaganskiy/system-static-aurelia-loader https://github.com/MaximBalaganskiy/system-static-aurelia-loader-sample

thomas-darling commented 7 years ago

@MaximBalaganskiy Awesome work there - proving the value of making this work would be huge! I'm on vacation this week, but I'll take a closer look when I get back - have you seen any performance improvements so far?

MaximBalaganskiy commented 7 years ago

@thomas-darling it "seems" faster... my old motorola android phone used to take 5-6 seconds to spin up aurelia after the scripts initial load. Now it's 2-3. You can try it here https://inhouse.thinkwin.com.au/AquaWeb/Staging/Portal/, can't give the credentials, but at least you'll get a feeling. Mind our slow ADSL line :)

MaximBalaganskiy commented 7 years ago

@thomas-darling I did some more testing and experimenting and have to say that non-injected standard jspm bundles seem to be as fast as the sfx bundle on my slow phone.

By non-injected I mean the ones which were built with inject: false and referenced directly from index.html.

I think this issue should be closed. And, btw, I used systemjs-builder for bundling directly.

MaximBalaganskiy commented 7 years ago

I got an old iPad mini for tests and turns out my phone is not that slow after all. The static bundle does work faster on it. So, I'm retracting my previous comment about closing this issue :)

Here are the links I tested http://inhouse.thinkwin.com.au/StaticLoader/ http://inhouse.thinkwin.com.au/NormalLoader/

thomas-darling commented 7 years ago

Hmm, interesting... but does that mean you observed an improvement by switching from injected to non-injected bundles? or does it mean that the SFX bundling didn't improve anything?

I'm just getting back to this now, and so far, it seems that switching to non-injected bundles improve the load time by maybe around 5-7% in Chrome - but profiling the app, it looks like that is mostly related to the timing of the requests and maybe slightly more efficient parsing of the bundle files. The flame graphs and CPU time spend in SystemJS and Bluebird code look very similar to what we see with injected bundles.

I haven't had a chance to test this with an Android device yet, but unless it behaves very different on a phone, it doesn't look like a switch to non-injected bundles would help much.

MaximBalaganskiy commented 7 years ago

Sorry for the confusion, the gist is switching to non-injected bundles did improve performance on all mobiles. Switching to SFX made the site load even faster on slower mobiles like iPad mini.

As for testing in Chrome desktop, it's not showing any significant gain. It's mainly old mobile which suffers from promises.

Alexander-Taran commented 6 years ago

@MaximBalaganskiy think we can close this?

EisenbergEffect commented 6 years ago

I don't think we'll add any new features around this. If it's still an issue, I would advise either an adoption of Webpack or using our CLI with require.js potentially.