Getting started with Angular universal
There are many blogs that offers tutorial on angular universal. However, most of it has some issues. You can clone entire sample from here. Build and run instruction are given as well.
To get it working from scratch, my app is called webapp
ng new webapp --routing
cd webapp
ng g universal --client-project webapp
# New Render Engine
npm install @nguniversal/express-engine
# If using lazy loading
npm install @nguniversal/module-map-ngfactory-loader
npm install --save-dev express webpack ts-loader
# If using Firebase
npm install --save-dev ws xmlhttprequest
src/app/app.module.ts
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
AppRoutingModule, BrowserTransferStateModule
],
providers: [],
//bootstrap: [AppComponent]
})
export class AppModule { }
src/app/app.server.module.ts
import { NgModule } from '@angular/core';
import { ServerModule, ServerTransferStateModule} from '@angular/platform-server';
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
ModuleMapLoaderModule, ServerModule, AppModule,
ServerTransferStateModule,
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
Create server.ts in webapp root (not webapp/src folder) and ensure you change your APP_NAME, if you're not using webapp
// These are important and needed before anything else
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
// DOM libs required for Firebase
(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
import { enableProdMode } from '@angular/core';
import * as express from 'express';
import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { join } from 'path';
const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist');
const APP_NAME = 'webapp';
const {
AppServerModuleNgFactory,
LAZY_MODULE_MAP
} = require(`./dist/${APP_NAME}-server/main`);
enableProdMode();
const app = express();
// Set the engine
app.engine(
'html',
ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [provideModuleMap(LAZY_MODULE_MAP)]
})
);
app.set('view engine', 'html');
app.get('/**/*', (req, res) => {
res.render(join(DIST_FOLDER, APP_NAME, 'index'), {
req,
res
});
});
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, APP_NAME));
// Static Assets
app.get('*.*', express.static(join(DIST_FOLDER, APP_NAME)));
// Point all routes to Universal
app.get('*', (req, res) => {
res.render('index', { req });
});
// Start Express Server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
Create webpack.server.config.js again on webapp (root - not in webapp/src) and gain, please change your APP_NAME to your application name if you're not using webapp. Phew feel like a grandfather for reminding this again.
const path = require('path');
const webpack = require('webpack');
const APP_NAME = 'webapp';
module.exports = {
entry: { server: './server.ts' },
resolve: { extensions: ['.js', '.ts'] },
mode: 'none',
target: 'node',
externals: [/(node_modules|main\..*\.js)/],
output: {
path: path.join(__dirname, `dist/${APP_NAME}`),
filename: '[name].js'
},
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader' },
{
test: /(\\|\/)@angular(\\|\/)core(\\|\/).+\.js$/,
parser: { system: true }
}
]
},
plugins: [
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'),
{}
)
]
};
edit your package.json and add in the followings. Remember to change your app name (Line 1 and 2)
"build:ssr": "ng build --prod && ng run webapp:server && npm run webpack:server",
"serve:ssr": "node dist/webapp/server.js",
"webpack:server": "webpack --config webpack.server.config.js"
Now to build and run your a
npm run build:ssr && npm run serve:ssr
Next, browse to http://localhost:4000
Comments