Skip to content

Commit

Permalink
feat(core): use the native hasher by default (#15071)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cammisuli committed Feb 17, 2023
1 parent e575c49 commit 7d80f25
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 68 deletions.
11 changes: 6 additions & 5 deletions packages/nx/src/hasher/file-hasher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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: {
Expand All @@ -39,12 +37,12 @@ describe('explicit package json dependencies', () => {
npmScope: 'proj',
};

fsJson = {
await tempFs.createFiles({
'./package.json': `{
"name": "test",
"dependencies": [],
"devDependencies": []
}`,
"name": "test",
"dependencies": [],
"devDependencies": []
}`,
'./nx.json': JSON.stringify(nxJsonConfiguration),
'./tsconfig.base.json': JSON.stringify({}),
'./libs/proj2/package.json': JSON.stringify({ name: 'proj2' }),
Expand All @@ -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,
Expand Down Expand Up @@ -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) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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: [
{
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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',
};
Expand Down Expand Up @@ -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: {
Expand Down
28 changes: 9 additions & 19 deletions packages/nx/src/project-graph/build-project-graph.spec.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
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';

describe('project graph', () => {
let packageJson: any;
let packageLockJson: any;
let projects: ProjectsConfigurations;
let nxJson: NxJsonConfiguration;
let tsConfigJson: any;
let filesJson: any;
Expand Down Expand Up @@ -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 = [
Expand All @@ -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`);
}
});

Expand Down Expand Up @@ -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';`
);

Expand Down
57 changes: 57 additions & 0 deletions packages/nx/src/utils/testing/temp-fs.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}

1 comment on commit 7d80f25

@vercel
Copy link

@vercel vercel bot commented on 7d80f25 Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-nrwl.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx-five.vercel.app
nx.dev

Please sign in to comment.