Skip to content

Importing HTML and CSS

Now let's write a similar class and instead of importing the HTML file directly into a string, we will use the async function import(). This will not include the text of the HTML file in our bundle. It will be stored in an external file which will be loaded dynamically.

We will need an own HTML file for this:

src/amazing-button-dynamic.html

<div class="amazing-button card h-100">
  <div class="card-header">Amazing Dynamic 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" />
  </div>
</div>

We write now a new class that imports the HTML structure, insert it into the container element. Importing the HTML structure with the import() function returns a promise which resolves to a module. To get the HTML string you have to read the property`default from this returned module:

src/amazing-button-dynamic.js

import $ from "jquery";
import "./amazing-button.css";
export default class {
  #maximumNumber = 9;
  #button;
  get maximumNumber() {
    return this.#maximumNumber;
  }
  set maximumNumber(value) {
    this.#maximumNumber = value;
    if (this.#button)
      this.#button.html(`Show number from 1 to ${this.#maximumNumber}`);
  }
  constructor(element) {
    console.debug("Starting Dynamic Button");
    import("./amazing-button-dynamic.html").then((html) => { // (1)!
      $(element).html(html.default); // (2)!
      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 and wait for resolving the promise
  2. Use the HTML text with the property defaultfrom the resolved value

Let's add another container in which we will start the new class:

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 { default as MySvgApp } from "./amazing-button-svg";
import { default as MyDynamicApp } from "./amazing-button-dynamic";

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;

createTestContainer("Testing Import SVG", "test-container-svg");
new MySvgApp(document.getElementById("test-container-svg"));

createTestContainer("Testing Dynamic Imports", "test-container-dynamic");
let myDynamicInstance = new MyDynamicApp(
  document.getElementById("test-container-dynamic")
);
myDynamicInstance.maximumNumber = 55;

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

When you run npm run build you can see the results of dynamic importing HTML:

📁 dist
├─ walkthrough-env.<hash>.js
├─ walkthrough-env.<hash>.css
├─ index.html
├─ 📁 manifest
├─ 📁 vendor
├─ 📁 assets
└─ 📁 parts

The HTML file amazing-button-dynamic.html was moved into a subfolder parts. The file name is an ID assigned by Webpack.

This file name can be determined as follows:

src/amazing-button-dynamic.js

import $ from "jquery";
import "./amazing-button.css";
export default class {
  #maximumNumber = 9;
  #button;
  get maximumNumber() {
    return this.#maximumNumber;
  }
  set maximumNumber(value) {
    this.#maximumNumber = value;
    if (this.#button)
      this.#button.html(`Show number from 1 to ${this.#maximumNumber}`);
  }
  constructor(element) {
    console.debug("Starting Dynamic Button");
    import(
      /* webpackChunkName: "amazing-button-dynamic.html" */
      "./amazing-button-dynamic.html"
    ).then((html) => {
      $(element).html(html.default);
      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");
    });
  }
}

You could even define another subdirectory instead parts with:

/* webpackChunkName: "../other-directory/amazing-button-dynamic.html" */