formatjs icon indicating copy to clipboard operation
formatjs copied to clipboard

@formatjs/cli-lib version 7.0.0 is broken

Open aradzie opened this issue 1 year ago • 27 comments

Error [ERR_MODULE_NOT_FOUND]: 
   Cannot find module '/home/user/project/node_modules/@formatjs/cli-lib/lib_esnext/src/extract' 
   imported from /home/user/project/node_modules/@formatjs/cli-lib/lib_esnext/index.js

The package @formatjs/cli-lib as of version 7.0.0 is an EcmaScript module because of the following configuration in package.json:

 "type": "module",

However, the mandatory .js extensions are missing from the imported files. The package uses CommonJS naming convention where file extensions are optional in the required modules.

aradzie avatar Dec 08 '24 10:12 aradzie

We suggest to configure the eslint-plugin-n ESLint plugin with the n/file-extension-in-import rule to fix the missing extensions.

The rule is fixable so all the missing .js extensions in the imported modules can be automatically appended by running eslint --fix.

aradzie avatar Dec 08 '24 10:12 aradzie

apology for breaking this. Any reason you're not using the CLI?

longlho avatar Dec 09 '24 05:12 longlho

Any reason you're not using the CLI?

We have a custom integration. We extract keys by entrypoints by building dependency tree. So we are using Node API in our script instead of multiple command calls

izorg avatar Dec 09 '24 16:12 izorg

I just ran in to this as well. Since my custom CLI tool is small, I set type: module in package.json -- however, this did not fix the issue.

The error is about lib_esnext/src/extract but the file is lib_esnext/src/extract.js in ESM... the extensions need to exist.

Things that need to be fixed:

  • all imports must have extensions
  • folders can't be imported anymore, so for example, when importing ./formatters, you need to import instead ./formatters/index.js
  • import { hoistSelectors } from '@formatjs/icu-messageformat-parser/manipulator'; won't work without a package.json#exports config aliasing ./manipulator to ./manipulator.js -- which you can do via:
    "exports": {
      ".": "lib/index.js",
      "./*: "lib/*.js"
    }
    
    • this library has the same problem as the CLI-lib, there are no extensions on the relative imports

Even after fixing the above locally, I get this error:

ref_km24djpfvefothdey2goejyaoe/node_modules/@formatjs/cli-lib/lib_esnext/src/console_utils.js:1
import { green, red, supportsColor, yellow } from 'chalk';
         ^^^^^
SyntaxError: Named export 'green' not found. The requested module 'chalk' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'chalk';
const { green, red, supportsColor, yellow } = pkg;

So, thankfully the error says how to move forward. Alternatively, cli-lib could upgrade chalk, which is esm-only.

Same for fs-extra:

ref_vvl6jp6wpkowtgjpi5rqqcbici/node_modules/@formatjs/cli-lib/lib_esnext/src/compile.js:2
import { outputFile, readJSON } from 'fs-extra';
                     ^^^^^^^^
SyntaxError: Named export 'readJSON' not found. The requested module 'fs-extra' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'fs-extra';
const { outputFile, readJSON } = pkg;

(and since I'm upgrading from v6):

import CLI from '@formatjs/cli-lib';
       ^^^
SyntaxError: The requested module '@formatjs/cli-lib' does not provide an export named 'default'

so, this actually needs to be either:

import * as CLI from '@formatjs/cli-lib';

CLI.extractAndWrite(...)

or

import { extractAndWrite } from '@formatjs/cli-lib';

(my preference)

but then!! Another error:

Error [ERR_REQUIRE_CYCLE_MODULE]: 
  Cannot require() ES Module <.pnpm>/@[email protected]_patch_hash=pf5m2fqbj2gtwat25phxiuf5ty/node_modules/@formatjs/icu-messageformat-parser/lib/index.js 
  in a cycle. 
  (from <.pnpm>/@[email protected]/node_modules/@formatjs/ts-transformer/src/transform.js)

so it seems @formatjs/ts-transformer also has all the same problems as the other packages -- it needs a package.json#exports to target ESM/require differences

NullVoxPopuli avatar Dec 11 '24 17:12 NullVoxPopuli

For others, here is how you can move forward with v7 before they fix the builds if you need the features / fixes (like I did):

  • use pnpm (or a modern npm / yarn 4+ / some other modern package manager)
  • copy the attached patches to your patches directory
  • set this config (or similar for your package manager)
    "pnpm": {
      "patchedDependencies": {
        "@formatjs/cli-lib": "patches/@formatjs__cli-lib.patch",
        "@formatjs/[email protected]": "patches/@[email protected]",
        "@formatjs/[email protected]": "patches/@[email protected]"
      }
    }
    

@[email protected] @[email protected] @formatjs__cli-lib.patch

NullVoxPopuli avatar Dec 11 '24 19:12 NullVoxPopuli

apology for breaking this. Any reason you're not using the CLI?

I have build a custom workflow around the tools of formatjs. I have a script that:

  1. Scans multiple packages in a monorepo for translations.
  2. Synchronizes translations in different languages, keeps translation ids sorted, etc.
  3. Writes translations report.

To be honest, I wrote the script long time ago, and don't remember exactly, but I think it is impossible to achieve the same goals with just bare CLI tools.

aradzie avatar Dec 12 '24 10:12 aradzie

Not impossible. We have the same use case <3

NullVoxPopuli avatar Dec 12 '24 12:12 NullVoxPopuli

Thanks for the patience while I sort out this esm interop mess. Prob won't have time till EOW. The CLI supports vue which seems to go all in on esm while others still provide cjs which choked when we tried to upgrade it.

longlho avatar Dec 12 '24 12:12 longlho

I think the problem with "SyntaxError: Named export 'green' not found. The requested module 'chalk'" error might be fixed by switching to chalk 5.x (if I checked correctly v4 is CJS, but v5 switched to ESM which should do the trick).

krulis-martin avatar Dec 13 '24 21:12 krulis-martin

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.

github-actions[bot] avatar Jan 13 '25 02:01 github-actions[bot]

Not stale!

nstepien avatar Jan 13 '25 10:01 nstepien

This is still not fixed, any updates on when you will have time to address this @longlho? 🙏

bryansantamaria avatar Feb 10 '25 13:02 bryansantamaria

@longlho Also is waiting for this fix as soon as possible!!!

SergeyKrasnolobov avatar Mar 05 '25 12:03 SergeyKrasnolobov

Same, building a NX executor to extract strings and would love to use the Node API instead of exec-ing the CLI :)

TylerK avatar Mar 17 '25 18:03 TylerK

sry will try to find some time this week/end

longlho avatar Mar 17 '25 23:03 longlho

looks like this issue is still present on 7.3.3. these files need extensions:

node_modules/@formatjs/cli-lib/lib_esnext/index.js

NullVoxPopuli avatar Apr 01 '25 21:04 NullVoxPopuli

can you guys try latest version?

longlho avatar Apr 20 '25 05:04 longlho

7.3.4 fails for me with an error like this:

> formatjs-esm-repro@ test /Users/wburgin/Repositories/walkerburgin/formatjs-esm-repro
> ./test.mjs example.jsx

node:internal/modules/esm/resolve:188
  const resolvedOption = FSLegacyMainResolve(packageJsonUrlString, packageConfig.main, baseStringified);
                         ^

Error: Cannot find package '/Users/wburgin/Repositories/walkerburgin/formatjs-esm-repro/node_modules/@formatjs/cli-lib/package.json' imported from /Users/wburgin/Repositories/walkerburgin/formatjs-esm-repro/test.mjs
    at legacyMainResolve (node:internal/modules/esm/resolve:188:26)
    at packageResolve (node:internal/modules/esm/resolve:769:14)
    at moduleResolve (node:internal/modules/esm/resolve:831:20)
    at defaultResolve (node:internal/modules/esm/resolve:1036:11)
    at DefaultModuleLoader.resolve (node:internal/modules/esm/loader:251:12)
    at DefaultModuleLoader.getModuleJob (node:internal/modules/esm/loader:140:32)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:33)
    at link (node:internal/modules/esm/module_job:75:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v20.5.1
 ELIFECYCLE  Test failed. See above for more details.

It looks like package.json points to a main (index.js) that doesn't exist:

➜  formatjs-esm-repro git:(master) ls node_modules/@formatjs/cli-lib/
LICENSE.md   README.md    lib_esnext   node_modules package.json

It also looks like relative imports in the lib_esnext directory are still missing extensions as well.

Small standalone repro here if it's helpful: https://github.com/walkerburgin/formatjs-esm-repro

walkerburgin avatar Apr 20 '25 17:04 walkerburgin

Latest version doesn't support esm

longlho avatar Apr 20 '25 18:04 longlho

Latest version doesn't support esm

Why?

SergeyKrasnolobov avatar Apr 21 '25 08:04 SergeyKrasnolobov

Why?

That's a really good question. Our engineers are wondering this exact thing. It caused us some headaches and if there's a good reason, that may make it worth the headaches.

dustinlessard-wf avatar Apr 25 '25 11:04 dustinlessard-wf

We basically have to convert downstream packages to esm and that's a lot of breaking changes. Supporting both is even worse.

longlho avatar Apr 25 '25 11:04 longlho

In version 7.4.1, the following import does not work for me at all:

import { extract } from '@formatjs/cli-lib'

This is because there's no index.js file in the package root, even though the package.json of @formatjs/cli-lib declares it as the main entry point:

// node_modules/@formatjs/cli-lib/package.json
{
  ...
  "main": "index.js",
}

Temporary fixed by direct import from @formatjs/cli-lib/lib_esnext:

import { extract } from '@formatjs/cli-lib/lib_esnext'

avasuro avatar May 05 '25 14:05 avasuro

Currently, the API Expose of this library is not suitable for third-party integration development.

The webpack loader integration ^1 I am doing now copies some logic from this library. If I make another webpack plugin to do automatic extract messages, I will also need to copy some code

If more APIs can be exposed instead of this file-based API design, I believe there will be a better developer experience.

for example: develop a webpack plugin on rebuild than automatic re-generate extracted message file.

septs avatar Jun 30 '25 07:06 septs

In version 7.4.1, the following import does not work for me at all:

import { extract } from '@formatjs/cli-lib' This is because there's no index.js file in the package root, even though the package.json of @formatjs/cli-lib declares it as the main entry point:

// node_modules/@formatjs/cli-lib/package.json { ... "main": "index.js", } Temporary fixed by direct import from @formatjs/cli-lib/lib_esnext:

import { extract } from '@formatjs/cli-lib/lib_esnext'

import { extract } from '@formatjs/cli-lib/lib_esnext'

Not work in 7.4.2

Error: Directory import '...\apps\web\node_modules\@formatjs\cli-lib\lib_esnext' is not supported resolving ES modules imported from ...\apps\web\intl\extract.ts
Did you mean to import "@formatjs/cli-lib/lib_esnext/index.js"?
    at finalizeResolution (node:internal/modules/esm/resolve:262:11)
    at moduleResolve (node:internal/modules/esm/resolve:859:10)
    at defaultResolve (node:internal/modules/esm/resolve:983:11)
    at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:801:12)
    at ModuleLoader.#cachedDefaultResolve (node:internal/modules/esm/loader:725:25)
    at ModuleLoader.resolve (node:internal/modules/esm/loader:708:38)
    at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:309:38)
    at ModuleJob.#link (node:internal/modules/esm/module_job:202:49) {
  code: 'ERR_UNSUPPORTED_DIR_IMPORT',
  url: 'file:///.../apps/web/node_modules/@formatjs/cli-lib/lib_esnext'
}

for import { extract } from '@formatjs/cli-lib/lib_esnext/index.js'

Error: Cannot find module ...\node_modules\.pnpm\@[email protected]_@[email protected]\node_modules\@formatjs\cli-lib\lib_esnext\src\extract' imported from ...\node_modules\.pnpm\@[email protected]_@[email protected]\node_modules\@formatjs\cli-lib\lib_esnext\index.js
    at finalizeResolution (node:internal/modules/esm/resolve:274:11)
    at moduleResolve (node:internal/modules/esm/resolve:859:10)
    at defaultResolve (node:internal/modules/esm/resolve:983:11)
    at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:801:12)
    at ModuleLoader.#cachedDefaultResolve (node:internal/modules/esm/loader:725:25)
    at ModuleLoader.resolve (node:internal/modules/esm/loader:708:38)
    at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:309:38)
    at ModuleJob.#link (node:internal/modules/esm/module_job:202:49) {
  code: 'ERR_MODULE_NOT_FOUND',
  url: 'file:///.../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@formatjs/cli-lib/lib_esnext/src/extract'
}

a-ivanov81 avatar Aug 13 '25 13:08 a-ivanov81

someone still needs to go through all the imports and add extensions

NullVoxPopuli avatar Aug 13 '25 13:08 NullVoxPopuli

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '...\node_modules@formatjs\cli-lib\lib_esnext\src\extract' imported from ...\app\node_modules@formatjs\cli-lib\lib_esnext\index.js at finalizeResolution (node:internal/modules/esm/resolve:274:11) at moduleResolve (node:internal/modules/esm/resolve:864:10) at defaultResolve (node:internal/modules/esm/resolve:990:11) at #cachedDefaultResolve (node:internal/modules/esm/loader:768:20) at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:804:38) at ModuleLoader.resolveSync (node:internal/modules/esm/loader:827:52) at #cachedResolveSync (node:internal/modules/esm/loader:787:25) at ModuleLoader.getModuleJobForRequire (node:internal/modules/esm/loader:474:50) at #link (node:internal/modules/esm/module_job:441:34) at new ModuleJobSync (node:internal/modules/esm/module_job:414:17) { code: 'ERR_MODULE_NOT_FOUND', url: 'file:///.../node_modules/@formatjs/cli-lib/lib_esnext/src/extract' Node.js v24.8.0

i`ve tried 7.0.0 and 7.4.2 - same result compile function imported well but extract do not adding lib_esnext\index.js to import do not help at all the error apears when i run custom extract script (on 6 version run properly) also i using CommonJS do 7 version support CommonJS? is migration guide from 6 to 7 comming?

TheTempest7 avatar Sep 11 '25 10:09 TheTempest7