From 372354fa03afaa7aababd3e98420ef121f5bbe75 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Fri, 8 Apr 2016 17:24:10 +0100 Subject: [PATCH] feat(prod-build): add environment config --- README.md | 9 +++ .../ng2/files/config/environment.dev.ts | 3 + .../ng2/files/config/environment.prod.ts | 3 + .../blueprints/ng2/files/src/client/app.ts | 8 ++- .../ng2/files/src/client/app/environment.ts | 7 ++ lib/broccoli/angular2-app.js | 64 ++++++++++++------- tests/e2e/e2e_workflow.spec.js | 32 +++++----- 7 files changed, 85 insertions(+), 41 deletions(-) create mode 100644 addon/ng2/blueprints/ng2/files/config/environment.dev.ts create mode 100644 addon/ng2/blueprints/ng2/files/config/environment.prod.ts create mode 100644 addon/ng2/blueprints/ng2/files/src/client/app/environment.ts diff --git a/README.md b/README.md index 4b3921d59ffe..befa45fe8fdc 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,15 @@ ng build The build artifacts will be stored in the `dist/` directory. +### Environments + +At build time, the `src/client/app/environment.ts` will be replaced by either +`config/environment.dev.ts` or `config/environment.prod.ts`, depending on the +current cli environment. + +Environment defaults to `dev`, but you can generate a production build via +the `-prod` flag in either `ng build -prod` or `ng serve -prod`. + ### Running unit tests ```bash diff --git a/addon/ng2/blueprints/ng2/files/config/environment.dev.ts b/addon/ng2/blueprints/ng2/files/config/environment.dev.ts new file mode 100644 index 000000000000..ffe8aed76642 --- /dev/null +++ b/addon/ng2/blueprints/ng2/files/config/environment.dev.ts @@ -0,0 +1,3 @@ +export const environment = { + production: false +}; diff --git a/addon/ng2/blueprints/ng2/files/config/environment.prod.ts b/addon/ng2/blueprints/ng2/files/config/environment.prod.ts new file mode 100644 index 000000000000..3612073bc31c --- /dev/null +++ b/addon/ng2/blueprints/ng2/files/config/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/addon/ng2/blueprints/ng2/files/src/client/app.ts b/addon/ng2/blueprints/ng2/files/src/client/app.ts index 243090f41d12..eae710d422f5 100644 --- a/addon/ng2/blueprints/ng2/files/src/client/app.ts +++ b/addon/ng2/blueprints/ng2/files/src/client/app.ts @@ -1,4 +1,10 @@ import {bootstrap} from 'angular2/platform/browser'; +import {enableProdMode} from 'angular2/core'; +import {environment} from './app/environment'; import {<%= jsComponentName %>App} from './app/<%= htmlComponentName %>'; -bootstrap(<%= jsComponentName %>App, []); +if (environment.production) { + enableProdMode(); +} + +bootstrap(<%= jsComponentName %>App); diff --git a/addon/ng2/blueprints/ng2/files/src/client/app/environment.ts b/addon/ng2/blueprints/ng2/files/src/client/app/environment.ts new file mode 100644 index 000000000000..79ee96fdfdbd --- /dev/null +++ b/addon/ng2/blueprints/ng2/files/src/client/app/environment.ts @@ -0,0 +1,7 @@ +// The file for the current environment will overwrite this one during build +// Different environments can be found in config/environment.{dev|prod}.ts +// The build system defaults to the dev environment + +export const environment = { + production: false +}; diff --git a/lib/broccoli/angular2-app.js b/lib/broccoli/angular2-app.js index 2f6d50d34b5f..67ac87e24dff 100644 --- a/lib/broccoli/angular2-app.js +++ b/lib/broccoli/angular2-app.js @@ -94,12 +94,12 @@ class Angular2App { 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); @@ -139,7 +139,7 @@ class Angular2App { */ _contentFor(match, type) { var content = []; - + /*switch (type) { case 'head': this._contentForHead(content, config); break; case 'config-module': this._contentForConfigModule(content, config); break; @@ -151,14 +151,14 @@ class Angular2App { if (addonContent) { return content.concat(addonContent); } - + return content; }, content); - - + + return content.join('\n'); } - + /** * @private * @method _getReplacePatterns @@ -183,19 +183,19 @@ class Angular2App { 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. * @@ -223,7 +223,7 @@ class Angular2App { destDir: 'typings' }); } - + /** * Returns the TS tree. * @@ -234,6 +234,7 @@ class Angular2App { _getTsTree() { var typingsTree = this._getTypingsTree(); var sourceTree = this._getSourceTree(); + var configTree = this._getConfigTree(); var tsConfigPath = path.join(this._sourceDir, 'tsconfig.json'); var tsconfig = JSON.parse(fs.readFileSync(tsConfigPath, 'utf-8')); @@ -264,23 +265,23 @@ class Angular2App { // 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 mergedTree = mergeTrees([sourceTree, typingsTree, configTree], { overwrite: true }); + var tsTree = new compileWithTypescript(mergedTree, 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; } @@ -305,19 +306,19 @@ class Angular2App { 'angular2/bundles/router.dev.js', 'angular2/bundles/upgrade.dev.js' ]; - + if (this._options.vendorNpmFiles) { vendorNpmFiles = vendorNpmFiles.concat(this._options.vendorNpmFiles); } - + var vendorNpmTree = new Funnel('node_modules', { include: vendorNpmFiles, destDir: 'vendor' }); - + return vendorNpmTree; } - + /** * Returns the `assets` tree. * @@ -353,6 +354,23 @@ class Angular2App { allowEmpty: true }); } + + /** + * Returns the config files tree. + * + * @private + * @method _getConfigTree + * @return {Tree} The config files tree. + */ + _getConfigTree() { + var envConfigFile = isProduction ? 'environment.prod.ts' : 'environment.dev.ts'; + // console.log(envConfigFile); + return new Funnel('config', { + include: [envConfigFile], + destDir: 'src/client/app', + getDestinationPath: () => 'environment.ts' + }); + } } module.exports = Angular2App; diff --git a/tests/e2e/e2e_workflow.spec.js b/tests/e2e/e2e_workflow.spec.js index d08d002562ef..13ae817ef77d 100644 --- a/tests/e2e/e2e_workflow.spec.js +++ b/tests/e2e/e2e_workflow.spec.js @@ -57,26 +57,24 @@ describe('Basic end-to-end Workflow', function () { expect(path.basename(process.cwd())).to.equal('test-project'); }); - it('Can run `ng build` in created project', function () { + it('Supports production builds via `ng build --environment=production`', function() { this.timeout(420000); - return ng(['build', '--silent']) - .then(function () { - expect(existsSync(path.join(process.cwd(), 'dist'))).to.be.equal(true); - }) - .then(function () { - // Also does not create new things in GIT. - expect(sh.exec('git status --porcelain').output).to.be.equal(''); - }) - .catch(() => { - throw new Error('Build failed.'); - }); + // Can't user the `ng` helper because somewhere the environment gets + // stuck to the first build done + sh.exec('./node_modules/.bin/ng build --environment=production --silent'); + expect(existsSync(path.join(process.cwd(), 'dist'))).to.be.equal(true); + var envPath = path.join(process.cwd(), 'dist', 'app', 'environment.js'); + var envContent = fs.readFileSync(envPath, { encoding: 'utf8' }); + expect(envContent).to.include('production:true'); + // Also does not create new things in GIT. + expect(sh.exec('git status --porcelain').output).to.be.equal(''); }); - it('Supports production builds via `ng build --envinroment=production`', function() { + it('Can run `ng build` in created project', function () { this.timeout(420000); - return ng(['build', '--environment=production', '--silent']) + return ng(['build', '--silent']) .then(function () { expect(existsSync(path.join(process.cwd(), 'dist'))).to.be.equal(true); }) @@ -214,7 +212,7 @@ describe('Basic end-to-end Workflow', function () { expect(existsSync(cssFile)).to.be.equal(false); let scssExample = '.outer {\n .inner { background: #fff; }\n }'; fs.writeFileSync(scssFile, scssExample, 'utf8'); - + sh.exec('ng build --silent'); let destCss = path.join(process.cwd(), 'dist', 'app', 'test-component', 'test-component.css'); expect(existsSync(destCss)).to.be.equal(true); @@ -249,7 +247,7 @@ describe('Basic end-to-end Workflow', function () { expect(existsSync(cssFile)).to.be.equal(false); let lessExample = '.outer {\n .inner { background: #fff; }\n }'; fs.writeFileSync(lessFile, lessExample, 'utf8'); - + sh.exec('ng build --silent'); let destCss = path.join(process.cwd(), 'dist', 'app', 'test-component', 'test-component.css'); expect(existsSync(destCss)).to.be.equal(true); @@ -283,7 +281,7 @@ describe('Basic end-to-end Workflow', function () { expect(existsSync(cssFile)).to.be.equal(false); let stylusExample = '.outer {\n .inner { background: #fff; }\n }'; fs.writeFileSync(stylusFile, stylusExample, 'utf8'); - + sh.exec('ng build --silent'); let destCss = path.join(process.cwd(), 'dist', 'app', 'test-component', 'test-component.css'); expect(existsSync(destCss)).to.be.equal(true);