Угловой универсальный специфический маршрут не загружается - PullRequest
0 голосов
/ 21 октября 2019

У меня странная проблема в 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/app или http://localhost:4200/app/home, ничего не происходит, я даже не получаю ответ, и даже обратный вызов, который я пытался добавить в 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:

Iудалось сузить проблему до оператора RxJS, который я использую в моем ngOnInit из HomeComponent. Для этого компонента я делаю некоторые опросы, поэтому у меня есть что-то вроде:

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

Пытаясь обеспечить минимальный нерабочий компонент, я удалил все из своего компонента и добавил следующее к ngOnInit:

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

Теперь, когда я пытаюсь посетить маршрут, он все равно не загружается (как и ожидалось), но я вижу в консоли сервера значения из подписки.

1 Ответ

2 голосов
/ 22 октября 2019

Вы можете запустить опрос, как только приложение стабилизируется, введя ApplicationRef в компонент и подписавшись на isStable

...