Skip to content

Commit d81e4b1

Browse files
committed
feature: now use Handlebars for building the index.html. (angular#712)
1 parent 7ba388d commit d81e4b1

File tree

7 files changed

+108
-104
lines changed

7 files changed

+108
-104
lines changed

addon/ng2/blueprints/ng2/files/__path__/index.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
<meta charset="utf-8">
55
<title><%= jsComponentName %></title>
66
<base href="/">
7-
{{content-for 'head'}}
7+
8+
{{#unless environment.production}}
9+
<script src="/angular-cli-live-reload.js" type="text/javascript"></script>
10+
{{/unless}}
811
<link rel="icon" type="image/x-icon" href="favicon.ico"><% if (isMobile) { %>
912
<link rel="manifest" href="/manifest.webapp"><% } %>
1013
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -24,10 +27,7 @@
2427
<body>
2528
<<%= htmlComponentName %>-app>Loading...</<%= htmlComponentName %>-app>
2629

27-
<script src="vendor/es6-shim/es6-shim.js"></script>
28-
<script src="vendor/reflect-metadata/Reflect.js"></script>
29-
<script src="vendor/systemjs/dist/system.src.js"></script>
30-
<script src="vendor/zone.js/dist/zone.js"></script>
30+
{{#each scripts.polyfills}}<script src="{{.}}"></script>{{/each}}
3131

3232
<script>
3333
System.import('system-config.js').then(function () {

lib/broccoli/angular2-app.js

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,34 @@
22
const path = require('path');
33
const fs = require('fs');
44

5-
const isProduction = require('./is-production');
65
const BroccoliPlugin = require('broccoli-writer');
7-
const BroccoliConfigReplace = require('./broccoli-config-replace');
86
const BroccoliTypescript = require('./broccoli-typescript');
97
const BundlePlugin = require('./angular-broccoli-bundle');
108
const BroccoliFunnel = require('broccoli-funnel');
119
const BroccoliMergeTrees = require('broccoli-merge-trees');
1210
const BroccoliSource = require('broccoli-source');
1311
const UnwatchedDir = BroccoliSource.UnwatchedDir;
1412
const Project = require('ember-cli/lib/models/project');
13+
const HandlebarReplace = require('./broccoli-handlebars');
1514
const config = require('../../addon/ng2/models/config');
15+
const loadEnvironment = require('./environment');
1616

1717
class Angular2App extends BroccoliPlugin {
1818
constructor(project, inputNode, options) {
19-
const ngConfig = config.CliConfig.fromProject();
19+
super();
20+
this.ngConfig = config.CliConfig.fromProject();
2021

2122
if (!options) {
2223
options = inputNode;
2324
inputNode = null;
2425
}
2526

26-
super();
2727
options = options || {};
2828

2929
this._options = options;
3030
this._sourceDir = options.sourceDir
31-
|| (ngConfig.defaults && ngConfig.defaults.sourceDir)
31+
|| (this.ngConfig.defaults && this.ngConfig.defaults.sourceDir)
3232
|| 'src';
33-
this._inputNode = inputNode || this._buildInputTree();
3433
this._destDir = options.destDir || '';
3534

3635
// By default, add all spec files to the tsCompiler.
@@ -40,6 +39,7 @@ class Angular2App extends BroccoliPlugin {
4039

4140
this._initProject();
4241
this._notifyAddonIncluded();
42+
this._inputNode = inputNode || this._buildInputTree();
4343

4444
this._tree = this._buildTree();
4545
}
@@ -135,7 +135,7 @@ class Angular2App extends BroccoliPlugin {
135135

136136
var merged = new BroccoliMergeTrees(buildTrees, { overwrite: true });
137137

138-
if (isProduction) {
138+
if (loadEnvironment(this.project).production) {
139139
merged = this._getBundleTree(merged);
140140
}
141141

@@ -216,7 +216,6 @@ class Angular2App extends BroccoliPlugin {
216216
case 'config-module': this._contentForConfigModule(content, config); break;
217217
case 'app-boot': this._contentForAppBoot(content, config); break;
218218
}*/
219-
220219
content = this.project.addons.reduce(function (content, addon) {
221220
var addonContent = addon.contentFor ? addon.contentFor(type) : null;
222221
if (addonContent) {
@@ -226,22 +225,9 @@ class Angular2App extends BroccoliPlugin {
226225
return content;
227226
}, content);
228227

229-
230228
return content.join('\n');
231229
}
232230

233-
/**
234-
* @private
235-
* @method _getReplacePatterns
236-
* @return Array<Pattern> Replace patterns.
237-
*/
238-
_getReplacePatterns() {
239-
return [{
240-
match: /\{\{content-for ['"](.+)["']\}\}/g,
241-
replacement: isProduction ? '' : this._contentFor.bind(this)
242-
}];
243-
}
244-
245231
/**
246232
* Returns the tree for app/index.html.
247233
*
@@ -264,9 +250,26 @@ class Angular2App extends BroccoliPlugin {
264250
}
265251
});
266252

267-
return BroccoliConfigReplace(indexTree, {
268-
files: files,
269-
patterns: this._getReplacePatterns()
253+
return new HandlebarReplace(indexTree, {
254+
config: this.ngConfig,
255+
environment: loadEnvironment(this.project),
256+
scripts: {
257+
polyfills: this._options.polyfills || [
258+
'vendor/es6-shim/es6-shim.js',
259+
'vendor/reflect-metadata/Reflect.js',
260+
'vendor/systemjs/dist/system.src.js',
261+
'vendor/zone.js/dist/zone.js'
262+
]
263+
}
264+
}, {
265+
helpers: {
266+
'content-for': (name) => {
267+
// TODO: remove content-for.
268+
// eslint-disable-next-line no-console
269+
console.warn('"{{content-for}}" has been deprecated and will be removed before RC.');
270+
return this._contentFor(null, name);
271+
}
272+
}
270273
});
271274
}
272275

@@ -284,7 +287,7 @@ class Angular2App extends BroccoliPlugin {
284287
var tsTreeExcludes = ['*.d.ts', 'tsconfig.json'];
285288
var excludeSpecFiles = '**/*.spec.*';
286289

287-
if (isProduction) {
290+
if (loadEnvironment(this.project).production) {
288291
tsTreeExcludes.push(excludeSpecFiles);
289292
}
290293

@@ -350,6 +353,7 @@ class Angular2App extends BroccoliPlugin {
350353
* @return {Tree} The config files tree.
351354
*/
352355
_getConfigTree() {
356+
const isProduction = loadEnvironment(this.project).production;
353357
var envConfigFile = isProduction ? 'environment.prod.ts' : 'environment.dev.ts';
354358

355359
return new BroccoliFunnel('config', {

lib/broccoli/broccoli-config-replace.js

Lines changed: 0 additions & 71 deletions
This file was deleted.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
const fs = require('fs-extra');
4+
const path = require('path');
5+
const BroccoliCacheWriter = require('broccoli-caching-writer');
6+
const Handlebars = require('handlebars');
7+
8+
9+
class HandlebarReplace extends BroccoliCacheWriter {
10+
constructor(inputTree, context, options) {
11+
super([inputTree], options);
12+
if (options && options.helpers) {
13+
Object.keys(options.helpers).forEach((helperName) => {
14+
Handlebars.registerHelper(helperName, function() {
15+
const result = options.helpers[helperName].apply(null, arguments);
16+
return new Handlebars.SafeString(result);
17+
});
18+
})
19+
}
20+
this._context = context;
21+
}
22+
23+
build() {
24+
this.listFiles().forEach((filePath) => {
25+
const destPath = filePath.replace(this.inputPaths[0], this.outputPath);
26+
const content = fs.readFileSync(filePath, 'utf-8');
27+
const template = Handlebars.compile(content);
28+
29+
if (!fs.existsSync(path.dirname(destPath))) {
30+
fs.mkdirsSync(path.dirname(destPath));
31+
}
32+
fs.writeFileSync(destPath, template(this._context), 'utf-8');
33+
});
34+
}
35+
}
36+
37+
module.exports = HandlebarReplace;

lib/broccoli/environment.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
// Load the environment file defined by the EMBER_ENV environment variable.
3+
const fs = require('fs');
4+
const path = require('path');
5+
const ts = require('typescript');
6+
7+
8+
// Export the content of the transpiled file.
9+
module.exports = function loadEnvironment(project, environment) {
10+
let env = environment || process.env['EMBER_ENV'] || 'dev';
11+
switch (env) {
12+
case 'production': env = 'prod'; break;
13+
case 'development': env = 'dev'; break;
14+
}
15+
16+
// Load the content of the environment file.
17+
const filePath = path.join(project.root, `config/environment.${env}.ts`);
18+
const source = fs.readFileSync(filePath, 'utf-8');
19+
const result = ts.transpile(source, {
20+
target: ts.ScriptTarget.ES5,
21+
module: ts.ModuleKind.CommonJs
22+
});
23+
24+
const Module = module.constructor;
25+
const m = new Module();
26+
m._compile(result, filePath);
27+
return m.exports.environment;
28+
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"exit": "^0.1.2",
4444
"fs-extra": "^0.30.0",
4545
"glob": "^7.0.3",
46+
"handlebars": "^4.0.5",
4647
"leek": "0.0.21",
4748
"lodash": "^4.11.1",
4849
"opn": "4.0.1",

tests/e2e/e2e_workflow.spec.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,20 @@ describe('Basic end-to-end Workflow', function () {
7676
this.timeout(420000);
7777

7878
return ng(['build', '--silent'])
79+
.catch(() => {
80+
throw new Error('Build failed.');
81+
})
7982
.then(function () {
8083
expect(existsSync(path.join(process.cwd(), 'dist'))).to.be.equal(true);
84+
85+
// Check the index.html to have no handlebar tokens in it.
86+
const indexHtml = fs.readFileSync(path.join(process.cwd(), 'dist/index.html'), 'utf-8');
87+
expect(indexHtml).to.not.include('{{');
88+
expect(indexHtml).to.include('vendor/es6-shim/es6-shim.js');
8189
})
8290
.then(function () {
8391
// Also does not create new things in GIT.
8492
expect(sh.exec('git status --porcelain').output).to.be.equal(undefined);
85-
})
86-
.catch(() => {
87-
throw new Error('Build failed.');
8893
});
8994
});
9095

0 commit comments

Comments
 (0)