このガイド に従って、既存のangular-cliアプリケーションをangular-universalに変換しました。
私の完全なソースコード here を見ることができます。
ブラウザープロジェクトとクライアントプロジェクトの両方をビルドできますが、ブラウザーでアプリを表示すると次のエラーが発生します。
エラー:View.engine(D:\ ng-ssr-demo\dist\server.js:359545:23)でブートストラップするには、NgModuleまたはNgModuleFactoryを渡す必要があります
問題は私のserver.tsファイルにあり、AppServerModuleNgFactoryが未定義ですまた、このファクトリーはExpressバックエンドでアプリをブートストラップするために使用されるため、ブートストラップは失敗します。
./ server.ts:
const MockBrowser = require('mock-browser').mocks.MockBrowser;
const mock = new MockBrowser();
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express server
const app = express();
const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist');
// Fix for window error:
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.resolve('./', 'dist', 'browser/', 'index.html')).toString();
const win = domino.createWindow(template);
// workaround for leaflet
global['window'] = win;
global['document'] = win.document;
// workaround for nex-charts
win.screen = { deviceXDPI: 0, logicalXDPI: 0 };
global['MouseEvent'] = win.MouseEvent;
global['navigator'] = mock.getNavigator();
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
// AppServerModuleNgFactory is undefined
console.log('AppServerModuleNgFactory', AppServerModuleNgFactory);
// This is injected
console.log('LAZY_MODULE_MAP', LAZY_MODULE_MAP);
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
./ webpack.server.config.js:
module.exports = {
entry: {
// This is our Express server for Dynamic universal
server: './server.ts',
// This is an example of Static prerendering (generative)
prerender: './prerender.ts'
},
target: 'node',
resolve: { extensions: ['.ts', '.js'] },
// Make sure we include all node_modules etc
externals: [/node_modules/],
output: { path: path.join(__dirname, 'dist'), filename: '[name].js' },
module: { rules: [{ test: /\.ts$/, loader: 'ts-loader'}] },
plugins: [
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'), {}
)
]
}
./ src/tsconfig.server.json:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"module": "commonjs",
"baseUrl": "./",
"types": ["node"],
"typeRoots": ["../node_modules/@types"],
"paths": {
"@angular/*": [
"../node_modules/@angular/*"
],
"@nebular/*": [
"../node_modules/@nebular/*"
]
}
},
"exclude": [
"test.ts",
"**/*.spec.ts"
],
"angularCompilerOptions": {
"entryModule": "app/app.server.module#AppServerModule",
"platform": 1
}
}
./ src/main.server.ts:
export { AppServerModule } from './app/app.server.module';
./ src/app/app.module.ts:
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule.withServerTransition({appId: 'my-app'}),
BrowserAnimationsModule,
HttpModule,
AppRoutingModule,
NgbModule.forRoot(),
ThemeModule.forRoot(),
CoreModule.forRoot(),
environment.production ? ServiceWorkerModule.register('./ngsw-worker.js') : [],
],
bootstrap: [AppComponent],
providers: [
{ provide: APP_BASE_HREF, useValue: '/' }, WebWorkerService,
],
})
export class AppModule {
}
./ src/app/app.server.module.ts:
@NgModule({
imports: [
AppModule,
ServerModule,
ModuleMapLoaderModule
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
ANGULAR 8 UPDATE(v8.0.1-2019年6月現在)
私にとっては、Angular CLIを使用してユニバーサルセットアップを実行しましたが、そのままでは機能しませんでした。何時間もそれを読んだ後、パッケージが一致していないことがわかりました。 Angular 8プロジェクトを実行していますが、package.jsonのnguniversalパッケージはv7で指定されています。
これらを同じバージョンのangularインストールしたバージョンに更新することをお勧めします。CLIはデフォルトで実際にこれを実行するはずですが、(まだ?).
Angular 8の場合、執筆時(2019年6月)はバージョン@next
、または@8.0.0-rc.1
なので、次のコマンドを実行して更新します。
npm i --save @nguniversal/express-engine@next @nguniversal/module-map-ngfactory-loader@next
これを更新した後もエラーが発生し、別の問題を特定することができました。また、サーバー側アプリケーションのIvyコンパイラーをオフにする必要がありました。これを行うために、次の行をtsconfig.server.json
に追加しました。
{
"extends": "./tsconfig.app.json",
...
"angularCompilerOptions": {
...
"enableIvy": false
}
...
}
Angular 8では、Ivyはデフォルトでオフになっていますが、tsconfig.server.json
がtsconfig.app.json
を拡張し、アプリ構成でIvyがオンになっているため、明示的にオフにする必要がありました。サーバー構成。
このすべての後、コンテンツに対するサーバー要求が実際に機能し始めました。
これで問題が解決しない場合は、angular docsに記載されているユニバーサルサンプルプロジェクトをダウンロードすることをお勧めします。
ダウンロード: https://angular.io/generated/zips/universal/universal.Zip ドキュメント: https://angular.io/guide/universal
ダウンロードしたら、すべての関連ファイルを比較して、同じであることを確認します。独自のプロジェクトで引き続きエラーが発生してもサンプルが機能する場合は、設定ファイル、モジュール、コンポーネントなどをサンプルプロジェクト内で1つずつ移動して、何が問題を引き起こしているかを確認してください。これにより、破損したのはtsconfig.server.json
ファイルであることがわかりました。
私はあなたのリポジトリをチェックアウトし、ブラウザでそのエラーなしにdistを細かく見ることができました。ビルドを実行するときに、フラグ-prod
を追加するのを忘れたのではないでしょうか?これをお試しください
ng build --prod
また、distを完全に削除したり、node_modulesを削除したり、npm cache clean
を実行したり、npm install
を実行してから再度ビルドしたりすることもできます。
Npmスクリプトを使用している場合、/ serverビルドに--prod
フラグがないことがわかります。これをお試しください
"build:server": "ng build --prod --app 1 --output-hashing=false",
使用する mode: 'development',
for webpack.config.js
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
'AppServerModuleNgFactory'がmain.bundleに存在することを確認してください。他の名前である可能性があるので、「ModuleNgFactory」のみでチェックして、どのNgFactoryがアプリをエクスポートしているかを確認し、ファクトリー名を置き換えます。