Angular Universal 12(服务器端)在延迟加载时不加载模块

Posted

技术标签:

【中文标题】Angular Universal 12(服务器端)在延迟加载时不加载模块【英文标题】:Angular Universal 12 ( Server side ) not loading modules on lazy load 【发布时间】:2021-11-29 02:06:17 【问题描述】:

我有一个只有一个模块的小型应用程序,该应用程序工作正常,但它没有在页面源上呈现组件。 问题是当我使用 npm run dev:s-s-r 启动应用程序时,一切都很好(在页面源代码上,您有在标签之后加载的组件(在我的情况下为主页组件),您可以看到元标签,所以一切看起来工作正常),在 npm run serve:s-s-r 上仍然是一样的,一切看起来都很好,似乎一切正常。 但问题是当我发布应用程序时,在服务器上,标签后缺少 home-component。

这是 npm run dev:s-s-r 页面源的图片:

这是已发布版本的页面来源图片:

这里是 tsconfig.server.json


  "extends": "./tsconfig.app.json",
  "compilerOptions": 
    "outDir": "./out-tsc/server",
    "target": "es2019",
    "types": [
      "node"
    ]
  ,
  "files": [
    "src/main.server.ts",
    "server.ts"
  ],
  "angularCompilerOptions": 
    "entryModule": "./src/app/app.server.module#AppServerModule"
  

这是我的 server.ts 文件:

    import 'zone.js/dist/zone-node';

    import  ngExpressEngine  from '@nguniversal/express-engine';
    import * as express from 'express';
    import  join  from 'path';

    import  AppServerModule  from './src/main.server';
    import  APP_BASE_HREF  from '@angular/common';
    import  existsSync  from 'fs';

    // The Express app is exported so that it can be used by serverless Functions.
    export function app(): express.Express 
      const server = express();
      const distFolder = join(process.cwd(), 'dist/browser');
      const indexhtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

      // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
      server.engine('html', ngExpressEngine(
        bootstrap: AppServerModule,
      ));

      server.set('view engine', 'html');
      server.set('views', distFolder);

      // Example Express Rest API endpoints
      // server.get('/api/**', (req, res) =>  );
      // Serve static files from /browser
      server.get('*.*', express.static(distFolder, 
        maxAge: '1y'
      ));

      // All regular routes use the Universal engine
       server.get('*', (req: express.Request, res: express.Response) => 
        res.render(indexHtml,  req, providers: [ provide: APP_BASE_HREF, useValue: req.baseUrl ] );
      );

      return server;
    

    function run(): void 
      const port = process.env.PORT || 4000;

      // Start up the Node server
      const server = app();
      server.listen(port, () => 
        console.log(`Node Express server listening on http://localhost:$port`);
      );
    

    // Webpack will replace 'require' with '__webpack_require__'
    // '__non_webpack_require__' is a proxy to Node 'require'
    // The below code is to ensure that the server is run only when not requiring the bundle.
    declare const __non_webpack_require__: NodeRequire;
    const mainModule = __non_webpack_require__.main;
    const moduleFilename = mainModule && mainModule.filename || '';
    if (moduleFilename === __filename || moduleFilename.includes('iisnode')) 
      run();
    

    export * from './src/main.server';


<!-- end snippet -->

**Here is main.serve.ts file:**



    import '@angular/platform-server/init';

    import  enableProdMode  from '@angular/core';

    import  environment  from './environments/environment';

    if (environment.production) 
      enableProdMode();
    

    export  AppServerModule  from './app/app.server.module';
    export  renderModule, renderModuleFactory  from '@angular/platform-server';

    export  AppServerModule  from './app/app.server.module';
    export  renderModule, renderModuleFactory  from '@angular/platform-server';
**Here is app.server.module.ts file:** <!-- begin snippet: js hide: false console: true babel: false --> <!-- language: lang-js --> import NgModule from '@angular/core'; import ServerModule from '@angular/platform-server'; import AppModule from './app.module'; import AppComponent from './app.component'; @NgModule( imports: [ AppModule, ServerModule, ], bootstrap: [AppComponent], ) export class AppServerModule

这里是 app.server.module.ts 文件:

import  NgModule  from '@angular/core';
import  ServerModule  from '@angular/platform-server';

import  AppModule  from './app.module';
import  AppComponent  from './app.component';

@NgModule(
  imports: [
    AppModule,
    ServerModule,
  ],
  bootstrap: [AppComponent],
)
export class AppServerModule 

这里是 app.module.ts 文件:

import  HttpClientModule  from '@angular/common/http';
import  NgModule  from '@angular/core';
import  BrowserModule  from '@angular/platform-browser';
import  RouterModule  from '@angular/router';

import  AppRoutingModule  from './app-routing.module';
import  AppComponent  from './app.component';

@NgModule(
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule.withServerTransition( appId: 'serverApp' ),
    HttpClientModule,
    RouterModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
)
export class AppModule  

这是我的 app-routing.module.ts 文件:

 import  NgModule  from '@angular/core';
    import  RouterModule, Routes  from '@angular/router';

    const routes: Routes = [
      
        path        : '',
        redirectTo  : 'home',
        pathMatch   : 'full',
      ,
      
        path         : 'home',
        loadChildren : () => import('./home/home.module').then(m => m.HomeModule)  
      ,
      
        path        : '**',
        redirectTo  : '',
        pathMatch   : 'full',
      ,
    ];

    @NgModule(
      imports: [
        RouterModule.forRoot(routes)
      ],
      exports: [RouterModule]
    )
    export class AppRoutingModule  

编辑: 我目前找到的解决方案是在 tsconfig.server.json 文件中添加 module: commonjs,该应用程序比平时慢了一点,但它正在完成它的工作。如果有人有更好的解决方案,请随时留下答案。

【问题讨论】:

你在使用 angular service-worker/pwa 吗? @Pieterjan 不,我没有使用任何东西,我只是创建了新的应用程序,添加了@nguniversal/express-engine,添加了一个模块并使其延迟加载,我在组件中添加了元标记在那个延迟加载的模块中,就是这样,我没有做任何其他事情或将任何其他包添加到应用程序中。 您找到解决方案了吗?我这边也有同样的问题。 解决方案在我发布的帖子的末尾(在编辑部分)。我在 tsconfig.server.json 文件中添加了模块:commonjs,应用程序比平时慢,但它正在完成它的工作。 @Shakir 可以分享tsconfig.server.json的代码 【参考方案1】:

您缺少 Angular Universal 所需的 initialNavigation 属性。

@NgModule(
  imports: [RouterModule.forRoot(routes, 
    initialNavigation: 'enabled'
)],
  exports: [RouterModule],
)
export class AppRoutingModule 

【讨论】:

如果我添加 initialNavigation: 'enabled' 它根本不会打开我部署的应用程序,它只是在加载应用程序的选项卡上有微调器,但它根本没有打开。 还有@LukaszGawrys,initialNavigation: 'enabled' 在 Angular v11 link987654321@ 之后可以 1:1 替换为 enabledBlocking

以上是关于Angular Universal 12(服务器端)在延迟加载时不加载模块的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2 Universal - 使用手写笔和 pug 模板的服务器端渲染

Angular 5 Universal 在服务器端渲染期间等待 http 请求返回

使用 Angular Universal 在服务器端运行时找不到模块环境

Angular Universal 与 i18n(服务器端渲染)

在 VS Code 中调试 Angular Universal Starter App 的服务器端不起作用

使用 Angular Universal 进行服务器端渲染的防御性编程思路