feat(core): use the native hasher by default (#15071)

This commit is contained in:
Jonathan Cammisuli 2023-02-17 17:17:03 -05:00 committed by GitHub
parent e575c49c3e
commit 7d80f25833
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 114 additions and 68 deletions

View File

@ -8,12 +8,13 @@ import { join } from 'path';
import { NativeFileHasher } from './native-file-hasher';
function createFileHasher(): FileHasherBase {
// special case for unit tests
if (workspaceRoot === '/root') {
return new NodeBasedFileHasher();
}
try {
if (process.env.NX_NATIVE_HASHER) {
if (
!(
process.env.NX_NON_NATIVE_HASHER &&
process.env.NX_NON_NATIVE_HASHER == 'false'
)
) {
return new NativeFileHasher();
}

View File

@ -1,6 +1,8 @@
import '../../utils/testing/mock-fs';
import { TempFs } from '../../utils/testing/temp-fs';
const tempFs = new TempFs('explicit-package-json');
import { buildExplicitPackageJsonDependencies } from './explicit-package-json-dependencies';
import { vol } from 'memfs';
import { createProjectFileMap } from '../file-map-utils';
import { defaultFileHasher } from '../../hasher/file-hasher';
import {
@ -9,15 +11,11 @@ import {
} from '../../config/project-graph';
import { ProjectGraphBuilder } from '../project-graph-builder';
jest.mock('nx/src/utils/workspace-root', () => ({
workspaceRoot: '/root',
}));
describe('explicit package json dependencies', () => {
let ctx: ProjectGraphProcessorContext;
let projects: Record<string, ProjectGraphProjectNode>;
let fsJson;
beforeEach(() => {
beforeEach(async () => {
const projectsConfigurations = {
projects: {
proj: {
@ -39,7 +37,7 @@ describe('explicit package json dependencies', () => {
npmScope: 'proj',
};
fsJson = {
await tempFs.createFiles({
'./package.json': `{
"name": "test",
"dependencies": [],
@ -53,10 +51,9 @@ describe('explicit package json dependencies', () => {
dependencies: { proj2: '*', external: '12.0.0' },
devDependencies: { proj3: '*' },
}),
};
vol.fromJSON(fsJson, '/root');
});
defaultFileHasher.init();
await defaultFileHasher.init();
ctx = {
projectsConfigurations,
@ -89,6 +86,10 @@ describe('explicit package json dependencies', () => {
};
});
afterEach(() => {
tempFs.cleanup();
});
it(`should add dependencies for projects based on deps in package.json`, () => {
const builder = new ProjectGraphBuilder();
Object.values(projects).forEach((p) => {

View File

@ -1,14 +1,11 @@
import '../../utils/testing/mock-fs';
import { vol } from 'memfs';
import { TempFs } from '../../utils/testing/temp-fs';
const tempFs = new TempFs('explicit-project-deps');
import { defaultFileHasher } from '../../hasher/file-hasher';
import { createProjectFileMap } from '../file-map-utils';
import { ProjectGraphBuilder } from '../project-graph-builder';
import { buildExplicitTypeScriptDependencies } from './explicit-project-dependencies';
jest.mock('nx/src/utils/workspace-root', () => ({
workspaceRoot: '/root',
}));
// projectName => tsconfig import path
const dependencyProjectNamesToImportPaths = {
proj2: '@proj/my-second-proj',
@ -18,13 +15,13 @@ const dependencyProjectNamesToImportPaths = {
describe('explicit project dependencies', () => {
beforeEach(() => {
vol.reset();
tempFs.reset();
});
describe('static imports, dynamic imports, and commonjs requires', () => {
it('should build explicit dependencies for static imports, and top-level dynamic imports and commonjs requires', () => {
it('should build explicit dependencies for static imports, and top-level dynamic imports and commonjs requires', async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -68,9 +65,9 @@ describe('explicit project dependencies', () => {
]);
});
it('should build explicit dependencies for static exports', () => {
it('should build explicit dependencies for static exports', async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -108,9 +105,9 @@ describe('explicit project dependencies', () => {
]);
});
it(`should build explicit dependencies for TypeScript's import/export require syntax, and side-effectful import`, () => {
it(`should build explicit dependencies for TypeScript's import/export require syntax, and side-effectful import`, async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -148,9 +145,9 @@ describe('explicit project dependencies', () => {
]);
});
it('should build explicit dependencies for nested dynamic imports and commonjs requires', () => {
it('should build explicit dependencies for nested dynamic imports and commonjs requires', async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -209,9 +206,9 @@ describe('explicit project dependencies', () => {
]);
});
it('should build explicit dependencies when relative paths are used', () => {
it('should build explicit dependencies when relative paths are used', async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -248,9 +245,9 @@ describe('explicit project dependencies', () => {
]);
});
it('should not build explicit dependencies when nx-ignore-next-line comments are present', () => {
it('should not build explicit dependencies when nx-ignore-next-line comments are present', async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -340,9 +337,9 @@ describe('explicit project dependencies', () => {
expect(res).toEqual([]);
});
it('should not build explicit dependencies for stringified or templatized import/require statements', () => {
it('should not build explicit dependencies for stringified or templatized import/require statements', async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -423,9 +420,9 @@ describe('explicit project dependencies', () => {
* https://angular.io/guide/deprecations#loadchildren-string-syntax
*/
describe('legacy Angular loadChildren string syntax', () => {
it('should build explicit dependencies for legacy Angular loadChildren string syntax', () => {
it('should build explicit dependencies for legacy Angular loadChildren string syntax', async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -476,9 +473,9 @@ describe('explicit project dependencies', () => {
]);
});
it('should not build explicit dependencies when nx-ignore-next-line comments are present', () => {
it('should not build explicit dependencies when nx-ignore-next-line comments are present', async () => {
const sourceProjectName = 'proj';
const { ctx, builder } = createVirtualWorkspace({
const { ctx, builder } = await createVirtualWorkspace({
sourceProjectName,
sourceProjectFiles: [
{
@ -544,7 +541,7 @@ interface VirtualWorkspaceConfig {
* Prepares a minimal workspace and virtual file-system for the given files and dependency
* projects in order to be able to execute `buildExplicitTypeScriptDependencies()` in the tests.
*/
function createVirtualWorkspace(config: VirtualWorkspaceConfig) {
async function createVirtualWorkspace(config: VirtualWorkspaceConfig) {
const nxJson = {
npmScope: 'proj',
};
@ -625,9 +622,9 @@ function createVirtualWorkspace(config: VirtualWorkspaceConfig) {
fsJson['./tsconfig.base.json'] = JSON.stringify(tsConfig);
vol.fromJSON(fsJson, '/root');
await tempFs.createFiles(fsJson);
defaultFileHasher.init();
await defaultFileHasher.init();
return {
ctx: {

View File

@ -1,14 +1,9 @@
import '../utils/testing/mock-fs';
import { TempFs } from '../utils/testing/temp-fs';
const tempFs = new TempFs('explicit-package-json');
import { vol, fs } from 'memfs';
jest.mock('nx/src/utils/workspace-root', () => ({
workspaceRoot: '/root',
}));
import { buildProjectGraph } from './build-project-graph';
import * as fastGlob from 'fast-glob';
import { defaultFileHasher } from '../hasher/file-hasher';
import { ProjectsConfigurations } from '../config/workspace-json-project-json';
import { NxJsonConfiguration } from '../config/nx-json';
import { stripIndents } from '../utils/strip-indents';
import { DependencyType } from '../config/project-graph';
@ -16,7 +11,6 @@ import { DependencyType } from '../config/project-graph';
describe('project graph', () => {
let packageJson: any;
let packageLockJson: any;
let projects: ProjectsConfigurations;
let nxJson: NxJsonConfiguration;
let tsConfigJson: any;
let filesJson: any;
@ -190,8 +184,8 @@ describe('project graph', () => {
'./apps/api/project.json': JSON.stringify(apiProjectJson),
};
vol.reset();
vol.fromJSON(filesJson, '/root');
tempFs.reset();
await tempFs.createFiles(filesJson);
await defaultFileHasher.init();
const globResults = [
@ -208,17 +202,13 @@ describe('project graph', () => {
});
it('should throw an appropriate error for an invalid json config', async () => {
vol.appendFileSync('/root/tsconfig.base.json', 'invalid');
tempFs.appendFile('tsconfig.base.json', 'invalid');
try {
await buildProjectGraph();
fail('Invalid tsconfigs should cause project graph to throw error');
} catch (e) {
expect(e.message).toMatchInlineSnapshot(`
"InvalidSymbol in /root/tsconfig.base.json at 1:248
> 1 | {\\"compilerOptions\\":{\\"baseUrl\\":\\".\\",\\"paths\\":{\\"@nrwl/shared/util\\":[\\"libs/shared/util/src/index.ts\\"],\\"@nrwl/shared-util-data\\":[\\"libs/shared/util/data/src/index.ts\\"],\\"@nrwl/ui\\":[\\"libs/ui/src/index.ts\\"],\\"@nrwl/lazy-lib\\":[\\"libs/lazy-lib/src/index.ts\\"]}}}invalid
  |  ^^^^^^^
"
`);
expect(e.message).toContain(`${tempFs.tempDir}/tsconfig.base.json`);
expect(e.message).toContain(`invalid`);
}
});
@ -284,8 +274,8 @@ describe('project graph', () => {
});
it('should handle circular dependencies', async () => {
fs.writeFileSync(
'/root/libs/shared/util/src/index.ts',
tempFs.writeFile(
'libs/shared/util/src/index.ts',
`import * as ui from '@nrwl/ui';`
);

View File

@ -0,0 +1,57 @@
import { join } from 'path';
import { tmpdir } from 'os';
import {
mkdtempSync,
readFile,
outputFile,
rmSync,
emptyDirSync,
} from 'fs-extra';
import { joinPathFragments } from '../path';
import { appendFileSync, writeFileSync } from 'fs';
type NestedFiles = {
[fileName: string]: string;
};
export class TempFs {
readonly tempDir: string;
constructor(private dirname: string, overrideWorkspaceRoot = true) {
this.tempDir = mkdtempSync(join(tmpdir(), this.dirname));
if (overrideWorkspaceRoot) {
process.env.NX_WORKSPACE_ROOT_PATH = this.tempDir;
}
}
async createFiles(fileObject: NestedFiles) {
await Promise.all(
Object.keys(fileObject).map(async (path) => {
await this.createFile(path, fileObject[path]);
})
);
}
async createFile(filePath: string, content: string) {
await outputFile(joinPathFragments(this.tempDir, filePath), content);
}
async readFile(filePath: string): Promise<string> {
return await readFile(filePath, 'utf-8');
}
appendFile(filePath: string, content: string) {
appendFileSync(joinPathFragments(this.tempDir, filePath), content);
}
writeFile(filePath: string, content: string) {
writeFileSync(joinPathFragments(this.tempDir, filePath), content);
}
cleanup() {
rmSync(this.tempDir, { recursive: true });
}
reset() {
emptyDirSync(this.tempDir);
}
}