Skip to content

fix(react-intl): named esm exports #3261

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

Merged
merged 4 commits into from
Nov 9, 2021
Merged

fix(react-intl): named esm exports #3261

merged 4 commits into from
Nov 9, 2021

Conversation

snyamathi
Copy link
Contributor

@snyamathi snyamathi commented Nov 8, 2021

v5.8.0 introduced a bug where some of the named exports such as injectIntl are no longer statically analyzable by cjs-module-lexer, breaking the named export for es modules.

// index.mjs
import { injectIntl } from 'react-intl';
         ^^^^^^^^^^

SyntaxError: Named export 'injectIntl' not found. The requested module 'react-intl' is a CommonJS module, which may not support all module.exports as named exports.


The root cause is because of a change in Typescript between versions 3.9.7 and 4.0.5 where the added __importDefault function call no longer matches the static analysis lexer (docs) due to the potential for side effects.

  Object.defineProperty(exports, "injectIntl", {
    enumerable: true,
    get: function () {
-     return injectIntl_1.default;                  // v5.7.2
+     return __importDefault(injectIntl_1).default; // v5.8.0
    }
  });

There has been some back and fourth between the Typescript folks and the author of the lexer

with the tl;dr being that the lexer will not be updated since it would effectively cause module loading to work differently in different versions of node and it's better to just be consistent.


The fix here is to remove any export { default as ... from index.js, separating the import and export so that the export is once again statically analyzable.

This is still tree shakable, so we won't pull injectIntl into all code using react-intl or anything like that.

A reasonable test for this might look like this, though I'm not sure exactly how to work this into the build system. I'm having some issues with the bazel setup y'all have here no such package '@npm//ts-node': npm_install failed but I'll see if I can debug those and shoehorn this test in (or something similar).

const reactIntl = require('react-intl');
const lexer = require('cjs-module-lexer');
const fs = require('fs');

const filePath = require.resolve('react-intl');
const content = fs.readFileSync(filePath, 'utf8');
const parsed = lexer.parse(content);

it.each(Object.keys(reactIntl))('should have a named esm export "%s"', name => {
  expect(parsed.exports).toContain(name);
});
 FAIL  ./index.test.js
  ✓ should have a named esm export "createIntlCache" (3 ms)
  ✓ should have a named esm export "MessageDescriptor" (1 ms)
  ✓ should have a named esm export "IntlCache"
  ✓ should have a named esm export "Formatters"
  ✓ should have a named esm export "IntlFormatters" (1 ms)
  ✓ should have a named esm export "FormatDisplayNameOptions"
  ✓ should have a named esm export "FormatListOptions" (1 ms)
  ✓ should have a named esm export "FormatPluralOptions" (1 ms)
  ✓ should have a named esm export "FormatRelativeTimeOptions"
  ✓ should have a named esm export "FormatNumberOptions" (1 ms)
  ✓ should have a named esm export "FormatDateOptions" (1 ms)
  ✓ should have a named esm export "CustomFormatConfig" (1 ms)
  ✓ should have a named esm export "CustomFormats"
  ✓ should have a named esm export "UnsupportedFormatterError" (1 ms)
  ✓ should have a named esm export "InvalidConfigError"
  ✓ should have a named esm export "MissingDataError"
  ✓ should have a named esm export "MessageFormatError"
  ✓ should have a named esm export "MissingTranslationError" (1 ms)
  ✓ should have a named esm export "ReactIntlErrorCode" (1 ms)
  ✓ should have a named esm export "ReactIntlError"
  ✓ should have a named esm export "defineMessages"
  ✓ should have a named esm export "defineMessage"
  ✕ should have a named esm export "injectIntl" (7 ms)
  ✓ should have a named esm export "RawIntlProvider"
  ✓ should have a named esm export "IntlContext" (1 ms)
  ✕ should have a named esm export "useIntl" (1 ms)
  ✕ should have a named esm export "IntlProvider" (2 ms)
  ✓ should have a named esm export "createIntl" (1 ms)
  ✓ should have a named esm export "FormattedDate" (1 ms)
  ✓ should have a named esm export "FormattedTime" (1 ms)
  ✓ should have a named esm export "FormattedNumber" (1 ms)
  ✓ should have a named esm export "FormattedList" (1 ms)
  ✓ should have a named esm export "FormattedDisplayName"
  ✓ should have a named esm export "FormattedDateParts" (1 ms)
  ✓ should have a named esm export "FormattedTimeParts" (1 ms)
  ✓ should have a named esm export "FormattedNumberParts"
  ✓ should have a named esm export "FormattedListParts" (1 ms)
  ✕ should have a named esm export "FormattedRelativeTime" (1 ms)
  ✕ should have a named esm export "FormattedPlural"
  ✕ should have a named esm export "FormattedMessage" (1 ms)
  ✕ should have a named esm export "FormattedDateTimeRange" (1 ms)

@longlho
Copy link
Member

longlho commented Nov 8, 2021

you can add the test, CI can run it

@snyamathi snyamathi force-pushed the esm branch 2 times, most recently from eaef5a9 to 85d5cc0 Compare November 8, 2021 06:10
@snyamathi
Copy link
Contributor Author

@longlho Done 😄 I couldn't figure out how to load the dist file, but I was able to use the typescript compiler programmatically to generate a failing (now passing) test case.

@@ -1,4 +1,8 @@
import * as ReactIntl from '../../'
import * as ts from 'typescript'
import fs from 'fs'
import lexer from 'cjs-module-lexer'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like you need to declare this dep in package.json, then you can add it to the BUILD file, along with typescript

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha - I believe 1bc01f2 should have that sorted out. First time using Bazel so not 100% sure if that's correct.

@longlho longlho merged commit 05edd2c into formatjs:main Nov 9, 2021
@longlho
Copy link
Member

longlho commented Nov 9, 2021

Thanks a lot for your contributions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants