Closed TheTomasJ closed 8 months ago
We continued using Angular as our frontend because of this promise. Due to having a MVC Razor base page with important functionality for our site, we have used the technique of injecting our index.html into a razor page. This means that our .js and .css files are not hosted at the same URL as the base page. We have had some success with manually adding the URLs of the .js and .css files to our page, but this technique does not work with lazy loaded modules. I would imagine users that host their files on a CDN would have similar issues.
Had some discussion on this today. Our general stance is that --deploy-url
is discouraged and we have found <base href>
to be a less confusing alternative: https://angular.dev/tools/cli/deployment#--deploy-url. To be clear we still have not removed --deploy-url
, it still exists in the browser
and browser-esbuild
builders.
We've been hesitant to add --deploy-url
to application
builder unless we find that it is a significant migration blocker for many applications. However, I think this issue would be helpful to collect feedback from the community, so I'll leave it open for now.
If moving off --deploy-url
is viable but particularly challenging for you, then please thumbs up the issue so we know it's important to unblock adoption of application
builder.
Separately, if you have a specific use case which requires --deploy-url
(and is incompatible with <base href>
), please post your use case here. We can use this data to inform the longer term future of --deploy-url
and what use cases we might need to improve support for.
Hi, if it's discouraged... Can the docs be updated?
https://angular.io/guide/deployment
On the footer says Last reviewed on Mon Feb 28 2022
So perhaps new users need to understand why it doesn't work
I'm creating a simple flask application, and don't want to manage the frontend assets with an external server.
Without setting baseHref
, the built assets are expected to be requested from URLs like /main.<hash>.js
.
The only way to configure flask to serve the asset in this location is to set static_url_path="/"
. We get a route list such as this:
Endpoint Methods Rule
---------------------------------- ------- --------------------------------------
home.catch_all_route GET /
home.catch_all_route GET /<path:path>
static GET /<path:filename>
Unfortunately, when defining this, the static_route overrides the catch_all that serves the index.html. When navigating to a frontend route, the server logically returns a 404 (it tried to find an asset file for that route and failed).
The hack by setting baseHref="/static" and APP_BASE_HREF="/" would work, but breaks all CTRL-click, which is 100% not acceptable (I mean, it's a dealbreaker, the kind that leads to migrate to another framework).
The only solution I found is to build using the browser
builder as @dgp1130 suggested, set "deployUrl": "static/"
and leave baseHref
undefined. This way, Flask can be configured with static_url_path="/static"
which gives the following routing table:
Endpoint Methods Rule
---------------------------------- ------- --------------------------------------
home.catch_all_route GET /
home.catch_all_route GET /<path:path>
static GET /static/<path:filename>
I get a warning that deployUrl
is deprecated, which means that angular will stop working at some point :/
Hi, if it's discouraged... Can the docs be updated?
https://angular.io/guide/deployment#the-deploy-url states:
base href
is generally the better option.
https://angular.dev/tools/cli/deployment#--deploy-url also discourages it.
The hack by setting
baseHref="/static"
andAPP_BASE_HREF="/"
would work, but breaks all CTRL-click
What Ctrl+click behavior are your referring to? Do you mean ctrl+clicking a link where the browser opens it in a new tab? I don't see how --deploy-url
or <base href>
would break that behavior.
Unfortunately, when defining this, the static_route overrides the catch_all that serves the index.html. When navigating to a frontend route, the server logically returns a 404 (it tried to find an asset file for that route and failed).
I'm not familiar with Flask specifically, but if I'm understanding your comment correctly it seems like it is not feasible to configure the server to both serve a static directory and also fallback to index.html
on 404? Those don't feel like mutually conflicting requirements and I personally would expect that to be possible in any server. Is there a Flask feature request to support this or any reasoning from the Flask team for rejecting such a feature?
Just in case someone who don't know how to switch the builder from application
to browser
in the angular.json
. Here is the diff for that:
Separately, if you have a specific use case which requires
--deploy-url
(and is incompatible with<base href>
), please post your use case here. We can use this data to inform the longer term future of--deploy-url
and what use cases we might need to improve support for.
My use case - I deploy my front-end to an app server, but then a CDN pull zone caches static assets and serves from the CDN. I use --deploy-url to set the CDN url.
eg My app is at domain.com CDN looks at domain.com and caches files to cdn.com I build with --deploy-url=cdn.com and upload to domain.com Users get index.html from domain.com, but all assets are served from cdn.com
We use angular/elements for building microfrontends with angular which each are hosted under a separate deploy url (e.g. /microservice-1, /microservice-2, etc...). The main chunk is loaded into our shell at runtime. The index.html of the microservices will never be loaded by the shell and therefore baseHref is not working.
--deploy-url
is necessary.
I just want to set cdn url, don't want to effect the router url.
They are different things. separate them. Don't make things complicated.
The hack by setting
baseHref="/static"
andAPP_BASE_HREF="/"
would work, but breaks all CTRL-clickWhat Ctrl+click behavior are your referring to? Do you mean ctrl+clicking a link where the browser opens it in a new tab? I don't see how
--deploy-url
or<base href>
would break that behavior.
@dgp1130 The ctrl+click would be broken when we use a relative link. Say we serve a site on http://www.aaa.com/bbb
, and the user ctrl+click a link like <a href="foo"></a>
, then with baseHref="/static/"
the browser would open http://www.aaa.com/static/foo
, but the url we want to open is http://www.aaa.com/foo
. Similar use cases include but are not limited to window.open(link)
, window.location = link
, fetch(link)
, ...
Of course we could use javascript to intercept these cases and build an absolute url for use, but it's cumbersome and not intuitive. SDKs with business logic that are shared among sites built on different web frameworks would have to take it into account if we want to adopt them in Angular apps. There are also scenarios without javascript like SSR (used by crawler and SEO).
It seems the reasons to deprecate --deploy-url
are about build speed and bundle size. I think developers should have a chance to choose between "intuitive relative link support" and "better build speed & bundle size" if we couldn't figure out a better solution to achieve both.
@dgp1130 The ctrl+click would be broken when we use a relative link. Say we serve a site on
http://www.aaa.com/bbb
, and the user ctrl+click a link like<a href="foo"></a>
, then withbaseHref="/static/"
the browser would openhttp://www.aaa.com/static/foo
, but the url we want to open ishttp://www.aaa.com/foo
. Similar use cases include but are not limited towindow.open(link)
,window.location = link
,fetch(link)
, ...
@Mensu That sounds like the typical behavior of <base href>
to me? Is the click behavior different from ctrl+click in this scenario? I suspect this might be because ctrl+click opens in a new tab and thus performs a server-side navigation whereas click performs a client-side navigation. However if that's a problem then it is likely a configuration issue with your server.
If you can create a minimal reproduction of a scenario where click and ctrl+click behavior are different, then I would be very interested to see it.
Our use case is that we host two versions of our site on one domain as we are slowly migrating to Angular.
To facilitate this, we are using --deploy-url to store all of our resources on a path so that we can then use cloudfront rules to direct path/.*
to our new angular s3, and *.*
to the old s3 bucket. We have tried, but it seems like we can't accomplish this in any other way so we are currently not able to switch to the application builder.
@Mensu That sounds like the typical behavior of
<base href>
to me? Is the click behavior different from ctrl+click in this scenario? I suspect this might be because ctrl+click opens in a new tab and thus performs a server-side navigation whereas click performs a client-side navigation. However if that's a problem then it is likely a configuration issue with your server.
@dgp1130 In fact the url opened by normal click is the same as ctrl+click, and I agree that's the typical behavior of <base href>
, but I don't want this <base href>
behavior to take effect when I use relative links because we share some codes from sites without <base href>
and relative link resolution results are different between sites with <base href>
and sites without <base href>
.
My application is served in mydomain.com, and the CSS and Javascript chunks are served from the Cloudfront CDN for performance reasons.
Removing Deploy Url prevents this extremely common use case.
I think this option should be added back, as the removal was preventing us from upgrading to the new Angular 17 esbuild-based application builder, and our use case is extremely common.
So it must be affecting a lot of people.
Here is the script that I added to my build pipeline to add the CDN url manually to the bundles.
This allowed me to use the EsBuild build in production:
console.log(`Running apply-cdn-url.js...`);
const fs = require('fs');
const cheerio = require('cheerio');
// Load the HTML content
const htmlContent = fs.readFileSync('dist/browser/index.html.original', 'utf8');
const $ = cheerio.load(htmlContent);
// CDN prefix to be appended
const cdnPrefix = process.argv[2];
console.log(`Applying CDN URL: ${cdnPrefix} to the HTML file...`);
// Locate and modify script and CSS tags
$('script[src], link[rel="stylesheet"]').each(function () {
let tagName = $(this).get(0).tagName;
if (tagName === 'script') {
let src = $(this).attr('src');
if (!src?.startsWith('http')) {
$(this).attr('src', cdnPrefix + src);
}
}
else if (tagName === 'link') {
let href = $(this).attr('href');
if (!href?.startsWith('http')) {
$(this).attr('href', cdnPrefix + href);
}
}
});
// Output or save the modified HTML
const modifiedHtml = $.html();
const outputPath = 'dist/browser/index.html';
console.log(`Saving modified HTML to ${outputPath}...`);
fs.writeFileSync(outputPath, modifiedHtml);
We use a business scenario when we replace the history of pages via window.history.pushState. This is necessary so that when the user on the bank payment page presses the browser’s back arrow, he returns to the site page we need. But if the base hrev (cdn address) is different from the main domain, then we get the error "Uncaught DOMException: Failed to execute 'pushState' on 'History'"
We also serve our application from one domain, and our CSS and javascript from cloudfront for performance purposes. I'd really like to upgrade to the application
builder.
To be clear, at least as far as I can tell, our use case requires deployUrl
and is incompatible with baseHref
. This really seems to be a blocker for us to migrate to the application
builder, which we'd like to do because it seems like the way forward for server-side rendering (something we are not doing yet).
To be clear, at least as far as I can tell, our use case requires deployUrl and is incompatible with baseHref. This really seems to be a blocker for us to migrate to the application builder, which we'd like to do because it seems like the way forward for server-side rendering (something we are not doing yet).
This use case should be possible with the combination of the baseHref
option and the APP_BASE_HREF
token. The baseHref
option should be set to the CDN location and the browser will automatically use that for all relative requests including files used from the assets
option (something deployUrl does not do).
The APP_BASE_HREF
token which controls the Angular router should be something similar to the following:
{ provide: APP_BASE_HREF, useValue: location.origin }
or the following if the app is located on a subpath:
{ provide: APP_BASE_HREF, useValue: new URL('/my-app', location.origin).href }
If the application is not using the Angular router than the APP_BASE_HREF
token is unneeded. This token is really the Router base URL and, besides its default value being derived from the HTML base HREF if present, it is otherwise unrelated to the HTML base HREF.
If you encounter further issues with this setup, please open a separate issue with a minimal reproduction if possible.
While the HTML base HREF does affect most relative requests it does not affect all. However, while ctrl+click behavior with relative links may be a concern for some applications, some others may not have an issue. The aforementioned suggestion may provide a solution to some that does not require the use of a heavyweight solution such as deploy URL which hard codes a specific path throughout the entire application in numerous locations. This not only makes the application non-transportable but also does not fully cover all file reference usages (assets
being a key one). It can also make certain development pipelines problematic such as test/staging/production environment promotion without full rebuilds. However, each application's requirements are unique and having multiple options to solve a particular problem can allow those requirements to be adequately met. And to support that, the deployUrl
functionality will be brought to the new build system. Until this is released, the compatibility builder (browser-esbuild
) currently supports the option as well as containing many of the performance benefits of the full new build system.
thanks for your effort and patience :)
The base-href purpose is different in W3C specification and in angular "recommended" way. I created minimal repo to proof that "recommended" way is not eligible in general. Deploy url is different construct and should not be deprecated. Please see my general example below:
To be clear, at least as far as I can tell, our use case requires deployUrl and is incompatible with baseHref. This really seems to be a blocker for us to migrate to the application builder, which we'd like to do because it seems like the way forward for server-side rendering (something we are not doing yet).
This use case should be possible with the combination of the
baseHref
option and theAPP_BASE_HREF
token. ThebaseHref
option should be set to the CDN location and the browser will automatically use that for all relative requests including files used from theassets
option (something deployUrl does not do). TheAPP_BASE_HREF
token which controls the Angular router should be something similar to the following:{ provide: APP_BASE_HREF, useValue: location.origin }
or the following if the app is located on a subpath:
{ provide: APP_BASE_HREF, useValue: new URL('/my-app', location.origin).href }
Thanks for that clear explanation. I hadn't previously understood exactly how we were intended to replace deployUrl
. I'd tried it that way, then a couple others when that didn't work, never quite sure I was doing what I should.
Unfortunately, If I do what you suggest, it causes a couple of issues, most notably, that all of the relative links on the websites (that directly assign the href with href=
) that users might click now point to the path on the CDN instead of one of our websites. Having such relative links is necessary because there are parts of our websites that exist outside of the Angular application; while we are slowly converting out legacy site to Angular, it is a work in progress.
In addition, other resources we load on the page via relative links (such as additional js files) also now improperly point to the CDN (which really only hosts the files deployed for Angular). Essentially, the only requests that should go to the CDN are those for files generated by the ng build
.
Additionally, API requests to our back end which have relative URLS are also going to the CDN. This part I suppose I could fix with an interceptor, if the rest worked, but overriding the entire baseHref
to point to a domain that hosts ONLY the code generated by ng build
, then correcting everything else back to what it would have been without baseHref
seems like the wrong approach.
What seems like the right approach is deployUrl
, which seems to do exactly what we need to separate the Angular requests from all of the other requests.
I suppose I could open an issue for this, but it feels like it would just be a duplicate.
Based on what you have described, what would the deployUrl
option need to do with its value to meet the needs of the application? For instance, is the Angular CLI generating the index.html
for the application or is something else? Would adding a prefix to the injected scripts/styles be sufficient or is there more that would need to be done? Would a generated manifest file of build outputs be more useful so that a custom post-build step could generate an index that meets the exact requirements of the application? Or would more extensive index.html
templating be a better option?
The Angular CLI is generating our index.html
file, mostly. We also insert some of our own necessary scripts and other content into the file as well, before we serve it from one of our main domains. Adding the prefix specified by deployUrl
to all requests for files generated by ng build
would, I think, do everything we need it to do. The only files we serve from the the deployUrl
are the ones generated by ng build
.
I don't think a manifest of file build outputs would be more useful, at least for our use case. A more extensive index.html
templating option also would not help us here, I think, because what we add varies by endpoint, and has to be determined in our PHP application on our server.
As an aside, deployUrl
is also really helpful for our development process. Each of our developers has a remote dev server with a full installation of our application (including both the Angular and non-Angular parts, etc), and runs ng serve
on their local system. Developers set deployUrl
to //localhost:4200/
. We do have to rsync
a copy of the generated index.html
over to the dev server, but then it is possibly to run the application on the dev server exactly as if it were the production application, with localhost standing in for our CDN.
We have a different use case. Perhaps it's too edge case to consider for the new deployUrl option, but I'll share just in case a native solution can cover our needs as well. We do what many called out and have our app files hosted on a CDN domain (unique per environment) that differs from the domain serving the application to the user. However, we also do not use the CLI generated index.html file. We pull the generated resource tags (CSS, Script, and component tag) and inject them into an index.html file managed and hosted by our CMS. To get all this working without using the currently deprecated deployUrl option requires us to:
We haven't yet looked at moving to ng17 as we're waiting for angular-builders to add support for esbuild, but if we could simplify all of this with a deployUrl option and/or index templates, that'd be great.
In my use case, there is micro frontend (angular element) that used as hostile component or remote app in none angular host apps and all resource files are not the same host app assets path. To deprecate this --deploy-url
hits so much the current implementation. I vote not to deprecating this --deploy-url
.
Thanks to the team for adding this feature to the application builder! Definitely appreciated!
Thank you very much for supporting and keeping this deployUrl
.
Hi @alan-agius4,
I saw that your PR status above was merged and I'm wondering when or what version this deployUrl
fix will be fully available?
Thanks in advance.
@tclyit, it will be available in 17.3 which will be released as the latest version later on today.
This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.
I am referencing following response from @dgp1130, where is stated that "team does not expect that any existing use cases to suddenly become unsupported". From v17 there is no possibility to reference static assets with absolute url. Using base hrefs is not proper replacement because relative links must stay relative to root when users wants to open links in new tab (ctrl + click) and also for non javascript consumers of server side rendered pages. Combinations with APP_BASE_HREF are not applicable for this use case. Due to this we believe this is regression for no good reason.
Originally posted by @dgp1130 in https://github.com/angular/angular-cli/issues/22113#issuecomment-1099723870
Updated 23.2.2024 with minimal reproduction: https://github.com/TheTomasJ/angular-router-example