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.
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.
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.
{
"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.