Skip to content

Commit

Permalink
chore(build): add typescript to the cjs build.
Browse files Browse the repository at this point in the history
Refactor the file extension logic in traceur plugin to simplify
  • Loading branch information
alexeagle committed Apr 10, 2015
1 parent b5002fb commit f0477e1
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 55 deletions.
42 changes: 26 additions & 16 deletions Brocfile-js_cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ var Funnel = require('broccoli-funnel');
var mergeTrees = require('broccoli-merge-trees');
var stew = require('broccoli-stew');
var TraceurCompiler = require('./tools/broccoli/traceur');
var TypescriptCompiler = require('./tools/broccoli/typescript');
var renderLodashTemplate = require('broccoli-lodash');

var modulesTree = new Funnel('modules', {include: ['**/**'], exclude: ['angular2/src/core/zone/vm_turn_zone.es6']});
var modulesTree = new Funnel(
'modules', {include: ['**/**'], exclude: ['angular2/src/core/zone/vm_turn_zone.es6']});

// Use Traceur to transpile original sources to ES6
var cjsTree = new TraceurCompiler(modulesTree, '.js', {
// Use Traceur to transpile original sources to ES5
var traceurOpts = {
sourceMaps: true,
annotations: true, // parse annotations
types: true, // parse types
Expand All @@ -17,18 +19,13 @@ var cjsTree = new TraceurCompiler(modulesTree, '.js', {
// Don't use type assertions since this is partly transpiled by typescript
typeAssertions: false,
modules: 'commonjs'
}, true);

// Munge the filenames since we use an '.es6' extension
cjsTree = stew.rename(cjsTree, function(relativePath) {
return relativePath.replace(/\.(js|es6)\.map$/, '.map').replace(/\.es6$/, '.js');
});
};
var cjsTree = new TraceurCompiler(modulesTree, '.js', '.map', traceurOpts);

// Now we add a few more files to the es6 tree that Traceur should not see
// Add the LICENSE file in each module
['angular2', 'benchmarks', 'benchmarks_external', 'benchpress', 'examples', 'rtts_assert'].forEach(
function(destDir) {
var extras = new Funnel('.', {files: ['LICENSE'], destDir: destDir});
cjsTree = mergeTrees([cjsTree, extras]);
cjsTree = mergeTrees([cjsTree, new Funnel('.', {files: ['LICENSE'], destDir: destDir})]);
});

extras = new Funnel(modulesTree, {include: ['**/*.md', '**/*.png'], exclude: ['**/*.dart.md']});
Expand All @@ -53,12 +50,25 @@ var COMMON_PACKAGE_JSON = {
};

// Add a .template extension since renderLodashTemplate strips one extension
var packageJsons = stew.rename(new Funnel(modulesTree, {include: ['**/package.json']}), '.json', '.json.template');
packageJsons = renderLodashTemplate(packageJsons, {
files: ["**/**"],
context: { 'packageJson': COMMON_PACKAGE_JSON }
var packageJsons =
stew.rename(new Funnel(modulesTree, {include: ['**/package.json']}), '.json', '.json.template');
packageJsons = renderLodashTemplate(
packageJsons, {files: ["**/**"], context: {'packageJson': COMMON_PACKAGE_JSON}});

var typescriptTree = new TypescriptCompiler(modulesTree, {
target: 'ES5',
sourceMap: true,
mapRoot: '', /* force sourcemaps to use relative path */
module: /*system.js*/'commonjs',
allowNonTsExtensions: false,
typescript: require('typescript'),
//declarationFiles: true,
noEmitOnError: true,
outDir: 'angular2'
});

// For now, we just overwrite the Traceur-compiled files with their Typescript equivalent
cjsTree = mergeTrees([cjsTree, typescriptTree], { overwrite: true });
cjsTree = mergeTrees([cjsTree, extras, packageJsons]);

module.exports = stew.mv(cjsTree, 'js/cjs');
9 changes: 2 additions & 7 deletions Brocfile-js_dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var path = require('path');
var modulesTree = new Funnel('modules', {include: ['**/**'], exclude: ['**/*.cjs'], destDir: '/'});

// Use Traceur to transpile original sources to ES6
var es6DevTree = new TraceurCompiler(modulesTree, '.es6', {
var es6DevTree = new TraceurCompiler(modulesTree, '.es6', '.map', {
sourceMaps: true,
annotations: true, // parse annotations
types: true, // parse types
Expand All @@ -21,14 +21,9 @@ var es6DevTree = new TraceurCompiler(modulesTree, '.es6', {
typeAssertions: true,
outputLanguage: 'es6'
});
// Munge the filenames since we use an '.es6' extension
es6DevTree = stew.rename(es6DevTree, function(relativePath) {
return relativePath.replace(/\.(js|es6)\.map$/, '.map').replace(/\.js$/, '.es6');
});

// Call Traceur again to lower the ES6 build tree to ES5
var es5DevTree = new TraceurCompiler(es6DevTree, '.js', {modules: 'instantiate', sourceMaps: true});
es5DevTree = stew.rename(es5DevTree, '.es6.map', '.js.map');
var es5DevTree = new TraceurCompiler(es6DevTree, '.js', '.js.map', {modules: 'instantiate', sourceMaps: true});

// Now we add a few more files to the es6 tree that Traceur should not see
['angular2', 'benchmarks', 'benchmarks_external', 'benchpress', 'examples', 'rtts_assert'].forEach(
Expand Down
9 changes: 2 additions & 7 deletions Brocfile-js_prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var path = require('path');
var modulesTree = new Funnel('modules', {include: ['**/**'], destDir: '/'});

// Use Traceur to transpile original sources to ES6
var es6ProdTree = new TraceurCompiler(modulesTree, '.es6', {
var es6ProdTree = new TraceurCompiler(modulesTree, '.es6', '.map', {
sourceMaps: true,
annotations: true, // parse annotations
types: true, // parse types
Expand All @@ -21,14 +21,9 @@ var es6ProdTree = new TraceurCompiler(modulesTree, '.es6', {
typeAssertions: false,
outputLanguage: 'es6'
});
// Munge the filenames since we use an '.es6' extension
es6ProdTree = stew.rename(es6ProdTree, function(relativePath) {
return relativePath.replace(/\.(js|es6)\.map$/, '.map').replace(/\.js$/, '.es6');
});

// Call Traceur again to lower the ES6 build tree to ES5
var es5ProdTree = new TraceurCompiler(es6ProdTree, '.js', {modules: 'instantiate', sourceMaps: true});
es5ProdTree = stew.rename(es5ProdTree, '.es6.map', '.js.map');
var es5ProdTree = new TraceurCompiler(es6ProdTree, '.js', '.js.map', {modules: 'instantiate', sourceMaps: true});

// Now we add a few more files to the es6 tree that Traceur should not see
['angular2', 'benchmarks', 'benchmarks_external', 'benchpress', 'examples', 'rtts_assert'].forEach(
Expand Down
4 changes: 0 additions & 4 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -761,10 +761,6 @@ gulp.task('broccoli.js.cjs', function() {
gulp.task('build.js.cjs', function(done) {
runSequence(
'broccoli.js.cjs',
//['build/transpile.js.cjs', 'build/copy.js.cjs', 'build/multicopy.js.cjs'],
// Overwrite the .js.cjs transpilation with typescript outputs
// We still need traceur outputs everywhere else, for now.
'build/transpile.ts.cjs',
['build/linknodemodules.js.cjs'],
'build/transformCJSTests',
done
Expand Down
15 changes: 5 additions & 10 deletions tools/broccoli/traceur/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 7 additions & 11 deletions tools/broccoli/traceur/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ var Writer = require('broccoli-writer');
var xtend = require('xtend');

class TraceurFilter extends Writer {
constructor(private inputTree, private destExtension: string = '.js',
private options = {}, private hackSourceMapExtension: boolean = false) {}
static RUNTIME_PATH = traceur.RUNTIME_PATH;

constructor(private inputTree, private destExtension: string,
private destSourceMapExtension: string, private options = {}) {}

write(readTree, destDir) {
return readTree(this.inputTree)
.then(srcDir => {
Expand All @@ -29,21 +31,15 @@ class TraceurFilter extends Writer {

// TODO: we should fix the sourceMappingURL written by Traceur instead of overriding
// (but we might switch to typescript first)
var url = path.basename(filepath).replace(/\.es6$/, '') +
(this.destExtension === '.js' ? '.js.map' : '.map');
if (this.hackSourceMapExtension) {
url = path.basename(filepath).replace(/\.\w+$/, '') + '.map';
}
result.js = result.js + `\n//# sourceMappingURL=./${url}`;
var mapFilepath = filepath.replace(/\.\w+$/, '') + this.destSourceMapExtension;
result.js = result.js + `\n//# sourceMappingURL=./${path.basename(mapFilepath)}`;

var destFilepath = filepath.replace(/\.\w+$/, this.destExtension);
var destFile = path.join(destDir, destFilepath);
fse.mkdirsSync(path.dirname(destFile));
var destMap = path.join(destDir, destFilepath + '.map');


fs.writeFileSync(destFile, result.js, fsOpts);

var destMap = path.join(destDir, mapFilepath);
result.sourceMap.file = destFilepath;
fs.writeFileSync(destMap, JSON.stringify(result.sourceMap), fsOpts);
});
Expand Down
61 changes: 61 additions & 0 deletions tools/broccoli/typescript/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions tools/broccoli/typescript/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
var fs = require('fs');
var path = require('path');
var ts = require('typescript');
var walkSync = require('walk-sync');
var Writer = require('broccoli-writer');
var xtend = require('xtend');

class TSCompiler extends Writer {
constructor(private inputTree, private options = {}) { super(inputTree, options); }

write(readTree, destDir) {
var options: ts.CompilerOptions = xtend({outDir: destDir}, this.options);
if (this.options.outDir) {
options.outDir = path.resolve(destDir, options.outDir);
}
if (options.out) {
options.out = path.resolve(destDir, options.out);
}
options.target = ts.ScriptTarget[options.target];
return readTree(this.inputTree)
.then(srcDir => {
var files = walkSync(srcDir)
.filter(filepath => path.extname(filepath).toLowerCase() === '.ts')
.map(filepath => path.resolve(srcDir, filepath));

if (files.length > 0) {
var program = ts.createProgram(files, options);
var emitResult = program.emit();

var allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);

var errMsg = '';
allDiagnostics.forEach(diagnostic => {
var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
if (!diagnostic.file) {
errMsg += `\n${message}`;
return;
}
var {line, character} =
diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
errMsg += `\n${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`;
});

if (emitResult.emitSkipped) {
throw new Error(errMsg);
}
}
});
}
}
module.exports = TSCompiler;

0 comments on commit f0477e1

Please sign in to comment.