Working With Assets and Global Styles and Scripts in Angular

By Maina Wycliffe on February 25, 2019

In this post, we are going to take a closer look at how we to work with assets (web assets) and global styles and scripts on our angular project. The three (Assets, Styles and Scripts) cover all the resources you might need for your Angular app. We will cover common scenarios in which you might come across while working with web resources for your project.

So, without further ado, let’s get started:

Working with Assets

Let’s start with assets, this could be anything from images, videos, json files to styles and scripts. By default, Angular has an asset directory, located under the /src directory at the root of your angular project. This is copied over to the build directory by Angular CLI during the build process of your app. If you have some images, you can simply drop them in to this directory. Then, just reference to them as show below:

<img src="/assets/image.png" ... />

You can even drop a directory with assets inside the assets’ directory, and everything will be copied as is.

<img src="/assets/images/image.jpg" ... />

And if you don’t want to use the assets directory, Angular got you covered here as well. You can configure Angular CLI to automatically copy a file or directory over to the build directory by adding those files to the assets array inside angular.json.

{
  // ...
  "projects": {
    "project-name": {
      // ...
      "architect": {
        "build": {
          // ...
          "options": {
            //...
            "assets": [
              "src/favicon.ico", // default
              "src/assets" //default
              // Add more assets here
            ]
            // ...
          }
          // ...
        }
        // ...
      }
    }
    // ...
  }
  // ...
}

By default, there are two files in the assets array, the assets directory and favicon.ico file, as show above. You can add your own assets, relative to the root of your Angular workspace. The above assets will apply to both development and production builds of your app.

But if you wanted, you can also have different assets for each deployment environment in Angular too. For instance, if you had a different logo for each build environment, you might want the logo to be copied in the same exact location, in each environment, to make it easier to reference to it.

<img src="path/to/logo" ... />

To achieve this, you can use the objects for assets configurations, instead of a simple path string shown above. Inside this object you need to specify the following properties:

{
  "glob": "pattern of files to copy (can include a filename)",
  "ignore": ["files to ignore"],
  "input": "path to directory in which the assets are",
  "output": "directory to copy assets to (inside build directory)"
}

For instance, if you wanted a different set of assets for productions, you just need to add the assets array, with necessary assets:

{
  // ...
  "projects": {
    "project-name": {
      // ...
      "architect": {
        "build": {
          // ...
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "assets": [
                {
                  "glob": "**/*", // copy everything
                  "input": "src/prod/assets",
                  "output": "/assets/"
                },
                {
                  "glob": "favicon.ico", // copy only favicon.ico
                  "input": "src/prod",
                  "output": "/" // copy to root directory
                }
              ]
              // ...
            }
          }
        }
        // ...
      }
    }
  }
}

NB: By adding an assets array for a specific build environment i.e. production, Angular CLI will ignore all assets specified for all environments and use only those specified for that environment only.

Local Global Styles and Scripts

In the previous section we were focusing on general assets, but let’s now focus only on stylesheets and scripts. By default, Angular CLI adds an empty stylesheet file – styles.css – inside the src directory. The extension of that file will depend on the stylesheet you chose when you were prompted for when you were creating a new project. You can simply add your CSS/SASS/LESS styles here and you are good to go. Remember to change the stylesheet extension appropriately.

But things are never that easy, inside angular.json, there is an array for scripts and styles, much similar to the one for assets above. Inside the two arrays, you can add paths to your styles and scripts, in the appropriate array.

{
  //...
  "styles": ["src/styles.scss"],
  "scripts": ["some/path/to/a/script"]
  // ...
}

Unlike the assets array above, where the files are simply copied over to the build directory, this will be bundled in to the angular final build bundles. However, if you don’t want that, you can use an object to configure either style or script. This will allow you to specify how each style or script will be built. The object configuration can have up to 3 fields:

{
  "input": "", // path to style or script file (required)
  "bundleName": "", // output bundle name, don’t add extension
  "lazy": false // when set to true, the file will not be added to index.html
}

When the bundleName is specified, the resulting file is added independently to index.html, in the order specified in the array. The third field specifies whether the resulting bundle, will be included inside the index.html file. If set to true, it will be bundled and added to the build directory but will not added inside the index.html. A hash will also not be added to the name of the bundle, making it easy to refer to it. This allows you to be able to lazy load such a script or style inside your app later along.

Lazy Loading Local and Remote Scripts

Some scripts are only required on very specific times, hence adding them to the index.html doesn’t make sense. For instance, PayPal Checkout.js is only required when the user is checking out and not when browsing the list of products. Therefore, adding it to the index.html and having it loaded alongside other important resources doesn’t make sense. It makes sense to load it only when required and not a moment before, which could have a negative impact on your app performance.

You can load such scripts and styles inside your app, as shown below:

Script:

return new Promise(resolve => {
  const scriptElement = document.createElement('script');
  scriptElement.src = 'URL TO SCRIPT';
  scriptElement.onload = resolve;
  document.body.appendChild(scriptElement);
});

Styles:

return new Promise((resolve, reject) => {
  const styleElement = document.createElement('link');
  styleElement.href = styleUrl;
  styleElement.onload = resolve;
  document.head.appendChild(styleElement);
});

NB: If you enable caching for your web app, only the initial load will take some noticeable time, subsequent loads will use the cached script, and will be much faster.

Comments