Skip to content

Angular 18 Asset Referencing in Workspace Projects

Problem Statement

In Angular workspaces created with @angular/cli@18, developers face challenges referencing static assets (images, fonts, etc.) placed in the new public folder. While Angular 17 used an src/assets structure and simple <img src="assets/image.png"> references, Angular 18's workspace structure causes:

  1. Asset paths not resolving correctly in templates
  2. Files in /public not copied to build output (dist)
  3. Confusion between project root paths and workspace paths

This occurs specifically in multi-project workspaces with this structure:

bash
workspace-name

└── projects/
    └── application-name/
        ├── public/
        └── src/

Default Configuration (Cleanest Approach)

Angular 18 configures asset handling in angular.json by default. Place assets anywhere in the project's public folder and reference them relative to the root URL.

  1. Folder structure:

    bash
    projects/
    └── application-name/
        └── public/
            ├── img/
       └── logo.png
            ├── pdf/
       └── guide.pdf
            └── favicon.ico
  2. Reference in templates (omit public/):

    html
    <!-- Component template -->
    <img src="img/logo.png" alt="Logo">
    <a href="pdf/guide.pdf">Download Guide</a>

The default angular.json configuration:

json
{
  "architect": {
    "build": {
      "options": {
        "assets": [
          {
            "glob": "**/*",
            "input": "public"  // Path relative to project root
          }
        ]
      }
    }
  }
}

Alternative Approach: Absolute Paths

For clearer path resolution, create an assets subfolder in public and use absolute paths:

  1. Folder structure:

    bash
    public/
    └── assets/
        └── img/
            └── banner.jpg
  2. Template reference:

    html
    <img src="/assets/img/banner.jpg">

Hybrid Configuration (Legacy Support)

To maintain compatibility with Angular 17's asset structure:

  1. Create src/assets/ in your project:

    bash
    projects/
    └── application-name/
        ├── public/
        └── src/
            └── assets/
  2. Update angular.json:

    json
    "assets": [
      {
        "glob": "**/*",
        "input": "public"
      },
      {
        "glob": "**/*",
        "input": "src/assets",
        "output": "/assets/"  // Optional: maps to /assets/ in dist
      }
    ]
  3. Reference legacy assets:

    html
    <img src="assets/legacy-image.png" alt="Legacy Asset">

CSS Font Reference

When accessing fonts from CSS files, use absolute paths with ^ prefix:

css
@font-face {
  font-family: 'Inter';
  src: url('^public/fonts/Inter.woff2') format('woff2');
}

Troubleshooting Checklist

If assets still fail to load:

  • Verify folder location: Assets must be in project-specific public/, not workspace root
  • Check angular.json: Ensure input path is relative to project root
  • Restart dev server: Run ng serve after configuration changes
  • Inspect build output: Verify files appear in dist/ after ng build
  • Use output mapping: For custom distribution paths:
    json
    {
      "glob": "**/*",
      "input": "public",
      "output": "static-assets/"
    }

Key Concepts

  • Input Paths: Relative to project root (e.g., projects/your-app)
  • Output Paths: Relative to build output (dist/your-app)
  • Path Resolution: Always omit public/ in references
  • Glob Patterns: **/* matches all files recursively

Migration Tip

For projects upgraded from Angular 17, use the hybrid configuration approach for a smoother transition. New projects should use the default public/ structure.

Avoid Absolute Paths in Source

Don't use /public/... in source paths - the public folder name never appears in the compiled application.

Asset Reference Examples

<button data-md-type="code" data-md-lang="html">Template Reference</button>
```html

View PDF

<link rel="icon" href="favicon.ico"> ```
<button data-md-type="code" data-md-lang="typescript">Component Logic</button>
```typescript // Get asset URL programmatically const iconUrl = 'icons/settings.svg';

// Use with [src] binding <img [src]="iconUrl">


## Configuration Best Practices
1. **Multiple Project Workspaces**: Each app/library should have its own `public` folder
2. **Environment Variations**: Use file replacements for environment-specific assets
3. **Asset Optimization**: Utilize Angular's built-in optimization for:
   - Image compression (WebP conversion)
   - Font inlining
   - Cache busting
4. **Security**: Always sanitize dynamic asset URLs with `DomSanitizer`

```typescript
import { DomSanitizer } from '@angular/platform-browser';

constructor(private sanitizer: DomSanitizer) {}

getSafeUrl(path: string) {
  return this.sanitizer.bypassSecurityTrustResourceUrl(path);
}