fix(config): fix modules not being resolved from correct path (#3255)

This commit is contained in:
Tommy Nguyen 2024-08-01 18:59:26 +02:00 коммит произвёл GitHub
Родитель ced638a91e
Коммит 0c5a9d05bb
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
8 изменённых файлов: 230 добавлений и 239 удалений

Просмотреть файл

@ -0,0 +1,5 @@
---
"@rnx-kit/config": patch
---
Fix modules not being resolved from correct path

Просмотреть файл

@ -42,7 +42,6 @@
},
"devDependencies": {
"@rnx-kit/eslint-config": "*",
"@rnx-kit/jest-preset": "*",
"@rnx-kit/metro-plugin-cyclic-dependencies-detector": "*",
"@rnx-kit/metro-plugin-duplicates-checker": "*",
"@rnx-kit/metro-serializer-esbuild": "*",
@ -52,16 +51,8 @@
"@types/node": "^20.0.0",
"@types/semver": "^7.0.0",
"eslint": "^8.56.0",
"jest": "^29.2.1",
"metro": "^0.80.0",
"prettier": "^3.0.0",
"typescript": "^5.0.0"
},
"jest": {
"preset": "@rnx-kit/jest-preset/private",
"moduleDirectories": [
"node_modules",
"test/__fixtures__/node_modules"
]
}
}

Просмотреть файл

@ -26,10 +26,13 @@ export type GetKitConfigOptions = {
export function getKitConfig(
options: GetKitConfigOptions = {}
): KitConfig | undefined {
const cwd = options.cwd || process.cwd();
// find the package dir that holds the rnx-kit configuration
const packageDir = options.module
? path.dirname(require.resolve(options.module + "/package.json"))
: options.cwd || process.cwd();
? path.dirname(
require.resolve(options.module + "/package.json", { paths: [cwd] })
)
: cwd;
// try to read package.json
try {

Просмотреть файл

@ -1,64 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`getKitConfig() returns rnx-kit configuration when using a module name 1`] = `
{
"bundle": {
"bundleOutput": "./app.bundle",
"entryFile": "./core-entry.js",
"id": "core",
"platforms": {
"android": {
"assetsDest": "./build-out/res",
},
},
"targets": [
"ios",
"android",
"macos",
"windows",
],
},
}
`;
exports[`getKitConfig() returns rnx-kit configuration when using an explicit working directory 1`] = `
{
"bundle": {
"bundleOutput": "./app.bundle",
"entryFile": "./core-entry.js",
"id": "core",
"platforms": {
"android": {
"assetsDest": "./build-out/res",
},
},
"targets": [
"ios",
"android",
"macos",
"windows",
],
},
}
`;
exports[`getKitConfig() returns rnx-kit configuration when using the current working directory 1`] = `
{
"bundle": {
"bundleOutput": "./app.bundle",
"entryFile": "./core-entry.js",
"id": "core",
"platforms": {
"android": {
"assetsDest": "./build-out/res",
},
},
"targets": [
"ios",
"android",
"macos",
"windows",
],
},
}
`;

Просмотреть файл

@ -1,3 +1,5 @@
import { deepEqual, equal, ok, throws } from "node:assert/strict";
import { describe, it } from "node:test";
import type { BundleConfig } from "../src/bundleConfig";
import {
getBundleConfig,
@ -19,103 +21,104 @@ const kitConfig: KitConfig = {
};
describe("getBundleConfig()", () => {
test("returns undefined when the bundle property is not set", () => {
expect(getBundleConfig({})).toBeUndefined();
it("returns undefined when the bundle property is not set", () => {
ok(!getBundleConfig({}));
});
test("returns undefined when the bundle property is set to undefined", () => {
expect(getBundleConfig({ bundle: undefined })).toBeUndefined();
it("returns undefined when the bundle property is set to undefined", () => {
ok(!getBundleConfig({ bundle: undefined }));
});
test("fails when the bundle property is set to true (no longer supported)", () => {
expect(() =>
getBundleConfig({ bundle: true as unknown as BundleConfig })
).toThrow(
/The rnx-kit configuration property 'bundle' no longer supports boolean values./i
it("fails when the bundle property is set to true (no longer supported)", () => {
throws(
() => getBundleConfig({ bundle: true as unknown as BundleConfig }),
new Error(
"The rnx-kit configuration property 'bundle' no longer supports boolean values. Bundling is always enabled with sensible defaults. You should remove the 'bundle' property to make use of the defaults, or specify the bundle configuration as an object."
)
);
});
test("returns the bundle config associated with the given id", () => {
it("returns the bundle config associated with the given id", () => {
const d = getBundleConfig(kitConfig, "123abc");
expect(d?.id).toEqual("123abc");
expect(Array.isArray(d?.targets)).toBe(true);
expect(d?.targets?.length).toBe(3);
expect(d?.targets).toEqual(["ios", "android", "windows"]);
equal(d?.id, "123abc");
ok(Array.isArray(d?.targets));
equal(d?.targets?.length, 3);
deepEqual(d?.targets, ["ios", "android", "windows"]);
});
test("returns undefined when the bundle id is not found", () => {
expect(getBundleConfig(kitConfig, "does-not-exist")).toBeUndefined();
it("returns undefined when the bundle id is not found", () => {
ok(!getBundleConfig(kitConfig, "does-not-exist"));
});
test("returns undefined when trying to find the first bundle and none are defined in config", () => {
expect(getBundleConfig({ bundle: [] })).toBeUndefined();
it("returns undefined when trying to find the first bundle and none are defined in config", () => {
ok(!getBundleConfig({ bundle: [] }));
});
test("returns the first bundle definition when an id is not given", () => {
it("returns the first bundle definition when an id is not given", () => {
const d = getBundleConfig(kitConfig);
expect(d?.id).toEqual("8");
expect(Array.isArray(d?.targets)).toBe(true);
expect(d?.targets.length).toBe(1);
expect(d?.targets).toEqual(["windows"]);
equal(d?.id, "8");
ok(Array.isArray(d?.targets));
equal(d?.targets?.length, 1);
deepEqual(d?.targets, ["windows"]);
});
test("fails when bundle config contains renamed property experimental_treeShake", () => {
expect(() =>
getBundleConfig({
bundle: { experimental_treeShake: true } as BundleConfig,
})
).toThrow(
/The bundle configuration property 'experimental_treeShake' is no longer supported. Use 'treeShake' instead./i
it("fails when bundle config contains renamed property experimental_treeShake", () => {
throws(
() =>
getBundleConfig({
bundle: { experimental_treeShake: true } as BundleConfig,
}),
new Error(
"The bundle configuration property 'experimental_treeShake' is no longer supported. Use 'treeShake' instead."
)
);
});
test("fails when bundle config contains renamed property entryPath", () => {
expect(() =>
getBundleConfig({
bundle: { entryPath: "x" } as BundleConfig,
})
).toThrow(
/The bundle configuration property 'entryPath' is no longer supported. Use 'entryFile' instead./i
it("fails when bundle config contains renamed property entryPath", () => {
throws(
() => getBundleConfig({ bundle: { entryPath: "x" } as BundleConfig }),
new Error(
"The bundle configuration property 'entryPath' is no longer supported. Use 'entryFile' instead."
)
);
});
test("fails when bundle config contains renamed property sourceMapPath", () => {
expect(() =>
getBundleConfig({
bundle: { sourceMapPath: "x" } as BundleConfig,
})
).toThrow(
/The bundle configuration property 'sourceMapPath' is no longer supported. Use 'sourcemapOutput' instead./i
it("fails when bundle config contains renamed property sourceMapPath", () => {
throws(
() => getBundleConfig({ bundle: { sourceMapPath: "x" } as BundleConfig }),
new Error(
"The bundle configuration property 'sourceMapPath' is no longer supported. Use 'sourcemapOutput' instead."
)
);
});
test("fails when bundle config contains renamed property sourceMapSourceRootPath", () => {
expect(() =>
getBundleConfig({
bundle: { sourceMapSourceRootPath: "x" } as BundleConfig,
})
).toThrow(
/The bundle configuration property 'sourceMapSourceRootPath' is no longer supported. Use 'sourcemapSourcesRoot' instead./i
it("fails when bundle config contains renamed property sourceMapSourceRootPath", () => {
throws(
() =>
getBundleConfig({
bundle: { sourceMapSourceRootPath: "x" } as BundleConfig,
}),
new Error(
"The bundle configuration property 'sourceMapSourceRootPath' is no longer supported. Use 'sourcemapSourcesRoot' instead."
)
);
});
test("fails when bundle config contains defunct property distPath", () => {
expect(() =>
getBundleConfig({
bundle: { distPath: "x" } as BundleConfig,
})
).toThrow(
/The bundle configuration property 'distPath' is no longer supported./i
it("fails when bundle config contains defunct property distPath", () => {
throws(
() => getBundleConfig({ bundle: { distPath: "x" } as BundleConfig }),
new Error(
"The bundle configuration property 'distPath' is no longer supported. You can control the bundle path and source-map path using 'bundleOutput' and 'sourcemapOutput', respectively."
)
);
});
test("fails when bundle config contains defunct property bundlePrefix", () => {
expect(() =>
getBundleConfig({
bundle: { bundlePrefix: "x" } as BundleConfig,
})
).toThrow(
/The bundle configuration property 'bundlePrefix' is no longer supported./i
it("fails when bundle config contains defunct property bundlePrefix", () => {
throws(
() => getBundleConfig({ bundle: { bundlePrefix: "x" } as BundleConfig }),
new Error(
"The bundle configuration property 'bundlePrefix' is no longer supported. You can control the bundle file name using 'bundleOutput'."
)
);
});
});
@ -135,18 +138,18 @@ const bundleConfig: BundleConfig = {
};
describe("getBundlePlatformConfig()", () => {
test("returns the input bundle config when no platform overrides exist", () => {
it("returns the input bundle config when no platform overrides exist", () => {
const d = getPlatformBundleConfig(bundleConfigWithoutPlatforms, "android");
expect(d).toBe(bundleConfigWithoutPlatforms);
equal(d, bundleConfigWithoutPlatforms);
});
test("returns the input bundle config when the given platform doesn't have any overrides", () => {
it("returns the input bundle config when the given platform doesn't have any overrides", () => {
const d = getPlatformBundleConfig(bundleConfig, "android");
expect(d).toBe(bundleConfig);
equal(d, bundleConfig);
});
test("returns the a platform-specific bundle config", () => {
it("returns the a platform-specific bundle config", () => {
const d = getPlatformBundleConfig(bundleConfig, "ios");
expect(d.bundleOutput).toEqual("main.ios.jsbundle");
equal(d.bundleOutput, "main.ios.jsbundle");
});
});

Просмотреть файл

@ -1,145 +1,165 @@
import { deepEqual, doesNotThrow, equal, throws } from "node:assert/strict";
import { describe, it } from "node:test";
import { getKitCapabilities } from "../src/getKitCapabilities";
describe("getKitCapabilities()", () => {
const consoleWarnSpy = jest.spyOn(global.console, "warn");
it("throws when supported React Native versions is invalid", (t) => {
const warnMock = t.mock.method(console, "warn", () => null);
afterEach(() => {
consoleWarnSpy.mockReset();
throws(() => getKitCapabilities({}));
throws(() => getKitCapabilities({ reactNativeVersion: "" }));
doesNotThrow(() => getKitCapabilities({ reactNativeVersion: "0" }));
doesNotThrow(() => getKitCapabilities({ reactNativeVersion: "0.64" }));
doesNotThrow(() => getKitCapabilities({ reactNativeVersion: "0.64.0" }));
equal(warnMock.mock.calls.length, 0);
});
test("throws when supported React Native versions is invalid", () => {
expect(() => getKitCapabilities({})).toThrow();
expect(() => getKitCapabilities({ reactNativeVersion: "" })).toThrow();
it("throws when React Native dev version does not satisfy supported versions", (t) => {
const warnMock = t.mock.method(console, "warn", () => null);
expect(() => getKitCapabilities({ reactNativeVersion: "0" })).not.toThrow();
expect(() =>
getKitCapabilities({ reactNativeVersion: "0.64" })
).not.toThrow();
expect(() =>
getKitCapabilities({ reactNativeVersion: "0.64.0" })
).not.toThrow();
expect(consoleWarnSpy).not.toHaveBeenCalled();
});
test("throws when React Native dev version does not satisfy supported versions", () => {
expect(() =>
throws(() =>
getKitCapabilities({
reactNativeVersion: "0.64.0",
reactNativeDevVersion: "0",
})
).toThrow();
);
expect(() =>
throws(() =>
getKitCapabilities({
reactNativeVersion: "0.64.0",
reactNativeDevVersion: "0.64",
})
).toThrow();
);
expect(
equal(
getKitCapabilities({
reactNativeVersion: "0.64.0",
reactNativeDevVersion: "0.64.0",
}).reactNativeVersion
).toBe("0.64.0");
}).reactNativeVersion,
"0.64.0"
);
expect(() =>
throws(() =>
getKitCapabilities({
reactNativeVersion: "^0.63 || ^0.64",
reactNativeDevVersion: "0.62.2",
})
).toThrow();
);
expect(
equal(
getKitCapabilities({
reactNativeVersion: "^0.63 || ^0.64",
reactNativeDevVersion: "0.64.0",
}).reactNativeVersion
).toBe("^0.63 || ^0.64");
}).reactNativeVersion,
"^0.63 || ^0.64"
);
expect(consoleWarnSpy).not.toHaveBeenCalled();
equal(warnMock.mock.calls.length, 0);
});
test("returns declared React Native dev version", () => {
expect(
it("returns declared React Native dev version", (t) => {
const warnMock = t.mock.method(console, "warn", () => null);
equal(
getKitCapabilities({
reactNativeVersion: "^0.63 || ^0.64",
reactNativeDevVersion: "0.64.0",
}).reactNativeDevVersion
).toBe("0.64.0");
expect(
}).reactNativeDevVersion,
"0.64.0"
);
equal(
getKitCapabilities({
reactNativeVersion: "^0.63 || ^0.64",
reactNativeDevVersion: "^0.64.0",
}).reactNativeDevVersion
).toBe("^0.64.0");
expect(consoleWarnSpy).not.toHaveBeenCalled();
}).reactNativeDevVersion,
"^0.64.0"
);
equal(warnMock.mock.calls.length, 0);
});
test("returns minimum supported React Native version as dev version when unspecified", () => {
expect(
it("returns minimum supported React Native version as dev version when unspecified", (t) => {
const warnMock = t.mock.method(console, "warn", () => null);
equal(
getKitCapabilities({
reactNativeVersion: "0.64.0",
}).reactNativeDevVersion
).toBe("0.64.0");
}).reactNativeDevVersion,
"0.64.0"
);
expect(
equal(
getKitCapabilities({
reactNativeVersion: "^0.63 || ^0.64",
}).reactNativeDevVersion
).toBe("0.63.0");
}).reactNativeDevVersion,
"0.63.0"
);
expect(
equal(
getKitCapabilities({
reactNativeVersion: "^0.63.4 || ^0.64.0",
}).reactNativeDevVersion
).toBe("0.63.4");
}).reactNativeDevVersion,
"0.63.4"
);
expect(consoleWarnSpy).not.toHaveBeenCalled();
equal(warnMock.mock.calls.length, 0);
});
test("returns 'library' when 'kitType' is undefined", () => {
expect(getKitCapabilities({ reactNativeVersion: "0.64.0" }).kitType).toBe(
it("returns 'library' when 'kitType' is undefined", (t) => {
const warnMock = t.mock.method(console, "warn", () => null);
equal(
getKitCapabilities({ reactNativeVersion: "0.64.0" }).kitType,
"library"
);
expect(
equal(
getKitCapabilities({ reactNativeVersion: "0.64.0", kitType: "library" })
.kitType
).toBe("library");
.kitType,
"library"
);
expect(
equal(
getKitCapabilities({ reactNativeVersion: "0.64.0", kitType: "app" })
.kitType
).toBe("app");
.kitType,
"app"
);
expect(consoleWarnSpy).not.toHaveBeenCalled();
equal(warnMock.mock.calls.length, 0);
});
test("returns empty array when 'capabilities' is undefined", () => {
expect(
getKitCapabilities({ reactNativeVersion: "0.64.0" }).capabilities
).toEqual([]);
it("returns empty array when 'capabilities' is undefined", (t) => {
const warnMock = t.mock.method(console, "warn", () => null);
expect(
deepEqual(
getKitCapabilities({ reactNativeVersion: "0.64.0" }).capabilities,
[]
);
deepEqual(
getKitCapabilities({
reactNativeVersion: "0.64.0",
capabilities: ["core-ios"],
}).capabilities
).toEqual(["core-ios"]);
}).capabilities,
["core-ios"]
);
expect(consoleWarnSpy).not.toHaveBeenCalled();
equal(warnMock.mock.calls.length, 0);
});
test("warns when 'reactNativeDevVersion' is set and 'kitType' is 'app'", () => {
it("warns when 'reactNativeDevVersion' is set and 'kitType' is 'app'", (t) => {
const warnMock = t.mock.method(console, "warn", () => null);
getKitCapabilities({
reactNativeVersion: "^0.64",
reactNativeDevVersion: "0.64.2",
kitType: "app",
capabilities: ["core-ios"],
});
expect(consoleWarnSpy).toHaveBeenCalledWith(
expect.stringContaining("warn"),
equal(warnMock.mock.calls.length, 1);
equal(
warnMock.mock.calls[0].arguments[1],
"'reactNativeDevVersion' is not used when 'kitType' is 'app'"
);
});

Просмотреть файл

@ -1,46 +1,81 @@
import path from "path";
import { deepEqual, ok } from "node:assert/strict";
import { afterEach, describe, it } from "node:test";
import { URL, fileURLToPath } from "node:url";
import { getKitConfig } from "../src/getKitConfig";
describe("getKitConfig()", () => {
const currentWorkingDir = process.cwd();
function fixturePath(): string {
return path.join(currentWorkingDir, "test", "__fixtures__");
}
function packagePath(name: string): string {
return path.join(fixturePath(), "node_modules", name);
const url = new URL(`__fixtures__/node_modules/${name}`, import.meta.url);
return fileURLToPath(url);
}
afterEach(() => process.chdir(currentWorkingDir));
test("returns undefined for an unconfigured package when using the current working directory", () => {
it("returns undefined for an unconfigured package when using the current working directory", () => {
process.chdir(packagePath("kit-test-unconfigured"));
expect(getKitConfig()).toBeUndefined();
ok(!getKitConfig());
});
test("returns undefined for an unconfigured package when using an explicit working directory", () => {
expect(
getKitConfig({ cwd: packagePath("kit-test-unconfigured") })
).toBeUndefined();
it("returns undefined for an unconfigured package when using an explicit working directory", () => {
ok(!getKitConfig({ cwd: packagePath("kit-test-unconfigured") }));
});
test("returns undefined for an unconfigured package when using a module name", () => {
expect(getKitConfig({ module: "kit-test-unconfigured" })).toBeUndefined();
it("returns undefined for an unconfigured package when using a module name", () => {
const options = { module: "kit-test-unconfigured", cwd: packagePath(".") };
ok(!getKitConfig(options));
});
test("returns rnx-kit configuration when using the current working directory", () => {
it("returns rnx-kit configuration when using the current working directory", () => {
process.chdir(packagePath("kit-test-configured"));
expect(getKitConfig()).toMatchSnapshot();
deepEqual(getKitConfig(), {
bundle: {
bundleOutput: "./app.bundle",
entryFile: "./core-entry.js",
id: "core",
platforms: {
android: {
assetsDest: "./build-out/res",
},
},
targets: ["ios", "android", "macos", "windows"],
},
});
});
test("returns rnx-kit configuration when using an explicit working directory", () => {
expect(
getKitConfig({ cwd: packagePath("kit-test-configured") })
).toMatchSnapshot();
it("returns rnx-kit configuration when using an explicit working directory", () => {
deepEqual(getKitConfig({ cwd: packagePath("kit-test-configured") }), {
bundle: {
bundleOutput: "./app.bundle",
entryFile: "./core-entry.js",
id: "core",
platforms: {
android: {
assetsDest: "./build-out/res",
},
},
targets: ["ios", "android", "macos", "windows"],
},
});
});
test("returns rnx-kit configuration when using a module name", () => {
expect(getKitConfig({ module: "kit-test-configured" })).toMatchSnapshot();
it("returns rnx-kit configuration when using a module name", () => {
const options = { module: "kit-test-configured", cwd: packagePath(".") };
deepEqual(getKitConfig(options), {
bundle: {
bundleOutput: "./app.bundle",
entryFile: "./core-entry.js",
id: "core",
platforms: {
android: {
assetsDest: "./build-out/res",
},
},
targets: ["ios", "android", "macos", "windows"],
},
});
});
});

Просмотреть файл

@ -3847,7 +3847,6 @@ __metadata:
dependencies:
"@rnx-kit/console": "npm:^1.0.12"
"@rnx-kit/eslint-config": "npm:*"
"@rnx-kit/jest-preset": "npm:*"
"@rnx-kit/metro-plugin-cyclic-dependencies-detector": "npm:*"
"@rnx-kit/metro-plugin-duplicates-checker": "npm:*"
"@rnx-kit/metro-serializer-esbuild": "npm:*"
@ -3858,7 +3857,6 @@ __metadata:
"@types/node": "npm:^20.0.0"
"@types/semver": "npm:^7.0.0"
eslint: "npm:^8.56.0"
jest: "npm:^29.2.1"
metro: "npm:^0.80.0"
prettier: "npm:^3.0.0"
semver: "npm:^7.0.0"