Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Font Awesome in a component library - FontAwesome: Could not find icon with iconName=times and prefix=fas

I have an Angular 7 component library that uses FontAwesome icons.

First of all, output of ng version:

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.10.7
@angular-devkit/build-angular      0.10.7
@angular-devkit/build-ng-packagr   0.10.7
@angular-devkit/build-optimizer    0.10.7
@angular-devkit/build-webpack      0.10.7
@angular-devkit/core               7.0.7
@angular-devkit/schematics         7.0.7
@angular/cdk                       7.1.1
@angular/cli                       7.0.7
@angular/compiler-cli              7.0.4
@angular/language-service          7.0.4
@angular/material                  7.1.1
@ngtools/json-schema               1.1.0
@ngtools/webpack                   7.0.7
@schematics/angular                7.0.7
@schematics/update                 0.10.7
ng-packagr                         4.4.5
rxjs                               6.3.3
typescript                         3.1.3
webpack                            4.19.1

And relevant tidbits in package.json:

"@fortawesome/angular-fontawesome": "^0.3.0",
"@fortawesome/fontawesome-svg-core": "^1.2.8",
"@fortawesome/free-regular-svg-icons": "^5.5.0",
"@fortawesome/free-solid-svg-icons": "^5.5.0",

Here's my module definition:

import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';

import { faAngleDown } from '@fortawesome/free-solid-svg-icons/faAngleDown';
import { faBars } from '@fortawesome/free-solid-svg-icons/faBars';
import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons/faCalendarAlt';
import { faCaretLeft } from '@fortawesome/free-solid-svg-icons/faCaretLeft';
import { faChevronDown } from '@fortawesome/free-solid-svg-icons/faChevronDown';
import { faSortUp } from '@fortawesome/free-solid-svg-icons/faSortUp';
import { faSortDown } from '@fortawesome/free-solid-svg-icons/faSortDown';
import { faChevronUp } from '@fortawesome/free-solid-svg-icons/faChevronUp';
import { faChevronLeft } from '@fortawesome/free-solid-svg-icons/faChevronLeft';
import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes';
import { faUser } from '@fortawesome/free-solid-svg-icons/faUser';
import { faSignOutAlt } from '@fortawesome/free-solid-svg-icons/faSignOutAlt';
import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons/faQuestionCircle';
import { faGlobeAmericas } from '@fortawesome/free-solid-svg-icons/faGlobeAmericas';

<app imports>

library.add(
    faAngleDown, faBars, faCalendarAlt, faCaretLeft, faChevronDown,
    faChevronLeft, faChevronUp, faGlobeAmericas, faQuestionCircle, 
    faSignOutAlt, faSortDown, faSortUp, faTimes, faUser
);

@NgModule({
    declarations: [
        <app components>
    ],
    exports: [
        <app components>
    ],
    imports: [
        FontAwesomeModule,
        <other app imports>
    ]
})
export class LibModule {
    public static forRoot(): ModuleWithProviders {
        return {
            ngModule: LibModule,
            providers: [
                <some providers>
            ]
        };
    }
}

Here's public_api.ts:

export * from './lib/lib.module';
<component exports>

I can build this module with ng build mylib --prod just fine. However, when I try to use it in an application, whenever the --prod flag is used to build or serve, I get the following errors:

FontAwesome: Could not find icon with iconName=times and prefix=fas

Here's the app.module.ts file for the application:

import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons';
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { LibModule } from 'libmodule';

<app imports>

library.add(faCalendarAlt);

@NgModule({
    bootstrap: [ AppComponent ],
    declarations: [
        AppComponent,
    ],
    imports: [
        FontAwesomeModule,
        LibModule.forRoot(),
    ]
})
export class AppModule {
}

app.component.ts is using the faCalendarIcon, and also bringing in components from LibModule which in turn are using the icons described in the lib module definition.

The calendar icon displays just fine when using ng serve --prod or ng build --prod and then serving the application not through the baked angular dev server. However, every icon used by the library components themselves don't show up, and I see the error from the title in the console for every one of them.

Please note that this doesn't happen when I use ng serve without the prod flag, so it may have something to do with tree-shaking?

How can I use FontAwesomeModule within a library and make sure that the consumers of the library can see the icons as well? I'd rather not have to make all consumers import all icons used by the library.

Note that I'm using deep imports with my FontAwesome icons, I've also tried to do "shallow" imports as such:

import {
  faAngleDown,
  faBars,
  faCalendarAlt,
  faCaretLeft,
  faChevronDown,
  faChevronLeft,
  faChevronUp,
  faGlobeAmericas,
  faQuestionCircle,
  faSignOutAlt,
  faSortDown,
  faSortUp,
  faTimes,
  faUser
} from '@fortawesome/free-solid-svg-icons';

I've also tried for my lib module to export FontAwesomeModule, and not to export it. I've tried exporting each icon, but that's not possible it seems.

like image 910
Isabelle Plante Avatar asked Dec 12 '18 17:12

Isabelle Plante


2 Answers

OK, we figured it out internally.

In the library, the library.add(...) statements that were just floating in the library module definition file need to move to the module constructor. This solves the issue.

like image 64
Isabelle Plante Avatar answered Oct 11 '22 02:10

Isabelle Plante


There is another option.

  1. Create a new project ng new ng-fontawesome
  2. Create a new library in the project ng generate library ng-fa
  3. Install font-awesome packages npm install --save @fortawesome/angular-fontawesome @fortawesome/fontawesome-svg-core @fortawesome/free-regular-svg-icons
  4. Update projects/ng-fa/src/lib/ng-fa.module.ts to import/export the fontawesome module

    import { NgModule } from '@angular/core';
    import { NgFaComponent } from './ng-fa.component';
    import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
    
    @NgModule({
      declarations: [NgFaComponent],
      imports: [FontAwesomeModule],
      exports: [NgFaComponent, FontAwesomeModule]
    })
    export class NgFaModule { }
    
  5. Update projects/ng-fa/src/lib/ng-fa.component.ts to utilize a fontawesome icon

    import { Component } from '@angular/core';
    // import { IconDefinition } from '@fortawesome/fontawesome-common-types';
    import { faAddressBook } from '@fortawesome/free-regular-svg-icons';
    @Component({
      selector: 'lib-ng-fa',
      template: `
        <fa-icon [icon]="icon"></fa-icon>
      `,
      styles: []
    })
    export class NgFaComponent {
      // icon: IconDefinition = faAddressBook;
      icon = faAddressBook;
    }
    
  6. Update src/app/app.module.ts to import your library module by name(not relative path)

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { AppComponent } from './app.component';
    import { NgFaModule } from 'ng-fa';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule, NgFaModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
  7. Add npm scripts to cause the library to be built before the application is. In the scripts tag in the main package.json file I added to entries.

    • "build:ng-fa": "ng build ng-fa"
    • "prestart": "npm run build:ng-fa"

I tested this with the start command but you would need to do the same thing for your build command.

I then ran npm run start(dev) and npm run start -- --prod to test both builds and they are working fine. This greatly reduces the need for all of the imports as you are doing it above. Here you only need to import the icons in the components that actually need them(not in the module as well).

I have created a GitHub repo with this sample as well.

like image 28
peinearydevelopment Avatar answered Oct 11 '22 03:10

peinearydevelopment