Skip to content

ES6 imports breaking client in Expo #5485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
BrianUribe6 opened this issue Sep 27, 2024 · 6 comments
Open

ES6 imports breaking client in Expo #5485

BrianUribe6 opened this issue Sep 27, 2024 · 6 comments
Labels
Needs: Attention 👋 type:bug A broken experience TypeScript Pull requests that update Javascript code WIP

Comments

@BrianUribe6
Copy link

What are you generating using Kiota, clients or plugins?

API Client/SDK

In what context or format are you using Kiota?

Nuget tool

Client library/SDK language

TypeScript

Describe the bug

Relative Imports now include a "index.js" suffix which seems to be causing issues when bundling in React native/expo.

Possible related issue #4950

Imports are currently generated as 
// @ts-ignore
import { DocumentsRequestBuilderNavigationMetadata, type DocumentsRequestBuilder } from './documents/index.js';
// @ts-ignore
import { ProfilesRequestBuilderNavigationMetadata, ProfilesRequestBuilderRequestsMetadata, type ProfilesRequestBuilder } from './profiles/index.js';
// @ts-ignore
import { ThreadsRequestBuilderNavigationMetadata, type ThreadsRequestBuilder } from './threads/index.js';

Example error message by Expo

Android Bundling failed 63ms C:\Users\[REDACTED]\node_modules\expo-router\entry.js (1 module)
Unable to resolve "../../../models/index.js" from "lib\api\v1\auth\register\index.ts"

Expected behavior

Imports should be generated as

// @ts-ignore
import { DocumentsRequestBuilderNavigationMetadata, type DocumentsRequestBuilder } from './documents';
// @ts-ignore
import { ProfilesRequestBuilderNavigationMetadata, ProfilesRequestBuilderRequestsMetadata, type ProfilesRequestBuilder } from './profiles';
// @ts-ignore
import { ThreadsRequestBuilderNavigationMetadata, type ThreadsRequestBuilder } from './threads';

Or provide an additional flag to override the default behaviour.

How to reproduce

Generate any typescript client with kiota generate

Open API description file

No response

Kiota Version

1.18.0+5c6b5d0ef23865ba2f9d9f0b9fe4b944cf26b1ec

Latest Kiota version known to work for scenario above?(Not required)

1.15

Known Workarounds

  • Search and replace to remove "/index.js".
  • Downgrade to version 1.15

Configuration

No response

Debug output

Click to expand log ```
</details>


### Other information

This is most likely due to  #4815 
@BrianUribe6 BrianUribe6 added status:waiting-for-triage An issue that is yet to be reviewed or assigned type:bug A broken experience labels Sep 27, 2024
@github-project-automation github-project-automation bot moved this to Needs Triage 🔍 in Kiota Sep 27, 2024
@msgraph-bot msgraph-bot bot added the TypeScript Pull requests that update Javascript code label Sep 27, 2024
@andrueastman
Copy link
Member

Thanks for raising this @BrianUribe6

To confirm, any chance you've updated your project to use the config as outlined at this link?
https://learn.microsoft.com/en-us/openapi/kiota/quickstarts/typescript#project-configuration

@andrueastman andrueastman added status:waiting-for-author-feedback Issue that we've responded but needs author feedback to close and removed status:waiting-for-triage An issue that is yet to be reviewed or assigned labels Oct 1, 2024
@andrueastman andrueastman moved this from Needs Triage 🔍 to Waits for author 🔁 in Kiota Oct 1, 2024
@BrianUribe6
Copy link
Author

Yes, some of the settings are already defined in "expo/tsconfig.base", but to make sure I included them again. I'd like to re-emphasize that by completely removing "/index" from every import the client works as expected even with expo's default tsconfig.

tsconfig.json

{
	"extends": "expo/tsconfig.base",
	"compilerOptions": {
		"strict": true,
		"paths": {
			"@/*": ["./*"]
		},
		"lib": ["DOM", "ESNext", "ES2015"],
		"esModuleInterop": true,
		"forceConsistentCasingInFileNames": true,
		"moduleResolution": "NodeNext",
		"module": "NodeNext"
	},
	"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}

expo/tsconfig.base

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Expo",

  "compilerOptions": {
    "allowJs": true,
    "esModuleInterop": true,
    "jsx": "react-native",
    "lib": ["DOM", "ESNext"],
    "moduleResolution": "node",
    "noEmit": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "target": "ESNext"
  },

  "exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"]
}

@baywet
Copy link
Member

baywet commented Feb 20, 2025

for anybody following along this conversation, a PR was started at #6173 but we still need more evidence this would be a positive change. Please join there.

@baywet baywet added status:waiting-for-author-feedback Issue that we've responded but needs author feedback to close and removed Needs: Attention 👋 labels Apr 9, 2025
@HavenDV
Copy link

HavenDV commented Apr 14, 2025

We still need this, right now we are using this workaround:
fix-generated-api-client.js

// eslint-disable-next-line @typescript-eslint/no-require-imports
const fs = require("fs");
// eslint-disable-next-line @typescript-eslint/no-require-imports
const path = require("path");

const directory = "./lib/api-client";
const search = "/index.js';";
const replace = "/index';";

function processDirectory(dir) {
  const files = fs.readdirSync(dir);

  files.forEach((file) => {
    const fullPath = path.join(dir, file);
    const stat = fs.statSync(fullPath);

    if (stat.isDirectory()) {
      processDirectory(fullPath);
    } else if (stat.isFile()) {
      const content = fs.readFileSync(fullPath, "utf-8");
      if (content.includes(search)) {
        const updatedContent = content.replace(
          new RegExp(search, "g"),
          replace
        );
        fs.writeFileSync(fullPath, updatedContent, "utf-8");
        console.log(`Updated: ${fullPath}`);
      }
    }
  });
}

processDirectory(directory);
console.log("Replacement complete.");

and these commands in package.json:

    "download-openapi": "curl https://someurl/openapi/v1.json -o openapi.json",
    "generate-client": "kiota generate -l typescript -d ./openapi.json -c ApiClient -o ./lib/api-client --clean-output && node fix-generated-api-client.js",
    "update-client": "npm run download-openapi && npm run generate-client",

@baywet
Copy link
Member

baywet commented Apr 14, 2025

Hey everyone,

We had a PR opened at #6173 where I had left a bunch of questions which were never answered.

Here is the reason why I originally added index.js in the es6 module change

You cannot omit the file extension or the index.js file name. This behavior has been inherited by Node's ESM implementation, but it is not a part of the ECMAScript specification.

There's technically a segment of the population that might transpile but not bundle the end result. In which case, if the backend is not smart enough to map the request to index.js, things will break. The question then becomes: is that population bigger or smaller than the rest of the ecosystem which does NOT want index.js?

Also, since the path is valid, I'd argue that React native/expo should be able to handle it properly.

I think a couple of additional data points would help us make an educated decision here:

  • are there other scenarios in which the index.js breaks imports?
  • do react native and expo have issues about that? have we tried creating one?
  • can we find authoritative guidance that'd contradict MDN?

Getting answers to those questions would help make a decision with a high degree of confidence here.

@BrianUribe6
Copy link
Author

BrianUribe6 commented Apr 17, 2025

@baywet as it is Kiota may not work on any bundled front-end library/framework just because of a file extension

This is a barebones example where I just generated a client using the sample Pet Store OpenAPI Spec and tried instantiating it
https://codesandbox.io/p/sandbox/y6m7v7

As you can see it is not even usable because of the imports.

Since the time I submitted this issue my team and I have moved to other generators which are more suitable for typescript such as openapi-typescript. I think Kiota should take advantage of the rich type system that TypeScript has instead of adding anything in the runtime.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Attention 👋 and removed status:waiting-for-author-feedback Issue that we've responded but needs author feedback to close labels Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs: Attention 👋 type:bug A broken experience TypeScript Pull requests that update Javascript code WIP
Projects
Status: Waits for author 🔁
Development

Successfully merging a pull request may close this issue.

4 participants