Include html into typescript using webpack

Attempting to include HTML content into a variable using TypeScript and webpack has been my challenge.

This is the current setup:

package.json:

{
  "devDependencies": {
    "awesome-typescript-loader": "^3.2.3",
    "html-loader": "^0.5.1",
    "ts-loader": "^2.3.7",
    "typescript": "^2.5.3",
    "webpack": "^3.6.0"
  }
}

webpack.config.js:

const path = require('path');
const webpack = require('webpack');

module.exports = {
  context: path.join(__dirname),
  entry: './main',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'app.js'
  },
  resolve: {
    // Include '.ts' and '.tsx' as resolvable extensions.
    extensions: [".ts", ".js"],
    modules: [
      "node_modules",
      path.join(__dirname, 'app'),
    ],
  },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.html$/,
        loader: 'html-loader',
      },
      // Faster alternative to ts-loader
      { 
        test: /\.tsx?$/, 
        loader: 'awesome-typescript-loader',
        options: {
          configFileName: 'tsconfig.json',
        },
        exclude: /(node_modules)/,
      },
    ],
  },  
};

main.ts:

import template from './template.html';
console.log(template);

template.html:

<p>Hello World !</p>

Upon attempting to compile with webpack:

$ ./node_modules/.bin/webpack 

[at-loader] Using <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d5b1bcd5e5bfccd5c9dfccc288d8ffedbcb9">[email protected]</a> from typescript and "tsconfig.json" from /tmp/test/tsconfig.json.


[at-loader] Validation carried out in a separate process...

[at-loader] Finished verification with 1 issue
Hash: d06d08edc313f90c0533
Version: webpack 3.6.0
Time: 2194ms
 Asset     Size  Chunks             Chunk Names
app.js  2.72 kB       0  [emitted]  main
   [0] ./main.ts 136 bytes {0} [built]
   [1] ./template.html 40 bytes {0} [built]

ERROR in [at-loader] ./main.ts:1:22 
    TS2307: Module './template.html' not found.

I've spent half a day on this task and can confirm that template.html is located where it should be.

Based on the webpack configuration, the html-loader should preprocess the file first so as to load the HTML content into the variable. It worked correctly with ES6 previously...

Could someone advise me on loading HTML content into a variable using webpack/typescript? Alternatively, point out any flaws in my approach.

Answer №1

If you're looking for a simple solution, try sticking with CommonJS "require" instead of using import when loading non-TypeScript assets:

const template = require('./template.html');

However, if you prefer to continue using import, you can configure the TypeScript compiler to load the file as a string. The following method worked well for me with TypeScript 2.4.2.

Just add this code block to your project's type declarations file (I named mine typings.d.ts):

// typings.d.ts
declare module '*.html' {
  const content: string;
  export default content;
}

Now you can import HTML files like this:

// main.ts
import template from './template.html';
console.log(template); // <p>Hello world !</p>

Keep in mind that my project may have utilized different loaders compared to yours (as shown below).

// webpack.config.js
config.module = {
  rules: [
    {
      test: /\.ts$/,
      loader: '@ngtools/webpack'
    },
    {
      test: /\.html$/,
      use: 'raw-loader'
    }
  ]
}

If you're interested, there is a discussion about other solutions on a Github thread available here.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Create a functioning implementation for retrieving a list of objects from a REST API

I am looking to incorporate an Angular example that retrieves a list from a REST API. Here is what I have attempted: SQL query: @Override public Iterable<Merchants> findAll() { String hql = "select e from " + Merchants.class.getName ...

Error: monaco has not been declared

My goal is to integrate the Microsoft Monaco editor with Angular 2. The approach I am taking involves checking for the presence of monaco before initializing it and creating an editor using monaco.editor.create(). However, despite loading the editor.main.j ...

What are the steps to resolve the "EADDRINUSE: address already in use :::3000" error in an integration test?

While testing my simple endpoint using jest and superTest in my TypeScript project, I encountered the listen EADDRINUSE: address already in use :::3000 error. The file app.ts is responsible for handling express functionalities and it is the one being impo ...

Troubles with Typescript typings when including an empty object in an array with specific typings

, I am facing a dilemma with displaying houses in a cart. Each house has an image, but since they load asynchronously, I need to show empty cards until the data is fetched. Initially, I added empty objects to the array representing the houses, which worked ...

Tips for dynamically updating localeData and LOCALE_ID for i18n websites during the build process in Angular 9

I am currently developing an application that needs to support multiple languages, specifically up to 20 different languages. The default language set for the application is en-US. The translated versions are generated successfully during the build proces ...

Attempting to create a promise for a dropdown menu in React-Select

I am facing an issue here: type Person = { value: string; label: string; }; Furthermore, I have a promise-containing code block that fetches data from an API and transforms it into the appropriate array type for a React component. My intention is to r ...

Guide on deactivating the div in angular using ngClass based on a boolean value

displayData = [ { status: 'CLOSED', ack: false }, { status: 'ESCALATED', ack: false }, { status: 'ACK', ack: false }, { status: 'ACK', ack: true }, { status: 'NEW', ack ...

"Enhancing user experience with MaterialUI Rating feature combined with TextField bordered outline for effortless input

I'm currently working on developing a custom Rating component that features a border with a label similar to the outlined border of a TextField. I came across some helpful insights in this and this questions, which suggest using a TextField along with ...

Issue with Angular 4: Radio button defaults not being set

After hardcoding the value in component.ts, I am able to see the pre-selected radio button. However, when attempting to retrieve the value from sessionStorage, it does not work as expected. The value is visible in the console though. Could someone please ...

The "if(x in obj)" statement in Typescript does not properly narrow down my custom Record

I am struggling with a code snippet where I am trying to check if a string exists in my custom record using the if(x in obj) guard statement, but it seems to not be working as expected. Below is the sample code snippet that is throwing an error: type Ans ...

Issue with Material UI DateTimePicker not submitting default form value

Currently, I am utilizing React for my frontend and Ruby on Rails for my backend. My issue lies in submitting the value from my materialUI DateTimePicker via a form. The problem arises when I attempt to submit the form with the default DateTime value (whic ...

Exploring the possibilities of utilizing package.json exports within a TypeScript project

I have a local Typescript package that I am importing into a project using npm I ./path/to/midule. The JSON structure of the package.json for this package is as follows: { "name": "my_package", "version": "1.0.0&q ...

Tips for conducting tests on ngrx/effects using Jasmine and Karma with Angular 5 and ngrx 5

Here is the file that I need to test. My current focus is on some effects service while working with Angular5 (^5.2.0) and ngrx5 (^5.2.0). I have been struggling to properly implement the code below for testing purposes. Any tips or suggestions would be ...

The error in node.js on line 17 is caused by the inability to locate the module "."

I'm currently working on a Rails application with webpacker integration. The entry file I am using looks like this: import grapesjs from 'grapesjs'; import loadBlocks from './../../../node_modules/grapesjs-mjml/src/blocks'; impo ...

Error: Unable to inject UrlHandlingStrategy as no provider was found

I recently upgraded my application to Angular 14 and encountered a challenging error. Despite configuring RouterModule for Root and child with lazy loading, I am now facing a circular dependency issue related to the Router. I'm unsure how to further d ...

Issues with Firebase Cloud Messaging functionality in Angular 10 when in production mode

Error: Issue: The default service worker registration has failed. ServiceWorker script at https://xxxxxx/firebase-messaging-sw.js for scope https://xxxxxxxx/firebase-cloud-messaging-push-scope encountered an error during installation. (messaging/failed-ser ...

Develop a versatile class for storing an array of key-value pairs (dictionary) using TypeScript

I am looking to implement a Dictionary class in my application. I have created a class with an Array of KeyValuePair to store my list. export class KeyValuePair<TKey, TVal>{ key:TKey; value:TVal; constructor(key:TKey, val:TVal){ this.key = key; ...

Is there a way to trigger validation with a disabled property?

My form element is set up like this: <input type="text" id="country" formControlName="Country" /> The form group looks like this: this.myForm = this.formbuilder.group({ 'Country': [{ value: this.user.Country, disabled: this.SomeProperty= ...

Angular Universal involves making two HTTP calls

When using Angular Universal, I noticed that Http calls are being made twice on the initial load. I attempted to use transferState and implemented a caching mechanism in my project, but unfortunately, it did not resolve the issue. if (isPlatf ...

Upon receiving data from the Api, the data cannot be assigned to the appropriate datatype within the Angular Object

I am encountering an issue with the normal input fields on my page: https://i.stack.imgur.com/qigTr.png Whenever I click on the "+" button, it triggers an action which in turn calls a service class with simple JSON data. My intention is to set selectionC ...