Angular "InvalidPipeArgument: Missing locale data" 当使用 optimization=true 构建或服务时(--prod 选项)

Angular "InvalidPipeArgument: Missing locale data" when build or serve with optimization=true (--prod option)

初始上下文

我用法语构建了一个 Angular 应用程序。

我使用原生日期管道 | date 和日期选择器组件 (@danielmoncada/angular-datetime-picker)。

我想以法式显示日期并且日期选择器组件已本地化为法文(月份名称,...)

代码示例:

<p>raw: {{today}}</p>
<p>date pipe: {{today | date}}</p>
<p>date pipe 'dd/MM/yyyy': {{today | date:'dd/MM/yyyy'}}</p>
<p>
  date picker:
  <input [owlDateTime]="dt1" [owlDateTimeTrigger]="dt1" placeholder="Date Time">
  <owl-date-time [firstDayOfWeek]="1" [pickerType]="'calendar'" #dt1></owl-date-time>
</p>

未设置任何语言环境的结果

正如预期的那样,这是 英语

添加一些法语本地化内容

现在我按照我对 angular 中本地化的理解,在我的 AppModule 中导入带有 registerLocaleData 的法语语言环境并相应地设置 LOCALE_ID

import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';

registerLocaleData(localeFr, 'fr');

@NgModule({
  declarations: [],
  imports     : [],
  providers   : [
    { provide: LOCALE_ID, useValue: 'fr'}
  ]
})

此法语区域设置的结果

这是法语,符合预期。

好的,好的!

我不得不说,我在这里使用经典的 ng serve angular-cli 命令启动开发中的应用程序。

在测试环境中部署 = 问题!

但是当将应用程序部署到测试环境时,这些与日期相关的东西不起作用并且由于浏览器控制台中的 javascript 错误而破坏了应用程序:

ERROR Error: InvalidPipeArgument: 'Missing locale data for the locale "fr".' for pipe 'e'

使用此法语区域设置并使用 --prod / optimization=true 提供的结果

由于控制台错误中断了页面生成,因此未显示日期和日期选择器...

第一次分析

我们猜测这是因为我们在构建生产环境时使用了optimization=true(在angular.json文件中设置的参数)

此参数位于architect.build.configurations.production in angular.json:

  "architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {...},
      "configurations": {
        "production": {
          "fileReplacements": [...],
          "optimization": true,
          "outputHashing": "all",
          "sourceMap": false,
          "extractCss": true,
          "namedChunks": false,
          "extractLicenses": true,
          "vendorChunk": false,
          "buildOptimizer": true,
...

的确,如果我们设置成false,问题就来了!

但这不能在生产中禁用优化。

正在开发中尝试在本地重现

我使用命令 ng serve --prod 在本地启动了我的应用程序,这将 使用上述生产构建 ,并将优化设置为 true。

>> 我重现错误!!

然后我尝试在 angular.json 中的 architect.serve.configurations.production 位置用 optimization: false 覆盖:

    "serve": {
      "builder": "@angular-devkit/build-angular:dev-server",
      "options": {
        "browserTarget": "dpe-front:build"
      },
      "configurations": {
        "production": {
          "browserTarget": "dpe-front:build:production",
          "optimization": false
        }
      }
    },

>> 我不会重现这个错误!!

结论:

问题好像是在“优化”上处理的。

设置为 true 时,我的 LOCALE 定义不起作用,它会破坏应用程序...

为什么区域设置在这种情况下不起作用? 我错过了什么吗?

找到问题根源了!

TL;DR

这似乎是 Angular 10.x 中的一个 bug,由 过于激进的 tree shaking 引起在生产模式下构建 并且如果您的项目配置为 angular 严格模式.

确实:

  • 升级到 angular 11.x 解决了问题

  • 在应用程序的 package.json 文件中将 sideEffects 设置为 true 解决了问题

更多解释

strict 模式下启动新项目时,会在项目的 src/app 目录中创建一个 package.json 文件。

{
  "name": "myproject",
  "private": true,
  "description_1": "This is a special package.json file that is not used by package managers.",
  "description_2": "It is used to tell the tools and bundlers whether the code under this directory is free of code with non-local side-effect. Any code that does have non-local side-effects can't be well optimized (tree-shaken) and will result in unnecessary increased payload size.",
  "description_3": "It should be safe to set this option to 'false' for new applications, but existing code bases could be broken when built with the production config if the application code does contain non-local side-effects that the application depends on.",
  "description_4": "To learn more about this file see: https://angular.io/config/app-package-json.",
  "sideEffects": false
}

它有 sideEffects 选项告诉 webpack 捆绑器 它可以对该目录下的所有文件进行更积极的摇树 ,因为它们是“纯”。目标是最后得到更小的文件。

这里有更多详细信息: https://webpack.js.org/guides/tree-shaking/

因此,当 sideEffects 设置为 false(默认值)时,它表示所有文件都可用于“更激进的 tree shaking”。

将其设置为 true 或删除此 package.json 文件解决了我的问题。

然而,在一个全新的测试项目中做同样的事情不会导致同样的问题...

区别在于这个新项目是在 angular v11 中,而我的项目是使用 angular v10.

开始的

所以这个错误似乎已经在 angular 11 版本中解决了。

我在使用 DatePipe 时遇到了问题,但显然其他管道(如 AsyncPipe)可能会导致相同类型的“过于激进的 tree shaking 问题”,如本例所示:

希望这对其他人有帮助!