Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

481
Views
Integrate @angular/cli with server-side EJS templates

Goal: Modify Open Graph meta tags when web crawlers visit different routes.

I know Angular2 4.0.0 has a MetaService, and there is always jQuery, but web crawlers except Googlebot don't execute Javascript, so it is kind of useless to my purpose. While Angular Universal sounds like an overkill for changing a couple meta tags.

So far my solution is to copy and paste the compiled index.html in /dist to index.ejs, and modify the necessary fields. Is it possible to integrate the workflow with the angular-cli compilation process, by having the entry point changed from index.html to index.ejs? If not, what are the alternatives that I should explore?

In my index.ejs :

<meta property="og:url" content="<%= url %>" />

In my Express route index.js :

res.render('index', {
  url: site_url,
});

In my server.js:

app.set('views', path.join(__dirname, '/dist'));
app.set('view engine', 'ejs');

Please refrain your answer to the current @angular/cli version (v1.0.1 compatible).

Some related discussions: Add customization options for HtmlWebpackPlugin #3338 Conditional template logic in index.html for beta.11-webpack #1544 Provide config to rename index.html in dist folder #2241

about 4 years ago · Santiago Trujillo
1 answers
Answer question

0

I was able to solve this by using Nunjucks to render templates served via Angular Universal. I'm sure it's possible to use other engines such as EJS as well. Here are the relevant portions of my server.ts:

import * as dotenv from 'dotenv';
dotenv.config();

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import * as nunjucks from 'nunjucks';

import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';

import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();

const PORT = process.env.PORT || 4201;
const DIST_FOLDER = join(process.cwd(), 'dist');

// Our index.html we'll use as our template
const template = readFileSync(join(DIST_FOLDER, 'index.html')).toString();

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist-server/main.bundle');

const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader');

nunjucks.configure(DIST_FOLDER, {
  autoescape: true,
  express: app,
});

app.engine('html', (_, options, callback) => {
  renderModuleFactory(AppServerModuleNgFactory, {
    // Our index.html
    document: template,
    url: options.req.url,
    // DI so that we can get lazy-loading to work differently (since we need it to just instantly render it)
    extraProviders: [
      provideModuleMap(LAZY_MODULE_MAP)
    ]
  }).then(html => {
    callback(null, html);
  });
});

app.set('view engine', 'html');

// Server static files from dist folder
app.get('*.*', express.static(DIST_FOLDER));

// All regular routes use the Universal engine
// You can pass in server-side values here to have Nunjucks render them
app.get('*', (req, res) => {
  res.render('index', { req, yourVar: 'some-value' });
});

// Start up the Node server
app.listen(PORT, () => {
  console.log(`Node server listening on http://localhost:${PORT}`);
});
about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!