Skip to content
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

Dynamically loading locales broken for application build #26904

Closed
1 task done
jasedwards opened this issue Jan 19, 2024 · 7 comments
Closed
1 task done

Dynamically loading locales broken for application build #26904

jasedwards opened this issue Jan 19, 2024 · 7 comments

Comments

@jasedwards
Copy link

jasedwards commented Jan 19, 2024

Command

build

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

16

Description

Since angular 2 came out there have been ongoing discussions about the best way to load locales if you don't know the locale ahead of time. For example, my company supports over 200 locales so importing each one at the top of the file is not realistic. The most recent accepted workaround was to do the below. Now with esbuild this no longer works. Is there an accepted way to do this now?

          /* webpackMode: "lazy-once" */
          /* webpackChunkName: "i18n-base" */
          /* webpackExclude: /(^en)\.js/ */
          /* webpackExclude: /\.d\.ts$/ */
          `@/../node_modules/@angular/common/locales/${localeId}.mjs`
        ).then(
          module => {
            registerLocaleData(module.default, localeId);
            resolve();
          },
          () => {
            import(
              /* webpackMode: "lazy-once" */
              /* webpackChunkName: "i18n-base" */
              /* webpackExclude: /(^en)\.js/ */
              /* webpackExclude: /\.d\.ts$/ */
              `@/../node_modules/@angular/common/locales/${localeId.split('-')[0]}.mjs`
            )
              .then(module => {
                registerLocaleData(module.default, localeId);
                resolve();
              })
              .catch((e) => {
                console.error(e);
                //Need to fall back to something
                return this.handleEnglishLocale(localeId, resolve, reject);
              });

Minimal Reproduction

ng build after having a service that tries to load locale dynamically.

Exception or Error

Failed to resolve module specifier '@/../node_modules/@angular/common/locales/it.mjs'

Your Environment

17.0.8

Anything else relevant?

No response

@alan-agius4
Copy link
Collaborator

The previously mentioned pattern was never officially supported since it was a feature specific to Webpack. Esbuild necessitates that imports be statically analyzable for processing.

Nevertheless, you can achieve the desired outcome by referencing each locale lazily in a manner compatible with all bundlers. The following is equivalent to what Webpack was doing during the build process.

function loadLocale(locale: string) {
  return {
     'en': () => import('@angular/common/locales/en'),
     'fr': () => import('@angular/common/locales/fr'),
     'de': () => import('@angular/common/locales/de'),
  }
}

@alan-agius4 alan-agius4 closed this as not planned Won't fix, can't repro, duplicate, stale Jan 22, 2024
@alan-agius4
Copy link
Collaborator

You could also do something like

const localeData = await import(`../node_modules/@angular/common/locales/${localeId}.mjs`);

@piozygmunt
Copy link

Hey, based on my understanding how building works your first suggestion will work similar to what webpack does

The previously mentioned pattern was never officially supported since it was a feature specific to Webpack. Esbuild necessitates that imports be statically analyzable for processing.

Nevertheless, you can achieve the desired outcome by referencing each locale lazily in a manner compatible with all bundlers. The following is equivalent to what Webpack was doing during the build process.

function loadLocale(locale: string) {
  return {
     'en': () => import('@angular/common/locales/en'),
     'fr': () => import('@angular/common/locales/fr'),
     'de': () => import('@angular/common/locales/de'),
  }
}

but could you explain a bit more solution from your last comment?

You could also do something like

const localeData = await import(`../node_modules/@angular/common/locales/${localeId}.mjs`);

Won't esbuild generate as many chunks as there are locales in node_modules/@angular/common/locales/ directory with this approach? So it's not exactly what webpack does with "magic comments". Or am i missing something here?

@jasedwards
Copy link
Author

For the moment I moved on to other issues. I don't think it's reasonable to have to manually import 250 cultures as we are an actual enterprise application that has to work globally. It is too bad something could not have been done on angular's side to actually make what I assume is a common functionality supportable. I did try ../node_modules... but no matter what path I try it either fails during build time or during runtime.

@JeanMeche
Copy link
Member

@jasedwards FWIW we're investigating using the Intl API to drop the requirement for those locale files.

@jcompagner
Copy link

this is not just about the locales that angular ships but any kind
I ported our product to Angular 17.x with now the new application builder but that had quite some changes which are quite horrible if you ask me. I also added here:
evanw/esbuild#700 (comment)

a comment about that, the thing is that now you need to hard code languages or locales, if that are 10 or 20 then it is doable
But maintaining this is horrible (i now need to check constantly when i update 3 or 4 3rd party components/packages if they have new language/locale files)
And yes for Angular this is not doable because i think it could be up to 1000 files..

As you can read in the above comment, i left angular to be dynamic (because of the many files and because angular at least is already a esm module, not a commonjs that needs to be wrapped).
But i notice that that has more problems, because now the import statement is not rewritten at all and i need to take care of the base ref of the page my self and make sure it download the correct file..:

Servoy/servoy-eclipse@cb3ffb3#diff-9252feff0331dcff3d2e09667dc94116340079476026a6ab44a5b522af22eb3aR166

besides that i also need to tweak the server side because mjs files that are now downloaded don't have by default the correct mime type set...

So not supporting dynamically loading of modules based does cause code explosion and maintenance nightmare..

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 23, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants