title: Angular 4 with universal
body: <p>I am using angular 2 with a universal.</p>
  
  <p>I am trying to this.</p>
  
  <p>First I create a new project :</p>
  
  <pre><code>ng new universaldemo.
  </code></pre>
  
  <p>I installed these packages :</p>
  
  <pre><code>npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader @nguniversal/express-engine.
  </code></pre>
  
  <p>Here is my app.module.ts :</p>
  
  <pre><code>import { BrowserModule } from '@angular/platform-browser';
  import { NgModule } from '@angular/core';
  
  import { AppComponent } from './app.component';
  
  @NgModule({
    declarations: [
      AppComponent
    ],
    imports: [
      BrowserModule.withServerTransition({ appId: 'universaldemo' }),
    ],
    providers: [],
    bootstrap: [AppComponent]
  })
  export class AppModule { }
  </code></pre>
  
  <p>Here is my app.server.module.ts</p>
  
  <pre><code>import { NgModule } from '@angular/core';
  import { ServerModule } from '@angular/platform-server';
  import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
  
  import { AppModule } from './app.module';
  import { AppComponent } from './app.component';
  
  @NgModule({
    imports: [
      AppModule,
      ServerModule,
      ModuleMapLoaderModule
    ],
    providers: [
      // Add universal-only providers here
    ],
    bootstrap: [ AppComponent ],
  })
  export class AppServerModule {}
  </code></pre>
  
  <p>Here is my server.ts :</p>
  
  <p>// These are important and needed before anything else</p>
  
  <pre><code>import 'zone.js/dist/zone-node';
  import 'reflect-metadata';
  
  import { enableProdMode } from '@angular/core';
  
  import * as express from 'express';
  import { join } from 'path';
  
  // 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');
  
  // * NOTE :: leave this as require() since this file is built Dynamically from webpack
  const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
  
  // Express Engine
  import { ngExpressEngine } from '@nguniversal/express-engine';
  // Import module map for lazy loading
  import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
  
  app.engine('html', ngExpressEngine({
    bootstrap: AppServerModuleNgFactory,
    providers: [
      provideModuleMap(LAZY_MODULE_MAP)
    ]
  }));
  
  app.set('view engine', 'html');
  app.set('views', join(DIST_FOLDER, 'browser'));
  
  // TODO: implement data requests securely
  app.get('/api/*', (req, res) =&gt; {
    res.status(404).send('data requests are not supported');
  });
  
  // Server static files from /browser
  app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));
  
  // All regular routes use the Universal engine
  app.get('*', (req, res) =&gt; {
    res.render(join(DIST_FOLDER, 'browser', 'index.html'), { req });
  });
  
  // Start up the Node server
  app.listen(PORT, () =&gt; {
    console.log(`Node server listening on http://localhost:${PORT}`);
  });
  Here is my webpack.server.config.js :
  
  const path = require('path');
  const webpack = require('webpack');
  
  module.exports = {
    entry: { server: './server.ts' },
    resolve: { extensions: ['.js', '.ts'] },
    target: 'node',
    // this makes sure we include node_modules and other 3rd 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'),
        {}
      )
    ]
  };
  </code></pre>
  
  <p>Finally i create tsconfig.server.json :</p>
  
  <pre><code>{
    "extends": "../tsconfig.json",
    "compilerOptions": {
      "outDir": "../out-tsc/app",
      "baseUrl": "./",
      "module": "commonjs",
      "types": []
    },
    "exclude": [
      "test.ts",
      "**/*.spec.ts"
    ],
    "angularCompilerOptions": {
      "entryModule": "app/app.server.module#AppServerModule"
    }
  }
  </code></pre>
  
  <p>Below lines are added to my package.json :</p>
  
  <pre><code>"scripts": {
      ...
      "build:universal": "npm run build:client-and-server-bundles &amp;&amp; npm run webpack:server",
      "serve:universal": "node dist/server.js",
      "build:client-and-server-bundles": "ng build --prod &amp;&amp; ng build --prod --app 1 --output-hashing=false",
      "webpack:server": "webpack --config webpack.server.config.js --progress --colors"
      ...
  }
  </code></pre>
  
  <p>I try to create build and serve my app :</p>
  
  <pre><code>npm run build:universal
  </code></pre>
  
  <p>It works.</p>
  
  <p>I try to run my app.using this command</p>
  
  <pre><code>npm run serve:universal.
  </code></pre>
  
  <p>I got this error.</p>
  
  <blockquote>
    <p>ReferenceError: webpackJsonp is not defined at Object</p>
  </blockquote>
  
  <p>How can I fix this issue?</p>