Orval fails to find my custom instance mutator when there's `await import` inside of it
What happens
Orval fails to find my custom instance mutator function when there's await import inside any of the mutator function dependency imported packages.
What are the steps to reproduce this issue?
- create a normal orval config.
- override the mutator to have a custom instance.
- make sure the custom instance has an imported module that has
await importin it.
Example
Here's my orval.config.ts:
import { defineConfig } from "orval";
export default defineConfig({
project: {
input: "./openapi.json",
output: {
target: "./src/services/api.ts",
prettier: true,
client: "react-query",
mode: "split",
override: {
mutator: {
path: "./src/utils/http/custom-instance.ts",
name: "customInstance",
},
requestOptions: false,
},
},
},
});
Here's src/utils/http/custom-instance.ts:
import type { FetchError, FetchOptions } from "@/types/http";
import { baseHttpInstance } from "./base-http-instance";
if (!process.env.NEXT_PUBLIC_API_URL) {
throw new Error("NEXT_PUBLIC_API_URL is not defined");
}
export const customInstance = <T>(config: FetchOptions): Promise<T> => {
return baseHttpInstance<T>({
...config,
baseURL: process.env.NEXT_PUBLIC_API_URL,
});
};
export type ErrorType<Error> = FetchError<Error>;
As you can see there's a named export called customInstance, but if I run orval in the CLI, it fails to find it and gives me the following error:
🍻 Start orval v6.31.0 - A swagger client generator for typescript
Your mutator file doesn't have the customInstance exported function
So, I kept tracking what's breaking it and found out that this line is the culprit:
import { baseHttpInstance } from "./base-http-instance";
after commenting this line, orval generates just fine and finds the customInstance just fine.
So, I kept digging.
Here's my src/utils/http/base-http-instance.ts:
import { FetchOptions } from "@/types/http";
import { fetchInstance, HTTP_INSTANCE } from "./http-instance";
export const baseHttpInstance = async <T>(config: FetchOptions): Promise<T> => {
const headers = {
...HTTP_INSTANCE.headers,
...config.headers,
};
const options: FetchOptions = {
...config,
headers,
};
const overridedOptions = await Object.values(
HTTP_INSTANCE.interceptors,
).reduce(async (acc, interceptor) => {
return interceptor(await acc);
}, Promise.resolve(options));
const response = await fetchInstance<T>(overridedOptions);
return response.data;
};
Again, in this file everything was fine except for this import:
import { fetchInstance, HTTP_INSTANCE } from "./http-instance";
So, I checked it and here's my src/utils/http/http-instance.ts (the file is big so I truncated it and only showed the culprit part):
import type { Maybe } from "yup";
import { DEFAULT_LOCALE } from "@/constants/contries";
import { CURRENCY_COOKIE_NAME, LOCALE_COOKIE_NAME } from "@/constants/cookies";
import { SERVER_PATHNAME_HEADER } from "@/constants/headers";
import type { FetchOptions, FetchResponse, HttpInstance } from "@/types/http";
import { getUrlLocale } from "../getUrlLocale";
export const HTTP_INSTANCE: HttpInstance = {
baseURL: "",
headers: {},
interceptors: {},
};
export const fetchInstance = async <T>(
config: FetchOptions,
): Promise<FetchResponse<T>> => {
...
const defaultCurrency = "USD";
let locale: Maybe<string>;
let currency: Maybe<string>;
if (typeof window === "undefined") {
const { cookies, headers } = await import("next/headers");
locale =
cookies().get(LOCALE_COOKIE_NAME)?.value ||
getUrlLocale(headers().get(SERVER_PATHNAME_HEADER)) ||
DEFAULT_LOCALE;
currency = cookies().get(CURRENCY_COOKIE_NAME)?.value || defaultCurrency;
} else {
const { default: cookies } = await import("js-cookie");
locale =
cookies.get(LOCALE_COOKIE_NAME) ||
getUrlLocale(window.location.pathname) ||
DEFAULT_LOCALE;
currency = cookies.get(CURRENCY_COOKIE_NAME) || defaultCurrency;
}
...
};
Now as you can see I use different packages to extract the cookies data, while on the server side I use the next/headers, and on the client side I use js-cookie. This is done by this dynamic import.
When I commented these two await import lines everything worked just fine.
What happens?
Orval fails to generate anything because it fails to find the mutator custom instance function exported.
What were you expecting to happen?
Orval to succeed in generating everything just fine because Orval doesn't run the code and doesn't check if it works, so why is the await import in a dependency module breaking Orval's ability of detecting the exported function from the custom mutator instance?
Any logs, error output, etc?
🍻 Start orval v6.31.0 - A swagger client generator for typescript
Your mutator file doesn't have the customInstance exported function
What versions are you using?
System:
OS: Linux 6.8 Ubuntu 24.04.1 LTS 24.04.1 LTS (Noble Numbat)
CPU: (12) x64 13th Gen Intel(R) Core(TM) i7-1365U
Memory: 5.36 GB / 15.28 GB
Container: Yes
Shell: 5.9 - /usr/bin/zsh
npmPackages:
@tanstack/react-query: ^4.35.3 => 4.35.3
next: ^13.5.2 => 13.5.2
orval: ^6.31.0 => 6.31.0
react: ^18.2.0 => 18.2.0
+1
Changing compilerOptions.target to ES2022 in tsconfig.json helped me
any update for this?
It seems like dynamic imports were introduced in ES2020 so anything before that will cause problem for orval
Source: https://2ality.com/2017/01/import-operator.html?m=1