angularangular-ssr

How to use express server in dev mode in Angular 17 application builder?


The documentation (https://angular.dev/guide/ssr) states that:

Angular CLI will scaffold an initial server implementation focused on server-side rendering your Angular application. This server can be extended to support other features such as API routes, redirects, static assets, and more. See Express documentation for more details.

And this is fine, but when you run angular (ng serve) the server (server.ts) is not even used so none of our API routes are registered.

What is the recommended approach here? Should we spin our own express.js server for API routes in development?


Solution

  • I just ran into this problem myself. The solution I came up with was to (1) create a barebones copy of the server that runs on a different local port, (2) set up ng serve to proxy requests to my API over to that second server, and (3) change my start command over to concurrently run both of these.

    1. Barebones API server

    I kept all of my API-specific code in /src/api, so this file is /src/api/dev-server.ts:

    import express from "express";
    import {configureAPI} from "./index";
    
    // This is ONLY used to start the server in development mode; do not use in production, and do not add any special
    // handling logic in here.
    
    const server = express();
    
    server.use('/api', configureAPI(express.Router()));
    // configureAPI takes a router, adds all my routes, then returns it; do whatever
    // server config here you want
    
    const port = process.env['API_PORT'] || 3000;
    server.listen(port, () => {
      console.log(`Dev API server listening on port ${port}`);
    });
    

    I then set up nodemon with this nodemon.json (you'll need to npm install -D nodemon ts-node):

    {
      "ignore": ["**/*.test.ts", "**/*.spec.ts", "node_modules"],
      "watch": ["src/api"],
      "exec": "ts-node src/api/dev-server.ts",
      "ext": "ts"
    }
    

    So now, if I run nodemon, my API starts up on port 3000.

    2. ng serve proxying

    This is actually built in! Make a new file, proxy.conf.json:

    {
      "/api":
      {
        "target": "http://localhost:3000",
        "secure": false,
        "changeOrigin": true,
        "cookieDomainRewrite": "localhost:4200"
      }
    }
    

    Now if you run ng serve --proxy-config proxy.conf.json, it'll start up your server as normal, but any requests to /api will be sent to the API server running over on port 3000.

    3. Putting it all together

    First, npm install -D concurrently. Here's the relevant scripts in my package.json:

    {
      "scripts": {
        "start": "concurrently 'npm:start:angular' 'npm:start:dev-server'",
        "start:angular": "ng serve --proxy-config proxy.conf.json",
        "start:dev-server": "nodemon",
      }
    }
    

    Now, just npm start, and it all just works :D