Logo

SEO Helper

Sitemap.xml

Google is sometimes blind. A sitemap is the map for crawlers. It lists all your pages so that even deeply nested content can be found.

In a traditional website, the crawler simply follows the links. In an Angular app (SPA), links often only appear through user interaction. Crawlers have become smarter and execute JavaScript, but I prefer not to rely on luck.

With a sitemap.xml, I serve Google all my URLs on a silver platter. This is especially important for pages that are not directly linked through the menu (e.g., old blog posts).

1. Sitemap Simulator

Define your routes on the left. On the right, you can see the XML format that search engines expect.

Active Routes
sitemap.xml Preview

2. Automation (Post-Build)

Nobody writes XML by hand. And since Angular doesn't have static HTML files, we need to generate the sitemap. I use a simple Node.js script that runs after the build.

Step 1: Create the Script

Create a folder scripts in the root and add the file there. The script writes the XML file directly into the dist folder of your app.

scripts/generate-sitemap.js
const fs = require('fs');

// 1. Define all routes (in real apps often fetched dynamically from an API)
const routes = [
  '/',
  '/about',
  '/blog',
  '/blog/angular-seo'
];

const baseUrl = 'https://www.your-domain.com';
const distPath = './dist/my-app/browser/sitemap.xml';

// 2. Build XML header
let xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`;

// 3. Loop through routes
routes.forEach(route => {
  xml += `
  <url>
    <loc>${baseUrl}${route}</loc>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>`;
});

xml += `</urlset>`;

// 4. Write file (after the build!)
fs.writeFileSync(distPath, xml);
console.log('✅ Sitemap generated at ' + distPath);

Step 2: Integrate into the Build

Now we need to ensure that the script always runs when we deploy. We extend the build command in the package.json.

package.json
{
  "scripts": {
    "start": "ng serve",
    // Chain command: First build, then generate sitemap
    "build": "ng build && node scripts/generate-sitemap.js"
  }
}
💡

Dynamic Data: In large apps, I don't hardcode the routes. I extend the script to fetch my API (e.g., retrieve all blog IDs) using axios or fetch and generate the URLs from that.