diff --git a/e2e/test-app-v10/jest.config.js b/e2e/test-app-v10/jest.config.js index 3f9bf5d212..9a0b3a0821 100644 --- a/e2e/test-app-v10/jest.config.js +++ b/e2e/test-app-v10/jest.config.js @@ -1,3 +1,5 @@ +require('jest-preset-angular/ngcc-jest-processor'); + /** @type {import('@jest/types').Config.InitialOptions} */ module.exports = { moduleNameMapper: { diff --git a/e2e/test-app-v10/package.json b/e2e/test-app-v10/package.json index c69e341982..6e8a901540 100644 --- a/e2e/test-app-v10/package.json +++ b/e2e/test-app-v10/package.json @@ -7,7 +7,6 @@ "build": "ng build", "test-cjs-uniso": "jest --clearCache && jest -c=jest-cjs-uniso.config.js", "test-cjs-iso": "jest --clearCache && jest -c=jest-cjs-iso.config.js", - "postinstall": "ngcc --properties es2015 browser module main", "lint": "ng lint" }, "private": true, diff --git a/e2e/test-app-v11/jest.config.js b/e2e/test-app-v11/jest.config.js index 3f9bf5d212..9a0b3a0821 100644 --- a/e2e/test-app-v11/jest.config.js +++ b/e2e/test-app-v11/jest.config.js @@ -1,3 +1,5 @@ +require('jest-preset-angular/ngcc-jest-processor'); + /** @type {import('@jest/types').Config.InitialOptions} */ module.exports = { moduleNameMapper: { diff --git a/e2e/test-app-v11/package.json b/e2e/test-app-v11/package.json index 37a2491927..f0c889a1b4 100644 --- a/e2e/test-app-v11/package.json +++ b/e2e/test-app-v11/package.json @@ -7,7 +7,6 @@ "build": "ng build", "test-cjs-uniso": "jest --clearCache && jest -c=jest-cjs-uniso.config.js", "test-cjs-iso": "jest --clearCache && jest -c=jest-cjs-iso.config.js", - "postinstall": "ngcc --properties es2015 browser module main", "lint": "ng lint" }, "private": true, diff --git a/e2e/test-app-v9/jest.config.js b/e2e/test-app-v9/jest.config.js index 3f9bf5d212..9a0b3a0821 100644 --- a/e2e/test-app-v9/jest.config.js +++ b/e2e/test-app-v9/jest.config.js @@ -1,3 +1,5 @@ +require('jest-preset-angular/ngcc-jest-processor'); + /** @type {import('@jest/types').Config.InitialOptions} */ module.exports = { moduleNameMapper: { diff --git a/e2e/test-app-v9/package.json b/e2e/test-app-v9/package.json index 2d6689f8b0..2cb3f604c9 100644 --- a/e2e/test-app-v9/package.json +++ b/e2e/test-app-v9/package.json @@ -7,7 +7,6 @@ "build": "ng build", "test-cjs-uniso": "jest --clearCache && jest -c=jest-cjs-uniso.config.js", "test-cjs-iso": "jest --clearCache && jest -c=jest-cjs-iso.config.js", - "postinstall": "ngcc --properties es2015 browser module main", "lint": "ng lint" }, "private": true, diff --git a/ngcc-jest-processor.js b/ngcc-jest-processor.js new file mode 100644 index 0000000000..eca2ea7e6a --- /dev/null +++ b/ngcc-jest-processor.js @@ -0,0 +1 @@ +module.exports = require('./build/utils/ngcc-jest-processor'); diff --git a/scripts/e2e.js b/scripts/e2e.js index 53979e0a33..279618505b 100755 --- a/scripts/e2e.js +++ b/scripts/e2e.js @@ -44,6 +44,7 @@ const executeTest = (projectRealPath) => { copySync(join(cwd, 'jest-preset.js'), `${presetDir}/jest-preset.js`); copySync(join(cwd, 'index.js'), `${presetDir}/index.js`); + copySync(join(cwd, 'ngcc-jest-processor.js'), `${presetDir}/ngcc-jest-processor.js`); copySync(join(cwd, 'package.json'), `${presetDir}/package.json`); copySync(join(cwd, 'build'), `${presetDir}/build`); diff --git a/src/utils/ngcc-jest-processor.ts b/src/utils/ngcc-jest-processor.ts new file mode 100644 index 0000000000..c29d4ebd54 --- /dev/null +++ b/src/utils/ngcc-jest-processor.ts @@ -0,0 +1,60 @@ +/** + * 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'; + +const IGNORE_ARGS = ['--clearCache', '--help', '--init', '--listTests', '--showConfig']; +const canRunNgcc = !process.argv.find((arg) => IGNORE_ARGS.includes(arg)); +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. Please make sure you are running jest from root level of your project`, + ); +} + +if (canRunNgcc) { + process.stdout.write('ngcc-jest-processor: running ngcc\n'); + // 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. + */ + ...['es2015', '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: string = error?.message ?? ''; + + throw new Error(`${errorMessage} NGCC failed ${errorMessage ? ', see above' : ''}.`); + } +}