Je travaille sur un projet Webpack Angular4 auquel je voulais ajouter AngularUniversal pour rendre le rendu côté serveur possible. Mais la plupart des tutoriels utilisent cli.Il s'intéresse à Universal avec webpack.J'ai essayé de suivre ceci tutoriel sans chance. Quelqu'un peut-il aider s'il vous plaît.
This Angular Universal est uniquement pour Angular 2. Si vous voulez recommencer à zéro, vous pouvez utiliser ceci Angular 4 Universal Seed qui a toutes les fonctionnalités comme:
Ou si vous avez déjà un projet Angular 4 en cours d'exécution, vous pouvez intégrer Universal en définissant les paramètres suivants dans votre code:
Installez ces paquets: npm install @angular/{common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router,animations}@latest TypeScript@latest --save
npm install express @types/express --save-dev
Ajoutez ceci dans votre fichier app.module.ts
import { BrowserModule } from '@angular/platform-browser';
BrowserModule.withServerTransition({
appId: 'my-app-id' // withServerTransition is available only in Angular 4
}),
Créer les fichiers suivants
src/uni/app.server.ts
import { NgModule } from '@angular/core';
import { APP_BASE_HREF } from '@angular/common';
import { ServerModule } from '@angular/platform-server';
import { AppComponent } from '../app/app';
import { AppModule } from '../app/app.module';
import 'reflect-metadata';
import 'zone.js';
@NgModule({
imports: [
ServerModule,
AppModule
],
bootstrap: [
AppComponent
],
providers: [
{provide: APP_BASE_HREF, useValue: '/'}
]
})
export class AppServerModule {
}
src/uni/server-uni.ts
import 'zone.js/dist/zone-node';
import 'zone.js';
import 'reflect-metadata';
import { enableProdMode } from '@angular/core';
import { AppServerModuleNgFactory } from '../../aot/src/uni/app.server.ngfactory';
import * as express from 'express';
import { ngUniversalEngine } from './universal-engine';
enableProdMode();
const server = express();
// set our angular engine as the handler for html files, so it will be used to render them.
server.engine('html', ngUniversalEngine({
bootstrap: [AppServerModuleNgFactory]
}));
// set default view directory
server.set('views', 'src');
// handle requests for routes in the app. ngExpressEngine does the rendering.
server.get(['/', '/dashboard', '/heroes', '/detail/:id'], (req:any, res:any) => {
res.render('index.html', {req});
});
// handle requests for static files
server.get(['/*.js', '/*.css'], (req:any, res:any, next:any) => {
let fileName: string = req.originalUrl;
console.log(fileName);
let root = fileName.startsWith('/node_modules/') ? '.' : 'src';
res.sendFile(fileName, { root: root }, function (err:any) {
if (err) {
next(err);
}
});
});
// start the server
server.listen(3200, () => {
console.log('listening on port 3200...');
});
src/uni/universal-engine.ts
import * as fs from 'fs';
import { renderModuleFactory } from '@angular/platform-server';
const templateCache = {}; // cache for page templates
const outputCache = {}; // cache for rendered pages
export function ngUniversalEngine(setupOptions: any) {
return function (filePath: string, options: { req: Request }, callback: (err: Error, html: string) => void) {
let url: string = options.req.url;
let html: string = outputCache[url];
if (html) {
// return already-built page for this url
console.log('from cache: ' + url);
callback(null, html);
return;
}
console.log('building: ' + url);
if (!templateCache[filePath]) {
let file = fs.readFileSync(filePath);
templateCache[filePath] = file.toString();
}
// render the page via angular platform-server
let appModuleFactory = setupOptions.bootstrap[0];
renderModuleFactory(appModuleFactory, {
document: templateCache[filePath],
url: url
}).then(str => {
outputCache[url] = str;
callback(null, str);
});
};
}
Ajoutez la configuration ci-dessous dans votre fichier tsconfig.ts que je suppose situé dans le répertoire racine
{
"compilerOptions": {
"baseUrl": "",
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2016", "dom"],
"moduleResolution": "node",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"target": "es5",
"module": "commonjs",
"types": ["node"],
"typeRoots": [
"node_modules/@types"
]
},
"files": [
"src/uni/app.server.ts",
"src/uni/server-uni.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"entryModule": "./src/app/app.module#AppModule",
"skipMetadataEmit": true
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}
Atlast votre webpack.config.uni.js dans le répertoire racine
const ngtools = require('@ngtools/webpack');
const webpack = require('webpack');
const path = require('path');
const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin");
module.exports = {
devtool: 'source-map',
entry: {
main: ['./src/uni/app.server.ts', './src/uni/server-uni.ts']
},
resolve: {
extensions: ['.ts', '.js']
},
target: 'node',
output: {
path: path.join(__dirname, "dist"),
filename: 'server.js'
},
plugins: [
new ngtools.AotPlugin({
tsConfigPath: './tsconfig.json'
})
],
module: {
rules: [
{
test: /\.(scss|html|png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
use: 'raw-loader'
},
{ test: /\.ts$/, loader: require.resolve('@ngtools/webpack') },
{
test: /\.(png|jpg|woff|woff2|eot|ttf|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url?limit=512&&name=[path][name].[ext]?[hash]'
},
{ test: /\.scss$/, use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}] }
]
}
}
Ajoutez les scripts ci-dessous dans votre fichier package.json:
"ngc-build": "ngc -p ./tsconfig.json", // To generate ngFactory file
"build:uni": "webpack --config webpack.config.uni.js",
"serve:uni": "node dist/server.js",
Il y a certaines choses que nous devrions garder à l'esprit:
window
, document
, navigator
et d'autres types de navigateurs - n'existent pas sur le serveur - donc leur utilisation, ou toute bibliothèque qui les utilise (jQuery par exemple) ne fonctionnera pas. Vous avez quelques options données dans ce link si vous avez vraiment besoin de certaines de ces fonctionnalités.Universel angulaire est utilisé uniquement pour 2.x angulaire. Angular 4.x, vous devez utiliser le serveur de la plateforme. Les exemples sont les suivants:
Pour angulaire 2.X.X:
Projet de semences de AngularClass utilisant express/universal
https://github.com/angular/universal-starter
Pour les versions angulaires 4.X.X Utilisez le serveur de plate-forme angulaire
https://github.com/ng-seed/universal
Il y a quelques autres exemples aussi:
L'exemple mentionné dans ce didacticiel utilise l'exemple mentionné dans la section Angular Resources. Ils ont récemment mis à jour leur documentation et n'ont pas encore fourni la documentation détaillée pour mettre en œuvre @ angular/universal. This était la page que vous cherchez, mais certains problèmes ont été signalés ici . Peut-être que c'est pourquoi ils l'ont enlevé et ont décidé de le réécrire.
Vous pouvez trouver un tutoriel Angular 4 sur le rendu côté serveur avec Webpack sur ce blog .
Caractéristiques:
Le résultat final peut être visualisé facilement sur un hôte Docker comme suit:
(dockerhost)$ docker run -it -p 8002:8000 oveits/angular_hello_world:centos bash
(container)# git clone https://github.com/oveits/ng-universal-demo
(container)# cd ng-universal-demo
(container)# npm i
(container)# npm run start
J'ai choisi le port 8002 ci-dessus, car j'utilise déjà d'autres exemples sur les ports 8000 et 8001; Si l'hôte de docker s'exécute sur Virtualbox, vous aurez peut-être besoin d'un mappage de port entre 8002 de l'hôte Virtualbox et 8002 de la machine virtuelle Virtualbox.
Sur un navigateur, accédez à http: // localhost: 8002/blog . Vous verrez le contenu d'un article de blog téléchargé à partir de l'API Wordpress. Avec clic droit-> voir la source, vous verrez le contenu HTML. Cela montre qu'il s'agit d'une page rendue côté serveur.
PS: Comme le didacticiel que vous avez essayé, le didacticiel est basé sur un projet Git créé à l'origine par Rob Wormald , mais avec ce fork de FrozenPandaz , j'ai trouvé une version mise à niveau. to Angular 4 et a mieux fonctionné avec Webpack (voir l’annexe de le blog pour plus de détails).