How to set up Angular cli + Angular universal?

戏子无情 提交于 2019-11-27 19:53:31

Angular Cli now supports this in version 1.3.0-rc.0 and up.

You can install this version using

npm install -g @angular/cli


Setup Instructions from Angular Cli Wiki on Universal Rendering

I have a demo app which can be found on GitHub

Source: https://github.com/joejordanbrown/angular-cli-universal

Live Demo: https://uixd.co.uk/open-source-software/angular-cli-universal/


Step 1: Create new Angular Cli App

$ ng new angular-cli-universal

Step 2: Install @angular/platform-server

Install @angular/platform-server into your project. Make sure you use the same version as the other @angular packages in your project.

$ npm install --save-dev @angular/platform-server

or

$ yarn add @angular/platform-server

Step 3: Prepare your app for Universal rendering

The first thing you need to do is make your AppModule compatible with Universal by adding .withServerTransition() and an application ID to your BrowserModule import:

src/app/app.module.ts:

@NgModule({
  bootstrap: [AppComponent],
  imports: [
    // Add .withServerTransition() to support Universal rendering.
    // The application ID can be any identifier which is unique on
    // the page.
    BrowserModule.withServerTransition({appId: 'my-app'}),
    ...
  ],

})
export class AppModule {}

Next, create a module specifically for your application when running on the server. It's recommended to call this module AppServerModule.

This example places it alongside app.module.ts in a file named app.server.module.ts:

src/app/app.server.module.ts:

import {NgModule} from '@angular/core';
import {ServerModule} from '@angular/platform-server';

import {AppModule} from './app.module';
import {AppComponent} from './app.component';

@NgModule({
  imports: [
    // The AppServerModule should import your AppModule followed
    // by the ServerModule from @angular/platform-server.
    AppModule,
    ServerModule,
  ],
  // Since the bootstrapped component is not inherited from your
  // imported AppModule, it needs to be repeated here.
  bootstrap: [AppComponent],
})
export class AppServerModule {}

Step 4: Create a server main file and tsconfig to build it

Create the main file for your Universal bundle. This file only needs to export your AppServerModule. It can go in src. This example calls this file main.server.ts:

src/main.server.ts:

export {AppServerModule} from './app/app.server.module';

Copy tsconfig.app.json to tsconfig-server.json and change it to build with a "module" target of "commonjs".

Add a section for "angularCompilerOptions" and set "entryModule" to your AppServerModule, specified as a path to the import with a hash (#) containing the symbol name. In this example, this would be src/app/app.server.module#AppServerModule.

src/tsconfig.server.json:

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "baseUrl": "./",
    // Set the module format to "commonjs":
    "module": "commonjs",
    "types": []
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts"
  ],
  // Add "angularCompilerOptions" with the AppServerModule you wrote
  // set as the "entryModule".
  "angularCompilerOptions": {
    "entryModule": "app/app.server.module#AppServerModule"
  }
}

Step 5: Create a NodeJS server file You need to create a NodeJS server to render and serve the app. This example uses express.

Install express and compression

$ npm install --save express compression @nguniversal/express-engine

or

$ yarn add express compression @nguniversal/express-engine

src/express.server.js:

const path = require('path');
const fs = require('fs');
const express = require('express');
const compression = require('compression');
const ngExpressEngine = require('@nguniversal/express-engine').ngExpressEngine;

require('zone.js/dist/zone-node');
require('rxjs/add/operator/filter');
require('rxjs/add/operator/map');
require('rxjs/add/operator/mergeMap');

var hash;
fs.readdirSync(__dirname).forEach(file => {
  if (file.startsWith('main')) {
    hash = file.split('.')[1];
  }
});

const AppServerModuleNgFactory = require('./main.' + hash + '.bundle').AppServerModuleNgFactory;

const app = express();
const port = Number(process.env.PORT || 8080);

app.engine('html', ngExpressEngine({
  baseUrl: 'http://localhost:' + port,
  bootstrap: AppServerModuleNgFactory
}));


app.set('view engine', 'html');
app.set('views', path.join(__dirname, '/../browser'));

app.use(compression());
app.use('/', express.static(path.join(__dirname, '/../browser'), {index: false}));


app.get('/*', function (req, res) {
  res.render('index', {
    req: req,
    // res: res
  });
});

app.listen(port, function() {
  console.log(`Listening at ${port}`);
});

Step 6: Create a new project in .angular-cli.json

In .angular-cli.json there is an array under the key "apps". Copy the configuration for your client application there, and paste it as a new entry in the array, with an additional key "platform" set to "server".

Then, remove the "polyfills" key - those aren't needed on the server and adjust "main", and "tsconfig" to point to the files you wrote in step 2. Finally, adjust "outDir" to a new location (this example uses dist/server).

.angular-cli.json:

{
  ...
  "apps": [
    {
      // Keep your original application config the same apart from changing outDir to dist/browser.
      // It will be app 0.
      "outDir": "dist/browser",
    },
    {
      // This is your server app. It is app 1.
      "platform": "server",
      "root": "src",
      // Build to dist/server instead of dist. This prevents
      // client and server builds from overwriting each other.
      "outDir": "dist/server",
      "assets": [
        "assets",
        "favicon.ico",
        "express.server.js"
      ],
      "index": "index.html",
      // Change the main file to point to your server main.
      "main": "main.server.ts",
      // Remove polyfills.
      // "polyfills": "polyfills.ts",
      "test": "test.ts",
      // Change the tsconfig to point to your server config.
      "tsconfig": "tsconfig.server.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "styles.css"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  ...
}

Building the bundle

With these steps complete, you should be able to build a server bundle for your application, using the --app flag to tell the CLI to build the server bundle, referencing its index of 1 in the "apps" array in .angular-cli.json:

# This builds the client application in dist/browser/
$ ng build --prod
...
# This builds the server bundle in dist/server/
$ ng build --prod --app 1
Date: 2017-07-24T22:42:09.739Z
Hash: 9cac7d8e9434007fd8da
Time: 4933ms
chunk {0} main.988d7a161bd984b7eb54.bundle.js (main) 9.49 kB [entry] [rendered]
chunk {1} styles.d41d8cd98f00b204e980.bundle.css (styles) 0 bytes [entry] [rendered]

Starting the express server

$ node dist/server/express.server.js

View the Angular Cli Wiki for more details https://github.com/angular/angular-cli/wiki/stories-universal-rendering

You can use universal-cli from https://github.com/devCrossNet/angular-cli

It is a fork from angular-cli but this work with angular universal.

After you intalled with npm install -g universal-cli create a new project with

ung new PROJECT_NAME --universal

Then the project should be ready to serve with

cd PROJECT_NAME ung serve

I have not tested with a existing angular-cli project but maybe ung init --universal could help

Now Angular-cli 1.3 has been released the documentation has been updated to cover Universal with a guide here. There is a guide and sample for getting it all working with Universal + material 2 and an Express server here.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!