facebook / fbt

A JavaScript Internationalization Framework
https://facebook.github.io/fbt
MIT License
3.88k stars 178 forks source link

FBT default import has issues with ESModules/CommonJS interop #115

Open fruchtose opened 4 years ago

fruchtose commented 4 years ago

🐛 Bug Report

I'm working in an ES2017 codebase compiled with TypeScript, Babel, and webpack. It seems that in certain contexts, using the default import of FBT fails because babel-plugin-fbt says the variable fbt is not bound when using the fbt() syntax in code. Examining the value of the import, is an object with this structure:

{
  __esModule: true,
  FbtTranslations: { /* ... */ },
  GenderConst: { /* ... */ },
  default: f (),
  fbt: f (),
  init: f (e),
}

I'm not sure which step of tooling is responsible for making the default export an object.

I've confirmed that a reliable workaround is to write const { fbt } = require('fbt') rather than const fbt = require('fbt').

I believe that the fault lies in babel-plugin-fbt, since I am able to use the default exports of other libraries without issue.

To Reproduce

Not certain what the minimal replication case is.

Expected behavior

When using TypeScript and/or webpack, FBT should work reliably when using the default export.

envinfo

 System:
    OS: macOS Sierra 10.12.6
    CPU: (8) x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
    Memory: 288.96 MB / 16.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 12.12.0 - ~/.nvm/versions/node/v12.12.0/bin/node
    Yarn: 1.19.1 - /usr/local/bin/yarn
    npm: 6.11.3 - ~/.nvm/versions/node/v12.12.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
kayhadrin commented 4 years ago

We already use const fbt = require('fbt'); in our code successfully, so that shouldn't be the issue. We even have unit test cases to verify that it works:

https://github.com/facebookincubator/fbt/blob/master/packages/babel-plugin-fbt/__tests__/fbt-test.js#L159-L161

It'd be best to submit a minimum repro case as a small git repo so that we could look into this. For now, I'd wager that another Babel transform changed the AST in such a way that babel-plugin-fbt couldn't detect the fbt import.

kayhadrin commented 4 years ago

Following our talk, I'd suggest to use this code to output the transient JS code that is present when the error occurs:

https://github.com/facebook/fbt/blob/master/packages/fb-babel-plugin-utils/TestUtil.js#L63-L78

/**
 * Generate formatted JS source code from a given Babel AST object.
 * Note: JS comments are preserved.
 * See `__tests__/TestUtil-test.js` for example.
 *
 * @param {BabelNode} babelNode BabelNode object obtained after parsing JS code
 * or from a Babel Transform.
 * @return {string} JS source code
 */
function generateFormattedCodeFromAST(babelNode) {
  return generate(babelNode, {comments: true}, '').code.trim();
}

function formatSourceCode(input) {
  return generateFormattedCodeFromAST(parse(input));
}
jorisre commented 4 years ago

@kayhadrin As we discussed in #137, you can find a minimal reproduction of this issue

Repro use Next.js & Typescript.

In src/pages/index.tsx, I've describe 3 cases, one of which does not works.

➡️ https://github.com/joris-/fbt-issue

kayhadrin commented 4 years ago

FYI: someone wrote an article that could be useful to others using typescript: https://medium.com/@frenchyooy/configuring-fbt-api-with-typescript-and-react-create-app-492ee72f44bb

yrichard commented 4 years ago

FYI: I was having the same problem and switched to import {fbt} from "fbt";