我一直试图拼凑如何预先生成现有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.js
的{{1}}脚本,我将在下面展示。
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'),
{}
)
]
};
我从the guide's server.ts
file和a book by Philippe Martin获取了提示。该指南还没有解释如何做这些事情,菲利普的书中的例子并不适合我。
pre-render.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(...)
,那么我会收到这个错误:
NullInjectorError:没有InjectionToken MODULE_MAP的提供程序
很明显,财产必须对某些事情很重要。
此外,我注意到,extraProviders
属性与document
和url
并列无效,即使extraProviders
属性是不带{{1}的字符串元素。
答案 0 :(得分:0)
所有遗漏的是claim.Children.AddRange (newChildren)
属性,其中包含字符串中的document
元素。
当我将此对象作为第二个参数传递给<app-root></app-root>
时,它可以正常工作。请注意添加renderModuleFactory
属性:
document
现在,虽然这会导致呈现某些内容,但这并不完全是正确的,因为我们的开头的document: `<!DOCTYPE html>
<html>
<body>
<app-root></app-root>
</body>
</html>`,
url: args[0],
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
字符串与document
的内容不同。< / p>
要解决这个问题,只需执行Angular Universal Starter在its prerender.ts
file中所做的事情:
index.html
注意他们如何读取已编译的const index = readFileSync(join('browser', 'index.html'), 'utf8');
renderModuleFactory(AppServerModuleNgFactory, {
document: index,
url: route,
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
})
文件的内容,并使用 字符串作为browser/index.html
属性。
答案 1 :(得分:-1)
在server.ts文件中添加以下行。
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
这将有助于在服务器端映射模块。