mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-26 01:01:13 +08:00
We need to preserve the paths to be the same during build as they are in source repo, so that editor and build pipeline are aligned.
251 lines
6.5 KiB
JavaScript
251 lines
6.5 KiB
JavaScript
var path = require('path');
|
|
var Concat = require('broccoli-concat');
|
|
var configReplace = require('./broccoli-config-replace');
|
|
var compileWithTypescript = require('./broccoli-typescript').default;
|
|
var SwManifest = require('./service-worker-manifest').default;
|
|
var fs = require('fs');
|
|
var Funnel = require('broccoli-funnel');
|
|
var mergeTrees = require('broccoli-merge-trees');
|
|
var Project = require('ember-cli/lib/models/project');
|
|
|
|
module.exports = Angular2App;
|
|
|
|
function Angular2App(defaults, options, additionalPaths) {
|
|
this._initProject();
|
|
this._notifyAddonIncluded();
|
|
this.options = options;
|
|
this.additionalPaths = additionalPaths || [];
|
|
}
|
|
|
|
Angular2App.prototype.toTree = function() {
|
|
var sourceDir = 'src';
|
|
|
|
var sourceTree = new Funnel('src', {
|
|
destDir: 'src'
|
|
});
|
|
|
|
var typingsTree = new Funnel('typings', {
|
|
include: ['browser.d.ts', 'browser/**'],
|
|
destDir: 'typings'
|
|
});
|
|
|
|
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 && this.options.vendorNpmFiles) {
|
|
vendorNpmFiles = vendorNpmFiles.concat(this.options.vendorNpmFiles);
|
|
}
|
|
|
|
var tsconfig = JSON.parse(fs.readFileSync('src/tsconfig.json', 'utf-8'));
|
|
var tsConfigCompilerOptions = tsconfig.compilerOptions;
|
|
|
|
|
|
// TODO(i): why do we need these additional paths? remove?
|
|
tsConfigCompilerOptions.rootFilePaths = this.additionalPaths.map(function(name) {
|
|
return path.join(process.cwd(), sourceDir, name)
|
|
});
|
|
|
|
// TODO(i): kill rootFilePaths in broccoli-typescript and use tsconfig.json#files instead
|
|
tsConfigCompilerOptions.rootFilePaths = tsConfigCompilerOptions.rootFilePaths.
|
|
concat(tsconfig.files.map(function(p) {
|
|
// TODO(i): this is a hack - for some reason we need to prefix all paths with srcDir because
|
|
// tsc's "rootDir" doesn't take effect when resolving "files" paths
|
|
return path.join(sourceDir, p);
|
|
}));
|
|
|
|
|
|
var srcAndTypingsTree = mergeTrees([sourceTree, typingsTree]);
|
|
|
|
var tsTree = compileWithTypescript(srcAndTypingsTree, tsConfigCompilerOptions);
|
|
|
|
tsTree = new Funnel(tsTree, {
|
|
srcDir: 'src',
|
|
exclude: ['*.d.ts', 'tsconfig.json']
|
|
});
|
|
|
|
var tsSrcTree = new Funnel(sourceDir, {
|
|
include: ['**/*.ts'],
|
|
allowEmpty: true
|
|
});
|
|
|
|
var jsTree = new Funnel(sourceDir, {
|
|
include: ['**/*.js'],
|
|
allowEmpty: true
|
|
});
|
|
|
|
var assetTree = new Funnel(sourceDir, {
|
|
include: ['**/*.*'],
|
|
exclude: ['**/*.ts', '**/*.js'],
|
|
allowEmpty: true
|
|
});
|
|
|
|
var vendorNpmTree = new Funnel('node_modules', {
|
|
include: vendorNpmFiles,
|
|
destDir: 'vendor'
|
|
});
|
|
|
|
var thirdPartyJsTree = new Funnel('node_modules', {
|
|
include: ['ng2*/bundles/*.js'],
|
|
exclude: ['ng2*/bundles/*.min.js', 'ng2*/bundles/*.standalone.js'],
|
|
});
|
|
|
|
var thirdPartyJs = new Concat(thirdPartyJsTree, {
|
|
inputFiles: ['**/*.js'],
|
|
outputFile: '/thirdparty/libs.js',
|
|
allowNone: true
|
|
});
|
|
|
|
var merged = mergeTrees([
|
|
assetTree,
|
|
tsSrcTree,
|
|
tsTree,
|
|
jsTree,
|
|
this.index(),
|
|
vendorNpmTree,
|
|
thirdPartyJs
|
|
], { overwrite: true });
|
|
|
|
return mergeTrees([merged, new SwManifest(merged)]);
|
|
};
|
|
|
|
/**
|
|
@private
|
|
@method _initProject
|
|
@param {Object} options
|
|
*/
|
|
Angular2App.prototype._initProject = function() {
|
|
this.project = Project.closestSync(process.cwd());
|
|
|
|
/*if (options.configPath) {
|
|
this.project.configPath = function() { return options.configPath; };
|
|
}*/
|
|
};
|
|
|
|
/**
|
|
@private
|
|
@method _notifyAddonIncluded
|
|
*/
|
|
Angular2App.prototype._notifyAddonIncluded = function() {
|
|
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);
|
|
};
|
|
|
|
/**
|
|
Loads and initializes addons for this project.
|
|
Calls initializeAddons on the Project.
|
|
|
|
@private
|
|
@method initializeAddons
|
|
*/
|
|
Angular2App.prototype.initializeAddons = function() {
|
|
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 = [];
|
|
|
|
/*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 _configReplacePatterns
|
|
@return
|
|
*/
|
|
Angular2App.prototype._configReplacePatterns = function() {
|
|
return [/*{
|
|
match: /\{\{EMBER_ENV\}\}/g,
|
|
replacement: calculateEmberENV
|
|
}, */{
|
|
match: /\{\{content-for ['"](.+)["']\}\}/g,
|
|
replacement: this.contentFor.bind(this)
|
|
}/*, {
|
|
match: /\{\{MODULE_PREFIX\}\}/g,
|
|
replacement: calculateModulePrefix
|
|
}*/];
|
|
};
|
|
|
|
|
|
/**
|
|
Returns the tree for app/index.html
|
|
|
|
@private
|
|
@method index
|
|
@return {Tree} Tree for app/index.html
|
|
*/
|
|
Angular2App.prototype.index = function() {
|
|
var htmlName = 'index.html';
|
|
var files = [
|
|
'index.html'
|
|
];
|
|
|
|
var index = new Funnel('src', {
|
|
files: files,
|
|
description: 'Funnel: index.html'
|
|
});
|
|
|
|
|
|
return configReplace(index, {
|
|
files: [ htmlName ],
|
|
patterns: this._configReplacePatterns()
|
|
});
|
|
};
|