Correctly handle relative browserslistConfigFile paths (#13031)

* Correctly handle relative `browserslistConfigFile`

* Fix flow
This commit is contained in:
Nicolò Ribaudo 2021-03-26 20:07:28 +01:00 committed by GitHub
parent 16d83002de
commit e68f2ce195
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 24 deletions

View File

@ -19,6 +19,8 @@ import type {
PluginItem, PluginItem,
} from "./validation/options"; } from "./validation/options";
import { resolveBrowserslistConfigFile } from "./resolve-targets";
// Represents a config object and functions to lazily load the descriptors // Represents a config object and functions to lazily load the descriptors
// for the plugins and presets so we don't load the plugins/presets unless // for the plugins and presets so we don't load the plugins/presets unless
// the options object actually ends up being applicable. // the options object actually ends up being applicable.
@ -71,6 +73,19 @@ function* handlerOf<T>(value: T): Handler<T> {
return value; return value;
} }
function optionsWithResolvedBrowserslistConfigFile(
options: ValidatedOptions,
dirname: string,
): ValidatedOptions {
if (typeof options.browserslistConfigFile === "string") {
options.browserslistConfigFile = resolveBrowserslistConfigFile(
options.browserslistConfigFile,
dirname,
);
}
return options;
}
/** /**
* Create a set of descriptors from a given options object, preserving * Create a set of descriptors from a given options object, preserving
* descriptor identity based on the identity of the plugin/preset arrays * descriptor identity based on the identity of the plugin/preset arrays
@ -83,7 +98,7 @@ export function createCachedDescriptors(
): OptionsAndDescriptors { ): OptionsAndDescriptors {
const { plugins, presets, passPerPreset } = options; const { plugins, presets, passPerPreset } = options;
return { return {
options, options: optionsWithResolvedBrowserslistConfigFile(options, dirname),
plugins: plugins plugins: plugins
? () => createCachedPluginDescriptors(plugins, dirname)(alias) ? () => createCachedPluginDescriptors(plugins, dirname)(alias)
: () => handlerOf([]), : () => handlerOf([]),
@ -112,7 +127,7 @@ export function createUncachedDescriptors(
let presets; let presets;
return { return {
options, options: optionsWithResolvedBrowserslistConfigFile(options, dirname),
*plugins() { *plugins() {
if (!plugins) { if (!plugins) {
plugins = yield* createPluginDescriptors( plugins = yield* createPluginDescriptors(

View File

@ -126,7 +126,7 @@ export default function* loadPrivatePartialConfig(
const options: NormalizedOptions = { const options: NormalizedOptions = {
...merged, ...merged,
targets: resolveTargets(merged, absoluteRootDir, absoluteRootDir), targets: resolveTargets(merged, absoluteRootDir),
// Tack the passes onto the object itself so that, if this object is // Tack the passes onto the object itself so that, if this object is
// passed back to Babel a second time, it will be in the right structure // passed back to Babel a second time, it will be in the right structure

View File

@ -3,12 +3,19 @@
import type { ValidatedOptions } from "./validation/options"; import type { ValidatedOptions } from "./validation/options";
import getTargets, { type Targets } from "@babel/helper-compilation-targets"; import getTargets, { type Targets } from "@babel/helper-compilation-targets";
export function resolveBrowserslistConfigFile(
// eslint-disable-next-line no-unused-vars
browserslistConfigFile: string,
// eslint-disable-next-line no-unused-vars
configFilePath: string,
): string | void {
return undefined;
}
export function resolveTargets( export function resolveTargets(
options: ValidatedOptions, options: ValidatedOptions,
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
root: string, root: string,
// eslint-disable-next-line no-unused-vars
configFilePath: string | void,
): Targets { ): Targets {
let { targets } = options; let { targets } = options;
if (typeof targets === "string" || Array.isArray(targets)) { if (typeof targets === "string" || Array.isArray(targets)) {

View File

@ -11,10 +11,16 @@ import type { ValidatedOptions } from "./validation/options";
import path from "path"; import path from "path";
import getTargets, { type Targets } from "@babel/helper-compilation-targets"; import getTargets, { type Targets } from "@babel/helper-compilation-targets";
export function resolveBrowserslistConfigFile(
browserslistConfigFile: string,
configFileDir: string,
): string | void {
return path.resolve(configFileDir, browserslistConfigFile);
}
export function resolveTargets( export function resolveTargets(
options: ValidatedOptions, options: ValidatedOptions,
root: string, root: string,
configFilePath: string = root,
): Targets { ): Targets {
let { targets } = options; let { targets } = options;
if (typeof targets === "string" || Array.isArray(targets)) { if (typeof targets === "string" || Array.isArray(targets)) {
@ -25,13 +31,17 @@ export function resolveTargets(
targets = { ...targets, esmodules: "intersect" }; targets = { ...targets, esmodules: "intersect" };
} }
const { browserslistConfigFile } = options;
let configFile; let configFile;
if (typeof options.browserslistConfigFile === "string") { let ignoreBrowserslistConfig = false;
configFile = path.resolve(configFilePath, options.browserslistConfigFile); if (typeof browserslistConfigFile === "string") {
configFile = browserslistConfigFile;
} else {
ignoreBrowserslistConfig = browserslistConfigFile === false;
} }
return getTargets((targets: any), { return getTargets((targets: any), {
ignoreBrowserslistConfig: options.browserslistConfigFile === false, ignoreBrowserslistConfig,
configFile, configFile,
configPath: root, configPath: root,
browserslistEnv: options.browserslistEnv, browserslistEnv: options.browserslistEnv,

View File

@ -100,19 +100,6 @@ describe("browserslist", () => {
).toEqual({ chrome: "80.0.0" }); ).toEqual({ chrome: "80.0.0" });
}); });
// TODO: browserslistConfig is currently resolved starting from the root
// rather than from the config file.
// eslint-disable-next-line jest/no-disabled-tests
it.skip("loads nested .browserslistrc files if explicitly specified", () => {
expect(
loadOptions({
cwd: join(cwd, "fixtures", "targets"),
filename: "./node_modules/dep/test.js",
babelrcRoots: ["./node_modules/dep/"],
}).targets,
).toEqual({ edge: "14.0.0" });
});
describe("browserslistConfigFile", () => { describe("browserslistConfigFile", () => {
it("can disable config loading", () => { it("can disable config loading", () => {
expect( expect(
@ -132,16 +119,26 @@ describe("browserslist", () => {
).toEqual({ firefox: "74.0.0" }); ).toEqual({ firefox: "74.0.0" });
}); });
it("is relative to the project root", () => { it("is relative to the cwd even if specifying 'root'", () => {
expect( expect(
loadOptions({ loadOptions({
cwd: join(cwd, "fixtures", "targets"), cwd: join(cwd, "fixtures", "targets"),
root: "..", root: "..",
filename: "./nested/test.js", filename: "./nested/test.js",
browserslistConfigFile: "./targets/.browserslistrc-firefox", browserslistConfigFile: "./.browserslistrc-firefox",
}).targets, }).targets,
).toEqual({ firefox: "74.0.0" }); ).toEqual({ firefox: "74.0.0" });
}); });
it("is relative to the config files that defines it", () => {
expect(
loadOptions({
cwd: join(cwd, "fixtures", "targets"),
filename: "./node_modules/dep/test.js",
babelrcRoots: ["./node_modules/dep/"],
}).targets,
).toEqual({ edge: "14.0.0" });
});
}); });
describe("browserslistEnv", () => { describe("browserslistEnv", () => {