What is the best way to implement component lazy loading in Preact?

My objective is to create two bundles during the build process, one for the index.tsx file and another for the lazy.tsx file. I am confident that there are one or two options that I am overlooking.

Check out the example project on GitHub - example project link

File src/index.tsx

import { render, h } from 'preact';

let a: any = null;
let b = 0;

const App = () => (
  <div>
    <button
      onClick={() => {
        import('./lazy').then(M => {
          console.log('LOADED COMPONENT');
          a = <M.default />;
          b++;
          render(<App></App>, document.body);
        });
      }}
    >
      test
    </button>
    {a} {b}
  </div>
);

render(<App></App>, document.body);

src/lazy.tsx

import { h, FunctionComponent } from 'preact';

console.log('LAZY');

interface LazyProps {}

const Lazy: FunctionComponent<LazyProps> = props => {
  const {} = props;

  return <div>LAZY LOADED COMPONENT</div>;
};

export default Lazy;

Webpack configuration

{
  entry: {
    index: `${__dirname}/src/index.tsx`
  },
  output: {
    path: resolve(__dirname, 'dist'),
    chunkFilename: '[name].[id].js',
    filename: '[name].bundle.js'
  },

  plugins: [new HtmlWebpackPlugin()],

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: [/node_modules/]
      }
    ]
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js']
  },
  optimization: {
    minimize: false
  }
}

Although the above code is error-free and functioning properly, it does not produce multiple bundles as intended when using Webpack's code splitting feature.

Edit: Check out the working example project here.

Answer №1

Your setup has encountered two issues.

Starting with your TypeScript configuration:

{
  "compilerOptions": {
    "target": "ES5",
    "module": "ESNext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "react",
    "jsxFactory": "h",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  },

  "include": [
    "src/**/*.tsx"
  ]
}

Remember these two essential properties:

  1. module: 'ESNext'
  2. moduleResolution: 'node'

Changing module to ESNext means your Webpack configuration cannot be in TypeScript since it requires commonjs for module. Switch it to plain JS using CommonJS format:

const Configuration = require('webpack').Configuration;
const Dev = require('webpack-dev-server').Configuration;
const resolve = require('path').resolve;
const HtmlWebpackPlugin = require('html-webpack-plugin');


const config = {
  entry: {
    index: `${__dirname}/src/index.tsx`
  },
  output: {
    path: resolve(__dirname, 'dist'),
    chunkFilename: '[name].[id].js',
    filename: '[name].bundle.js'
  },

  plugins: [new HtmlWebpackPlugin()],

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: [/node_modules/]
      }
    ]
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js']
  },
  optimization: {
    minimize: false
  }
};

module.exports = config;

This adjustment should address your issue.

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

Error received - CORS request denied on Firefox browser (Ubuntu)

I encountered a CORS error (CORS request rejected: https://localhost:3000/users) while attempting to register a new user. This issue arose from content in the book Building APIs with node.js, Chapter 12. I am currently using Firefox on Ubuntu and have tr ...

"Utilizing FileReader to seamlessly integrate data into FormData without the risk

Currently, I'm in the process of constructing an ajax file uploader. This is made possible thanks to the recently introduced FormData interface. Everything seems to work as expected when using the original file. However, I encounter issues when conver ...

- Utilize bullet points to exhibit keywords within a D3.js div by appending them

I'm looking to showcase the comma-separated values from a JSON file as a list in a mouseover tooltip on each node. Here is my current code snippet: div.append("div") .attr("class", "tooltip") .style("opacity", 1) .html("Node name : " + d.NodeName + ...

Efficiently managing AJAX requests in PHP

One aspect of my work involves a substantial amount of UI coding that requires sending AJAX requests to the backend PHP. I've been managing this by using: if(isset($_REQUEST["UniquePostName"])){ /* Do Something*/ } if(isset($_REQUEST["AnotherUniqueP ...

Is it possible to have the Save Success Alert fade out only once?

After incorporating this code snippet, I implemented a fade effect on the success alert whenever it is triggered. However, I noticed that the fade effect only occurs the first time I click "save". Subsequent clicks do not trigger the fade effect, causing ...

non-concurrent in Node.js and JavaScript

I'm a beginner in the world of NodeJS and I have a question that's been bugging me. Node is known for its asynchronous nature, but JavaScript itself also has asynchronous features (like setTimeout). So why weren't concepts like Promise intr ...

"React Antd Element Type Validation Failure: received an unexpected object instead of the required element type. Issue

I recently upgraded from antd version 3.7.0 to the latest version 3.23.4 and now I'm encountering a strange error: Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite co ...

What are the limitations of using concatMap for handling multiple requests simultaneously?

In my current function, I am receiving an array of objects called data/ids as a parameter. Within this function, I need to execute a post request for each element/id: fillProfile(users) { const requests = []; console.log( 'USERS.length:&apos ...

How come the link function of my directive isn't being triggered?

I'm encountering a strange issue with this directive: hpDsat.directive('ngElementReady', [function() { return { restrict: "A", link: function($scope, $element, $attributes) { // put watche ...

Efficiently flattening an array in JavaScript using recursive functions without the need for loops

Currently I am studying recursion and attempting to flatten an array without using loops (only recursion). Initially, I tried the iterative approach which was successful, but I am facing challenges with the pure recursive version: function flattenRecurs ...

Determine whether the regex pattern is positioned at the start of the string or following a designated character

I am working with a regex pattern and need to verify if it matches at the start of a string, after a new line, or after a white space. Additionally, I want to ensure that the pattern also matches the end of the string, after a new line, or a white space. ...

Having issues with InstaFeed (search) feature and jQuery Mobile

As a new developer, I am working on my first JQM site. However, I am facing an issue with my search input form where the instafeed photos do not show up until after a manual page refresh following submission. Despite numerous attempts, I cannot seem to res ...

Having difficulty retrieving data in mongodb using category id

Currently, I am attempting to sort and filter my pets based on categories. The pets are modeled as follows: const Pet = mongoose.model( 'Pet', new Schema({ name: { type: String, required: true, } ...

Refreshing a component using a sibling component in React

Currently, I am delving into the realm of React and embarking on a journey to create a ToDo App. However, I've hit a snag while attempting to add a new task to the list. Despite successfully adding an item to the list upon clicking the add button, upd ...

Utilizing Selenium automation to navigate a website that features a custom jQuery plugin-checkbox functionality

Utilizing Selenium WebDriver along with JavaScript to automate the testing of a website that features a custom jquery plugin named "jcf" (JavaScript Custom Forms) for aesthetically pleasing forms. You can find more information about this plugin here. I am ...

In all tests, except for the initial one, the DOM is not updated by test-utils once triggers have been fired

I have been facing an issue with checking for error messages related to field completion in HTML/DOM after vuelidate is triggered. The functionality works properly after the click trigger, and all tests pass successfully - including mounting, element searc ...

employing JavaScript code for targeting classes rather than IDs

I am facing an issue with a javascript function called MyFunc() that is currently only working with id="item_for_MyFunc". Within the function, there is a var elem = document.getElementById("item_for_MyFunc"); and the HTML body contains: <body onload= ...

Having trouble getting the Babel plugin transform-remove-console to function properly with the Vue CLI 4 and @vue/cli-plugin-babel/preset?

When you create a VueJS project using Vue CLI 4, Babel is configured with a useful preset in babel.config.js: module.exports = { presets: [ '@vue/cli-plugin-babel/preset', ], }; I am attempting to use babel-plugin-transform-remove-conso ...

Expanding upon passing arguments in JavaScript

function NewModel(client, collection) { this.client = client; this.collection = collection; }; NewModel.prototype = { constructor: NewModel, connectClient: function(callback) { this.client.open(callback); }, getSpecificCollection: ...

how to show an error in a modal window when encountering an error

Using Blazor and Blazorstrap, typically when the server disconnects, an "Error" message is displayed. However, with the BsModal from Blazorstrap, it appears in the background layer, making it unresponsive. How can this be fixed? Is it possible to close the ...