feat(ivy): find all packages to be compiled by ngcc (#25406)
PR Close #25406
This commit is contained in:
parent
68acc5b355
commit
7500f0eafb
@ -1,10 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -x
|
set -e -x
|
||||||
|
|
||||||
PATH=$PATH:$(npm bin)
|
PATH=$PATH:$(npm bin)
|
||||||
|
|
||||||
ivy-ngcc node_modules/@angular/common
|
ivy-ngcc fesm2015,esm2015
|
||||||
cp -r node_modules_ngtsc/* node_modules/
|
|
||||||
ngc -p tsconfig-app.json
|
ngc -p tsconfig-app.json
|
||||||
|
|
||||||
|
# Look for correct output
|
||||||
|
grep "directives: \[\S*\.NgIf\]" dist/src/main.js > /dev/null
|
||||||
|
@ -5,23 +5,87 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {resolve} from 'path';
|
import {existsSync, lstatSync, readFileSync, readdirSync} from 'fs';
|
||||||
|
import {posix as path} from 'path';
|
||||||
|
|
||||||
import {PackageTransformer} from './transform/package_transformer';
|
import {PackageTransformer} from './transform/package_transformer';
|
||||||
|
|
||||||
export function mainNgcc(args: string[]): number {
|
export function mainNgcc(args: string[]): number {
|
||||||
const packagePaths = args[0] ? [resolve(args[0])] : [];
|
const formats = args[0] ? args[0].split(',') : ['fesm2015', 'esm2015', 'fesm5', 'esm5'];
|
||||||
const formats = args[1] ? [args[1]] : ['fesm2015', 'esm2015', 'fesm5', 'esm5'];
|
const packagePaths = args[1] ? [path.resolve(args[1])] : findPackagesToCompile();
|
||||||
|
const targetPath = args[2] ? args[2] : 'node_modules';
|
||||||
// TODO: find all the package types to transform
|
|
||||||
// TODO: error/warning logging/handling etc
|
|
||||||
|
|
||||||
const transformer = new PackageTransformer();
|
const transformer = new PackageTransformer();
|
||||||
packagePaths.forEach(packagePath => {
|
packagePaths.forEach(packagePath => {
|
||||||
formats.forEach(format => {
|
formats.forEach(format => {
|
||||||
console.warn(`Compiling ${packagePath}:${format}`);
|
// TODO: remove before flight
|
||||||
transformer.transform(packagePath, format);
|
console.warn(`Compiling ${packagePath} : ${format}`);
|
||||||
|
transformer.transform(packagePath, format, targetPath);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO - consider nested node_modules
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given folder needs to be included in the ngcc compilation.
|
||||||
|
* We do not care about folders that are:
|
||||||
|
*
|
||||||
|
* - symlinks
|
||||||
|
* - node_modules
|
||||||
|
* - do not contain a package.json
|
||||||
|
* - do not have a typings property in package.json
|
||||||
|
* - do not have an appropriate metadata.json file
|
||||||
|
*
|
||||||
|
* @param folderPath The absolute path to the folder.
|
||||||
|
*/
|
||||||
|
function hasMetadataFile(folderPath: string): boolean {
|
||||||
|
const folderName = path.basename(folderPath);
|
||||||
|
if (folderName === 'node_modules' || lstatSync(folderPath).isSymbolicLink()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const packageJsonPath = path.join(folderPath, 'package.json');
|
||||||
|
if (!existsSync(packageJsonPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
||||||
|
if (!packageJson.typings) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: avoid if packageJson contains built marker
|
||||||
|
const metadataPath =
|
||||||
|
path.join(folderPath, packageJson.typings.replace(/\.d\.ts$/, '.metadata.json'));
|
||||||
|
return existsSync(metadataPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look for packages that need to be compiled.
|
||||||
|
* The function will recurse into folders that start with `@...`, e.g. `@angular/...`.
|
||||||
|
* Without an argument it starts at `node_modules`.
|
||||||
|
*/
|
||||||
|
function findPackagesToCompile(folder: string = 'node_modules'): string[] {
|
||||||
|
const fullPath = path.resolve(folder);
|
||||||
|
const packagesToCompile: string[] = [];
|
||||||
|
readdirSync(fullPath)
|
||||||
|
.filter(p => !p.startsWith('.'))
|
||||||
|
.filter(p => lstatSync(path.join(fullPath, p)).isDirectory())
|
||||||
|
.forEach(p => {
|
||||||
|
const packagePath = path.join(fullPath, p);
|
||||||
|
if (p.startsWith('@')) {
|
||||||
|
packagesToCompile.push(...findPackagesToCompile(packagePath));
|
||||||
|
} else {
|
||||||
|
packagesToCompile.push(packagePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return packagesToCompile.filter(path => recursiveDirTest(path, hasMetadataFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
function recursiveDirTest(dir: string, test: (dir: string) => boolean): boolean {
|
||||||
|
return test(dir) || readdirSync(dir).some(segment => {
|
||||||
|
const fullPath = path.join(dir, segment);
|
||||||
|
return lstatSync(fullPath).isDirectory() && recursiveDirTest(fullPath, test);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {readFileSync, writeFileSync} from 'fs';
|
import {existsSync, readFileSync, writeFileSync} from 'fs';
|
||||||
import {dirname, relative, resolve} from 'path';
|
import {dirname, relative, resolve} from 'path';
|
||||||
import {mkdir} from 'shelljs';
|
import {mkdir, mv} from 'shelljs';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {DtsFileTransformer} from '../../../ngtsc/transform';
|
import {DtsFileTransformer} from '../../../ngtsc/transform';
|
||||||
@ -49,9 +49,9 @@ import {getEntryPoints} from './utils';
|
|||||||
* - Some formats may contain multiple "modules" in a single file.
|
* - Some formats may contain multiple "modules" in a single file.
|
||||||
*/
|
*/
|
||||||
export class PackageTransformer {
|
export class PackageTransformer {
|
||||||
transform(packagePath: string, format: string): void {
|
transform(packagePath: string, format: string, targetPath: string = 'node_modules'): void {
|
||||||
const sourceNodeModules = this.findNodeModulesPath(packagePath);
|
const sourceNodeModules = this.findNodeModulesPath(packagePath);
|
||||||
const targetNodeModules = sourceNodeModules.replace(/node_modules$/, 'node_modules_ngtsc');
|
const targetNodeModules = resolve(sourceNodeModules, '..', targetPath);
|
||||||
const entryPoints = getEntryPoints(packagePath, format);
|
const entryPoints = getEntryPoints(packagePath, format);
|
||||||
|
|
||||||
entryPoints.forEach(entryPoint => {
|
entryPoints.forEach(entryPoint => {
|
||||||
@ -63,6 +63,7 @@ export class PackageTransformer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the TS program and necessary helpers.
|
// Create the TS program and necessary helpers.
|
||||||
|
// TODO : create a custom compiler host that reads from .bak files if available.
|
||||||
const host = ts.createCompilerHost(options);
|
const host = ts.createCompilerHost(options);
|
||||||
const packageProgram = ts.createProgram([entryPoint.entryFileName], options, host);
|
const packageProgram = ts.createProgram([entryPoint.entryFileName], options, host);
|
||||||
const typeChecker = packageProgram.getTypeChecker();
|
const typeChecker = packageProgram.getTypeChecker();
|
||||||
@ -195,6 +196,10 @@ export class PackageTransformer {
|
|||||||
|
|
||||||
writeFile(file: FileInfo): void {
|
writeFile(file: FileInfo): void {
|
||||||
mkdir('-p', dirname(file.path));
|
mkdir('-p', dirname(file.path));
|
||||||
|
const backPath = file.path + '.bak';
|
||||||
|
if (existsSync(file.path) && !existsSync(backPath)) {
|
||||||
|
mv(file.path, backPath);
|
||||||
|
}
|
||||||
writeFileSync(file.path, file.contents, 'utf8');
|
writeFileSync(file.path, file.contents, 'utf8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import {mainNgcc} from '../../src/ngcc/src/main';
|
|||||||
|
|
||||||
import {TestSupport, isInBazel, setup} from '../test_support';
|
import {TestSupport, isInBazel, setup} from '../test_support';
|
||||||
|
|
||||||
|
const OUTPUT_PATH = 'node_modules_ngtsc';
|
||||||
|
|
||||||
describe('ngcc behavioral tests', () => {
|
describe('ngcc behavioral tests', () => {
|
||||||
if (!isInBazel()) {
|
if (!isInBazel()) {
|
||||||
// These tests should be excluded from the non-Bazel build.
|
// These tests should be excluded from the non-Bazel build.
|
||||||
@ -26,7 +28,7 @@ describe('ngcc behavioral tests', () => {
|
|||||||
const {cp, mkdir, rm, set} = require('shelljs');
|
const {cp, mkdir, rm, set} = require('shelljs');
|
||||||
|
|
||||||
const tempRootDir = join(tmpdir(), 'ngcc-spec', format);
|
const tempRootDir = join(tmpdir(), 'ngcc-spec', format);
|
||||||
const outputDir = 'node_modules_ngtsc';
|
const outputDir = OUTPUT_PATH;
|
||||||
|
|
||||||
set('-e');
|
set('-e');
|
||||||
rm('-rf', tempRootDir);
|
rm('-rf', tempRootDir);
|
||||||
@ -44,7 +46,7 @@ describe('ngcc behavioral tests', () => {
|
|||||||
const commonPath = join(support.basePath, 'node_modules/@angular/common');
|
const commonPath = join(support.basePath, 'node_modules/@angular/common');
|
||||||
const format = 'fesm2015';
|
const format = 'fesm2015';
|
||||||
|
|
||||||
expect(mainNgcc([commonPath, format])).toBe(0);
|
expect(mainNgcc([format, commonPath, OUTPUT_PATH])).toBe(0);
|
||||||
|
|
||||||
onSpecCompleted(format);
|
onSpecCompleted(format);
|
||||||
});
|
});
|
||||||
@ -53,7 +55,7 @@ describe('ngcc behavioral tests', () => {
|
|||||||
const commonPath = join(support.basePath, 'node_modules/@angular/common');
|
const commonPath = join(support.basePath, 'node_modules/@angular/common');
|
||||||
const format = 'fesm5';
|
const format = 'fesm5';
|
||||||
|
|
||||||
expect(mainNgcc([commonPath, format])).toBe(0);
|
expect(mainNgcc([format, commonPath, OUTPUT_PATH])).toBe(0);
|
||||||
|
|
||||||
onSpecCompleted(format);
|
onSpecCompleted(format);
|
||||||
});
|
});
|
||||||
@ -62,7 +64,7 @@ describe('ngcc behavioral tests', () => {
|
|||||||
const commonPath = join(support.basePath, 'node_modules/@angular/common');
|
const commonPath = join(support.basePath, 'node_modules/@angular/common');
|
||||||
const format = 'esm2015';
|
const format = 'esm2015';
|
||||||
|
|
||||||
expect(mainNgcc([commonPath, format])).toBe(0);
|
expect(mainNgcc([format, commonPath, OUTPUT_PATH])).toBe(0);
|
||||||
|
|
||||||
onSpecCompleted(format);
|
onSpecCompleted(format);
|
||||||
});
|
});
|
||||||
@ -71,7 +73,7 @@ describe('ngcc behavioral tests', () => {
|
|||||||
const commonPath = join(support.basePath, 'node_modules/@angular/common');
|
const commonPath = join(support.basePath, 'node_modules/@angular/common');
|
||||||
const format = 'esm5';
|
const format = 'esm5';
|
||||||
|
|
||||||
expect(mainNgcc([commonPath, format])).toBe(0);
|
expect(mainNgcc([format, commonPath, OUTPUT_PATH])).toBe(0);
|
||||||
|
|
||||||
onSpecCompleted(format);
|
onSpecCompleted(format);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user