feat(core): use the native hasher by default (#15071)
This commit is contained in:
parent
e575c49c3e
commit
7d80f25833
@ -8,12 +8,13 @@ import { join } from 'path';
|
|||||||
import { NativeFileHasher } from './native-file-hasher';
|
import { NativeFileHasher } from './native-file-hasher';
|
||||||
|
|
||||||
function createFileHasher(): FileHasherBase {
|
function createFileHasher(): FileHasherBase {
|
||||||
// special case for unit tests
|
|
||||||
if (workspaceRoot === '/root') {
|
|
||||||
return new NodeBasedFileHasher();
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
if (process.env.NX_NATIVE_HASHER) {
|
if (
|
||||||
|
!(
|
||||||
|
process.env.NX_NON_NATIVE_HASHER &&
|
||||||
|
process.env.NX_NON_NATIVE_HASHER == 'false'
|
||||||
|
)
|
||||||
|
) {
|
||||||
return new NativeFileHasher();
|
return new NativeFileHasher();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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 { buildExplicitPackageJsonDependencies } from './explicit-package-json-dependencies';
|
||||||
import { vol } from 'memfs';
|
|
||||||
import { createProjectFileMap } from '../file-map-utils';
|
import { createProjectFileMap } from '../file-map-utils';
|
||||||
import { defaultFileHasher } from '../../hasher/file-hasher';
|
import { defaultFileHasher } from '../../hasher/file-hasher';
|
||||||
import {
|
import {
|
||||||
@ -9,15 +11,11 @@ import {
|
|||||||
} from '../../config/project-graph';
|
} from '../../config/project-graph';
|
||||||
import { ProjectGraphBuilder } from '../project-graph-builder';
|
import { ProjectGraphBuilder } from '../project-graph-builder';
|
||||||
|
|
||||||
jest.mock('nx/src/utils/workspace-root', () => ({
|
|
||||||
workspaceRoot: '/root',
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('explicit package json dependencies', () => {
|
describe('explicit package json dependencies', () => {
|
||||||
let ctx: ProjectGraphProcessorContext;
|
let ctx: ProjectGraphProcessorContext;
|
||||||
let projects: Record<string, ProjectGraphProjectNode>;
|
let projects: Record<string, ProjectGraphProjectNode>;
|
||||||
let fsJson;
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
const projectsConfigurations = {
|
const projectsConfigurations = {
|
||||||
projects: {
|
projects: {
|
||||||
proj: {
|
proj: {
|
||||||
@ -39,7 +37,7 @@ describe('explicit package json dependencies', () => {
|
|||||||
npmScope: 'proj',
|
npmScope: 'proj',
|
||||||
};
|
};
|
||||||
|
|
||||||
fsJson = {
|
await tempFs.createFiles({
|
||||||
'./package.json': `{
|
'./package.json': `{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
@ -53,10 +51,9 @@ describe('explicit package json dependencies', () => {
|
|||||||
dependencies: { proj2: '*', external: '12.0.0' },
|
dependencies: { proj2: '*', external: '12.0.0' },
|
||||||
devDependencies: { proj3: '*' },
|
devDependencies: { proj3: '*' },
|
||||||
}),
|
}),
|
||||||
};
|
});
|
||||||
vol.fromJSON(fsJson, '/root');
|
|
||||||
|
|
||||||
defaultFileHasher.init();
|
await defaultFileHasher.init();
|
||||||
|
|
||||||
ctx = {
|
ctx = {
|
||||||
projectsConfigurations,
|
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`, () => {
|
it(`should add dependencies for projects based on deps in package.json`, () => {
|
||||||
const builder = new ProjectGraphBuilder();
|
const builder = new ProjectGraphBuilder();
|
||||||
Object.values(projects).forEach((p) => {
|
Object.values(projects).forEach((p) => {
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
import '../../utils/testing/mock-fs';
|
import { TempFs } from '../../utils/testing/temp-fs';
|
||||||
import { vol } from 'memfs';
|
const tempFs = new TempFs('explicit-project-deps');
|
||||||
|
|
||||||
import { defaultFileHasher } from '../../hasher/file-hasher';
|
import { defaultFileHasher } from '../../hasher/file-hasher';
|
||||||
import { createProjectFileMap } from '../file-map-utils';
|
import { createProjectFileMap } from '../file-map-utils';
|
||||||
import { ProjectGraphBuilder } from '../project-graph-builder';
|
import { ProjectGraphBuilder } from '../project-graph-builder';
|
||||||
import { buildExplicitTypeScriptDependencies } from './explicit-project-dependencies';
|
import { buildExplicitTypeScriptDependencies } from './explicit-project-dependencies';
|
||||||
|
|
||||||
jest.mock('nx/src/utils/workspace-root', () => ({
|
|
||||||
workspaceRoot: '/root',
|
|
||||||
}));
|
|
||||||
|
|
||||||
// projectName => tsconfig import path
|
// projectName => tsconfig import path
|
||||||
const dependencyProjectNamesToImportPaths = {
|
const dependencyProjectNamesToImportPaths = {
|
||||||
proj2: '@proj/my-second-proj',
|
proj2: '@proj/my-second-proj',
|
||||||
@ -18,13 +15,13 @@ const dependencyProjectNamesToImportPaths = {
|
|||||||
|
|
||||||
describe('explicit project dependencies', () => {
|
describe('explicit project dependencies', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vol.reset();
|
tempFs.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('static imports, dynamic imports, and commonjs requires', () => {
|
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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
sourceProjectFiles: [
|
||||||
{
|
{
|
||||||
@ -340,9 +337,9 @@ describe('explicit project dependencies', () => {
|
|||||||
expect(res).toEqual([]);
|
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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
sourceProjectFiles: [
|
||||||
{
|
{
|
||||||
@ -423,9 +420,9 @@ describe('explicit project dependencies', () => {
|
|||||||
* https://angular.io/guide/deprecations#loadchildren-string-syntax
|
* https://angular.io/guide/deprecations#loadchildren-string-syntax
|
||||||
*/
|
*/
|
||||||
describe('legacy Angular 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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
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 sourceProjectName = 'proj';
|
||||||
const { ctx, builder } = createVirtualWorkspace({
|
const { ctx, builder } = await createVirtualWorkspace({
|
||||||
sourceProjectName,
|
sourceProjectName,
|
||||||
sourceProjectFiles: [
|
sourceProjectFiles: [
|
||||||
{
|
{
|
||||||
@ -544,7 +541,7 @@ interface VirtualWorkspaceConfig {
|
|||||||
* Prepares a minimal workspace and virtual file-system for the given files and dependency
|
* 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.
|
* projects in order to be able to execute `buildExplicitTypeScriptDependencies()` in the tests.
|
||||||
*/
|
*/
|
||||||
function createVirtualWorkspace(config: VirtualWorkspaceConfig) {
|
async function createVirtualWorkspace(config: VirtualWorkspaceConfig) {
|
||||||
const nxJson = {
|
const nxJson = {
|
||||||
npmScope: 'proj',
|
npmScope: 'proj',
|
||||||
};
|
};
|
||||||
@ -625,9 +622,9 @@ function createVirtualWorkspace(config: VirtualWorkspaceConfig) {
|
|||||||
|
|
||||||
fsJson['./tsconfig.base.json'] = JSON.stringify(tsConfig);
|
fsJson['./tsconfig.base.json'] = JSON.stringify(tsConfig);
|
||||||
|
|
||||||
vol.fromJSON(fsJson, '/root');
|
await tempFs.createFiles(fsJson);
|
||||||
|
|
||||||
defaultFileHasher.init();
|
await defaultFileHasher.init();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ctx: {
|
ctx: {
|
||||||
|
|||||||
@ -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 { buildProjectGraph } from './build-project-graph';
|
||||||
import * as fastGlob from 'fast-glob';
|
import * as fastGlob from 'fast-glob';
|
||||||
import { defaultFileHasher } from '../hasher/file-hasher';
|
import { defaultFileHasher } from '../hasher/file-hasher';
|
||||||
import { ProjectsConfigurations } from '../config/workspace-json-project-json';
|
|
||||||
import { NxJsonConfiguration } from '../config/nx-json';
|
import { NxJsonConfiguration } from '../config/nx-json';
|
||||||
import { stripIndents } from '../utils/strip-indents';
|
import { stripIndents } from '../utils/strip-indents';
|
||||||
import { DependencyType } from '../config/project-graph';
|
import { DependencyType } from '../config/project-graph';
|
||||||
@ -16,7 +11,6 @@ import { DependencyType } from '../config/project-graph';
|
|||||||
describe('project graph', () => {
|
describe('project graph', () => {
|
||||||
let packageJson: any;
|
let packageJson: any;
|
||||||
let packageLockJson: any;
|
let packageLockJson: any;
|
||||||
let projects: ProjectsConfigurations;
|
|
||||||
let nxJson: NxJsonConfiguration;
|
let nxJson: NxJsonConfiguration;
|
||||||
let tsConfigJson: any;
|
let tsConfigJson: any;
|
||||||
let filesJson: any;
|
let filesJson: any;
|
||||||
@ -190,8 +184,8 @@ describe('project graph', () => {
|
|||||||
'./apps/api/project.json': JSON.stringify(apiProjectJson),
|
'./apps/api/project.json': JSON.stringify(apiProjectJson),
|
||||||
};
|
};
|
||||||
|
|
||||||
vol.reset();
|
tempFs.reset();
|
||||||
vol.fromJSON(filesJson, '/root');
|
await tempFs.createFiles(filesJson);
|
||||||
await defaultFileHasher.init();
|
await defaultFileHasher.init();
|
||||||
|
|
||||||
const globResults = [
|
const globResults = [
|
||||||
@ -208,17 +202,13 @@ describe('project graph', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an appropriate error for an invalid json config', async () => {
|
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 {
|
try {
|
||||||
await buildProjectGraph();
|
await buildProjectGraph();
|
||||||
fail('Invalid tsconfigs should cause project graph to throw error');
|
fail('Invalid tsconfigs should cause project graph to throw error');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).toMatchInlineSnapshot(`
|
expect(e.message).toContain(`${tempFs.tempDir}/tsconfig.base.json`);
|
||||||
"InvalidSymbol in /root/tsconfig.base.json at 1:248
|
expect(e.message).toContain(`invalid`);
|
||||||
[0m[31m[1m>[22m[39m[90m 1 | [39m{\\"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[0m
|
|
||||||
[0m [90m | [39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[0m
|
|
||||||
"
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -284,8 +274,8 @@ describe('project graph', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should handle circular dependencies', async () => {
|
it('should handle circular dependencies', async () => {
|
||||||
fs.writeFileSync(
|
tempFs.writeFile(
|
||||||
'/root/libs/shared/util/src/index.ts',
|
'libs/shared/util/src/index.ts',
|
||||||
`import * as ui from '@nrwl/ui';`
|
`import * as ui from '@nrwl/ui';`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
57
packages/nx/src/utils/testing/temp-fs.ts
Normal file
57
packages/nx/src/utils/testing/temp-fs.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user