Configure Angular 2 CLI (webpack.beta.17)

Alexey Okhrimenko
5 min readSep 18, 2016

--

UPD: this article is updated to match webpack.beta.17+

Yesterday Angular-CLI beta 14 was released. With new shiny webpack inside of it. And they did amazing job at making it imposible to configure webpack. The ammount of time they spend to prevent any configuration is astonishing.

If you want configuration you DOOMED (at least for now, Angular team promised to do something about it in the future).

But for those who still want to configure webpack build config (for example to add AutoPrefixer), the only way is to clone angular-cli repository locally, modify it and npm link it. You will have problems on each and every update, but you will get access to webpack configuration.

Step 1 — Configure Angular CLI

First of all remove Angular CLI (if it’s installed).

npm uninstall -g angular-cli
npm cache clean

Then clone repo somewhere and npm link it.

git clone https://github.com/angular/angular-cli.git
cd angular-cli

We have a problem here, git clone will get us whole repository and switch to “default” branch automaticly. But default branch sometimes is broken or have inconsistent changes of whatever. So we have to switch to latest tag (for now it’s beta 17 — make sure that you use latest tag)

git checkout v1.0.0-beta.17

Short path

Copy this git-patch file (https://www.dropbox.com/s/9pawe5jo2soplqw/angular-cli-patch.diff?dl=1) to angular-cli folder, apply it and install npm dependencies

git apply angular-cli-patch.diff
npm install

If you did this, then you can skip “Long path” and go directly to “Last actions with Custom Angular CLI

Long path

If you have decided to do things manually, you need to modify the config. Open angular-cli in your editor of choice and go to /packages/angular-cli/models/webpack-build-common.ts

Here you have a common webpack config that used for every task. Let’s add AutoPrefixer. Since Angular CLI already using PostCSS loader we don’t need to configure it. So we can go straight to adding AutoPrefixer. Let’s install it and other dependencies.

npm install # this one will install default deps
npm install autoprefixer --save-dev

Then at the top of the file (webpack-build-common.ts) require AutoPrefixer.

const autoprefixer = require('autoprefixer');

And at the bottom of the file (inside ‘plugins’ section — line 105) add this:

new webpack.LoaderOptionsPlugin({
options: {
postcss: function () {
return [autoprefixer];
}
}
}),

Now we need to apply some changes to a different file. Open /packages/angular-cli/models/webpack-config.ts and replace webpackMerge with this.betterWebpackMerge everywere except at the top of the file (where we importing webpackMerge).

At line 5 import webpack.

import * as webpack from 'webpack';

One last thing. We need to add implementation of betterWebpackMerge at line 61.

betterWebpackMerge(baseConfig: any, targetConfig: any, targetTypeScriptConfig?: any) {
let basePlugins = (baseConfig && baseConfig.plugins) || [];
let targetPlugins = (targetConfig && targetConfig.plugins) || [];
let targetTypeScriptPlugins = (targetTypeScriptConfig && targetTypeScriptConfig.plugins) || [];
let baseOptionsPlugins = basePlugins
.filter((plugin: any) => plugin instanceof webpack.LoaderOptionsPlugin)
.map((plugin: any) => plugin.options.options );
let targetOptionsPlugins = targetPlugins
.filter((plugin: any) => plugin instanceof webpack.LoaderOptionsPlugin)
.map((plugin: any) => plugin.options.options );
let targetTypeScriptOptionsPlugins = targetTypeScriptPlugins
.filter((plugin: any) => plugin instanceof webpack.LoaderOptionsPlugin)
.map((plugin: any) => plugin.options.options );
let mergedConfig = webpackMerge(
baseConfig,
targetConfig,
targetTypeScriptConfig
);
if (
baseOptionsPlugins.length > 0 ||
targetOptionsPlugins.length > 0 ||
targetTypeScriptOptionsPlugins.length > 0
) {
let mergedBase = baseOptionsPlugins.reduce((base: any, next: any) => {
Object.assign(base, next);
return base;
}, {});
let mergedTarget = targetOptionsPlugins.reduce((base: any, next: any) => {
Object.assign(base, next);
return base;
}, {});
let mergedTargetTypeScript = targetTypeScriptOptionsPlugins.reduce((base: any, next: any) => {
Object.assign(base, next);
return base;
}, {});
if (mergedConfig.plugins) {
mergedConfig.plugins = mergedConfig.plugins.filter((plugin: any) => {
return !(plugin instanceof webpack.LoaderOptionsPlugin);
});
mergedConfig.plugins.push(new webpack.LoaderOptionsPlugin({
options: Object.assign(mergedBase, mergedTarget, mergedTargetTypeScript)
}));
}
}
return mergedConfig;
}

Last actions with Custom Angular CLI

Now we need to do two more things, we need to build angular cli source code.

npm run build

And then we need to navigate to builded code and link it as global package.

cd dist/angular-cli/
npm link

That’s it. Now we have “custom” Angular CLI with AutoPrefixer.

Step 2 — Use “custom” Angular CLI

Let’s create a new project (if you have one already you can skip project creation part) and link your local angular-cli installation inside of the project (this step is mandatory).

cd ~ # here you can go to any folder you want your project to be
ng new foo # you can skip this step if you have a project already
cd foo
npm link angular-cli

npm link is required because …

npm link angular-cli is needed because by default the globally installed angular-cli just loads the local angular-cli from the project which was fetched remotely from npm. npm link angular-cli symlinks the global angular-clipackage to the local angular-cli package. Now the angular-cli you cloned before is in three places: The folder you cloned it into, npm’s folder where it stores global packages and the angular-cli project you just created.

Now to the last step, lets modify our css files and add ‘user-select’ rule and see what happens. If you just created a project go to /foo/src/app/app.component.css and add this:

h1 {
user-select: none;
}

Now you can start a web server.

ng serve

And navigate to http://localhost:4200. If you open developer tools you will see AutoPrefixed styles. Well done, now we can save some keystrokes for our Angular 2 project :)

One downside

This aproach have only one downside, each time new version of Angular CLI will appear you will have to rebase it inside of you local copy or repeat Step1 again. So be aware.

PS: Don’t forget to like article if it was usefull or comment if something is not working as described. I will be happy to help.

--

--

Alexey Okhrimenko

Angular GDE. Ex AngularMoscow Organizer. Author of Russian documentation http://angular24.ru and twitter account AngularRussia.