Skip to content

Importing HTML, CSS and Assets

Now we will demonstrate how to import separate HTML and CSS files. Both of them will include assets like images or import further stylesheet files which will be extracted and handled separately.

As we need some example assets we will copy for the sake of simplicity the default favicon.png from the static directory into a subdirectory src/images:

mkdir src/images
cp static/favicon.png src/images/

First we create an HTML structure for our container. Instead of creating each element by code like in the chapters before, we will outsource the HTML structure in an own file. This file will be placed in the src folder to include its content as variable in our library.

In this HTML structure we will point to:

  • An image which we have copied in the src/images folder.
  • A SVG graphics files which was taken from the installed package bootstrap-icons.

Let's create the HTML file:

src/amazing-button.html

<div class="amazing-button card h-100">
  <div class="card-header">Amazing Button</div>
  <div class="card-body">
    <p class="card-text">
      <button class="btn btn-secondary">Press Me</button>
    </p>
    <div class="result border border-primary mb-2">No Result</div>
    <img src="images/favicon.png" width="30%" />
    <img src="~bootstrap-icons/icons/bootstrap.svg" width="30%" /> <!-- (1)! -->
  </div>
</div>
  1. Note the ~ at the beginning. This means that the resource should be searched from the packages in the node_modules directory.

Now we create a stylesheet file. As in the JavaScript files we will use some really useful CSS proposals like nesting classes and variables. All these proposals will be transpiled into CSS that runs in mostly each relevant browser out there.

In this CSS we will point also to the image favicon.png. Of course, SVG files can also be referenced here.

src/amazing-button.css

.amazing-button {
  --my-color: #f30000;

  text-align: center;

  & .card-header {
    color: var(--my-color);
    background-image: url("images/favicon.png");
    background-size: contain;
    background-repeat: no-repeat;
    background-position-x: left;
  }
}

Finally, we will install the Bootstrap package to import its stylesheets. First, the package must be installed:

npm i bootstrap

Then we write a global style.css in which we import all Bootstrap stylesheets:

style.css

@import url("bootstrap/scss/bootstrap.scss");

Remarks:

  • We import here the complete library. You could also import only parts of them. Read more about importing Bootstrap here
  • We have to use the @import url("...") syntax instead of @import "" like noted in their official documentation.
  • As you can see we can mix CSS and SCSS however we want. You do not need to use the file extension scss.
  • Instead of importing the Bootstrap SCSS we could inject the precompiled CSS of Bootstrap by extending the extrenals configuration with:

    {
      module: "bootstrap",
      entries: [
        "dist/css/bootstrap.min.css",
        "dist/js/bootstrap.bundle.min.js"
      ]
    }
    

This style.css we will simply import in our main index.js entrypoint. This results in this stylesheet being included in our CSS bundle:

src/index.js

import createTestContainer from "./create-test-container";

import { default as MyVanillaApp } from "./amazing-button-vanilla";
import { default as MyPackagesApp } from "./amazing-button-packages";

import "./style.css";

createTestContainer("Testing Vanilla JS", "test-container-vanilla");
let myVanillaInstance = new MyVanillaApp(
  document.getElementById("test-container-vanilla")
);
myVanillaInstance.maximumNumber = 99;

createTestContainer("Testing Packages", "test-container-packages");
let myPackagesInstance = new MyPackagesApp(
  document.getElementById("test-container-packages")
);
myPackagesInstance.maximumNumber = 49;

To avoid of bundling any Bootstrap JavaScript libraries in our bundle we should exclude them (even if we do not use them in our walkthrough):

webpack.config.js

const ccWebpack = require("@codecoupler/cc-webpack");
module.exports = (env) =>
  ccWebpack(
    {
      externals: [
        {
          module: "jquery",
          global: "jQuery",
          entries: ["dist/jquery.min.js"]
        },
        {
          module: "bootstrap-icons",
          entries: ["font/bootstrap-icons.min.css"],
          copy: ["font/fonts"]
        },
        {
          module: "bootstrap",
          entries: ["dist/js/bootstrap.bundle.min.js"]
        }
      ]
    },
    env,
    {}
  );

Now we are finished with the preparations.

We write now a new class that imports the HTML structure and insert it into the container element. The CSS file will be simply imported:

src/amazing-button-import.js

import $ from "jquery";
import htmlTemplate from "./amazing-button.html"; // (1)!
import "./amazing-button.css"; // (2)!
export default class {
  #maximumNumber = 9;
  #button;
  get maximumNumber() {
    return this.#maximumNumber;
  }
  set maximumNumber(value) {
    this.#maximumNumber = value;
    this.#button.html(`Show number from 1 to ${this.#maximumNumber}`);
  }
  constructor(element) {
    console.debug("Starting Import Button");
    $(element).html(htmlTemplate); // (3)!
    this.#button = $(element)
      .find("button")
      .html(`Show number from 1 to ${this.#maximumNumber}`)
      .on("click", () => {
        this.resultDiv.html(Math.floor(Math.random() * this.#maximumNumber));
      });
    this.resultDiv = $(element).find("div.result");
  }
}
  1. Import HTML file as text.
  2. Import CSS file to get included in our CSS bundle.
  3. Use the HTML text to put into a DOM element.

Let's add another container in which we will start the Bootstrap based application:

src/index.js

import createTestContainer from "./create-test-container";

import { default as MyVanillaApp } from "./amazing-button-vanilla";
import { default as MyPackagesApp } from "./amazing-button-packages";
import { default as MyImportApp } from "./amazing-button-import";

import "./style.css";

createTestContainer("Testing Vanilla JS", "test-container-vanilla");
let myVanillaInstance = new MyVanillaApp(
  document.getElementById("test-container-vanilla")
);
myVanillaInstance.maximumNumber = 99;

createTestContainer("Testing Packages", "test-container-packages");
let myPackagesInstance = new MyPackagesApp(
  document.getElementById("test-container-packages")
);
myPackagesInstance.maximumNumber = 49;

createTestContainer("Testing Import HTML/CSS/Assets", "test-container-import");
let myImportInstance = new MyImportApp(
  document.getElementById("test-container-import")
);
myImportInstance.maximumNumber = 79;

When you run npm run start you should see the running example in your browser.

When you run npm run build:dev you can see the results of importing assets from HTML or CSS:

📁 dist
├─ walkthrough-env.<hash>.js
├─ walkthrough-env.<hash>.css
├─ index.html
├─ 📁 manifest
├─ 📁 vendor
└─ 📁 assets
  • Assets: Look into the subdirectory assets. You will find there the Image favicon.png. Subfolders like images was kept, thus the final target directory is assets/images.

    Note also that a hash value has been added to the file name. Whenever the image is changed, this value changes and this guarantees that the browser always loads the most recent version instead of the one that may be stored in a cache.

    But where is the included SVG file? It was not outsourced into an own external file, because it was small enough to be included into your JavaScript bundle. This means that the SVG file is included directly in the HTML code instead of loading it later.

  • CSS Bundle: You will also find a new CSS file. This is your CSS Bundle. In this file all stylesheets was extracted that you have imported. In addition, all stylesheets that were included via @import statements are also included.