angular / angular-cli

CLI tool for Angular
https://cli.angular.io
MIT License
26.74k stars 11.98k forks source link

CSS images with relative path not included in production build #4806

Closed arntj closed 7 years ago

arntj commented 7 years ago

Please provide us with the following information:

OS?

Windows 10

Versions.

1.0.0-beta.32.3

Repro steps.

  1. Create new app with ng new.
  2. Add an image anywhere outside the app directory, e.g. in the assets directory.
  3. Reference this image from the app.component.css, using a relative path. Example: background-image: url(../assets/some_image.png)
  4. Do the following: ng build --prod.
  5. Verify that the image is not copied along with the CSS in the build output, meaning the image reference is now broken.

The log given by the failure.

N/A

Mention any other details that might be useful.

The image is correctly copied if doing ng build without the --prod switch.


Thanks! We'll be in touch soon.

filipesilva commented 7 years ago

Heya @arntj, can you do me a favor and verify the image really is broken within you app? For images smaller than 10kb we actually inline them, which is why it wouldn't be copied over.

arntj commented 7 years ago

Yes, I loaded it in an HTTP server and verified that the image was broken in the web browser. The image I tested it with is 60 kb.

arntj commented 7 years ago

The production output CSS links to a hashed image file that doesn't exist in the output dir.

filipesilva commented 7 years ago

I can verify this happens:

Will investigate.

filipesilva commented 7 years ago

This seems to be related with AoT.

Workarounds for now:

JimiC commented 7 years ago

In my case, cause I use base-href './' the workaround is as follows:

b4youleap commented 7 years ago

This is a little different but maybe related? OS? Windows 10 Versions. 1.0.0-beta.32.3 Upgrading project from beta-31 - my issue showing up in dev when running ng serve

Under my src directory I have a theme file: ui-framework-theme.css It is referenced in my index.html as <link href="ui-framework-theme.css" rel="stylesheet" /> (apologies if this is bad practice - I'm learning) Was getting a 404 error on the file until I changed it to <link href="/src/ui-framework-theme.css" rel="stylesheet" />

janwo commented 7 years ago

I referenced my images in html like <img src="../../someimage.svg"> and webpack is also not emitting this file.

janwo commented 7 years ago

@filipesilva Does this affect images in html as well?

filipesilva commented 7 years ago

@janwo no, images in html aren't processed at all.

kylecordes commented 7 years ago

@filipesilva It would be nice to have the same processing of images referred to from CSS versus HTML. Ideally with the typical webpack processing for both, alternatively disabling asset URL processing for both would be more consistent and easier to understand and explain than the current feature set. Is a move toward one of those things on the roadmap?

filipesilva commented 7 years ago

@kylecordes it would be nice if we could have HTML processing on part with CSS processing but I haven't looked into it much.

I had a short look at https://github.com/webpack-contrib/html-loader but wasn't too sure of the interactions between image urls and interpolated properties.

If someone knows how safe it is, I'd be happy to add it in.

kylecordes commented 7 years ago

So if I understand right, the obstacle is: we need to be confident that HTMLLoader (or a fork thereof) applies its usual processing to plain URLs, but leaves any attribute values that look like an Angular expression, unchanged.

Here are its test cases:

https://github.com/webpack-contrib/html-loader/blob/master/test/loaderTest.js

It appears as though there is already a way to pass a config which tells it to ignore expressions that match a pattern:

https://github.com/webpack-contrib/html-loader/blob/master/test/loaderTest.js#L68

The example used in the test case tells it to leave expressions that include "{{" untouched. I wonder if that bit of config would be enough for what CLI needs?

clydin commented 7 years ago

The HTML templates are inherently dynamic, as a result static analysis to determine asset usage is exceedingly error prone. Combine that will the vast multitude of methods to reference assets (and their varying foms) and attempts at HTML template static analysis becomes far more trouble than it's worth.

kylecordes commented 7 years ago

@clydin Certainly there will always be cases where a template can be made to referenced an asset that could not be determined statically. But I have applications that have highly numerous assets that are always mentioned statically from HTML templates. Handling those the same way as assets mentioned from CSS would be a great improvement to ergonomics.

kylecordes commented 7 years ago

Also related, this person suggests a set of HtmlLoader settings to work with Angular templates:

https://github.com/webpack-contrib/html-loader/issues/67#issuecomment-277502048

martinmcwhorter commented 7 years ago

Rather than --no-aot shouldn't -oh bundles be a sufficient workaround with absolute image paths?

filipesilva commented 7 years ago

@kylecordes I had a preliminary look at html-loader and it seems to be ok with Angular templates overall.

I couldn't find how to rewrite absolute urls without processing them though. I had to do that for absolute styles in this bit of code: https://github.com/angular/angular-cli/blob/master/packages/@angular/cli/models/webpack-configs/styles.ts#L50-L60

Do you know of a similar way to do it with html? The root query parameter won't work since afterwards it will process the url.

@martinmcwhorter I don't see how that would work. Can you elaborate?

clydin commented 7 years ago

Something to note from an app design standpoint is that outside actual page content (which will be overwhelming dynamic anyway), css background images and icon fonts (SVG in particular for custom design elements) are a far more flexible alternative to static HTML img elements.

filipesilva commented 7 years ago

Yeah it wouldn't be a big problem in image urls on html would always need to be absolute.

martinmcwhorter commented 7 years ago

@filipesilva -- I experienced the issue where the images filenames in CSS (actually SCSS if that matters) were being hashed, but the actual image file names were not being hashed on build.

To work around this issue I used absolute file names in CSS, example /assets/logo.png and built with the -oh=bundles flag, rather than --no-aot, to prevent webpack from adding the hash to the path in CSS.

This workaround works for me, though I don't know the internals of Angular-CLI or the webpack config that is used -- so I understand I may be mistaken on the specifics.

filipesilva commented 7 years ago

@martinmcwhorter I see now, yeah. Your workaround would work, since you're taking the resource extraction out of the equation. You shouldn't have to do that though... next release it should be ok.

martinmcwhorter commented 7 years ago

Yep, I'm looking forward to hashed images :)

On Wed, 22 Feb 2017, 11:05 Filipe Silva, notifications@github.com wrote:

@martinmcwhorter https://github.com/martinmcwhorter I see now, yeah. Your workaround would work, since you're taking the resource extraction out of the equation. You shouldn't have to do that though... next release it should be ok.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/angular/angular-cli/issues/4806#issuecomment-281638319, or mute the thread https://github.com/notifications/unsubscribe-auth/ABI5-pZE-2PvKnpnrgKk6EA0bSAO06tLks5rfBZcgaJpZM4MFDL4 .

wtho commented 6 years ago

So is there a way to configure the cli to end up with relative paths in the CSS, e.g. url('assets/...')?

demiahmed commented 6 years ago

Hey guys! I'm new to angular and I'm facing the same problem in my app where the local version works perfectly great whereas the github deployment breaks all the URLs for images. My images are placed in src/assets/xyz.jpg directory and I have tried changing the base href as well as my image url and still the image appears to be broken.

I'm using angular 6. Would be really thankful if I get my issue sorted out.

Thanks in advance.

yousefashraf commented 6 years ago

Hey guys! I'm new to angular and I'm facing the same problem in my app where the local version works perfectly great whereas the github deployment breaks all the URLs for images. My images are placed in src/assets/xyz.jpg directory and I have tried changing the base href as well as my image url and still the image appears to be broken.

I'm using angular 6. Would be really thankful if I get my issue sorted out.

Thanks in advance.

i have this issue too

frostbytedata commented 5 years ago

No news on this issue? I am seeing the same thing on Angular 6. Building on Unix seems to be broken, but strangely, I never have the issue when building on Windows.

Oddly enough, when I reference assets in this fashion:

url("/assets/myimage.jpg")

instead of

url("../../../assets/myimage.jpg")

it works fine locally, and during my unix production build.

benwelker commented 5 years ago

Similar to @frostbytedata but I'm on Angular 7 and my url still differed slightly to get it working.

url("assets/myimage.png")

Having that preceding forward slash before assets was breaking for me, along with the other method of the url("../../assets/myimage.png")

nhhockeyplayer commented 5 years ago

Im having to hardwire with an appRootPrefix in environment.ts in order to serve up internationalized language files beneath my assets folder and various sporadic app images off the template or from within the component fed to the template.

export const environment = {
    appRootPrefix: '/api',
}

and then

    ngOnInit() {
        this.image.nativeElement.setAttribute(
            'src',
            `${environment.appRootPrefix}/assets/logo-pp.png`
        )
    }

or

        this.image.nativeElement.setAttribute(
            'src',
            `${environment.appRootPrefix}/assets/avatar.png`
        )

or

export function HttpLoaderFactory(http: HttpClient) {
    return new TranslateHttpLoader(
        http,
        `${environment.appRootPrefix}/assets/i18n/`,
        '.json'
    )
}

not good for production


C:\apache-tomcat-9.0.14\api>ng --version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / ? \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/

Angular CLI: 7.2.3
Node: 8.12.0
OS: win32 x64
Angular: 7.2.2
... animations, cdk, common, compiler, compiler-cli, core, forms
... http, language-service, material, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.12.3
@angular-devkit/build-angular     0.12.3
@angular-devkit/build-optimizer   0.12.3
@angular-devkit/build-webpack     0.12.3
@angular-devkit/core              7.2.3
@angular-devkit/schematics        7.2.3
@angular/cli                      7.2.3
@angular/flex-layout              7.0.0-beta.19
@ngtools/webpack                  7.2.3
@schematics/angular               7.2.3
@schematics/update                0.12.3
rxjs                              6.3.3
typescript                        3.2.4
webpack                           4.28.4

C:\apache-tomcat-9.0.14\api>
akgupta002 commented 5 years ago

No news on this issue? I am seeing the same thing on Angular 6. Building on Unix seems to be broken, but strangely, I never have the issue when building on Windows.

Oddly enough, when I reference assets in this fashion:

url("/assets/myimage.jpg")

instead of

url("../../../assets/myimage.jpg")

it works fine locally, and during my unix production build.

It worked in my case too. After removing ellipsis, angular7 found this asset in no time. Amazing! Thank you @frostbytedata for sharing this.

angular-automatic-lock-bot[bot] commented 5 years ago

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.