refactor(compiler-cli): add support for browser compiler bundle (#17979)

PR Close #17979
This commit is contained in:
Abhimanyu Deora 2017-07-13 13:56:12 -07:00 committed by Miško Hevery
parent 6279e50d78
commit ce47546188
3 changed files with 112 additions and 32 deletions

View File

@ -0,0 +1,79 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import commonjs from 'rollup-plugin-commonjs';
import * as path from 'path';
import 'reflect-metadata';
var m = /^\@angular\/((\w|\-)+)(\/(\w|\d|\/|\-)+)?$/;
var location = normalize('../../dist/packages-dist') + '/';
var rxjsLocation = normalize('../../node_modules/rxjs');
var tslibLocation = normalize('../../node_modules/tslib');
var esm = 'esm/';
var locations = {
'tsc-wrapped': normalize('../../dist/tools/@angular') + '/',
'compiler-cli': normalize('../../dist/packages') + '/'
};
var esm_suffixes = {};
function normalize(fileName) {
return path.resolve(__dirname, fileName);
}
function resolve(id, from) {
// console.log('Resolve id:', id, 'from', from)
if (id == '@angular/tsc-wrapped') {
// Hack to restrict the import to not include the index of @angular/tsc-wrapped so we don't
// rollup tsickle.
return locations['tsc-wrapped'] + 'tsc-wrapped/src/collector.js';
}
var match = m.exec(id);
if (match) {
var packageName = match[1];
var esm_suffix = esm_suffixes[packageName] || '';
var loc = locations[packageName] || location;
var r = loc !== location && (loc + esm_suffix + packageName + (match[3] || '/index') + '.js') ||
loc + packageName + '/@angular/' + packageName + '.es5.js';
// console.log('** ANGULAR MAPPED **: ', r);
return r;
}
if (id && id.startsWith('rxjs/')) {
const resolved = `${rxjsLocation}${id.replace('rxjs', '')}.js`;
return resolved;
}
if (id == 'tslib') {
return tslibLocation + '/tslib.es6.js';
}
}
// hack to get around issues with default exports
var banner = `ts['default'] = ts['default'] || ts; fs['default'] = fs['default'] || fs;`;
export default {
entry: '../../dist/packages-dist/compiler-cli/src/ngc.js',
dest: './browser-bundle.umd.js',
format: 'umd',
moduleName: 'ng.compiler_cli_browser',
exports: 'named',
external: [
'fs',
'path',
'typescript',
'reflect-metadata',
],
globals: {
'typescript': 'ts',
'path': 'path',
'fs': 'fs',
},
banner: banner,
plugins: [{resolveId: resolve}, commonjs()]
}

View File

@ -122,30 +122,14 @@ function getProjectDirectory(project: string): string {
return isFile ? path.dirname(project) : project; return isFile ? path.dirname(project) : project;
} }
export function main( export function performCompilation(
args: string[], consoleError: (s: string) => void = console.error, files?: string[], basePath: string, files: string[], options: ts.CompilerOptions, ngOptions: any,
options?: ts.CompilerOptions, ngOptions?: any): number { consoleError: (s: string) => void = console.error, tsCompilerHost?: ts.CompilerHost) {
try { try {
const parsedArgs = require('minimist')(args);
const project = parsedArgs.p || parsedArgs.project || '.';
const projectDir = getProjectDirectory(project);
// file names in tsconfig are resolved relative to this absolute path
const basePath = path.resolve(process.cwd(), projectDir);
if (!files || !options || !ngOptions) {
const {parsed, ngOptions: readNgOptions} = readConfiguration(project, basePath);
if (!files) files = parsed.fileNames;
if (!options) options = parsed.options;
if (!ngOptions) ngOptions = readNgOptions;
}
// Ignore what the tsconfig.json for baseDir and genDir
ngOptions.basePath = basePath; ngOptions.basePath = basePath;
ngOptions.genDir = basePath; ngOptions.genDir = basePath;
let host = ts.createCompilerHost(options, true); let host = tsCompilerHost || ts.createCompilerHost(options, true);
host.realpath = p => p; host.realpath = p => p;
const rootFileNames = files.map(f => path.normalize(f)); const rootFileNames = files.map(f => path.normalize(f));
@ -189,18 +173,34 @@ export function main(
}); });
} catch (e) { } catch (e) {
if (isSyntaxError(e)) { if (isSyntaxError(e)) {
console.error(e.message);
consoleError(e.message); consoleError(e.message);
return 1; return 1;
} else {
consoleError(e.stack);
consoleError('Compilation failed');
return 2;
} }
} }
return 0; return 0;
} }
export function main(args: string[], consoleError: (s: string) => void = console.error): number {
try {
const parsedArgs = require('minimist')(args);
const project = parsedArgs.p || parsedArgs.project || '.';
const projectDir = fs.lstatSync(project).isFile() ? path.dirname(project) : project;
// file names in tsconfig are resolved relative to this absolute path
const basePath = path.resolve(process.cwd(), projectDir);
const {parsed, ngOptions} = readConfiguration(project, basePath);
return performCompilation(basePath, parsed.fileNames, parsed.options, ngOptions, consoleError);
} catch (e) {
consoleError(e.stack);
consoleError('Compilation failed');
return 2;
}
}
// CLI entry point // CLI entry point
if (require.main === module) { if (require.main === module) {
process.exit(main(process.argv.slice(2), s => console.error(s))); process.exit(main(process.argv.slice(2), s => console.error(s)));

View File

@ -11,7 +11,7 @@ import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as ts from 'typescript'; import * as ts from 'typescript';
import {main} from '../src/ngc'; import {main, performCompilation} from '../src/ngc';
function getNgRootDir() { function getNgRootDir() {
const moduleFilename = module.filename.replace(/\\/g, '/'); const moduleFilename = module.filename.replace(/\\/g, '/');
@ -81,8 +81,8 @@ describe('ngc command-line', () => {
spyOn(mockConsole, 'error'); spyOn(mockConsole, 'error');
const result = main( const result = performCompilation(
['-p', basePath], mockConsole.error, [path.join(basePath, 'test.ts')], { basePath, [path.join(basePath, 'test.ts')], {
experimentalDecorators: true, experimentalDecorators: true,
skipLibCheck: true, skipLibCheck: true,
types: [], types: [],
@ -91,7 +91,7 @@ describe('ngc command-line', () => {
module: ts.ModuleKind.ES2015, module: ts.ModuleKind.ES2015,
moduleResolution: ts.ModuleResolutionKind.NodeJs, moduleResolution: ts.ModuleResolutionKind.NodeJs,
}, },
{}); {}, mockConsole.error);
expect(mockConsole.error).not.toHaveBeenCalled(); expect(mockConsole.error).not.toHaveBeenCalled();
expect(result).toBe(0); expect(result).toBe(0);
}); });
@ -419,9 +419,8 @@ describe('ngc command-line', () => {
export class FlatModule { export class FlatModule {
}`); }`);
const exitCode = main( const exitCode = performCompilation(
['-p', path.join(basePath, 'tsconfig.json')], undefined, basePath, [path.join(basePath, 'public-api.ts')], {
[path.join(basePath, 'public-api.ts')], {
target: ts.ScriptTarget.ES5, target: ts.ScriptTarget.ES5,
experimentalDecorators: true, experimentalDecorators: true,
noImplicitAny: true, noImplicitAny: true,
@ -439,6 +438,8 @@ describe('ngc command-line', () => {
flatModuleOutFile: 'index.js', flatModuleOutFile: 'index.js',
skipTemplateCodegen: true skipTemplateCodegen: true
}); });
expect(exitCode).toEqual(0); expect(exitCode).toEqual(0);
shouldExist('index.js'); shouldExist('index.js');
shouldExist('index.metadata.json'); shouldExist('index.metadata.json');