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);
}