How to bundle vendor fonts when creating libraries with Angular cli
Asked Answered
S

3

8

I am creating a component library with the Angular CLI (v7.x) and am having trouble figuring out how I get 3rd party font assets needed for css rules to be included in my dist folder generated by ng-packagr.

Due to ng-packagr not supporting scss bundling as per this issue, I am using scss-bundle in a post build task to perform the bundling for me and to put the final bundled scss file into my dist folder.

However, some of the css rules such as font declarations include url references to relative font folders, and these I don't yet have being included in my dist folder.

So for example, in my angular library application I have styles.scss file which contains an entry to import an icon stylesheet:

@import "~primeicons/primeicons.css";

But there is a relative fonts folder where these primeicons live in my node_modules folder which are used for the css.

enter image description here

One approach is I could write a further post build step to bundle these and put them into a fonts folder alongside my concatenated scss file in my dist folder so they can be resolved.

I wondered if there was a smarter way, or some built in way either with ng-packager or angular-cli when building my library to do this?

Update

So I tried the approach of having a fonts folder in my library project root (actually under an assets folder) and copy this to the root of my dist folder after I build my library.

And in my playground app where I try to use the packaged styles in my actual lib I have this:

my-lib-playground/src/styles.scss

@import "../../../dist/my-lib/styles";

But when trying to build my playground app with the CLI, I get:

ERROR in ./src/styles.scss (/Users/someone/Documents/Github/my-lib-playground/node_modules/@angular-devkit/build-angular/src/angular-cli-files/plugins/raw-css-loader.js!/Users/someone/Documents/Github/my-lib-playground/node_modules/postcss-loader/src??embedded!/Users/someone/Documents/Github/my-lib-playground/node_modules/sass-loader/lib/loader.js??ref--14-3!./src/styles.scss)
Module Error (from /Users/someone/Documents/Github/my-lib-playground/node_modules/postcss-loader/src/index.js):
(Emitted value instead of an instance of Error) CssSyntaxError: /Users/someone/Documents/Github/my-lib-playground/dist/my-lib-playground/styles.scss:609:56: Can't resolve './fonts/open-sans-v15-latin-700.eot' in '/Users/someone/Documents/Github/my-lib-playground/projects/my-lib-playground/src'

So my actual question:

How do I get my consuming 'playground' application to include\resolve the font files correctly when building with the cli? These are obviously trying to be resolved relative to my playground app currently. Whats the correct solution here? Or have I done something(s) totally wrong?

Another Way

Make primeng a peerDependency of my library and leave it the responsibility of the developer to add primengto their app and include the relevant style in the angular.json as per the suggested answer from Daniel below. Is this the right way, only way?

Silures answered 11/4, 2019 at 11:7 Comment(4)
You need to put your font into asset folder then you can import like this @import "assets/fonts/primeicons/primeicons.css";Incitement
I dont think thats going to help me hereSilures
Really why not ? Is there any error ?Incitement
So you did stick with the peerDependency way? I have exactly the same issue, but I don't feel having to "force" future users to manually include font and css files other than my library. I'd like to have this transparent to them.Baalbeer
G
7

You should add primeicons as a peerDependency and then in the other project you should add in the angular.json the styles configuration.

"styles": [
  "node_modules/primeicons/primeicons.css",
],

After that you already have it imported so it doesn't need the import from my-lib-playground/src/styles.scss anymore.

PrimeNG has that example on the readme of the github. https://github.com/primefaces/primeng

Goldenseal answered 24/4, 2019 at 6:30 Comment(0)
U
3

The library project does not have a root directory, root directory always depends on project root where the library is consuming.

so either you have to import fonts into the main project, I know this you already tried,

so, the only option is to convert the font into base64 and assign into CSS.

convert font file to base64 - https://www.giftofspeed.com/base64-encoder/

declare font in CSS

@font-face {
    font-family: 'myfont';
    src: url(data:font/truetype;charset=utf-8;base64,<BASE64-STRING>) format('truetype');
}
Unanswerable answered 26/4, 2019 at 19:38 Comment(3)
But how do you re-declare an existing font-face declaration of an external lib in your own project?Baalbeer
re-declare means you want to use library font into a project where you are consuming that library?Unanswerable
Yes, exactly! I do have the exact same problem: I'm developing a library that uses another library that has custom CSS+font-face declarations; when I try to use my library in an app, build fails with the above problem. What I can think of is to copy the external lib's whole CSS and fonts to my library and use that instead of the external lib.Baalbeer
C
0

One strategy is to ask your library user to import your style definitions, and making sure these are working in that context.

my-lib

Place your font files in your library in my-lib/src/assets/fonts.
For exemple, let's say you have a file my-lib/src/assets/fonts/MyFont.ttf.

my-lib/src/assets/_index.scss

@font-face {
  font-family: "MyFont";
  src: url("./fonts/MyFont.ttf") format("truetype");
}

The name _index.scss is needed if you want sass to import it just using the library name.

This file, _index.scss, is now defining your font family. Now let's make sure they get exported when building your library:

my-lib/ng-package.json

{
 ...
 "dest": "../../dist/my-lib",
 "assets": [
    {
      "glob": "**/*",
      "input": "/src/assets/",
      "output": "/"
    }
 ]
 ...
}

Thanks to the assets section, when building, any file or folder located within my-lib/src/assets will be exported to your dist/my-lib/ folder.

You can put the style and font folder to other locations, but be sure that the relative path between _index.scss and the font files is working and remains the same before and after export.
In this exemple ./fonts/MyFont.ttf is valid both from my-lib/src/assets/_index.scss and from dist/my-lib/_index.scss

my-lib usage

Now, the application using your library just needs to include in one of their styles files the following line:

@import "my-lib";

To make sure that sass compiles and resolve "my-lib", regardless if you have published your library or not, use the following options in your angular,json file:

{
  "projects": {
    "my-app": {
      ...
      "architect": {
        "build": {
          ...
          "options": {
            ...
            "stylePreprocessorOptions": {
              "includePaths": [
                "node_modules/",
                "dist/"
              ]
            }
          }
        }
      }
    }
  }
}

node_modules/ allows sass to resolve deployed packages.
dist/ allows sass to resolve locally built packages.

Colloid answered 5/10, 2023 at 16:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.