Я пытался собрать воедино, как предварительно сгенерировать страницы существующего приложения Angular Universal. Я застрял на этом исключении:
Селектор app-root не соответствует ни одному элементу.
Я получаю это исключение, когда выполняю node dist/pre-render.js /
.
Обратите внимание, что это приложение отлично работает с ng serve
и npm run build:universal; npm run serve:universal
. Так что это не так просто, как забыть вставить что-то в app.module
declarations
.
Действия по воспроизведению:
- Беги
npm run build:universal
- Запустите
node dist/pre-render.js /
- Обратите внимание на ошибку
The selector "app-root" did not match any elements
Вот установка:
package.json
раздел скриптов
Я думаю, что это идентично руководству по Angular.
"build:universal": "npm run build:client-and-server-bundles && npm run webpack:server",
"serve:universal": "node dist/server.js",
"build:client-and-server-bundles": "ng build --prod && ng build --prod --app 1 --output-hashing=false",
"webpack:server": "webpack --config webpack.server.config.js --progress --colors"
webpack.server.config.js
Это также прямо из руководства, за исключением того, что вы заметили, что у меня дополнительный entry
, который создает мой pre-render.js
сценарий из pre-render.ts
, который я покажу дальше.
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
server: './server.ts',
'pre-render': './pre-render.ts'
},
resolve: { extensions: ['.js', '.ts'] },
target: 'node',
// This makes sure we include node_modules and other third-party libraries.
externals: [/(node_modules|main\..*\.js)/],
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [{
test: /\.ts$/,
loader: 'ts-loader'
}]
},
plugins: [
// Temporary Fix for issue: https://github.com/angular/angular/issues/11580
// for 'WARNING Critical dependency: the request of a dependency is an expression'
new webpack.ContextReplacementPlugin(
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
]
};
pre-render.ts
Я взял подсказки из server.ts
файла руководства и из книга Филиппа Мартина. В руководстве пока не объясняется, как это сделать, а пример из книги Филиппа мне не подошел.
import 'zone.js/dist/zone-node';
import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
const args = process.argv.slice(2);
if (args.length !== 1) {
process.stdout.write('Usage: node dist/pre-render.js <url>');
process.exit();
}
enableProdMode();
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
renderModuleFactory(
AppServerModuleNgFactory,
{
url: args[0],
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
}
).then(rendered => {
process.stdout.write(rendered);
});
Честно говоря, я понятия не имею, для чего это свойство extraProviders
и нужно ли туда бросать provideModuleMap(...)
. Но если я не дам ему ничего extraProviders
, я получаю такую ошибку:
NullInjectorError: нет поставщика для InjectionToken MODULE_MAP
Так ясно, что собственность должна быть для чего-то важна.
Кроме того, я заметил, что добавление свойства document
рядом с url
и extraProviders
не имеет никакого эффекта, даже если свойство document
является строкой без каких-либо элементов <app-root>
.
document
. Они также указали мне на github.com/angular/universal-starter, с которым я буду сравнивать мой код. Я должен узнать больше завтра. - person Matt Thomas   schedule 28.03.2018