Skip to content

Commit

Permalink
feat(compiler): provide ngcc-jest-processor util
Browse files Browse the repository at this point in the history
Jest parallel mode doesn't allow `ngcc` to run. The only way to run `ngcc` with Jest is invoking `ngcc` directly in `jest.config.js`. Because Jest reads `jest.config.js` only once before running tests, running `ngcc` is possible with it
  • Loading branch information
ahnpnl committed Nov 12, 2020
1 parent 003527d commit 5c6ae01
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 8 deletions.
2 changes: 2 additions & 0 deletions e2e/test-app-v10-zone-v11/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require('jest-preset-angular/ngcc-jest-processor');

/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
preset: 'jest-preset-angular',
Expand Down
3 changes: 1 addition & 2 deletions e2e/test-app-v10-zone-v11/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
"start": "ng serve",
"build": "ng build",
"test": "jest --no-cache",
"lint": "ng lint",
"postinstall": "ngcc"
"lint": "ng lint"
},
"private": true,
"dependencies": {
Expand Down
2 changes: 2 additions & 0 deletions e2e/test-app-v10/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require('jest-preset-angular/ngcc-jest-processor');

/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
preset: 'jest-preset-angular',
Expand Down
5 changes: 2 additions & 3 deletions e2e/test-app-v10/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
"start": "ng serve",
"build": "ng build",
"test": "jest --no-cache",
"lint": "ng lint",
"postinstall": "ngcc"
"lint": "ng lint"
},
"private": true,
"dependencies": {
Expand Down Expand Up @@ -36,4 +35,4 @@
"tslint": "~6.1.3",
"typescript": "~4.0.5"
}
}
}
2 changes: 2 additions & 0 deletions e2e/test-app-v9/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require('jest-preset-angular/ngcc-jest-processor');

/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
preset: 'jest-preset-angular',
Expand Down
5 changes: 2 additions & 3 deletions e2e/test-app-v9/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
"start": "ng serve",
"build": "ng build",
"test": "jest --no-cache",
"lint": "ng lint",
"postinstall": "ngcc"
"lint": "ng lint"
},
"private": true,
"dependencies": {
Expand Down Expand Up @@ -35,4 +34,4 @@
"ts-node": "^9.0.0",
"typescript": "~3.8.3"
}
}
}
1 change: 1 addition & 0 deletions ngcc-jest-processor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./build/compiler/ngcc-jest-processor');
1 change: 1 addition & 0 deletions scripts/e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const executeTest = (projectRealPath) => {
mkdirSync(presetDir);
}
copySync(join(cwd, 'jest-preset.js'), `${presetDir}/jest-preset.js`);
copySync(join(cwd, 'ngcc-jest-processor.js'), `${presetDir}/ngcc-jest-processor.js`);
copySync(join(cwd, 'setup-jest.js'), `${presetDir}/setup-jest.js`);
copySync(join(cwd, 'package.json'), `${presetDir}/package.json`);
copySync(join(cwd, 'build'), `${presetDir}/build`);
Expand Down
57 changes: 57 additions & 0 deletions src/compiler/ngcc-jest-processor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Mainly copied from https://github.com/angular/angular-cli/blob/master/packages/ngtools/webpack/src/ngcc_processor.ts
* and adjusted to work with Jest
*/
import { spawnSync } from 'child_process';
import { existsSync } from 'fs';
import { dirname, join } from 'path';

function findNodeModulesDirectory(startPoint: string): string {
let current = startPoint;
while (dirname(current) !== current) {
const nodePath = join(current, 'node_modules');
if (existsSync(nodePath)) {
return nodePath;
}

current = dirname(current);
}

throw new Error(`Cannot locate the 'node_modules' directory.`);
}

if (!existsSync(join(process.cwd(), 'angular.json'))) {
throw new Error('ngcc-jest-processor should be only run from root directory');
}

// We spawn instead of using the API because:
// - NGCC Async uses clustering which is problematic when used via the API which means
// that we cannot setup multiple cluster masters with different options.
// - We will not be able to have concurrent builds otherwise Ex: App-Shell,
// as NGCC will create a lock file for both builds and it will cause builds to fails.
const { status, error } = spawnSync(
process.execPath,
[
require.resolve('@angular/compiler-cli/ngcc/main-ngcc.js'),
'--source' /** basePath */,
findNodeModulesDirectory(process.cwd()),
'--properties' /** propertiesToConsider */,
/**
* There are various properties: fesm2015, fesm5, es2015, esm2015, esm5, main, module, browser to choose from.
* Currently Jest requires `commonjs` so we only need to ask `ngcc` to produce `umd` outputs. Later when switching
* to ESM, we can change to different properties to produce ESM outputs.
*/
...['main'],
'--first-only' /** compileAllFormats */,
'false', // make sure that `ngcc` runs on subfolders as well
'--async',
],
{
stdio: ['inherit', process.stderr, process.stderr],
},
);
if (status !== 0) {
const errorMessage = error?.message ?? '';

throw new Error(errorMessage + `NGCC failed${errorMessage ? ', see above' : ''}.`);
}

0 comments on commit 5c6ae01

Please sign in to comment.