Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic base href (APP_BASE_HREF) for SSR #29449

Open
alfaex opened this issue Jan 22, 2025 · 4 comments
Open

Dynamic base href (APP_BASE_HREF) for SSR #29449

alfaex opened this issue Jan 22, 2025 · 4 comments
Labels
area: @angular/ssr feature: votes required Feature request which is currently still in the voting phase feature Issue that requests a new feature

Comments

@alfaex
Copy link

alfaex commented Jan 22, 2025

Which @angular/* package(s) are relevant/related to the feature request?

No response

Description

I'm using Angular as SSR multi tenant app.

We differentiate the clients per domain.

exemple:
potato.com/portal
tomato.com/citizen
onion-tickets.com

The majority from our clients use a specific base href and just a few serve the app on the root.

Right now it's difficult to work with angular with this setup, I had to do some 'stuff' on the SSR server to make it work.

We use a similar configuration for development too because it's easy to use domains rather than keep changing the client for localhost. This also allows to have many clients configured at the same time.

For the development we simply add on the OS hosts file [CLIENT].local and have nginx running on docker.
This has sped up a lot of developing time.

We are migrating from angular 16 to 19 and already preparing for the AngularNodeAppEngine because from what I saw in the docs it will be the default instead of the ngExpressEngine and CommonEngine.

At the moment there are (what I believe is regression) some things that worked in v16 that don't work in v19, and it impacts production and development.

I was preparing a repo with an example app to list those problems, but later realized that if the APP_BASE_HREF doesn't work like before, none of the other stuff matters.

This is part of the code that we use to make it work.

// this will garantee that all the js are served from the right routes.
if (condition) {
  res.render(indexHtml, {
    req,
    document: docWithoutBaseHref
  });
} else {
  res.render(indexHtml, {
    req,
    providers: [{ provide: APP_BASE_HREF, useValue: clientBaseHref }],
    document: docWithBaseHref
  })
}

As you can see by the name of the variables docWithoutBaseHref and docWithBaseHref we also manually parse the index file to add and remove the base href according to the domain and base href from the request.

I look it up in the code for v19 and the base href is retrieved from the html generated on the bundling process by the .handle(req) method from AngularNodeAppEngine, this break our app because we need to put the base href that came from the SSR request, instead of reading from a static file.

Is there a possibility to have this again working with Angular?

We tested with commonEngine and it has the same capabilities from ngExpressEngine.

The problem is that I don't think the angular team will maintain multiple packages, considering that the Server routes it's supported only by AngularNodeAppEngine and it will be the future of angular SSR and the other options will be deprecated.

We would like to know if something like this will be considered to be supported by AngularNodeAppEngine?

We can still keep using the packages/code that allow our customization, but this will only delay the problem and will force us to stay attached to an older version of angular. And prevent the use of new features.

We rely on this information to make a decision about how to move forward.

Thanks.
Cheers.

Proposed solution

Allow for customization of html files from the SSR server instead of using hard coded values.
Allow to provide dynamic base href from SSR to the rendering of an angular route.

Alternatives considered

Keep using an older angular version and never upgrade.
Move to another framework.

@JeanMeche JeanMeche transferred this issue from angular/angular Jan 22, 2025
@alan-agius4 alan-agius4 changed the title # Dynamic base href (APP_BASE_HREF) for SSR Dynamic base href (APP_BASE_HREF) for SSR Jan 22, 2025
@alan-agius4
Copy link
Collaborator

Unless the APP_BASE_HREF differs from the HTML base href, there is no need to add this configuration. If it is necessary, it can be injected via dependency injection in the server.config.ts. Currently, with SSR (Server-Side Rendering) routes, both the routes and the base href are determined during the build process.

At this time, providing the base href option at runtime is not possible. If you need to use a different base href, an additional build will be required. However, since you're already using Nginx, this could potentially be handled at the Nginx level using the sub_filter directive.

For example (untested):

location /citizen {
  rewrite ^/citizen/(.*)$ /$1 break;

  sub_filter '<base href="/">' '<base href="/citizen/">';
  sub_filter_once on;
  sub_filter_types text/html;
}

We could introduce an option in AngularNodeAppEngine to specify a custom baseHref and augment it in the index.html.

@alan-agius4 alan-agius4 added the feature Issue that requests a new feature label Jan 23, 2025
@angular-robot angular-robot bot added the feature: votes required Feature request which is currently still in the voting phase label Jan 23, 2025
Copy link
Contributor

angular-robot bot commented Jan 23, 2025

This feature request is now candidate for our backlog! In the next phase, the community has 60 days to upvote. If the request receives more than 20 upvotes, we'll move it to our consideration list.

You can find more details about the feature request process in our documentation.

@alfaex
Copy link
Author

alfaex commented Jan 24, 2025

Hi.

It worked what you suggested with nginx. I imagine that some internal things changed since v16 because I actually don't quite understand why it worked.

When I first configured our project, no links or chuncks was generated correctlly changing only the html base href, it had to have the provided APP_BASE_HREF.

Any way, the important thing is that it worked (almost) 🤔.

Still have some problems that should be addressed like:

Vite don't respect the APP_BASE_HREF/html base href and does requests on the root route.

Vite requests files with @fs and @vite to the root.

http://tomato.local/@vite/client
http://tomato.local/@fs/home/metasix/Desktop/vite-ssr-nginx/.angular/cache/19.1.3/v19-module/vite/deps/chunk-LBBSG2YE.js?v=5394bb5c

Some chunks for lazy load don't respect the APP_BASE_HREF/html base href and does requests on the root route.

http://tomato.local/chunk-YQOESBWP.js

I think I found a bug, not shure if it's related with AngularNodeAppEngine but it's definetlly impacting APP_BASE_HREF/base href (html).

This is the repo that I was preparing as mentioned on the first interaction.

https://github.com/alfaex/vite-ssr-nginx/tree/bug-lazy-routerLink

On the branch bug-lazy-routerLink there is a reprodution of the problem.

With eagerly loaded routes the links on the components are generated correctlly.

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path:'', component: LazyComponent }
    ]
  },
  { path: 'page', component: PortalComponent }

];

Generates: http://tomato.local/portal/page

If you add a lazy load route the links break and don't respect the base href anymore.

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      {
        path:'',
        loadComponent: () => import('src/app/lazy/lazy.component').then(c => c.LazyComponent),
      }
    ]
  },
  { path: 'page', component: PortalComponent }

];

Generates: http://tomato.local/page

Thanks.

@alan-agius4
Copy link
Collaborator

Vite requires a configured base href or base path before the server starts. The base option specifies the root URL from which your application is served. If this option is not properly set during build time, Vite cannot serve files from the intended base path and will default to an incorrect one. See vite documentation: https://vite.dev/config/shared-options.html#base)](https://vite.dev/config/shared-options.html#base

Regarding the lazy loading issue, it occurs because the router generates absolute routes that are not relative to the base href. We could potentially solve this by providing an a baseHref option. That said, this approach seems brittle and not particularly future-proof. Many modern server frameworks, such as Vite, Nuxt, and Nitro, also require the baseURL to be defined before the server starts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: @angular/ssr feature: votes required Feature request which is currently still in the voting phase feature Issue that requests a new feature
Projects
None yet
Development

No branches or pull requests

2 participants