Angular 通用特定路由不加载

Angular universal specific route does not load

我在 Angular Universal 中遇到了一个奇怪的问题,当使用整页条目访问所有路由时,所有路由都正常工作,一个除外!这是我当前的配置:

应用路线:

const routes: Routes = [{
  path: '',
  pathMatch: 'full',
  redirectTo: '/home'
}, {
  path: 'admin',
  loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}, {
  path: 'home',
  loadChildren: () => import('./home/home.module').then(m => m.HomeModule)
}, {
  path: 'foo',
  loadChildren: () => import('./foo/foo.module').then(m => m.FooModule)
}, {
  path: '**',
  loadChildren: () => import('./not-found/not-found.module').then(m => m.NotFoundModule)
}];

server.ts:

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

import * as express from 'express';
import {join} from 'path';
import * as proxy from 'http-proxy-middleware';
// Express server
const app = express();

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap} = require('./dist/server/main');

// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', (_, options: { req, res }, callback) => {
  const engine = ngExpressEngine({
    bootstrap: AppServerModuleNgFactory,
    providers: [
      provideModuleMap(LAZY_MODULE_MAP),
      {provide: 'headers', useFactory: () => options.req.headers, deps: []}
    ]
  });

  engine(_, options, callback);
});

app.set('view engine', 'html');
app.set('views', DIST_FOLDER);

app.use(`/app/`, createRoutes());

function createRoutes() {
  const router = express.Router();
  router.get('*.*', express.static(DIST_FOLDER, {
    maxAge: '1y'
  }));

  router.get('*', (req, res) => {
    res.render('index', {req, res}, (error, html) => {
      return res.send(html);
    });
  });

  return router;
}

const apiProxy = proxy('/api', { target: 'http://localhost:8000'});
app.use('/api', apiProxy);

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

HomeRoutingModule:

import { HomeComponent } from './home.component';

const routes: Routes = [{ path: '', component: HomeComponent }];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class HomeRoutingModule { }

HomeComponent 对某些 HTTP 处理服务和 primeNg 的 MessageService 有两个依赖项。

因此,当我访问 http://localhost:4200/app/query 时,一切正常,然后我可以正确地浏览应用程序。但是当我访问 http://localhost:4200/apphttp://localhost:4200/app/home 时什么也没有发生,我什至没有得到响应,甚至我尝试添加到 express 中的 index 路由渲染的回调也没有被调用。

我在 dist/server/main.js 中进行了一些挖掘,并将问题缩小到以下函数:

function _render(platform, moduleRefPromise) {
    return moduleRefPromise.then((/**
     * @param {?} moduleRef
     * @return {?}
     */
    (moduleRef) => {
        /** @type {?} */
        const transitionId = moduleRef.injector.get(platform_browser["ɵTRANSITION_ID"], null);
        if (!transitionId) {
            throw new Error(`renderModule[Factory]() requires the use of BrowserModule.withServerTransition() to ensure
the server-rendered app can be properly bootstrapped into a client app.`);
        }
        /** @type {?} */
        const applicationRef = moduleRef.injector.get(core["ApplicationRef"]);
        return applicationRef.isStable.pipe((Object(first["a" /* first */])((/**
         * @param {?} isStable
         * @return {?}
         */
        (isStable) => isStable))))
            .toPromise()
            .then((/**
         * @return {?}
         */
        () => {
            /** @type {?} */
            const platformState = platform.injector.get(PlatformState);
            /** @type {?} */
            const asyncPromises = [];
            // Run any BEFORE_APP_SERIALIZED callbacks just before rendering to string.
            /** @type {?} */
            const callbacks = moduleRef.injector.get(BEFORE_APP_SERIALIZED, null);
            if (callbacks) {
                for (const callback of callbacks) {
                    try {
                        /** @type {?} */
                        const callbackResult = callback();
                        if (Object(core["ɵisPromise"])(callbackResult)) {
                            asyncPromises.push(callbackResult);
                        }
                    }
                    catch (e) {
                        // Ignore exceptions.
                        console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e);
                    }
                }
            }
            /** @type {?} */
            const complete = (/**
             * @return {?}
             */
            () => {
                /** @type {?} */
                const output = platformState.renderToString();
                platform.destroy();
                return output;
            });
            if (asyncPromises.length === 0) {
                return complete();
            }
            return Promise
                .all(asyncPromises.map((/**
             * @param {?} asyncPromise
             * @return {?}
             */
            asyncPromise => {
                return asyncPromise.catch((/**
                 * @param {?} e
                 * @return {?}
                 */
                e => { console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e); }));
            })))
                .then(complete);
        }));
    }));
}

这里发生的是,对于 /home 路由,我永远无法进入以 const platformState = platform.injector.get(PlatformState); 开头的回调。我不确定为什么会这样想。

有人有什么想法可以帮忙吗?


更新#1:

我设法将问题缩小到我在 HomeComponentngOnInit 中使用的 RxJS 运算符。对于这个组件,我正在做一些轮询,所以我有类似的东西:

timer(0, 15000).pipe(
  mergeMap(() => this.dataService.fetchData())
).subscribe(...)

为了提供最小的非工作组件,我从我的组件中删除了所有内容并将以下内容添加到 ngOnInit

timer(0, 20000).subscribe(
  (...args) => console.log(args), 
  (...args) => console.error(args)
);

现在,当我尝试访问该路线时,它仍然没有加载(如预期的那样),但我在服务器的控制台中看到了来自订阅的值。

您可以在应用程序稳定后触发轮询,在组件中注入 ApplicationRef,并订阅 isStable