# DISCUSSION: bundler-friendly aurelia

**URL:** <https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959>\
**Category:** Framework Knowledge\
**Created:** [March 24, 2018, 5:19am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959 "2018-03-24T05:19:23Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![obedm503](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/obedm503/32/83_2.png) [@obedm503](https://discourse.aurelia.io/u/obedm503)\
**Post date:** [March 24, 2018, 5:19am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/1 "2018-03-24T05:19:23Z")

</div>

with the almost done [pr by @bigopon](https://github.com/aurelia/framework/pull/858) it should be possible to define a component as global by passing the class directly instead of a string. this is a step in the right direction in terms of getting aurelia to work correctly with the already standard module syntax. after all aurelia prides itself in following standards.

* * *

I understand that when aurelia came to be, the module syntax was not part of the spec (similar to how angularjs came up with it’s own module system). so it had to bolt itself on to already existing loaders to reduce friction.

but the times have changed. now modules are part of the spec, and bundlers (like webpack, parcel, fusebox) use the standard syntax to make crazy optimizations to our code (tree shaking, dead code elimination, and all the buss words).

this post is not to dump on aurelia, as I said, at the time that was probably the best course of action. my purpose is to start a discussion on whether it’s time for aurelia’s module loading to align itself with the spec and let developers make better use of tools in the ecosystem without some required plugin ([webpack plugin](https://github.com/aurelia/webpack-plugin), [fusebox plugin](https://github.com/fuse-box/fuse-box-aurelia-loader)) to accomodate the framework.

### some routing examples

_adapted from the [documentation](http://aurelia.io/docs/routing/configuration#basic-configuration)_

this is the current way a router is defined

```auto
import {RouterConfiguration, Router} from 'aurelia-router';

export class App {
  router: Router;

  configureRouter(config: RouterConfiguration, router: Router): void {
    this.router = router;
    config.title = 'Aurelia';
    config.map([
      { route: ['', 'home'], name: 'home', moduleId: 'home/index' },
      { route: 'users', name: 'users', moduleId: 'users/index', nav: true, title: 'Users' },
      { route: 'users/:id/detail', name: 'userDetail', moduleId: 'users/detail' },
      { route: 'files/*path', name: 'files', moduleId: 'files/index', nav: 0, title: 'Files', href:'#files' }
    ]);
  }
}

```

my proposal is to allow us to pass the components directly instead of a string.

```auto
import {RouterConfiguration, Router} from 'aurelia-router';
import {HomePage} from './home/index';
import {UsersPage} from './users/index';

export class App {
  router: Router;

  configureRouter(config: RouterConfiguration, router: Router): void {
    this.router = router;
    config.title = 'Aurelia';
    config.map([
      { route: ['', 'home'], name: 'home', module: HomePage },
      { route: 'users', name: 'users', module: UsersPage, nav: true, title: 'Users' },
    ]);
  }
}

```

“but code splitting!!!”, I hear you say…

```auto
import {RouterConfiguration, Router} from 'aurelia-router';

export class App {
  router: Router;
  
  configureRouter(config: RouterConfiguration, router: Router): void {
    this.router = router;
    config.title = 'Aurelia';
    config.map([
      { route: ['', 'home'], name: 'home', module: () => import('./home/index') },
      { route: 'users', name: 'users', module: () => import('./users/index'), nav: true, title: 'Users' },
    ]);
  }
}

```

that way the code is understood by bundlers and they’ll know to split at that point, and aurelia doesn’t have to concern itself with loading modules.

## view templates using `@inlineView`

not a commonly used feature, `inlineView` might just be the key to make all of this possible. according to the documentation, inlineView has the following ts signature

```auto
inlineView(markup: string, dependencies?: Array, dependencyBaseUrl?: string): any

```

if you know about inlineView then you probably know about the first argument: the view of the component.

```auto
const view = `
  <template>
    sooper cool content
  </template>
`;

@inlineView(view)
class App {}

```

but I bet few people know about the second and third arguments. the second one is an `Array` of objects with `from` and `as` properties (similar to the `<require>` element’s `from` and `as` attributes.

```auto
const view = `
  <template>
    sooper cool content
    <custom-element></custom-element>
  </template>
`;

@inlineView(view, [{ from: '../custom-element', as: 'custom-element' }])
class App {}

```

but this still suffers from the same problems as the router, it’s not using standard syntax and so you need the magical `PLATFORM.moduleName` to tell the bundler to form the relationship. in reality it should be possible to simply pass in the class.

```auto
// custom-element.ts
@customElement('custom-element')
export class CustomElement {}

// app.ts
import {CustomElement} from './custom-element';

const view = `
  <template>
    sooper cool content
    <custom-element></custom-element>
  </template>
`;

@inlineView(view, [CustomElement])
class App {}

```

_I asked about this on [#585](https://github.com/aurelia/framework/pull/858). You can read @bigopon’s response there._

#### “but separation of concerns!!! I want my html on a different file”

although this is not part of the spec (and likely never will), all bundlers have the ability to import different file types (not sure about fusebox on this one), including html.

```auto
import view from './app.html';

@inlineView(view)
class App {}

```

#### “but other file types and async import are not part of the spec!!”

but neither are decorators… that is to say that something not being yet part of the spec hasn’t stopped aurelia from using it as part of the core api. there is precedent for these types of risks, and it’s very likely that dynamic imports _will_ become standard. In fact it might get there before decorators do.

### boostrapping

right now, manually bootstrapping an app is a mystery to me. but I believe this is a place that would also benefit from using standard module syntax.

if you’re using webpack, the way to boostrap right now is to set your app’s entry to `aurelia-bootstrapper` and it will magically know to use a `main` file and use the `configure` exported function. and it just happens. I would say this is not the way it should be. my dream api for this would be

```auto
<!-- src/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>the title</title>
  </head>
  <body>
    <main id="root"></main>
    <script src="./main"></script>
  </body>
</html>

```

```auto
// src/main.ts
import {bootstrap, Aurelia} from 'aurelia-framework';
import {App} from './app';

async function start(){
  const host = document.getElementById('root');
  const aurelia: Aurelia = await bootstrap(App, host);

  aurelia.use
    // add plugins here
    .standardConfiguration()
    .developmentLogging();

  await aurelia.start();
}

start();

```

and if you want to use parcel just point it to `src/index.html` and it knows what to do. if using webpack just point it to `src/main.ts` and it will know what to do without the need for special plugins. speaking of which…

### "but conventions!!! 😢 "

this is where I believe plugins have their place. instead of being an absolute necessity, they would add extra features like:

- no need to use `@customElement` to give the names yourself, the plugin would add the decorator based on the file name
- same with `@inlineView` as the plugin could find the html view file, add the decorator, and actually inline the html in there
- etc

### for the noobs

let’s be honest starting with aurelia is not as easy as we would want it to be. in my case, this was due to it not being as popular (lack of examples) and the “conventions” to which aurelia aligned itself where not always entirely clear. hopefully, this shift would lessen the initial mental burden of learning something new. because it would be just javascript.

### fin

hopefully my thoughts came through the text, and this can start a discussion to revamp/rethink aurelia’s module system

@Alexander-Taran the result of the gitter chat and some more thought

---

<div class="post-metadata">

**Author:** ![fkleuver](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/fkleuver/32/994_2.png) [@fkleuver](https://discourse.aurelia.io/u/fkleuver)\
**Post date:** [March 24, 2018, 9:07am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/2 "2018-03-24T09:07:03Z")

</div>

Excellent post and I agree with the idea of directly passing components rather than their module paths.

Ironically, in the way it currently works Aurelia makes quite a detour to get the constructor function corresponding to a module path. **It needs the constructor function to begin with**.  
Not to mention there is always a certain set of modules that your app needs during initial load anyway - there is no benefit in lazy loading those.

Simply changing to direct references for modules that should not be lazy-loaded, aside from being bundler-friendly, could make a huge positive impact on initial load times.

I should note that [aurelia-experiment](https://github.com/aurelia/experiment) looks very promising in terms of addressing this. The hard work of analyzing applied conventions can be done during build time, and highly efficient code can be generated that would take care of those imports among other things. We could keep the conventions without sacrificing any performance or bundler optimizations.

---

<div class="post-metadata">

**Author:** ![obedm503](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/obedm503/32/83_2.png) [@obedm503](https://discourse.aurelia.io/u/obedm503)\
**Post date:** [March 24, 2018, 8:03pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/3 "2018-03-24T20:03:14Z")

</div>

for anyone that’s curious, you can folow the progress in this **experimental** repo

> **[aurelia-contrib/bundler-friendly-aurelia](https://github.com/aurelia-contrib/bundler-friendly-aurelia)**
>
> working to make aurelia bundler-friendly. Contribute to aurelia-contrib/bundler-friendly-aurelia development by creating an account on GitHub.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [March 25, 2018, 9:31am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/4 "2018-03-25T09:31:48Z")

</div>

The newest PR at `templating` will make it easier to achieve this [https://github.com/aurelia/templating/pull/606](https://github.com/aurelia/templating/pull/606)

Please head there for a discussion 😄

---

<div class="post-metadata">

**Author:** ![HamedFathi](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/hamedfathi/32/2099_2.png) [@HamedFathi](https://discourse.aurelia.io/u/HamedFathi)\
**Post date:** [March 25, 2018, 8:11pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/5 "2018-03-25T20:11:46Z")

</div>

@obedm503

May I ask you about performance and memory allocation of the idea? Now Aurelia is so fast I want to know this changes can affect on the performance or not.

 ![1](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/1X/7ea4b06191bc27de57d8da51e8d8d3e13fe5e856.png)

![2](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/1X/fa97527c605242dbb544e9b7389647eb35972928.png)

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [March 25, 2018, 9:38pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/6 "2018-03-25T21:38:31Z")

</div>

The benchmark you see is for runtime performance of frameworks, which has little todo with this feature. Also this is better in term of start up performance, as resources loading and registration are “short circuited”

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [March 26, 2018, 10:42am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/7 "2018-03-26T10:42:19Z")

</div>

The AOT compiler looks very interesting. It’s obviously early days but I’m guessing at some point it will also support sourcemaps back to the original source?

I’ve looked at migrating to Webpack but while the Aurelia plugin doesn’t support tree-shaking or most of its other optimisations I didn’t really see the point.

If the improvements are anything like what Angular saw, AOT plus some changes to support static analysis could potentially see drastic improvements in startup and bundle size?

👏👏👏👏👏

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [March 27, 2018, 8:48am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/8 "2018-03-27T08:48:58Z")

</div>

Yes more static Aurelia means more tree shaking & scope hoisting friendly = less dynamic parts used =\> smaller bundle and faster startup.

Also there some ideas we can test out like Css modules and jsx for template creation. Example of jsx [https://stackblitz.com/edit/statically-aurelia-zwqj67?file=calendar.js](https://stackblitz.com/edit/statically-aurelia-zwqj67?file=calendar.js)

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [April 1, 2018, 10:49pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/9 "2018-04-01T22:49:27Z")

</div>

Update:

[https://github.com/aurelia/templating-router/issues/75](https://github.com/aurelia/templating-router/issues/75)

Static router view model declaration for more bundler friendliness

demo

> **[statically-aurelia-qu174c - StackBlitz](https://stackblitz.com/edit/statically-aurelia-qu174c?file=app.js)**
>
> Blank starter project for building ES6 apps.

---

<div class="post-metadata">

**Author:** ![huochunpeng](https://avatars.discourse-cdn.com/v4/letter/h/49beb7/32.png) [@huochunpeng](https://discourse.aurelia.io/u/huochunpeng)\
**Post date:** [April 2, 2018, 12:58am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/10 "2018-04-02T00:58:09Z")

</div>

Sounds like your work is very close to enable browserify to build aurelia app.

That can greatly simplify small app build. Personally I would not use browserify to build prod. But I really like to use it in testing together with tape. It is possible to cut karma off from test setup, and reduce all testing setup to a single line of npm script in package.json.

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [June 27, 2018, 3:55pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/11 "2018-06-27T15:55:20Z")

</div>

Sorry to bump this but it seems like the most appropriate place to ask.

@bigopon Thanks for your hard work on this, I’ve been testing some of the new features in the latest releases.

Apart from `templating-router/pull/75`, what else is left to realise our dream of a bundler friendly Aurelia?

It looks like there will still be issues for those using separate HTML files and that probably includes almost everybody. From what I understood this could be solved with some build tooling? Is there anything that we can help out with?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [June 28, 2018, 4:57am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/12 "2018-06-28T04:57:11Z")

</div>

> Thanks for your hard work on this, I’ve been testing some of the new features in the latest releases.

That’s nice, did they help ?

> Apart from templating-router/pull/75, what else is left to realise our dream of a bundler friendly Aurelia?

~~Because it’s decided to have `viewModel`, in addition to `moduleId` to indicate a direct reference, it will take a bit time to analyze the changes needed in `aurelia-router`, and also test.~~ the last bit beside that is dialog, with the same ability. At the moment it somewhat supports it, but only when module id is preserved. Its an easy but breaking change one. @timfish

> It looks like there will still be issues for those using separate HTML files and that probably includes almost everybody. From what I understood this could be solved with some build tooling?

Yes, build tool will be needed I think. The new features just helps to have an easy, static way of declaring a view template and its resources ( dependencies ), not loading it at runtime. I think it will mostly be :

```js
import view from './my-el.html';

export class MyEl {
  static $view = view;
}

```

> Is there anything that we can help out with?

Definitely, I’ll push another PR to Aurelia router soon, so you can help review and validate it to help progress it faster.

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [June 29, 2018, 11:04am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/13 "2018-06-29T11:04:11Z")

</div>

Yeah, the new features appear to be working although I haven’t tried them with a bundler + tree shaking yet. Our app is going to take some significant reworking to make that possible.

How would the build tool handle dependencies `<require>`'ed in the HTML? Would they all need adding to the `$resources` of the vm?

I’ll test all your changes!

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [June 29, 2018, 1:14pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/14 "2018-06-29T13:14:50Z")

</div>

> How would the build tool handle dependencies 'ed in the HTML? Would they all need adding to the $resources of the vm?

- static `$resource` is a way to declare some metadata that was previously defined with decorators, like `@customElement`, `@customAttribute`, `@valueConverter`, `@bindingBehavior`, `@templateController`, `@processContent`. What previously was defined with value converter can be alternatively done via static `$resource`, for example

- static `$view` is a way to declare a view for a custom element specifically, so it will be something like this for `<require/>`:

```html
<!-- app.html -->
<template>
  <require from='path/to/another-custom-element'></require>
  <require from='path/to/another-custom-attribute'></require>
  <require from='path/to/another-value-converter'></require>
  <require from='path/to/another-binding-behavior'></require>
</template>

```

Change to

```ts
import view from './app.html';

@view({
  template: view,
  dependencies: () => [
    // code splitting ready syntax, change to static import {} from '...' if needed
    import('path/to/resources'),
  ]
})
export class App {
}

```

or

```ts

import { SubElement } from 'path/to/other-element';
import view from './app.html';

// Note that if this value converter is local to the view of this element
// it can be stay local and be declared as a dependencies 
class LocalValueConverter {
  // ...
}

@view({
  template: view,
  dependencies: () => [
    SubElement,
    LocalCustomAttribute,
    LocalValueConverter
  ]
})
export class App {
}

```

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [October 15, 2018, 10:39pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/15 "2018-10-15T22:39:27Z")

</div>

@obedm503 Beside bundler friendly effort ongoing, with the PR at [https://github.com/aurelia/script-tag/pull/11](https://github.com/aurelia/script-tag/pull/11), you can now go bundler free. Have a check by pulling down PR branch and start a http-server in example folder

---

<div class="post-metadata">

**Author:** ![Alexander-Taran](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/alexander-taran/32/2308_2.png) [@Alexander-Taran](https://discourse.aurelia.io/u/Alexander-Taran)\
**Post date:** [October 16, 2018, 9:14pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/16 "2018-10-16T21:14:57Z")

</div>

It is merged already… so woo-hoo!!!  
Nice job

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [October 17, 2018, 9:27am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/17 "2018-10-17T09:27:36Z")

</div>

@bigopon did `import()` of routes get fixed/completed in vCurrent?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [October 17, 2018, 10:28am UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/18 "2018-10-17T10:28:02Z")

</div>

Ts conversion needs to happen first, and it’s getting merged soon. After that, I will kick start router with `import()`

---

<div class="post-metadata">

**Author:** ![lvparkington](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/lvparkington/32/736_2.png) [@lvparkington](https://discourse.aurelia.io/u/lvparkington)\
**Post date:** [October 25, 2018, 4:00pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/19 "2018-10-25T16:00:36Z")

</div>

Is it ready yet? Does it work? 🙂

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [October 25, 2018, 11:11pm UTC](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959/20 "2018-10-25T23:11:04Z")

</div>

The PRs are at:

- Router: [https://github.com/aurelia/router/pull/624](https://github.com/aurelia/router/pull/624)
- Templating Router: [https://github.com/aurelia/templating-router/pull/84](https://github.com/aurelia/templating-router/pull/84)

It will take a bit more time. But hopefully not too long. Implementation is basically done in router, now it’s the QA time with tests 🙂

[Next page](https://discourse.aurelia.io/t/discussion-bundler-friendly-aurelia/959.md?page=2)
