skip to Main Content

When I build my Angular 17 SSR project with ng build, I get this:

  ├── dist
  │  └── my-project
  │    ├── .DS_Store
  │    ├── 3rdpartylicenses.txt
  │    ├── browser
  │    │  ├── .DS_Store
  │    │  ├── assets
  │    │  │  ├── ...
  │    │  ├── chunk-5XNHKK4I.js
  │    │  ├── ...
  │    │  ├── favicon.ico
  │    │  ├── index.html
  │    │  ├── main-OTXGCZUU.js
  │    │  ├── media
  │    │  │  └── ...
  │    │  ├── polyfills-RT5I6R6G.js
  │    │  ├── styles-6I36XN7I.css
  │    ├── prerendered-routes.json
  │    └── server
  │      ├── chunk-2VXXU7NI.mjs
  │      ├── ...
  │      ├── index.server.html
  │      ├── main.server.mjs
  │      ├── polyfills.server.mjs
  │      ├── render-utils.server.mjs
  │      └── server.mjs

Now my question is: How do I publish this to my cPanel / Traditional hosting provider?

I imagine that Angular made it easy for deploying SSR on Firebase, and other mainstream cloud services, but what about local cloud services using cPanel?

Dragging and dropping the /dist into the /public_html folder in the cPanel. Not the solution 😅

2

Answers


  1. Chosen as BEST ANSWER

    I found a solution!

    Small prerequisite: Check if your cPanel allows you to create NodeJS.

    In the root of the Angular project, I've created a main.js file, and here's what's inside of it:

    async function run() {
      try {
        // Import the app from the ES module
        const server = await import("./server/server.mjs");
        const app = await server.app();
    
        const port = process.env["PORT"] || 4000;
    
        // Start up the Node server
        app.listen(port, () => {
          console.log(`Node Express server listening on http://localhost:${port}`);
        });
      } catch (error) {
        console.error("Failed to import app:", error);
      }
    }
    
    run();
    

    And here's how my server.ts file looks like:

    import 'zone.js/node';
    
    import { APP_BASE_HREF } from '@angular/common';
    import { CommonEngine } from '@angular/ssr';
    import express from 'express';
    import { fileURLToPath } from 'url';
    import { dirname, join, resolve } from 'path';
    import bootstrap from './src/main.server';
    
    // The Express app is exported so that it can be used by serverless Functions.
    export function app(): express.Express {
      const server = express();
      const serverDistFolder = dirname(fileURLToPath(import.meta.url));
      const browserDistFolder = resolve(serverDistFolder, '../browser');
      const indexHtml = join(serverDistFolder, 'index.server.html');
    
      const commonEngine = new CommonEngine();
    
      server.set('view engine', 'html');
      server.set('views', browserDistFolder);
    
      // Example Express Rest API endpoints
      // server.get('/api/**', (req, res) => { });
      // Serve static files from /browser
      server.get(
        '*.*',
        express.static(browserDistFolder, {
          maxAge: '1y',
        })
      );
    
      // All regular routes use the Angular engine
      server.get('*', (req, res, next) => {
        const { protocol, originalUrl, baseUrl, headers } = req;
    
        commonEngine
          .render({
            bootstrap,
            documentFilePath: indexHtml,
            url: `${protocol}://${headers.host}${originalUrl}`,
            publicPath: browserDistFolder,
            providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
          })
          .then((html) => res.send(html))
          .catch((err) => next(err));
      });
    
      return server;
    }
    
    export * from './src/main.server';
    

    Then in my project I've ran ng build which generated me the aforementioned file tree.

    These are the steps I took:

    1. Open cPanel
    2. Click "Setup Node.js App"
    3. Click "Create Application"
    4. I gave it main.js as the "Application startup file", this is important.
    5. Click "Create"

    Here's how the instance looked at the end:

    enter image description here

    Then I navigated to the application's root folder in the server. This was the rough file structure:

    ├── main.js
    ├── public
    ├── ... (some other files)
    └── tmp
    

    Then I just dumped the /dist/my-project folder's contents inside of it, so the end result looks something like this:

    ├── .htaccess
    ├── 3rdpartylicenses.txt
    ├── browser
    ├── main.js
    ├── prerendered-routes.json
    ├── public
    ├── server
    └── tmp
    

    Then go back to the Node.js instance in the cPanel and hit "Restart"!

    Then the Node.js instance in cPanel just knows what to do, because of main.js. Hope this helps!


  2. I have the same question. The closest answer I have found is at this link How to publish an Angular v17+ universal project to your hosting account. They say "Universal" but it is @angular/ssr which is included in the angular 17 version; there you will find a complete article on how to implement angular ssr application, but I think you only need to review from point 8 onwards; However, they do not clarify that it is shared hosting. I would appreciate it if you would share any other information you find; I will do the same.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search