Не так давно меня заинтересовала проблема миграции приложений, написанных с первым Angular.js на второй. Кстати, эта статья должна была быть именно об этом. Но вмешался случай. До этого я поднимал Angular2 только на Node.js. А тут, поскольку я в основном работаю из-под Visual Studio, я решил запустить его из-под нее. Когда я пришел в себе после всех ударов граблей, по которым мне пришлось пройти, я решил выделить развертывание Angular2 под Visual Studio 2015 в отдельную статью. И что-то мне подсказывает, что лишней она не будет.
Шаг первый. Реквизит.
Для начала нам нужно подготовить Visual Studio для работы с Node.js и NPM, так как почти все пакеты, от которых зависит Angular2, лежат в NPM.
Ставим NPM Task Runner и Package Installer. Они пригодятся нам для взаимодействия студии и npm.
И (а вот тут волшебник достает кролика) использоваться не будет.
Проблема заключается в том, что во время установки Node.js, в переменную среды PATH установщик Node, записывает путь к тому npm, который идет с ним. Поэтому, вызывая npm из-под консоли, вы будете обращаться именно к нему, а не к глобальному npm.
Для того чтобы исправить такое странное поведение, нужно
Найти место, куда был установлен глобальный (можно выполнить команду npm root -g)
Заменить путь, указанный в PATH с npm ноды, на npm глобальный. Не забудьте сделать это и для системы и для пользователя, а также перезагрузить машину.
После установки расширений, запускаем студию и создаем пустой веб проект. Теперь нам нужно обновить те node.js и npm, которые используются нашей Visual Studio. Студия использует не глобальный npm и node.js, а локальный. Она ничего не знает о том, что установлено у вас в системе и полагается на ту node.js которая лежит в External Web Tools. Если этого не знать, то студия будет использовать устаревшие компоненты и поднять приложение не получиться. Итак, кликнем на проекте и выберем quick install package. В появившемся окошке набираем gulp и ставим его. Конечно, делать это абсолютно не обязательно, но, честно говоря, мне лень создавать package.json вручную.
После установки gulp мы получаем package.json, с которым можно работать дальше.
И первое, что нам нужно сделать, это проверить версию node.js и npm, с которыми будет работать наша студия.
Добавим секцию scripts в package.json с командами «npm -v» и «node -v» и выполним их из-под task runner-a.
{
"name": "myproject",
"version": "1.0.0",
"devDependencies": {
"gulp": "^3.9.1"
},
"scripts": {
"getNpmVersion": "npm -v",
"getNodeVersion": "node -v"
}
}
Лично у меня результаты были впечатляющие: node v0.10.31 и npm 1.4.9. Еще раз обращаю внимание на то, что это версии, которые будут использоваться Visual Studio и ни установленный node, ни глобальный npm никакого отношения сейчас к ним не имеют.
Теперь, все это барахло нужно привести в порядок. Добавим новую команду в наш package.json: «updateNpm»: «npm install npm@latest» и запустим ее. Подождав немного, запустим getNpmVersion. Npm обновился и теперь он версии 3.10.5.
Однако с node.js этот подход не сработает. Если честно я не нашел способа обновить node.js, однако, нашел способ заставить студию использовать нужный мне экземпляр.
Итак, для начала найдите, где у вас установлен node.js и скопируйте туда путь. Теперь идем в Tools -> Options -> Projects and Solutions -> External web tools и добавляем новый путь, указывающий на нормальную версию ноды (если ее нет, просто скачайте и поставьте). Не забудьте поднять новый путь на самый верх. Перезагружаем студию (windows перезагружать не надо) и выполняем команду getNodeVersion. Вуаля, версия обновлена.
После всех этих танцев с бубнами предлагаю пойти попить кофе. Дальше тоже будет не просто.
Шаг второй. Установка зависимостей.
Продолжим мучить наш project.json. Теперь зальем в него все зависимости нашего приложения. Зависимости взяты из 5 MIN QUICKSTART, подредактированы с учетом windows, и одним маленьким но очень гордым нюансом.
Баг уже отправлен, результаты ожидаются.
{
"name": "myproject",
"version": "1.0.0",
"devDependencies": {
"gulp": "^3.9.1",
"typescript": "1.8.10",
"typings": "^1.0.4"
},
"dependencies": {
"@angular/common": "2.0.0-rc.4",
"@angular/compiler": "2.0.0-rc.4",
"@angular/core": "2.0.0-rc.4",
"@angular/forms": "0.2.0",
"@angular/http": "2.0.0-rc.4",
"@angular/platform-browser": "2.0.0-rc.4",
"@angular/platform-browser-dynamic": "2.0.0-rc.4",
"@angular/router": "3.0.0-beta.1",
"@angular/router-deprecated": "2.0.0-rc.2",
"@angular/upgrade": "2.0.0-rc.4",
"systemjs": "0.19.27",
"core-js": "^2.4.0",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"zone.js": "^0.6.12",
"angular2-in-memory-web-api": "0.0.14"
},
"scripts": {
"postinstall": "typings install",
"typings": "typings",
"cmd": "npm typescript",
"getNpmVersion": "npm -v",
"getNodeVersion": "node -v"
}
}
Теперь, из-под таск раннера запустим команду install и подождем, пока все пакеты установятся. Если все прошло хорошо, в папке node_modules у нас должно было появиться несколько других папок, среди которых должна быть папка "@angular". Если вы ее видите, значит пока что все идет хорошо и зависимости установлены. А если нет? Иногда могут возникать проблемы с cachem npm. Если пакеты не устанавливаются и вся консоль таск раннера красная от ошибок, попробуйте добавить еще одну команду в package.json — «npm cache clean» и выполнить ее. Возможно это поможет.
Шаг третий. Конфигурируем typescript для Visual Studio.
Настала очередь сделать еще несколько па в нашем бубновом танце.
Давайте добавим наш первый .ts файл. Создаем в корне папку app и добавляем туда пустой app.component.ts файл. Не стоит проявлять фантазию и придумывать свои имена. Все может сломаться даже от чиха. Теперь закрываем студию.
«experimentalDecorators»: true. Так вот, эти флаги устанавливаются в .csproj файле ручками… Подробнее можно почитать тут
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<TypeScriptRemoveComments>false</TypeScriptRemoveComments>
<TypeScriptSourceMap>true</TypeScriptSourceMap>
<TypeScriptTarget>ES5</TypeScriptTarget>
<TypeScriptJSXEmit>None</TypeScriptJSXEmit>
<TypeScriptCompileOnSaveEnabled>True</TypeScriptCompileOnSaveEnabled>
<TypeScriptNoImplicitAny>False</TypeScriptNoImplicitAny>
<TypeScriptModuleKind>System</TypeScriptModuleKind>
<TypeScriptOutFile />
<TypeScriptOutDir />
<TypeScriptGeneratesDeclarations>False</TypeScriptGeneratesDeclarations>
<TypeScriptNoEmitOnError>True</TypeScriptNoEmitOnError>
<TypeScriptMapRoot />
<TypeScriptSourceRoot />
<TypeScriptExperimentalDecorators>True</TypeScriptExperimentalDecorators>
<TypeScriptEmitDecoratorMetadata>True</TypeScriptEmitDecoratorMetadata>
</PropertyGroup>
Закрыв студию, находим наш *.csproj файл и добавляем в узел PropertyGroup две новые строки:
<TypeScriptExperimentalDecorators>true</TypeScriptExperimentalDecorators>
<TypeScriptEmitDecoratorMetadata>True</TypeScriptEmitDecoratorMetadata>
Теперь открываем проект, заходим в свойства и видим новую вкладку – TypeScript Build.
Выставляем там EcmaScript 6 и Module System — Common Js. Сохраняем.
Шаг четвертый. Код.
Вот теперь можно добавить первые строки кода в наш app.component.ts
Копируем туда вот это и билдим проект.
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }
Если все пошло как надо, билд пройдет без ошибок. Это наш основной компонент или, другими словами, это и есть наше приложение.
Теперь давайте настроим его запуск (bootstrap). Для этого в папку app добавляем файл
import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
bootstrap(AppComponent);
И опять билдим проект. Опять ошибок быть не должно. Можно, конечно, и не билдить, но мне как-то спокойнее.
Теперь в корень проекта добавляем
<html>
<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
и, тоже в корень,
/**
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function (global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'@angular': 'node_modules/@angular',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'rxjs': 'node_modules/rxjs'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'router-deprecated',
'upgrade',
];
// Individual files (~300 requests):
function packIndex(pkgName) {
packages['@angular/' + pkgName] = { main: 'index.js', defaultExtension: 'js' };
}
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['@angular/' + pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
// Add package entries for angular packages
ngPackageNames.forEach(setPackageConfig);
var config = {
map: map,
packages: packages
};
System.config(config);
})(this);
Шаг пятый. Попытка взлета.
А теперь запускаем космонавта! Ну, стартуем приложение.
Если все пошло хорошо, вы должны увидеть надпись My First Angular 2 App на вашем экране. Готовый код доступен на github вот тут.
Всем спасибо за внимание и безграбельного будущего.
Комментарии (43)
visortelle
19.07.2016 13:58+1«Если честно я не нашел способа обновить node.js..»
Для управления версиями ноды на одной машине можно использовать nvm(node version manager). Вот версия для винды. github.com/coreybutler/nvm-windows
kemsky
19.07.2016 14:45Я подключил через
/// <binding BeforeBuild='build' />
в gulp файле, а компиляцию через студию отключил, с ней перманентные проблемы, редактирую в Intellij Idea.
mtt
19.07.2016 15:16+1Чтобы получить angular библиотеку нужно установить менеджер пакетов bower и менеджер задач grunt. Чтобы установить менеджер пакетов bower вам сперва нужно установить менеджер пакетов npm. Чтобы установить менеджер пакетов npm вам сперва нужно установить среду исполнения node.js. Есть ли возможность использовать angular напрямую с какого либо cdn, минуя весь этот зоопарк в коммандной строке?
Drag13
19.07.2016 15:20Насколько я видел — нет.
supersmeh
19.07.2016 16:24+1На самом деле можно.
Надо правильно прописать в systemjs.config.js вот примерно таким образом:
(function(global) { var ngVer = '@2.0.0-rc.4'; // lock in the angular package version; do not let it float to current! var routerVer = '@3.0.0-beta.1'; // lock router version var formsVer = '@0.2.0'; // lock form version //map tells the System loader where to look for things var map = { 'app': 'app', '@angular': 'https://npmcdn.com/@angular', // sufficient if we didn't pin the version '@angular/router': 'https://npmcdn.com/@angular/router' + routerVer, '@angular/forms': 'https://npmcdn.com/@angular/forms' + formsVer, 'angular2-in-memory-web-api': 'https://npmcdn.com/angular2-in-memory-web-api', // get latest 'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.6', 'ts': 'https://npmcdn.com/plugin-typescript@4.0.10/lib/plugin.js', 'typescript': 'https://npmcdn.com/typescript@1.9.0-dev.20160409/lib/typescript.js', }; //packages tells the System loader how to load when no filename and/or no extension var packages = { 'app': { main: 'main.js', defaultExtension: 'js' }, 'rxjs': { defaultExtension: 'js' }, 'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' }, }; var ngPackageNames = [ 'common', 'compiler', 'core', 'http', 'platform-browser', 'platform-browser-dynamic', 'router-deprecated', 'upgrade', ]; // Add map entries for each angular package // only because we're pinning the version with `ngVer`. ngPackageNames.forEach(function(pkgName) { map['@angular/'+pkgName] = 'https://npmcdn.com/@angular/' + pkgName + ngVer; }); // Add package entries for angular packages ngPackageNames.forEach(function(pkgName) { // Bundled (~40 requests): packages['@angular/'+pkgName] = { main: 'bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }; // Individual files (~300 requests): //packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' }; }); // No umd for router yet packages['@angular/router'] = { main: 'index.js', defaultExtension: 'js' }; var config = { map: map, packages: packages } System.config(config); })(this);
bromzh
19.07.2016 15:55+1Для комфортной разработки достаточно только npm для зависимостей и webpack для сборки. В npm есть большинство фронтэнд библиотек, ангуляры в том числе. Вебпак лично для меня заменил и grunt и gulp (хотя это не совсем одно и то же). Задачи описываются в
package.json
в секции scripts. В итоге, чтобы запустить сервер разработчика (который сам отслеживает изменения, пересобирает проект и заменяет нужные js и css на странице) я набираюnpm start
, а чтобы собрать проект для прода (с минификацией и оптимизацией всего), я набираюnpm run build
. Единожды настроенная среда и скелет приложения экономят кучу времени. За основу можно взять этот проект.
Использовать напрямую можно, см. любой плюнкер из доков по ангуляру, например этот.
Однако, это очень неудобный вариант, который подходит только для демок.
Gbdrm
20.07.2016 10:03-1Если цель просто открыть проект с angular2 в студии то не понятно зачем все это делать вручную.
Пример создания проекта asp.net core + angular2 и открыть его в студии за 1 минуту:
npm install -g yo generator-aspnetcore-spa yo aspnetcore-spa
детали:
http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/Drag13
20.07.2016 10:27Причина проста. Изначальная задача состояла в переводи существующего приложения на MVC-5 + A1 на MVC-5 + A2. Поэтому установка Сore и с нуля не подходит.
Но за линк спасибо
ZOXEXIVO
21.07.2016 01:51+1Angular2 внешне начинает немного раздражать. На ранних beta делал небольшие проекты и даже нравилось.
Сейчас тупо не могу запустить туториал, а точнее говоря не могу понять, зачем наподключали десятки каких-то библиотек (zone.js, core-js итп).
gulpfile стал похож на утилиту копирования файлов из node_modules в wwwroot, systemjs.config тоже разбухает.
Такое ощущение что команда разработчиков хочет обеспечить безбедное существование армии фронтэндщиков на долгие годы.
Теперь еще вместо angular2 есть angular@. Прекрасноbromzh
21.07.2016 02:43Вообще-то всё наоборот. В бете всё было монолитно в 1-м npm-модуле. Начиная с RC проект разбили на отдельные модули с общим npm-scope
@angular
. В зависимостях проекта появилась возможность указать только то, что нужно. И разработка этих модулей может вестись независимо, что тоже хорошо.
Например, если раньше в проекте не нужен был роутер, то всё равно приходилось указывать в зависимостях пакет, где есть код этого роутера.
Сейчас же всё стало удобно: если тебе не нужна, например, работа с http-клиентом, то просто не включаешь@angular/http
в зависимости. Делаешь проект только для серверной платформы, а значит тебе не нужны фичи браузера? Убираешьplatform-browser
из зависимостей.
Что касается зависимостей от других библиотек, то тут всё как раньше: angular2 зависит только от
rxjs
иzone.js
.
core-js
используется для более удобного подключения нужных полифиллов, можно обойтись и без него.
А заместо gulp и systemjs лучше взять webpack. Systemjs вообще станет ненужным, при добавлении библиотек ничего никуда добавлять не придётся, конфиги не будут расти. Ну и вместо монструозного gulpfile останется небольшой конфиг вебпака, который практически не придётся изменять.
В качестве примера использования всего этого вместе можно посмотреть на этот стартер.
kemsky
21.07.2016 04:09Есть интресная статья на эту тему: http://blog.mgechev.com/2016/06/26/tree-shaking-angular2-production-build-rollup-javascript/
Ситуация будет менятся, правда на сколько пока не ясно. С одной стороны webpack 2, tree-shaking, с другой скомпилированные темплейты по-любому станут тяжелее в разы. Сейчас вебпак не может оптимизировать неиспользуемые модули и результате в билд попадает почти весь ангуляр. По сравнению с ангуляром и rxjs вклад других библиотек в итоговый размер бандла очень и очень скромный.
ZOXEXIVO
21.07.2016 12:35Спасибо за пояснение.
Пока очень сложно осознавать, что любой чих в npm делается через отдельный пакет.
Обычно же делается форк библиотеки о она встраивается в экосистему и есть какой-то эффект автономности всего фреймворка.
Понятно, что лишних ресурсов нет и поддерживать сложнее
RouR
Упаковка и минификация?
Drag13
Gulp? :D
Во-первых, а зачем? К минификации эта статья отношения особого не имеет, разве что с точки зрения академического интереса.
А во-вторых, лично мне минифицировать просто страшно. Ошибки в консоли и так чуть более чем не информативны, а тут даже представить боюсь что будет. Мне хватило той крови которую у меня выпила последняя версия typescript.
Впрочем, если вы считаете, что статья из-за этого не полна и у вас есть аргументы — есть два пути. Первый (быстрый) форк гитхаба. Не зря он тут. Второй, медленный. Возможно у меня руки дойдут проверить и попробовать минификацию этого счастья.
impwx
Как раз только что разбирался с тем, как минифицировать исходники самого ангуляра, чтобы можно было подключить их как единый файл и больше ничего динамически не подгружать. Определить корректную комбинацию плагинов для галпа, их настроек, порядка исходных файлов и прочего заняло практически неделю. Искренне надеюсь, что разработчики вернут SystemJS-бандлы, как это было в beta-сборках.
Drag13
В -rc используется System.js
Или я что то не правильно понял?
impwx
В beta последовательность действий для сборки была тривиальна:
bundles
в формате SystemJSgulp-concat
иgulp-uglify
)script
В этом скрипте все необходимые модули были заранее объявлены через
System.register
, поэтому SystemJS больше ничего с сервера не подгружал, и даже вызовSystem.config
вообще не был нужен.В RC собранные файлы в формате SystemJS убрали. Есть только файлы в формате UMD, но их нельзя просто конкатенировать и подключить — там нет информации о том, что это вообще был за модуль. Приходится сначала написать
system.config.js
, собирать часть пакетов с помощьюgulp-jspm-build
(в котором нашелся баг), остальную часть конкатенировать в нужной последовательности. Например, код самого SystemJS должен всегда располагаться первым в файле, иначе он не может найти собственный тегscript
и падает.В общем, банальная настройка окружения оказалась на два порядка более сложной и утомительной, чем написание самой логики тестового приложения.
Drag13
О как. Спасибо за развернутый ответ.
bromzh
Есть же source map.
Что, даже в проде всё в непожатом виде?
RouR
Поэтому в дебаге минифкация должна быть отключена, а при выполнении publish в VS проект должен собраться в релизе, все скрипты должны упаковаться и всё это выкатится на препрод сервер.
Это не академический интерес, это реальный процесс разработки и он должен быть автоматизирован, а не в консоли набирать команды каждый раз.
Drag13
RС на проде? + часть зависимостей уровня 0.Х
Я бы не рискнул.
RouR
Это сейчас он RС. Или потом эта инструкция будет дополняться?
Drag13
Я очень надеюсь, что потом в эту статью будут тыкать пальцами со словами «вот же динозавры мучились… ».
Т.е. я надеюсь что эти мучения в будущем повторять не придется.
А если все будет плохо, то или эта инструкция обновиться, или появится другая.
bromzh
А вы проводите аудит кода всех зависимостей и зависимостей зависимостей? Цифра в версии ничего не значит. А многие беты и RC порой качественнее обычных версий.
Drag13
1. Да.
2. «Цифра в версии ничего не значит». Это очень смелое допущение которое на проде может вылезти боком.
3. Да, есть беты которые качественнее релиз версий. Но чаще всего справедлива обратная ситуация. И если вы не проводите полный аудит кода сторонних зависимостей то, возможно, беты в проде это не лучший вариант.
В любом случае прод не мой, и решать вам или клиенту.
bromzh
Например, Flask (web-фреймворк для python) сейчас в версии 0.11, однако продукт очень хороший. А вот какой-нибудь битрикс уже версии 7 или больше, но зато сколько жалоб
В общем, мне повезло, что есть возможность использовать новые технологии. И вам пожелаю найти такую возможность, это здорово (хотя и ответственность возрастает).
Drag13
1. Пришли к консенсусу.
2. Согласен. Но это как с конвенцией о константах. Никто не запрещает менять значения переменных названных «SUPER_VARIABLE». Но **обычно** так никто не делает. Когда автор ставит 1.Х он тем самым декларирует что продукт готов. Когда автор ставит 0.Х он тем самым предупреждает, что могут быть любые изменения и если что — «я предупредил». В остальном соглашусь.
Ну и по последнему абзацу — это конечно плюс и вообще приятно)
Ateist602
Используем ASP.NET Core, Angular 2 и TypeScript уже несколько месяцев в продакшене.
Никаких проблем ни с минификацией и дебагом у браузере.
Благо, WebPack работает на ура.
Drag13
А можно поинтересоваться из каких соображений вы взяли на прод релиз кандидат ангуляра?
Я понимаю для себя или что то аналогичное, но идти с этим в продкашн…
Возможно я и не прав, так что буду благодарен за иную точку зрению.
bromzh
Я тоже взял (когда он был ещё в бете). И очень доволен.
Почему? Наверное, специфика проекта позволила: нет нужды поддерживать старые браузеры, довольно длительная тестировка перед запуском.
Drag13
Немного завидую :)
Ateist602
Потому что проект крупный и нужен фреймворк, который будет жить не один год, на который можно будет без проблем найти разработчиков. Angular2 обещает таковым быть. Даже сейчас на стадии последней (надеюсь) RC, он уже обзавелся приличной документацией и солидного размера комьюнити.
Поэтому, отвечая на Ваш вопрос «Почему мы взяли Angular 2 RC» на прод, отвечу, что это сделано с заделом на будущее.
bromzh
Взял по той же причине. Первый ангуляр несколько устарел и будет потихоньку умирать. Второй обещает долго жить и развиваться, исправляет недостатки первого, использует современные вещи и поддерживается многими спонсорами.
Начал делать прототип на бете и пока ни разу не пожалел. Теперь на нём 2 проекта, своя небольшая библиотека общих компонентов и в планах переписать на него 3-й проект.
Odrin
А в чем проблема? RC-4 прекрасно работает, явных багов нет. Forms и Routes, обновились с deprecated версий и глобальных изменений к релизу уже не будет.
Брать сейчас в прод первый ангуляр не рационально — он не может конкурировать по производительности ни с кем на сегодняшний день. Так что либо Angular 2 rc, либо что-то другое. Но, имхо, у ng нет альтернативы по набору возможностей из коробки.
P.S. TypeScript прекрасен :)
Odrin
Третий, верный, Angular CLI.
ng build -prod. Все, проект собран в bundle и минифицирован.
svekl
Вот очень интересная статья про минификацию
http://blog.mgechev.com/2016/06/26/tree-shaking-angular2-production-build-rollup-javascript/