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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

ng build base-href issue (angular cli 8) #14587

Closed
Mek89 opened this issue May 30, 2019 · 27 comments
Closed

ng build base-href issue (angular cli 8) #14587

Mek89 opened this issue May 30, 2019 · 27 comments

Comments

@Mek89
Copy link

Mek89 commented May 30, 2019

馃悶 Bug report

Command (mark with an x)

- [ ] new
- [x] build
- [ ] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Is this a regression?

Yes, works with angular: 7.2.0

Description

The base-href flag works differently in angular 8. I hope you can help.

In angular 7:
ng build --prod app1 --base-href /app1/

after the command all my relative path in the scss are changed to the proper one.
source:
.example { background: url('/assets/img/picture.png') no-repeat center center; }
deployed:
.example { background: url('/app1/assets/img/picture.png') no-repeat center center; }

With angular 8 nothing happen:
source:
.example { background: url('/assets/img/picture.png') no-repeat center center; }
deployed:
.example { background: url('/assets/img/picture.png') no-repeat center center; }

馃敩 Minimal Reproduction

-- get angular-cli 8.0.0 and create a new app (with scss)

npm install -g @angular/cli
ng new my-dream-app

-- add a new class to the css (src/style.scss)
.example { background: url('/assets/img/picture.png') no-repeat center center; }

-- add a new class to a html file (src/app/app.compontent.html)
<div class="example" style="text-align:center">

-- run the build
ng build --prod --base-href /app1/

馃敟 Exception or Error

no exception

馃實 Your Environment

Angular CLI: 8.0.0
Node: 10.16.0
OS: win32 x64
Angular: 8.0.0
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.800.0
@angular-devkit/build-angular     0.800.0
@angular-devkit/build-optimizer   0.800.0
@angular-devkit/build-webpack     0.800.0
@angular-devkit/core              8.0.0
@angular-devkit/schematics        8.0.0
@ngtools/webpack                  8.0.0
@schematics/angular               8.0.0
@schematics/update                0.800.0
rxjs                              6.4.0
typescript                        3.4.5
webpack                           4.30.0

Anything else relevant?
no

@clydin
Copy link
Member

clydin commented May 30, 2019

This is actually expected behavior. The HTML base HREF is intended to be a runtime value used by the web browser and not a build time constant. The rebaseRootRelativeCssUrls browser builder option can be used to maintain existing behavior for 8.x.

The release notes provide more detail regarding this change:

Root relative URLs are a standardized method to reference a resource path from the root of a host. The previous behavior of the Angular CLI prevented this from occuring and resulted in an inability to reference stylesheet assets in this manner. The initial reason for this behavior is no longer present in the internal implementation of the Angular CLI. Therefore, this now unnecessary and non-standard behavior is being phased out. If an application currently relies on this behavior, a compatibility option rebaseRootRelativeCssUrls has been provided for the 8.x release cycle to facilitate transition away from this non-standard and limiting behavior. The recommended method to transition is to use relative paths within the source stylesheet. This allows the build system to process and generate a full URL for the asset.

@clydin clydin closed this as completed May 30, 2019
@a616101
Copy link

a616101 commented May 31, 2019

I have the same problem.
Use Cli 8.0.1

@saury
Copy link

saury commented Jun 3, 2019

I have the same problem.
Use Cli 8.0.1

Add --rebase-root-relative-css-urls=true to your build script shall solve your problem for temp.

@Indreed
Copy link

Indreed commented Jun 3, 2019

So how should we create url paths to images that we want to keep in assets folder and use custom --base-href in the long run (Angular 8+)? From now on all images should be kept along with components? In my case in scss files:

url('../assets/images/example.jpg')

leads to CssSyntaxError - can't compile

url('/assets/images/example.jpg')

doesn't work after build because the resources are referenced to the root path of the url, not the one given in base-href or deploy-url

url('~src/assets/images/example.jpg')

works, however all images are copied from assets/images folder to the root folder of the build output, so I end up having two copies of each image on the server

@nfcf
Copy link

nfcf commented Jun 4, 2019

also interested in the answer to the above question.
I've tried url('assets/images/example.jpg') (without the trailing "/")
and it also makes a copy of each image to the root dist folder.

@acohenOT
Copy link
Contributor

acohenOT commented Jun 4, 2019

@clydin #12797 prevents using relative paths in stylesheets in many cases

@michael-letcher
Copy link

michael-letcher commented Jun 19, 2019

@clydin

The recommended method to transition is to use relative paths within the source stylesheet

But seeing at that is not even possible, who's bright idea was it to think that breaking the only viable solution with only a flag to restore it; that will be soon depricated post v8 was the best course of action....

So was the plan to just break it and have no solution?

@vinayak-kaviskar
Copy link

I solved the issue in angular 8 by adding following code in AppModule
providers: [{provide: APP_BASE_HREF, useValue: '.'}] . As mentioned in latest Angular.io docs
here

@DzmVasileusky
Copy link

I solved the issue in angular 8 by adding following code in AppModule
providers: [{provide: APP_BASE_HREF, useValue: '.'}] . As mentioned in latest Angular.io docs
here

Is not working for urls in less for me

@DzmVasileusky
Copy link

url('~src/assets/images/example.jpg')

Is working only in component styles and not working in main less file for me

@antch
Copy link

antch commented Aug 1, 2019

With all due respect @clydin, how is this issue solved when the only thing that seems to work (~src/assets/) results in two copies of the asset in the build output? Can you please provide some further guidance, perhaps an example of this "recommended method" using "relative path" that does not result in duplication of assets?

@michael-letcher
Copy link

as @DzmVasileusky has pointed out this does not work for LESS.

@clydin What is our solution for this closed ticket.

@clydin
Copy link
Member

clydin commented Aug 8, 2019

A newly generated project contains the following configuration option:

"assets": [
  "src/favicon.ico",
  "src/assets"
],

This tells the build system to copy all files verbatim that are within the src/assets directory to the output path . If a file is listed in the assets configuration option or within a directory listed therein, it will be copied to the output. These files are not in any other way managed by the build system as they are intended to be static assets outside the domain of the build pipeline.

By using a relative path for a resource file within a stylesheet, the build system is able to process and manage the resource. Since the build system is now managing the resource, it will process the file as needed and add it to the output of the application. File name hashing for long-term caching functionality being the only current processing.

This general behavior is common among typical standalone Webpack configurations, Vue.js, and Create React App. In fact, Create React App strongly recommends the use of relative URLs for files used within the application for the following reasons:

Scripts and stylesheets get minified and bundled together to avoid extra network requests.
Missing files cause compilation errors instead of 404 errors for your users.
Result filenames include content hashes so you don鈥檛 need to worry about browsers caching their old versions.

@acohenOT
Copy link
Contributor

acohenOT commented Aug 8, 2019

@clydin what about the cases where relative paths cannot be used in the style sheet? See #12797. The base-href flag is the only workaround for this at the moment.

@clydin
Copy link
Member

clydin commented Aug 8, 2019

That's an issue with Sass not rebasing URLs based on imports and not an issue with others such as LESS or Stylus since that functionality is provided. The typical method of addressing the issue is to use Sass variables to point to a resource location. This is used effectively in packages such as Font Awesome.

The Sass issue tracking the problem: sass/sass#2535

@antch
Copy link

antch commented Aug 8, 2019

@clydin What is the recommended way to import assets from LESS component styles, then? I used to be able to just do url("/assets/path/to/my/asset.png"), but now that no longer works (unless using rebaseRootRelativeCssUrls). It does compile but results in a 404 as the deployUrl is no longer prepended to the asset URL. Are you suggesting that I hardcode the deployUrl value inside of my styles (which seems so, so wrong) or am I missing another way?

Edit: After playing around with it it seems that going relative pathing from the .less location seems to work, but man is it clunky: url("../../../../assets/path/to/my/asset.png"). Yikes.

@KingDarBoja
Copy link

KingDarBoja commented Sep 6, 2019

I have been scratching my head for days after trying to make assets work on my site deploy with a custom href as stated by the author.

The relative approach sounds a bit messy if you ask me, because deeper components would have to go back several folders to find a single asset unless used on the same level, just saying.

EDIT: The relative approach also create copies of assets on my root folder.

@james-schwartzkopf
Copy link

Unless I'm missing something, the relative urls don't seem to pay any attention to the assets in the angular.json, which means as far as I can tell there is no way to provide a url for an asset in my library project. We were using absolute paths, as a hack workaround, but if rebaseRootRelativeCssUrls is removed, we wont even have that.

@arthur-clifford
Copy link

Rather than the rebaseRootRelativeCssUrls you might try programmatically setting the base href:

https://stackoverflow.com/questions/41515028/set-base-href-from-an-environment-variable-with-ng-build

That should give you a deprecation-tolerant work-around.

For some reason the environment.baseHref settings for angular 8 were not populating the document's base href. So relative image paths (in a src="" attribute) were breaking which had worked previously, I imagine relative url paths in styles would have the same problem. The solution above worked at least in chrome.

I think that the sass/less behavior being reported is possibly symptomatic of the issue of the baseHref not being honored in the output HTML. You shouldn't have to rebase anything if a configuration/environment's baseHref setting is properly being honored.

@niklas-wortmann
Copy link

@filipesilva & @clydin is this maybe something that should be added to update.angular.io? It's likely breaking a lot of people and I think it would be helpful to have proper documentation for it. What do you think about it?

@arthur-clifford
Copy link

My previous comment may not be true for earlier versions of some browsers. And is problematic if some resources load before programmatic setting of baseHref. The right solution is one that sets baseHref in index.html at compile time.

Doing a little further experimentation I've realized that the baseHref defined in the environment.ts (or replaced environment.ts) is not the one being used for the document when it loads.

If I specify baseHref in the angular.json file for a configuration then it appears as the href for the base tag in the compiled index.html file.

I don't know if I am misremembering or if something changed but I thought that putting things in the environment.ts files (for each config) meant that the config options would be grabbed from the environment file (after replacement) such that in my environment.dev.ts file if I set baseHref there and then set the replacement section in the "dev" configuration in angular.json to replace environment.ts with environment.dev.ts then my environment specific config values would be used from environment.dev.ts.

The behavior is more like the environment file is just for properties you want to make available for the specific deployment environment and the config section is completely independent so you have to put the same baseHref value in both places if you want to refer to environment.baseHref in the app and have the baseHref set to the right initial value when index.html is compiled.

My personal preference would be to be able to add config properties (other than replacements ) to environment files and have the config properties inherit from the replaced environment file so that I can set config properties I want to make available to the app in environment.x.ts and config properties only relevant to compilation available in angular.json and not have to replicate any values to both.

However, if in fact the environment files are going to be independent of compilation configuration that needs to be more clearly pointed out so that baseHref is set in angular.json for configurations for compiling and set in environment.x.ts for availability to the application.

@t00
Copy link

t00 commented Sep 23, 2019

@clydin Is there any estimate when rebase-root-relative-css-urls will be removed? v9? v10?

@Gil-Epshtain
Copy link

Gil-Epshtain commented Oct 3, 2019

Why is the thread closed??? so many people experience this problem, and no valid solution was presented yet. Did anyone manged to solve this issue, any workarounds???

@KingDarBoja
Copy link

Why is the thread closed??? so many people experience this problem, and no valid solution was presented by the Angular team. Did anyone manged to solve this issue, any workarounds???

We are still waiting for another solution since the provided one doesn't match the expectations.

@Wisdomb33r
Copy link

Wisdomb33r commented Oct 28, 2019

Wating for a better solution too. Currently I'm using the already-deprecated --rebase-root-relative-css-urls true option for prod build. Extracting the images from asset folder is imho bad for several different reasons :

  1. It does clutter the top-level folder on your server. Deployments should be performed by automatic tools, but you cannot always exclude a manual intervention on your server. If so, acting in a list of hundreds of files is risky.
  2. It does duplicate the assets. If you do not want duplication, you should move your CSS-relatively-referenced files to a folder which is not copy/pasted as-is into production build like "assets" folder (assuming "assets" is the default name when generating a project). But these files are eventually renamed using a hash, so you cannot use them in non-CSS contexts, for instance HTML templates.
  3. Due to the files being copy-pasted to the root output folder, multiple image files used by CSS can have conflicting names for local ng serve. Just add two different images into two different folder of the assets. Use them both in CSS with relative paths. Only one of them will be available due to conflicting name. Workaround : create an ng serve build configuration which is using the outputHash: 'media' similar to prod build.

@broweratcognitecdotcom
Copy link

broweratcognitecdotcom commented Nov 7, 2019

We do this:
<script type="text/javascript"> var parts = document.location.pathname.split('/'); var baseHref; for (var i=0; i<parts.length; i++) { var part = parts[i]; if (part.length > 0) { baseHref = part; break; } } document.write("<base href='" + baseHref ? "/" + baseHref + "/" : "/" + "' />"); </script> </body> </html>

@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jan 2, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests