【发布时间】:2018-03-28 21:03:40
【问题描述】:
我一直在尝试拼凑如何预先生成现有 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脚本部分
我认为这与the Angular guide 相同。
"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
这也是straight out of the guide,除了你会注意到我还有一个额外的entry,它会从pre-render.ts 生成我的pre-render.js 脚本,我接下来会展示它。
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
我从the guide's server.ts file 和a book by Philippe Martin 那里得到了提示。指南还没有解释如何做这些事情,菲利普书中的例子对我不起作用。
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 的提供者
很明显,属性对某事来说一定很重要。
另外,我注意到在url 和extraProviders 旁边放入document 属性没有任何效果,即使document 属性是一个没有任何<app-root> 元素的字符串。
【问题讨论】:
-
在gitter.im/angular/angular 人员的帮助下,我可能只是遗漏了要放入
document属性的正确内容。他们还向我指出了github.com/angular/universal-starter,我将用它来比较我的代码。明天我应该知道更多。