svelte-i18n: CJS / ESM conflict

From https://github.com/kaisermann/svelte-i18n/issues/209#issuecomment-1704354362


What I observed appears to have a different source. Somehow the modules are resolved the wrong way.

My application’s import resolves to node_modules/svelte-i18n/dist/runtime.cjs.js which has:

var IntlMessageFormat = require('intl-messageformat');
....
IntlMessageFormat.resolveLocale
...
new IntlMessageFormat(message, ...)

But the require('intl-messageformat') is resolved in such a way, that IntlMessageFormat is an object with a default property which contains the actual class, so the new IntlMessageFormat/IntlMessageFormat.resolveLocale errors. There probably is some mixing of CJS and ESM going on (this is always such a pain).

Unfortunately, I have not been able to create a minimal reproduction so far. This should probably be tracked in a separate issue.


The logged errors could maybe be more generic, as these are lies:

[svelte-i18n] The initial locale “de” is not a valid locale. [svelte-i18n] Message “…” has syntax error: IntlMessageFormat is not a constructor

_Originally posted by @brunnerh in https://github.com/kaisermann/svelte-i18n/issues/209#issuecomment-1704354362_

About this issue

  • Original URL
  • State: closed
  • Created 10 months ago
  • Comments: 22 (4 by maintainers)

Commits related to this issue

Most upvoted comments

I’ve released 3.7.5-alpha.1 with the updated intl-messageformat version. I’m gonna do a major bump soon with the appropriate pkg.exports field in the package.json, but just want to guarantee that the current major will be working in its final version.

I’ve tested it with the repo made by @Pierstoval and the build is passing and the preview working

Except that you might want to use the library on a Node server, so you don’t have to use another library to do the same thing you already do on the client. Which is exactly what I do.

ESM runs on the server as well. All SvelteKit projects have been ESM-only since day 1. Svelte 4 only outputs ESM. Vite is dropping CJS support for the server in Vite 5 to be released shortly and 70% of Svelte users use Vite. CJS support in Svelte is basically dead at this point. If you still need it for some reason you can always import the library as ESM and then bundle your project to CJS.

I recommend using publint to diagnose issues like these: https://publint.dev/svelte-i18n@3.7.4

Also, given that this is a Svelte-specific library, there’s really no reason to have a CJS build. The best solution would be to drop the CJS version which would simplify things a fair amount

works with 3.7.3 for me, but not with 3.7.4

I spent hours looking at different versions of the package and the behavior made no sense to me at all.

After seeing in #232 that installing the latest version fixed this, I went through the various 10.x.x versions to see what change might have caused the fix and it started to work at v.10.1.2 which is a completely broken release that only contains the raw source. Later versions like v.10.1.3 appear to work as well, meanwhile the changelog is useless for those versions:

Changelog Snippet

10.3.0 (2023-01-30)

Features

  • intl-messageformat: support more parse options in constructor (e6b43dc)

10.2.6 (2023-01-26)

Note: Version bump only for package intl-messageformat

10.2.5 (2022-12-02)

Note: Version bump only for package intl-messageformat

10.2.4 (2022-12-01)

Note: Version bump only for package intl-messageformat

10.2.3 (2022-12-01)

Note: Version bump only for package intl-messageformat

10.2.2 (2022-11-29)

Note: Version bump only for package intl-messageformat

10.2.1 (2022-10-17)

Note: Version bump only for package intl-messageformat

10.2.0 (2022-10-13)

Features

Also, a locally installed v.10 should not even be used as far as I understand it, as the version specified by svelte-i18n is ^9.13.0 which is not compatible with a major version change to version v.10.

It’s been breaking either way; for me since 3.4.0. Though my issue might be less common since I am not using SvelteKit which is rather popular and a first-party framework.

You should be able to make Vite’s SSR work by adding this to the vite.config.js:

export default defineConfig({
	// ...
	ssr: {
		noExternal: [
			'intl-messageformat',
			'@formatjs/icu-messageformat-parser',
			'@formatjs/icu-skeleton-parser',
		],
	},
});

Context:

Dependencies are “externalized” from Vite’s SSR transform module system by default when running SSR. This speeds up both dev and build.

If a dependency needs to be transformed by Vite’s pipeline, for example, because Vite features are used untranspiled in them, they can be added to ssr.noExternal.

There are also options related to optimization that could be relevant; there is a note regarding ESM modules referencing CJS modules. (Tried a few things there, but it did not seem to matter.)

Rather annoying that this doesn’t “just work”. As noted, both packages in theory support both module types. I’d say the issue may be on the side of the build tooling here.


@oyvindo found another fix/workaround (#232):

I fixed the problem by installing intl-messageformat in my project ^10.5.1

Tested that and it seems to work, the reason is beyond me…

i’m using vercel-adapter and getting it

@kaisermann Works for me now.

3.7.4 still has same issue

@brunnerh I don’t have time right now to try to reproduce this, but I’m aware of this type of cjs/esm import conflict. Thankfully, intl-messageformat also exports the class as a named export. I just released version 3.7.4 which replaces the default import for the named ones. Can you tell me if it fixes the issue for you?