# A note on Webpack's tree-shaking and why PLATFORM.moduleName is necessary

**URL:** <https://discourse.aurelia.io/t/a-note-on-webpacks-tree-shaking-and-why-platform-modulename-is-necessary/946>\
**Category:** Framework Knowledge\
**Created:** [March 21, 2018, 9:46pm UTC](https://discourse.aurelia.io/t/a-note-on-webpacks-tree-shaking-and-why-platform-modulename-is-necessary/946 "2018-03-21T21:46:10Z")\
**Posts on this page:** 6\
**Page:** 1

<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 21, 2018, 9:46pm UTC](https://discourse.aurelia.io/t/a-note-on-webpacks-tree-shaking-and-why-platform-modulename-is-necessary/946/1 "2018-03-21T21:46:10Z")

</div>

I’ve seen this question pop up from time to time, so for those who are having problems with modules not being loaded or are generally curious why/how this works:

Webpack applies a technique called [tree-shaking](https://webpack.js.org/guides/tree-shaking/). In summary, it statically analyzes your project files looking for `import` statements in order to determine what needs to be included in the bundle.  
It starts doing this at your bundle entry and recursively calls each imported module until every import is resolved. Any project file that is **not** imported anywhere, will **not** be included in the bundle.

### Before webpack

Aurelia has always had alternative means to reference modules outside of `import` statements. Examples:

- RouterConfiguration `moduleId: "path-to-module"`
- `au.setRoot("path-to-app-module")`
- `au.use.plugin("plugin-name")`
- `au.use.feature("path-to-feature-module")`
- `au.use.globalResources("path-to-resource-module")`

Traditionally this has never posed any problems because with pure RequireJS, SystemJS, as well as aurelia-cli projects, you explicitly defined your bundles with paths and globbing patterns. Any files resolved from those were included in the bundles.

### With webpack

In webpack, you don’t define your bundles anymore - rather, you define an entry point and that’s it. It uses the static structure of ES2015 module syntax to automatically determine the contents of the bundle.

Consequently, the “aurelia way” of referencing modules are not recognized as imports and the files are never included.

As described in the [webpack plugin docs](https://github.com/aurelia/webpack-plugin/wiki/AureliaPlugin-options) there is an `includeAll` option you can pass the aurelia plugin (`new AureliaPlugin({ includeAll: "src" })`) which forces **all** files under `src` to be included in the bundle and the “old” way will then work again, but this is typically not desirable for production apps.

### Enter PLATFORM.moduleName

You can think of `PLATFORM.moduleName` as aurelia’s version of `import`.

`PLATFORM.moduleName` in itself doesn’t do anything interesting in terms of ensuring webpack imports the module.  
However `aurelia-webpack-plugin` uses it to determine what files to include in the bundle, in much the same way webpack itself uses `import` statements for that.

In simple terms, the plugin goes through the raw javascript of each project file and looks for “PLATFORM.moduleName” as a magic string of sorts. It extracts the string from the call and gives that back to webpack in the form of a dependency. (additionally, as @jods4 pointed out, it disables optimizations which are not compatible with `aurelia-loader)`

As you might expect from a static analysis tool, this then won’t work for any programmatically created strings. Which is a bit unfortunate for those (including me) who used to programmatically create some of these configurations to keep things clean, but makes perfect sense when you realize that this never worked for `import` either.

### And finally…

It’s worth noting that once a module has been included via `PLATFORM.moduleName`, it doesn’t need to be included again. This allows you, for example, to do something like this as a replacement for what used to be bundle configurations:

`src/main.ts`:

```auto
// ensure the includes files is resolvable via the entry point
import "./includes"; 

```

`src/includes.ts`

```auto
import { PLATFORM } from "aurelia-pal";

// declare all pages we need
PLATFORM.moduleName("pages/page1");
PLATFORM.moduleName("pages/page2");
PLATFORM.moduleName("components/component1");
PLATFORM.moduleName("components/component2");

```

Now, wherever you need the modules declared above, you don’t need to use `PLATFORM.moduleName` anymore and you can even programmatically generate those route configs and such. They are already included in the bundle via `includes.ts` and don’t need to be included again.

Whether this is a nice solution or not depends on the situation, but it’s another tool in the toolbox which may come in handy.

As @jods4 pointed out, the modules listed above will then be a dependency of `includes.ts` and this will affect code splitting. Arguably it’s simply a slightly-less-harmful variant of the `includeAll` option, but still not something you’d want to do in a large production app where you want every optimization.

---

<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:** [March 21, 2018, 10:05pm UTC](https://discourse.aurelia.io/t/a-note-on-webpacks-tree-shaking-and-why-platform-modulename-is-necessary/946/2 "2018-03-21T22:05:08Z")

</div>

@fkleuver, man… I can only hope for it to be commited here

> **[aurelia-contrib/aurelia-getting-started](https://github.com/aurelia-contrib/aurelia-getting-started/tree/master/guides)**
>
> Basically a queue of topics and examples to cover. Contribute to aurelia-contrib/aurelia-getting-started development by creating an account on GitHub.

---

<div class="post-metadata">

**Author:** ![jods4](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/jods4/32/677_2.png) [@jods4](https://discourse.aurelia.io/u/jods4)\
**Post date:** [March 21, 2018, 10:09pm UTC](https://discourse.aurelia.io/t/a-note-on-webpacks-tree-shaking-and-why-platform-modulename-is-necessary/946/3 "2018-03-21T22:09:23Z")

</div>

This is a good summary!

Two points I feel are worth adding:

1. `aurelia-webpack-plugin` does a little more than replacing an `import`. It also disables a bunch of optimizations on the target module, such as tree shaking or scope hoisting.  
The reason being that those optimizations are not compatible with `aurelia-loader`.  
This is the reason why using `includeAll` is great to migrate your existing projects, do small demos or PoCs but it’s not recommended. When using `includeAll` you loose optimizations on _all_ your files, even if they are loaded through `import` and you won’t be able to use code splitting.

2. The `include.ts` script has some drawbacks. Because the dependency graph is not correct (everything is a dependency of `include.ts`), you won’t be able to use code splitting either.  
A better alternative if you go this way is to use `ModuleDependenciesPlugin` in your webpack config: syntax is better (no `PLATFORM.moduleName`); you can create Aurelia dependencies for any file in your dependency graph; and because webpack config is just JS, you can create those dependencies dynamically if you want to (programmatically created strings as you said).

---

<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 21, 2018, 10:19pm UTC](https://discourse.aurelia.io/t/a-note-on-webpacks-tree-shaking-and-why-platform-modulename-is-necessary/946/4 "2018-03-21T22:19:50Z")

</div>

Thanks for pointing that out, I included some notes of your points as to not put future readers on the wrong track with `includes.ts` 🙂

---

<div class="post-metadata">

**Author:** ![MaximBalaganskiy](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/maximbalaganskiy/32/831_2.png) [@MaximBalaganskiy](https://discourse.aurelia.io/u/MaximBalaganskiy)\
**Post date:** [March 21, 2018, 10:40pm UTC](https://discourse.aurelia.io/t/a-note-on-webpacks-tree-shaking-and-why-platform-modulename-is-necessary/946/5 "2018-03-21T22:40:55Z")

</div>

There is another issue with `includeAll` and css. This parameter imports all it can find from a dummy `empty-entry.js` module and if you don’t have a specific rule to use `css-loader` for css imported from `empty-entry.js` your build will fail.

---

<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:** [March 21, 2018, 11:10pm UTC](https://discourse.aurelia.io/t/a-note-on-webpacks-tree-shaking-and-why-platform-modulename-is-necessary/946/6 "2018-03-21T23:10:39Z")

</div>

> [@MaximBalaganskiy](#):
>
> There is another issue with includeAll and css.

a PR is very velcome (-: [https://github.com/aurelia-contrib/aurelia-getting-started/blob/master/knowledge-base/webpack-tree-shaking-and-platform-modulename.md](https://github.com/aurelia-contrib/aurelia-getting-started/blob/master/knowledge-base/webpack-tree-shaking-and-platform-modulename.md)
