refactor(compiler-cli): add support for browser compiler bundle (#17979)
PR Close #17979
This commit is contained in:
parent
6279e50d78
commit
ce47546188
|
@ -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()]
|
||||||
|
}
|
|
@ -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)));
|
||||||
|
|
|
@ -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, '/');
|
||||||
|
@ -41,7 +41,7 @@ describe('ngc command-line', () => {
|
||||||
write('tsconfig-base.json', `{
|
write('tsconfig-base.json', `{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"types": [],
|
"types": [],
|
||||||
"outDir": "built",
|
"outDir": "built",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
|
@ -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');
|
||||||
|
|
Loading…
Reference in New Issue