Integrating Third-Party Scripts and CSS into Your Angular App

Adding External Functionality to Your Angular App with Third-Party Scripts and CSS

In Angular, we have a few ways to add libraries, for example, using Angular schematics or using Angular libraries, which export modules to add to the app.module. But what happens when we have a standard library.js or ui.css and need to add it to use in Angular?

Angular.json is a file with all the settings of our Angular project, and also it helps us to work with 3rd party libraries with standard JavaScript and CSS files to merge into the final bundle or defer in a single file.

Instead of manually adding CSS and JavaScript files into the index.html, the Angular CLI does it for us, creating a bundle file for CSS and JavaScript and injecting it into the index.html automatically.

Note: This example use @angular/core v12.2.0

The Scenario

We are building an Angular application but want to use an external web component button-upload with two files, ' button-upload.cssandbutton-upload.js`.

For simplicity, the files are in the external/ directory, but they should be node_modules.

The button-upload.css

.fancy-uploader {
  background-color: red;
  color: whitesmoke;
  border: 1px solid gray;
}

button-upload.js

class ButtonUpload extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.innerHTML = `
    <div class="fancy-uploader">
      <label for="avatar">Image Uploader:</label>
      <input type="file"
           id="avatar" name="avatar"
           accept="image/png, image/jpeg">
    </div>
    `;
  }

}

window.customElements.define("button-upload", ButtonUpload);

First Approach

The first, easy, and fast approach is importing JavaScript and CSS into the index.html. It works, but comes with a price to pay:

  • Execution order and maintenance.

  • You add files manually, but the Angular CLI also adds files and CSS.

  • What happens if you have more scripts like tracking stuff?

  • What happens to keep the problem isolated in his bundle?

The Angular.json solves all of them, providing a single place for the maintenance of CSS and JavaScript files, with the option of eager loading, bundling, and optional injection in the index.html

Let's give an overview of angular.json.

The Angular.json

The Angular CLI uses angular.json to help us with the administration and configure the projects for building, serving, testing, and localization.

we are focused on how to add the third-party css and scripts. Learn more in the official Angular docs.

Angular.json configures every application or library in the project's node. We work in the section architect> build > options focus in styles and scripts to add our styles and CSS.

"architect": {
        "build":{
            "options":{
                 "styles":[],
                "scripts":[]
            }
    }
}

Bundle Files

The Angular.json takes the styles and scripts declared in these sections for the final script.js and styles.css and Injecting into the index.html

Add the button-upload.css file in the styles array and the button-upload.js in the script.

   "styles": [
              "external/button-upload/button-upload.css"
            ],
   "scripts": [
              "external/button-upload/button-upload.js"
   ]

Remember add CUSTOM_ELEMENTS_SCHEMA in the @NgModule to use custom elements. Read more

Run the ng build to merge all CSS files into the script file and styles in the styles.css

> ng build
✔ Browser application bundle generation complete.
✔ Copying assets completely.
✔ Index html generation complete.

Initial Chunk Files               | Names         |      Size
main.437835c56f488f70355e.js      | main          | 101.96 kB
polyfills.fc6cfcbe5c3a0e94edad.js | polyfills     |  33.11 kB
runtime.df8927e5b1e564860c37.js   | runtime       |   1.03 kB
scripts.5cf64c63898afa29a094.js   | scripts       | 370 bytes
styles.de2e542873613fb23f4a.css   | styles        |  73 bytes

Also, inject these files in the index.html

injected.png

Separate Bundles

Everything is working, but sometimes we want to split our code from the global CSS and JavaScript files into a bundle file.

The script allows adding files with an object configuration with the following options :

  • input: the file's path (CSS or JS)

  • inject: set to true to add by default in the index file.

  • bundleName: change the name of the bundle file.

"styles": [
      "src/styles.css",
      {
          "input": "external/button-upload/button-upload.css",
            "inject": true,
            "bundleName": "upload-button-css"
      }
     ],
"scripts": [
             {
                "input": "external/button-upload/button-upload.js",
                "inject": true,
                "bundleName": "upload-button-js"
              }

]

Old versions like eight use lazy instead inject.

The build creates a new file for each object with a bundle name:

PS C:\Users\dany.paredes\Desktop\labs\learn-ng-script> ng build
✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.

Initial Chunk Files                        | Names             |      Size
main.437835c56f488f70355e.js               | main              | 101.96 kB
polyfills.fc6cfcbe5c3a0e94edad.js          | polyfills         |  33.11 kB
runtime.df8927e5b1e564860c37.js            | runtime           |   1.03 kB
upload-button-js.5cf64c63898afa29a094.js   | upload-button-js  | 370 bytes
upload-button-css.de2e542873613fb23f4a.css | upload-button-css |  73 bytes
styles.31d6cfe0d16ae931b73c.css            | styles            |   0 bytes

The inject option injects the upload-button-css and upload-button-js bundles in the index.html.

bundle-files.png

Conclusion

We work with external JavaScript and CSS files in the global styles.css and script.js and split them into bundle files.

The source code Github