i18next / i18next-http-backend

i18next-http-backend is a backend layer for i18next using in Node.js, in the browser and for Deno.
MIT License
453 stars 70 forks source link

Usage with Webpack and Typescript importing cjs instead of esm #62

Closed villasv closed 3 years ago

villasv commented 3 years ago

🐛 Bug Report

A project setup with Typescript (targeting es5) and Webpack seems to be causing i18next-http-backend to be loaded via require which is configured to load the library from the cjs distribution.

If I chage my import to import i18nextHttpBackend from "i18next-http-backend/esm"; it works as expected, but then TypeScript cannot find the type declaration.

To Reproduce

Sandbox: https://codesandbox.io/s/re1sn (run npm start if not already running)

https://re1sn.sse.codesandbox.io/ (should show something like defaultBackend is undefined and esmBackend is function)

Expected behavior

import i18nextHttpBackend from "i18next-http-backend"; to result in i18nextHttpBackend !== undefined.

Your Environment

adrai commented 3 years ago

@pedrodurek any idea?

villasv commented 3 years ago

I don't know much about esm/cjs package resolution but I can imagine the cause is this config:

  "exports": {
   ...
    ".": {
      "require": "./cjs/index.js",
      "default": "./esm/index.js"
    },
   ...

I don't why this was configured this way so I won't dare to suggest a change.

A quick win would be replicating the index.d.ts inside the cjs and esm dirs so TypeScript users will have their types if they have to rely on those.

adrai commented 3 years ago

I'm not a TypeScript user, but probably this is because of the target option "es5" in the tsconfig.json ? You may want to change that to es6?

villasv commented 3 years ago

You may want to change that to es6?

Using es6 as target worked as intended! 🎉

I'll probably have to setup some polyfills, but well, I guess it's not reasonable to ask es5 compilation to be a first class citizen for new code. I'm good if you want to close this as wontfix ;-)

Thanks!

pedrodurek commented 3 years ago

Hey @villasv, This seems to be the problem: https://github.com/i18next/i18next-http-backend/blob/master/package.json#L7-L19

It's basically saying that if you import the library using es6 syntax (before compiling your code), it'll fallback to ./esm/index.js, and as you specified that your target is es5, it'll not include the ./esm/index.js file, only ./cjs/index.js. That's why is returning undefined.

import defaultBackend from "i18next-http-backend"; // Returns undefined

However, if you rely on the es5 syntax (require), it works! That's because it's pointing to ./cjs/index.js now.

const defaultWithRequire = require("i18next-http-backend"); // Returns the proper object

Here is an example: https://codesandbox.io/s/i18next-cjsvsesm-forked-6wypj?file=/src/App.tsx

This "export" rule should not be considered before your code is compiled.

I'll see what I can do in the coming days. Let's keep this issue opened for now.

pedrodurek commented 3 years ago

Hey @adrai, I think it'll be better to use rollup to solve this issue (we could copy and paste the same setup from other modules), what do you think?

adrai commented 3 years ago

Do you think this would solve this? Why?

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.