Is there a discussion/direction around Ember + Rollup for svelte builds?


#1

As the title implies, I’d like to learn more about Ember + Rollup to help shrink the builds.

Searching the web hasn’t been fruitful - I’ve only come across two Ember addons using Rollup.


#2

I’ve had some success using rollup for ember application, but my method is completely unsupported. Steps involved are:

  • Define your directory architecture, that is: how are components files named, etc. If ember-cli’s one is fine for you, just open its documentation and use it.
  • Get an input file, describing what to bundle. For me it’s a list of directories.
  • For each directory from the list, recursively scan the directory.
    • If a file is a template, compile it into js.
    • Identify whether the file is a registerable resource. For instance, models, services, routes, helpers, … Use the structure you defined in step 1 to identify them. Gather all of that into a list matching the ember resource type, name and file path, eg: ["routes", "product", "/my/project/modules/products/routes/product.js"].
  • Generate a registration file. It should have:
    • An import directive for every resource.
      Eg: import r42 from '/my/project/modules/products/routes/product.js'
    • An application initializer, in which you have:
      • An app.register call for every resource.
        Eg: app.register("route:product", r42);
      • A template registration for every template.
        Eg: Ember.TEMPLATES["product-template"] = r43;
  • Invoke rollup in IIFE mode on the registration file.
    → This will pull all imports, recursively add their dependencies and bundle the whole thing in one JS script. No AMD, no commonJS involved, rollup just makes sure modules come in dependency-correct order in the resulting file. As an added bonus, it automatically drops unused imports.

The whole procedure, implemented in python is about 150 lines long.

Advantage: no runtime overhead, all dependencies are resolved at bundling time. That makes a smaller js bundle (no module boilerplate) that starts faster (no runtime-resolution with require).

Drawback: rollup bundling is an all-or-nothing process. Every change must regenerate the bundle from scratch. Rollup is very fast though, on my laptop from 2014, I bundle a 400-file project in about 0.5s.

Additional drawback: you’re on your own. You build your bundling system so when it breaks, you get to fix it.


#3

@Garrick> FWIW, I converted my generator from python to node.js.

I uploaded it as a gist. It’s not “polished” as I don’t intend to release or support it in any kind of official way, but it works great on my Ember 2.14 project.

Notes:

  • it assumes a file named “component.js” to be a component, with name given by the immediate directory name and template being “template.hbs” next to it.
  • script files within an “initializers” directory are imported as is. Just put your initializers in there.
  • have a look at the sample configuration file at the bottom of the gist.

My very simplified tree looks like this:

article-manager/
    article-editor/
        component.js
        template.hbs
    article-state/
        component.js
        template.hbs
    controllers/
        article/
            edit.js
    models/
        article.js
    routes/
        article.js
        article/
            edit.js
    templates/
        article.hbs
        article/edit.hbs
library/
    helpers/
        date.js
        filesize.js
    ui-listview/
        component.js
        template.hbs
    ui-slug-field/
        component.js
        template.hbs
    ui-splitview/
        component.js
        template.hbs
main/
    initializers/
        router.js
    routes/
        application.js
    templates/
        application.hbs

(in reality I have many more directories at topmost level: gallery, dropbox, geographic data, you name it - all of them are equals when it comes to rolling up the final application though, which also means the article editor can use the picture-picker component from the gallery module)

The generator will create a javascript file that imports all relevant files and contains a “registrations” application initialiser that registers all classes and templates. I feed it into rollup that does its magic and voila.


#4

@spectras am I correct in grokking that this does not transpile the build? It gives you a way to bundle the entire ember application without running it through babel, minification, etc. I may explore something like this for our app because the ember build times are a bottle neck. Ideally I would break up the project into smaller ones but that seems like more work and maintenance overhead.


#5

@efx this only generates a “master” script that imports everything else and registers classes with Ember. That’s all.

You can then give that script as the main script to rollup so it bundles everything. I know rollup supports babel and I did use its uglify plugin successfully. I don’t use transpiling though as the ES5 and ES6 features I use are mostly supported by my targets.

Just to make it less abstract, here is a sample output from my script:

import Ember from 'ember';
import r0 from '../node_modules/@private/ember/helpers/can.js';
import r1 from '../node_modules/@private/ember/helpers/date.js';
import r5 from '../node_modules/@private/ember/services/notifications.js';
import r6 from '../node_modules/@private/ember/services/permissions.js';
import r7 from '../node_modules/@private/ember/services/workers.js';
import r12 from '../main/adapters/application.js';
import r13 from '../main/controllers/application.js';
import r14 from '../main/routes/application.js';
import r15 from '../main/ui-breadcrumbs/component.js';
import r17 from '../author/author-editor/component.js';
import r20 from '../author/models/author.js';
import r21 from '../author/routes/author.js';
import {} from '../main/initializers/router.js';

Ember.Application.initializer({
  name: 'registrations',
  initialize: function (app) {
    var t = Ember.TEMPLATES;
    app.registerOptionsForType('model', {singleton: false});
    app.register("helper:can", r0);
    app.register("helper:date", r1);
    app.register("service:notifications", r5);
    app.register("service:permissions", r6);
    app.register("service:workers", r7);
    app.register("adapter:application", r12);
    app.register("controller:application", r13);
    app.register("route:application", r14);
    app.register("component:ui-breadcrumbs", r15);
    app.register("component:author-editor", r17);
    app.register("model:author", r20);
    app.register("route:author", r21);
    t["application"] = Ember.HTMLBars.template({/* left out for brievity */});
    t["components/author-editor"] = Ember.HTMLBars.template({/* left out for brievity */});
  }
});

As you see, it’s all about emitting the proper imports and feeding the classes to Ember.


#6

Neat! makes sense. Those build times are quite impressive. At least for testing, the application I work on supports most ES5-6 features. Using your approach here could really help our build times. If I get to it I want to try it on our application.