From de2fded272a637551e9a2bb82725558fd4253d76 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Thu, 7 Apr 2016 19:09:40 -0700 Subject: [PATCH 1/2] design: Add a design document for ngConfig. --- docs/design/ngConfig.md | 69 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 docs/design/ngConfig.md diff --git a/docs/design/ngConfig.md b/docs/design/ngConfig.md new file mode 100644 index 000000000000..41887e041b0e --- /dev/null +++ b/docs/design/ngConfig.md @@ -0,0 +1,69 @@ +# ngConfig - Design + +## Goals + +Currently, a project scaffolded with the CLI have no way of specifying options and configurations affecting their projects. There are ways to affect the build (with the `angular-cli-build.js` file), but the following questions cannot be answered without actual project options: + +* Where in my directory is my karma.conf file? +* What is my firebase database URL? +* Where is my client code? +* How can I use a different +* Any other backend I want to run prior to `ng serve`? + +# Proposed Solution + +Since the data is static, we only need to keep it in a static store somewhere. + +One solution would be to keep the data in the `package.json`. Unfortunately, the metadata contains too much data and the `package.json` file would become unmanageable. + +Instead of polluting the package file, a `angular-cli.json` file will be created that contains all the values. Access to that file will be allowed to the user if he knows the structure of the file (unknown keys will be kept but ignored), and it's easy to read and write. We can also keep the file formatted. + + +## Fallback + +There should be two `angular-cli.json` files; one for the project and a general one. The general one should contain information that can be useful when scaffolding new apps, or informations about the user. + +The project `angular-cli.json` goes into the project root. The global configuration should live in the `$HOME` directory of the user. + +## Structure + +The structure should be defined by a JSON schema (see [here](http://json-schema.org/)). The schema will be used to generate the `d.ts`, but that file will be kept in the file system along the schema for IDEs. + +Every PR that would change the schema should include the update to the `d.ts`. + +# API + +## CLI + +#### Getting values + +The new command `get` should be used to output values on the terminal. It takes a set of flags and an optional array of [paths](#path); + +* `--glob` or `-g`; the path follows a glob format, where `*` can be replaced by any amount of characters and `?` by a single character. This will output `name=value` for each values matched. + +Otherwise, outputs the value of the path passed in. If multiple paths are passed in, they follow the format of `name=value`. + +#### Setting values + +The new command `set` should be used to set values in the local configuration file. It takes a set of flags and an optional array of `[path](#path)=value`; + +* `--global`; sets the value in the global configuration. +* `--remove`; removes the key (no value should be passed in). + +The schema needs to be taken into account when setting the value of the field; + +* If the field is a number, the string received from the command line is parsed. `NaN` throws an error. +* If the field is an object, an error is thrown. +* If the path is inside an object but the object hasn't been defined yet, sets the object with empty values (use the schema to create a valid object). + +#### Path + +The paths are json formatted path; each `.` separates a map, while `[]` indicates an index in an array. + +An example is the following: + + keyA.keyB.arrayC[3].value=123 + +## Model + +A model should be created that will include loading and saving the configuration, including the global configuration. \ No newline at end of file From 2fac21b695c9ac0fb0270f02cbf1ecb385f19a42 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Fri, 8 Apr 2016 16:22:27 -0700 Subject: [PATCH 2/2] build: Angular2App is now a class, and accepts options for css compilers. --- README.md | 1 + lib/broccoli/angular-broccoli-compass.js | 12 +- lib/broccoli/angular-broccoli-less.js | 6 +- lib/broccoli/angular-broccoli-sass.js | 29 +- lib/broccoli/angular-broccoli-stylus.js | 10 +- lib/broccoli/angular2-app.js | 640 ++++++++++++----------- 6 files changed, 358 insertions(+), 340 deletions(-) diff --git a/README.md b/README.md index a7270a228223..b157ffa09f3f 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,7 @@ We support all major CSS preprocessors: To use one just install for example `npm install node-sass` and rename `.css` files in your project to `.scss` or `.sass`. They will be compiled automatically. +The `Angular2App`'s options argument has `sassCompiler`, `lessCompiler`, `stylusCompiler` and `compassCompiler` options that are passed directly to their respective CSS preprocessors. ## Known issues diff --git a/lib/broccoli/angular-broccoli-compass.js b/lib/broccoli/angular-broccoli-compass.js index 5035cf099693..f3ac76d37f89 100644 --- a/lib/broccoli/angular-broccoli-compass.js +++ b/lib/broccoli/angular-broccoli-compass.js @@ -33,12 +33,12 @@ class CompassPlugin extends Plugin { } compile(fileName, inputPath, outputPath) { - let sassOptions = { - file: path.normalize(fileName), - includePaths: this.inputPaths, + let sassOptions = Object.assign(this.options, { data: '@import "compass"; .transition { @include transition(all); }', + file: fileName, + includePaths: [inputPath].concat(this.options.inputPaths || []), importer: compass - }; + }); let result = sass.renderSync(sassOptions); let filePath = fileName.replace(inputPath, outputPath).replace(/\.s[ac]ss$/, '.css'); @@ -47,13 +47,13 @@ class CompassPlugin extends Plugin { } } -exports.makeBroccoliTree = (sourceDir) => { +exports.makeBroccoliTree = (sourceDir, options) => { if (sass && compass) { let compassSrcTree = new Funnel(sourceDir, { include: ['**/*.scss', '**/*.sass'], allowEmpty: true }); - return new CompassPlugin([compassSrcTree]); + return new CompassPlugin([compassSrcTree], options); } }; diff --git a/lib/broccoli/angular-broccoli-less.js b/lib/broccoli/angular-broccoli-less.js index 077b7358c91b..1f2d928eab79 100644 --- a/lib/broccoli/angular-broccoli-less.js +++ b/lib/broccoli/angular-broccoli-less.js @@ -34,7 +34,7 @@ class LESSPlugin extends Plugin { compile(fileName, inputPath, outputPath) { let content = fs.readFileSync(fileName, 'utf8'); - return less.render(content) + return less.render(content, this.options) .then(output => { let filePath = fileName.replace(inputPath, outputPath).replace(/\.less$/, '.css'); fse.outputFileSync(filePath, output.css, 'utf8'); @@ -42,13 +42,13 @@ class LESSPlugin extends Plugin { } } -exports.makeBroccoliTree = (sourceDir) => { +exports.makeBroccoliTree = (sourceDir, options) => { if (less) { let lessSrcTree = new Funnel(sourceDir, { include: ['**/*.less'], allowEmpty: true }); - return new LESSPlugin([lessSrcTree]); + return new LESSPlugin([lessSrcTree], options); } }; diff --git a/lib/broccoli/angular-broccoli-sass.js b/lib/broccoli/angular-broccoli-sass.js index 8fc3a196d61a..f5458bdb8994 100644 --- a/lib/broccoli/angular-broccoli-sass.js +++ b/lib/broccoli/angular-broccoli-sass.js @@ -4,7 +4,6 @@ const requireOrNull = require('./require-or-null'); const Plugin = require('broccoli-caching-writer'); const fse = require('fs-extra'); -const path = require('path'); const Funnel = require('broccoli-funnel'); let sass = requireOrNull('node-sass'); @@ -24,26 +23,32 @@ class SASSPlugin extends Plugin { } build() { - this.listEntries().forEach(e => { - let fileName = path.resolve(e.basePath, e.relativePath); + this.listFiles().forEach(fileName => { this.compile(fileName, this.inputPaths[0], this.outputPath); }); } compile(fileName, inputPath, outputPath) { - let sassOptions = { - file: path.normalize(fileName), - includePaths: this.inputPaths - }; + const outSourceName = fileName.replace(inputPath, outputPath); + const outFileName = outSourceName.replace(/\.s[ac]ss$/, '.css'); - let result = sass.renderSync(sassOptions); - let filePath = fileName.replace(inputPath, outputPath).replace(/\.s[ac]ss$/, '.css'); + // We overwrite file, outFile and include the file path for the includePath. + // We also make sure the options don't include a data field. + const sassOptions = Object.assign(this.options, { + data: null, + file: fileName, + outFile: outFileName, + includePaths: [inputPath].concat(this.options.includePaths || []) + }); - fse.outputFileSync(filePath, result.css, 'utf8'); + const result = sass.renderSync(sassOptions); + fse.outputFileSync(outFileName, result.css, 'utf-8'); } } -exports.makeBroccoliTree = (sourceDir) => { +exports.makeBroccoliTree = (sourceDir, options) => { + options = options || {}; + // include sass support only if compass-importer is not installed let compass = requireOrNull('compass-importer'); if (!compass) { @@ -56,6 +61,6 @@ exports.makeBroccoliTree = (sourceDir) => { allowEmpty: true }); - return new SASSPlugin([sassSrcTree]); + return new SASSPlugin([sassSrcTree], options); } }; diff --git a/lib/broccoli/angular-broccoli-stylus.js b/lib/broccoli/angular-broccoli-stylus.js index d7ee8e99bc99..f867eb19a9b5 100644 --- a/lib/broccoli/angular-broccoli-stylus.js +++ b/lib/broccoli/angular-broccoli-stylus.js @@ -34,20 +34,24 @@ class StylusPlugin extends Plugin { compile(fileName, inputPath, outputPath) { let content = fs.readFileSync(fileName, 'utf8'); - return stylus.render(content, { filename: path.basename(fileName) }, function(err, css) { + const options = Object.assign(this.options, { + filename: path.basename(fileName) + }); + + return stylus.render(content, options, function(err, css) { let filePath = fileName.replace(inputPath, outputPath).replace(/\.styl$/, '.css'); fse.outputFileSync(filePath, css, 'utf8'); }); } } -exports.makeBroccoliTree = (sourceDir) => { +exports.makeBroccoliTree = (sourceDir, options) => { if (stylus) { let stylusSrcTree = new Funnel(sourceDir, { include: ['**/*.styl'], allowEmpty: true }); - return new StylusPlugin([stylusSrcTree]); + return new StylusPlugin([stylusSrcTree], options); } }; diff --git a/lib/broccoli/angular2-app.js b/lib/broccoli/angular2-app.js index 9a1d7dece0ef..604463ac1805 100644 --- a/lib/broccoli/angular2-app.js +++ b/lib/broccoli/angular2-app.js @@ -1,336 +1,344 @@ -var path = require('path'); -var isProduction = require('./is-production'); -var configReplace = require('./broccoli-config-replace'); -var compileWithTypescript = require('./broccoli-typescript'); -var SwManifest = require('./service-worker-manifest').default; -var fs = require('fs'); -var Funnel = require('broccoli-funnel'); -var mergeTrees = require('broccoli-merge-trees'); -var uglify = require('broccoli-uglify-js'); -var Project = require('ember-cli/lib/models/project'); -var sourceDir = 'src/client'; - -module.exports = Angular2App; - -function Angular2App(defaults, options) { - this._initProject(); - this._notifyAddonIncluded(); - this.options = options || {}; -} - -/** - * Create and return the app build system tree that: - * - Get the `assets` tree - * - Get the TS tree - * - Get the TS src tree - * - Get the index.html tree - * - Get the NPM modules tree - * - Apply/remove stuff based on the environment (dev|prod) - * - Return the app trees to be extended - * - * @public - * @method toTree - * @return {Array} The app trees that can be used to extend the build. - */ -Angular2App.prototype.toTree = function () { - var assetTree = this._getAssetsTree(); - var tsTree = this._getTsTree(); - var indexTree = this._getIndexTree(); - var vendorNpmTree = this._getVendorNpmTree(); - var excludeDotfilesTree = this._getPublicTree(); - - var buildTrees = [assetTree, tsTree, indexTree, vendorNpmTree]; - - if (fs.existsSync('public')) { - buildTrees.push(excludeDotfilesTree); +'use strict'; +const path = require('path'); +const isProduction = require('./is-production'); +const configReplace = require('./broccoli-config-replace'); +const compileWithTypescript = require('./broccoli-typescript'); +const SwManifest = require('./service-worker-manifest').default; +const fs = require('fs'); +const Funnel = require('broccoli-funnel'); +const mergeTrees = require('broccoli-merge-trees'); +const uglify = require('broccoli-uglify-js'); +const Project = require('ember-cli/lib/models/project'); + + +class Angular2App { + constructor(defaults, options) { + options = options || {}; + + this._options = options; + this._sourceDir = options.sourceDir || 'src/client'; + this._destDir = options._destDir || ''; + + this._initProject(); + this._notifyAddonIncluded(); } - buildTrees = buildTrees.concat( - require('./angular-broccoli-sass').makeBroccoliTree(sourceDir), - require('./angular-broccoli-less').makeBroccoliTree(sourceDir), - require('./angular-broccoli-stylus').makeBroccoliTree(sourceDir), - require('./angular-broccoli-compass').makeBroccoliTree(sourceDir) - ).filter(x => !!x); - - var merged = mergeTrees(buildTrees, { overwrite: true }); - - return mergeTrees([merged, new SwManifest([merged])]); -}; + /** + * Create and return the app build system tree that: + * - Get the `assets` tree + * - Get the TS tree + * - Get the TS src tree + * - Get the index.html tree + * - Get the NPM modules tree + * - Apply/remove stuff based on the environment (dev|prod) + * - Return the app trees to be extended + * + * @public + * @method toTree + * @return {Array} The app trees that can be used to extend the build. + */ + toTree() { + var assetTree = this._getAssetsTree(); + var tsTree = this._getTsTree(); + var indexTree = this._getIndexTree(); + var vendorNpmTree = this._getVendorNpmTree(); + var excludeDotfilesTree = this._getPublicTree(); + + var buildTrees = [assetTree, tsTree, indexTree, vendorNpmTree]; + + if (fs.existsSync('public')) { + buildTrees.push(excludeDotfilesTree); + } + buildTrees = buildTrees.concat( + require('./angular-broccoli-sass').makeBroccoliTree(this._sourceDir, + this._options.sassCompiler), + require('./angular-broccoli-less').makeBroccoliTree(this._sourceDir, + this._options.lessCompiler), + require('./angular-broccoli-stylus').makeBroccoliTree(this._sourceDir, + this._options.stylusCompiler), + require('./angular-broccoli-compass').makeBroccoliTree(this._sourceDir, + this._options.compassCompiler) + ).filter(x => !!x); + + var merged = mergeTrees(buildTrees, { overwrite: true }); + return new Funnel(mergeTrees([merged, new SwManifest([merged])]), { + destDir: this._destDir + }); + } -/** - * @private - * @method _initProject - * @param {Object} options - */ -Angular2App.prototype._initProject = function () { - this.project = Project.closestSync(process.cwd()); - // project root dir env used on angular-cli side for including packages from project - process.env.PROJECT_ROOT = process.env.PROJECT_ROOT || this.project.root; -}; + /** + * @private + * @method _initProject + * @param {Object} options + */ + _initProject() { + this.project = Project.closestSync(process.cwd()); -/** - * @private - * @method _notifyAddonIncluded - */ -Angular2App.prototype._notifyAddonIncluded = function () { - this.initializeAddons(); - this.project.addons = this.project.addons.filter(function (addon) { - addon.app = this; + // project root dir env used on angular-cli side for including packages from project + process.env.PROJECT_ROOT = process.env.PROJECT_ROOT || this.project.root; + } - if (!addon.isEnabled || addon.isEnabled()) { - if (addon.included) { - addon.included(this); + /** + * @private + * @method _notifyAddonIncluded + */ + _notifyAddonIncluded() { + this.initializeAddons(); + this.project.addons = this.project.addons.filter(function (addon) { + addon.app = this; + + if (!addon.isEnabled || addon.isEnabled()) { + if (addon.included) { + addon.included(this); + } + + return addon; } + }, this); + } - return addon; - } - }, this); -}; - - -/** - * Loads and initializes addons for this project. - * Calls initializeAddons on the Project. - * - * @private - * @method initializeAddons - */ -Angular2App.prototype.initializeAddons = function () { - this.project.initializeAddons(); -}; - + /** + * Loads and initializes addons for this project. + * Calls initializeAddons on the Project. + * + * @private + * @method initializeAddons + */ + initializeAddons() { + this.project.initializeAddons(); + } -/** - * Returns the content for a specific type (section) for index.html. - * - * Currently supported types: - * - 'head' - * //- 'config-module' - * //- 'app' - * //- 'head-footer' - * //- 'test-header-footer' - * //- 'body-footer' - * //- 'test-body-footer' - * - * Addons can also implement this method and could also define additional - * types (eg. 'some-addon-section'). - * - * @private - * @method _contentFor - * @param {RegExP} match Regular expression to match against - * @param {String} type Type of content - * @return {String} The content. - */ -Angular2App.prototype._contentFor = function (match, type) { - var content = []; + /** + * Returns the content for a specific type (section) for index.html. + * + * Currently supported types: + * - 'head' + * //- 'config-module' + * //- 'app' + * //- 'head-footer' + * //- 'test-header-footer' + * //- 'body-footer' + * //- 'test-body-footer' + * + * Addons can also implement this method and could also define additional + * types (eg. 'some-addon-section'). + * + * @private + * @method _contentFor + * @param {RegExP} match Regular expression to match against + * @param {String} type Type of content + * @return {String} The content. + */ + _contentFor(match, type) { + var content = []; + + /*switch (type) { + case 'head': this._contentForHead(content, config); break; + case 'config-module': this._contentForConfigModule(content, config); break; + case 'app-boot': this._contentForAppBoot(content, config); break; + }*/ + + content = this.project.addons.reduce(function (content, addon) { + var addonContent = addon.contentFor ? addon.contentFor(type) : null; + if (addonContent) { + return content.concat(addonContent); + } + + return content; + }, content); + + + return content.join('\n'); + } + + /** + * @private + * @method _getReplacePatterns + * @return Array Replace patterns. + */ + _getReplacePatterns() { + return [{ + match: /\{\{content-for ['"](.+)["']\}\}/g, + replacement: isProduction ? '' : this._contentFor.bind(this) + }]; + } - /*switch (type) { - case 'head': this._contentForHead(content, config); break; - case 'config-module': this._contentForConfigModule(content, config); break; - case 'app-boot': this._contentForAppBoot(content, config); break; - }*/ + /** + * Returns the tree for app/index.html. + * + * @private + * @method _getIndexTree + * @return {Tree} Tree for app/index.html. + */ + _getIndexTree() { + var htmlName = 'index.html'; + var files = [ + 'index.html' + ]; + + var index = new Funnel(this._sourceDir, { + files: files, + description: 'Funnel: index.html' + }); + + + return configReplace(index, { + files: [htmlName], + patterns: this._getReplacePatterns() + }); + } + + /** + * Returns the source root dir tree. + * + * @private + * @method _getSourceTree + * @return {Tree} Tree for the src dir. + */ + _getSourceTree() { + return new Funnel(this._sourceDir, { + include: ['*.ts', '**/*.ts', '**/*.d.ts'], + destDir: this._sourceDir + }); + } - content = this.project.addons.reduce(function (content, addon) { - var addonContent = addon.contentFor ? addon.contentFor(type) : null; - if (addonContent) { - return content.concat(addonContent); + /** + * Returns the typings tree. + * + * @private + * @method _getTypingsTree + * @return {Tree} Tree for the src dir. + */ + _getTypingsTree() { + return new Funnel('typings', { + include: ['browser.d.ts', 'browser/**'], + destDir: 'typings' + }); + } + + /** + * Returns the TS tree. + * + * @private + * @method _getTsTree + * @return {Tree} Tree for TypeScript files. + */ + _getTsTree() { + var typingsTree = this._getTypingsTree(); + var sourceTree = this._getSourceTree(); + + var tsConfigPath = path.join(this._sourceDir, 'tsconfig.json'); + var tsconfig = JSON.parse(fs.readFileSync(tsConfigPath, 'utf-8')); + + var sourceDir = this._sourceDir; + // Add all spec files to files. We need this because spec files are their own entry + // point. + fs.readdirSync(sourceDir).forEach(function addPathRecursive(name) { + const filePath = path.join(sourceDir, name); + if (filePath.match(/\.spec\.[jt]s$/)) { + tsconfig.files.push(name); + } else if (fs.statSync(filePath).isDirectory()) { + // Recursively call this function with the full sub-path. + fs.readdirSync(filePath).forEach(function (n) { + addPathRecursive(path.join(name, n)); + }); + } + }); + + // Because the tsconfig does not include the source directory, add this as the first path + // element. + tsconfig.files = tsconfig.files.map(name => path.join(this._sourceDir, name)); + + var srcAndTypingsTree = mergeTrees([sourceTree, typingsTree]); + var tsTree = new compileWithTypescript(srcAndTypingsTree, tsconfig); + + var tsTreeExcludes = ['*.d.ts', 'tsconfig.json']; + var excludeSpecFiles = '**/*.spec.*'; + + if (isProduction) { + tsTreeExcludes.push(excludeSpecFiles); + tsTree = uglify(tsTree); } + + tsTree = new Funnel(tsTree, { + srcDir: this._sourceDir, + exclude: tsTreeExcludes + }); + + return tsTree; + } - return content; - }, content); - - - return content.join('\n'); -}; - - -/** - * @private - * @method _getReplacePatterns - * @return Array Replace patterns. - */ -Angular2App.prototype._getReplacePatterns = function () { - return [{ - match: /\{\{content-for ['"](.+)["']\}\}/g, - replacement: isProduction ? '' : this._contentFor.bind(this) - }]; -}; - - -/** - * Returns the tree for app/index.html. - * - * @private - * @method _getIndexTree - * @return {Tree} Tree for app/index.html. - */ -Angular2App.prototype._getIndexTree = function () { - var htmlName = 'index.html'; - var files = [ - 'index.html' - ]; - - var index = new Funnel('src/client', { - files: files, - description: 'Funnel: index.html' - }); - - - return configReplace(index, { - files: [htmlName], - patterns: this._getReplacePatterns() - }); -}; - - -/** - * Returns the source root dir tree. - * - * @private - * @method _getSourceTree - * @return {Tree} Tree for the src dir. - */ -Angular2App.prototype._getSourceTree = function () { - return new Funnel('src/client', { - include: ['*.ts', '**/*.ts', '**/*.d.ts'], - destDir: 'src/client' - }); -}; - - -/** - * Returns the typings tree. - * - * @private - * @method _getTypingsTree - * @return {Tree} Tree for the src dir. - */ -Angular2App.prototype._getTypingsTree = function () { - return new Funnel('typings', { - include: ['browser.d.ts', 'browser/**'], - destDir: 'typings' - }); -}; - - -/** - * Returns the TS tree. - * - * @private - * @method _getTsTree - * @return {Tree} Tree for TypeScript files. - */ -Angular2App.prototype._getTsTree = function () { - var typingsTree = this._getTypingsTree(); - var sourceTree = this._getSourceTree(); - var tsconfig = JSON.parse(fs.readFileSync('src/client/tsconfig.json', 'utf-8')); - // Add all spec files to files. We need this because spec files are their own entry - // point. - fs.readdirSync(sourceDir).forEach(function addPathRecursive(name) { - const filePath = path.join(sourceDir, name); - if (filePath.match(/\.spec\.[jt]s$/)) { - tsconfig.files.push(name); - } else if (fs.statSync(filePath).isDirectory()) { - // Recursively call this function with the full sub-path. - fs.readdirSync(filePath).forEach(function (n) { - addPathRecursive(path.join(name, n)); - }); + /** + * Returns the `vendorNpm` tree by merging the CLI dependencies plus the ones + * passed by the user. + * + * @private + * @method _getVendorNpmTree + * @return {Tree} The NPM tree. + */ + _getVendorNpmTree() { + var vendorNpmFiles = [ + 'systemjs/dist/system-polyfills.js', + 'systemjs/dist/system.src.js', + 'es6-shim/es6-shim.js', + 'angular2/bundles/angular2-polyfills.js', + 'rxjs/bundles/Rx.js', + 'angular2/bundles/angular2.dev.js', + 'angular2/bundles/http.dev.js', + 'angular2/bundles/router.dev.js', + 'angular2/bundles/upgrade.dev.js' + ]; + + if (this._options.vendorNpmFiles) { + vendorNpmFiles = vendorNpmFiles.concat(this._options.vendorNpmFiles); } - }); - - // Because the tsconfig does not include the source directory, add this as the first path - // element. - tsconfig.files = tsconfig.files.map(name => path.join(sourceDir, name)); - - var srcAndTypingsTree = mergeTrees([sourceTree, typingsTree]); - var tsTree = new compileWithTypescript(srcAndTypingsTree, tsconfig); - - var tsTreeExcludes = ['*.d.ts', 'tsconfig.json']; - var excludeSpecFiles = '**/*.spec.*'; - - if (isProduction) { - tsTreeExcludes.push(excludeSpecFiles); - tsTree = uglify(tsTree); + + var vendorNpmTree = new Funnel('node_modules', { + include: vendorNpmFiles, + destDir: 'vendor' + }); + + return vendorNpmTree; } - - tsTree = new Funnel(tsTree, { - srcDir: 'src/client', - exclude: tsTreeExcludes - }); - - return tsTree; -}; - - -/** - * Returns the `vendorNpm` tree by merging the CLI dependencies plus the ones - * passed by the user. - * - * @private - * @method _getVendorNpmTree - * @return {Tree} The NPM tree. - */ -Angular2App.prototype._getVendorNpmTree = function () { - var vendorNpmFiles = [ - 'systemjs/dist/system-polyfills.js', - 'systemjs/dist/system.src.js', - 'es6-shim/es6-shim.js', - 'angular2/bundles/angular2-polyfills.js', - 'rxjs/bundles/Rx.js', - 'angular2/bundles/angular2.dev.js', - 'angular2/bundles/http.dev.js', - 'angular2/bundles/router.dev.js', - 'angular2/bundles/upgrade.dev.js' - ]; - - if (this.options.vendorNpmFiles) { - vendorNpmFiles = vendorNpmFiles.concat(this.options.vendorNpmFiles); + + /** + * Returns the `assets` tree. + * + * @private + * @method _getAssetsTree + * @return {Tree} The assets tree. + */ + _getAssetsTree() { + return new Funnel(this._sourceDir, { + include: ['**/*.*'], + exclude: [ + '**/*.ts', + '**/*.js', + '**/*.scss', + '**/*.sass', + '**/*.less', + '**/*.styl' + ], + allowEmpty: true + }); } - var vendorNpmTree = new Funnel('node_modules', { - include: vendorNpmFiles, - destDir: 'vendor' - }); - - return vendorNpmTree; -}; - - -/** - * Returns the `assets` tree. - * - * @private - * @method _getAssetsTree - * @return {Tree} The assets tree. - */ -Angular2App.prototype._getAssetsTree = function () { - return new Funnel(sourceDir, { - include: ['**/*.*'], - exclude: [ - '**/*.ts', - '**/*.js', - '**/*.scss', - '**/*.sass', - '**/*.less', - '**/*.styl' - ], - allowEmpty: true - }); -}; + /** + * Returns the `excludeDotfiles` tree. + * + * @private + * @method _getPublicTree + * @return {Tree} The dotfiles exclusion tree. + */ + _getPublicTree() { + return new Funnel('public', { + exclude: ['**/.*'], + allowEmpty: true + }); + } +} -/** - * Returns the `excludeDotfiles` tree. - * - * @private - * @method _getPublicTree - * @return {Tree} The dotfiles exclusion tree. - */ -Angular2App.prototype._getPublicTree = function () { - return new Funnel('public', { - exclude: ['**/.*'], - allowEmpty: true - }); -}; +module.exports = Angular2App;