【问题标题】:How to replace Angular module at build time with AOT?如何在构建时用 AOT 替换 Angular 模块?
【发布时间】:2019-10-12 06:20:10
【问题描述】:

我需要能够用一个非常简单的模块替换我的 Angular 应用程序中的一个相当大的模块,以使我的服务器端渲染构建负载(避免对一个过于丰富而无法在服务器上工作的组件的所有不必要的要求反正)。如果没有替换,代码将尝试加载windowdocument。我可以简单地用null-loader 替换一些库,但在这种情况下,我需要通过修剪这个特定的 Angular 模块来切断整个依赖树。

尽管我尝试覆盖原始模块,Angular (@ngtools/webpack) 仍然以某种方式成功地为我希望修剪的组件生成 require 调用...

我试过了:

  • 在编译器插件中使用hostReplacementPaths参数
new AngularCompilerPlugin({
    tsConfigPath: 'tsconfig.ssr.json',
    entryModule: path.join(__dirname, 'src/js/landing/landing.server.module.ts#LandingServerModule'),
    hostReplacementPaths: {
      [path.resolve('./src/js/app/help.module.ts')]: path.resolve('./src/js/landing/server-mock.module.ts')
    }
  })
  • 使用NormalModuleReplacementPlugin
new NormalModuleReplacementPlugin(
      /help\.module\./,
      resource => {
        resource.requestresource.request.replace('app/help.module.ts', 'landing/server-mock.module.ts')
      },
    ),
  • file-replace-loader
{
        test: /help\.module\.ts/,
        loader: 'file-replace-loader',
        options: {
          condition: 'if-replacement-exists',
          replacement: path.resolve('./src/js/landing/server-mock.module.ts'),
          async: true,
        }
      },

我怀疑 Angular 编译器正在扫描文件以查找 webpack 之外的依赖项...

有什么想法可以在构建时用模拟模块覆盖单个 Angular 模块吗?

【问题讨论】:

    标签: angular webpack angular-universal server-side-rendering


    【解决方案1】:

    我找到了解决方案。我必须创建一个中间模块 src/js/app/mock-intermediate-version-of-the-module.ts 来重新导出我需要修剪的模块

    import { NgModule } from '@angular/core';
    import { ModuleThatYouNeedToReplaceAtBuildTime } from '../app/module-to-replace-at-build-time';
    
    @NgModule({
      exports: [
        ModuleThatYouNeedToReplaceAtBuildTime,
      ],
    })
    export class IntermediateVersionOfTheModule {
    }
    

    并创建IntermediateVersionOfTheModule 的模拟版本:

    src/js/app/mock-intermediate-version-of-the-module.ts

    import { NgModule } from '@angular/core';
    
    @NgModule({
    })
    export class LandingHelpModule {
    }
    

    然后在AngularCompilerPlugin 配置中传递以下内容:

    new AotPlugin({
      tsConfigPath: 'tsconfig.ssr.json',
      entryModule: path.join(__dirname, 'src/js/landing/landing.server.module.ts#LandingServerModule'),
      hostReplacementPaths: {
        [path.resolve('intermediate-version-of-the-module.ts')]: path.resolve('./mock-intermediate-version-of-the-module.ts')
      }
    })
    

    诀窍是替换一个只是中间模块的模块,它重新导出我们想要修剪的实际模块。角度编译器会扫描我们的整个模块树,并且无法处理没有模块的任何组件以及具有相同组件的重复模块。

    希望对大家有用!

    【讨论】:

      【解决方案2】:

      我也有同样的问题。我们经常使用文件覆盖,我写了一个用于文件替换的 webpack 解析器插件。切换到 AOT 后,插件不再工作。覆盖仅在第一次构建时反映一次。但不知何故,@ngtools/webpack 仍然引用非覆盖文件,因此观察者不会检测和重新编译覆盖文件中的更改。

      我也尝试了 hostReplacementPaths,但就我而言,这不是一个解决方案,因为似乎 hostReplacementPath 替换不是“可传递的”。因此,通过 hostReplacement 插入的文件中的相对导入将不会在新上下文中找到。

      我现在的解决方案是使用 JIT 进行开发并在生产中切换到 AOT,尽管这有点容易出错。 ngtools/webpack 的文档在某种程度上表明 JIT 中的解析工作有些不同。

      跳过代码生成。可选,默认为 false。禁用代码生成并且不要将代码重构为引导程序。这将 templateUrl: "string" 替换为 template: require("string") (样式类似)以允许 webpack 正确链接资源。 (https://www.npmjs.com/package/@ngtools/webpack)

      启用 skipCodeGeneration 需要使用 platformBrowserDynamic 来引导应用程序并在 webpack 配置中进行一些小的修改(非 ngfactory 样式)。

      我猜这是 AOT 编译中的一些奇怪机制,将来会得到修复,但我对此没有任何希望。

      【讨论】:

        猜你喜欢
        • 2017-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-24
        • 2023-03-08
        • 2017-10-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多