Import an array of dynamic modules with Webpack that are known during compilation

For my project, I have the requirement to import specific modules whose actual paths are only known during compile time.

Imagine having components/A.js, components/B.js, and components/C.js. In my App.js, I need to include a subset of these modules that will only be determined at webpack's compile-time, perhaps from a JSON file.

My initial attempt:

//App.js
compileData = await getCompileDataSomehow()

import("./components/" + compileData.component + ".js")
   .then( /* Do something with the component */);

While this approach worked, webpack created a chunk for every components/*.js file resulting in unnecessary network roundtrips. To avoid this overhead, I tried providing an array of components but ran into issues since require([...]) is considered dynamic.

What I eventually came up with:

//App.js
import("./components/ALL.js") //this file doesn't actually exist
//webpack.config.js

const fs = require('fs')

const componentsToInclude = ["A", "B"] //read from a json


fs.writeFileSync('./src/components/ALL.js',
  `
export default [
    ${componentsToInclude.map(comp => `require("./${comp}.js")` )}
].map(c => c.default);

`)

module.exports = { 
// webpack config 
}

This method works, however, it is not the most elegant solution and can lead to potential bugs. Does anyone have a better approach to handle this scenario?

Answer №1

For the purpose of this response, let's assume there is a primary App.js file and a directory named components which includes files like A.js, B.js, C.js, D.js, etc. The requirement is to include only A.js and B.js in the bundle, while excluding all other files at compile time.

Exploring require.context

Webpack offers a specific method called require.context to handle a group of dependencies. It requires four parameters: the path to the directory containing files to be included, a boolean value to indicate whether subdirectories should be considered, a regular expression for filtering files, and a loading mode directive.

To bundle all components, we would use the following code:

// App.js
const req = require.context('./components')

(While this goes beyond the initial query, you can then utilize the exported functions from these files using the req variable. For instance, if each file exports a default function, you can execute them as follows:

const req = require.context('./components')
req.keys().forEach( key => {
    req( key )?.default()
} )

Refer to this question and its answers for more on requiring with require.context)


However, if we need to load only A.js and B.js, we must apply a filter with a regular expression to require.context. Assuming that we know the required files upfront, we can hardcode the regular expression like so:

// App.js
const req = require.context('./components', true, /(A|B)\.js$/)

The /(A|B)\.js$/ regex filters input to include either A.js or B.js. It can be expanded to accommodate more files such as /(A|B|C|D)\.js$/ or to target specific subdirectories. Webpack evaluates this regex at compile time, ensuring only matching files are bundled.

But the challenge arises when the filtering criteria are unknown during compilation due to dynamically generated filenames.

Utilizing webpack.DefinePlugin

By leveraging webpack.DefinePlugin, we can set global variables in our webpack.config.js known at compile time. These variables become statically accessible across all files by Webpack. For example, we can assign our regex pattern to a global variable like __IMPORT_REGEX__:

//webpack.config.js
module.exports = {
    ...
    plugins: [
        new webpack.DefinePlugin( {
            __IMPORT_REGEX__: "/(A|B)\\.js$/"
        } )
    ]
}
// App.js
const req = require.context('./components', true, __IMPORT_REGEX__)

Note that values defined via DefinePlugin must be stringified, hence raw RegExp objects are not supported. All backslashes must be properly escaped.

If the filenames are stored in an array, say fetched from a JSON file, we can dynamically construct the required regex in webpack.config.js. Here's a simple approach - concatenate filenames using the pipe symbol as a separator:

// webpack.config.js
const fileNames = ["A", "B"];

const importRegex = `/(${ fileNames.join("|") })\\.js$/`; // will return '/(A|B)\\.js$/'

module.exports = { ...

Bringing it Together

// webpack.config.js
const fileNames = ["A", "B"];

const importRegex = `/(${ fileNames.join("|") })\\.js$/`;

module.exports = {
    ...
    plugins: [
        new webpack.DefinePlugin( {
            __IMPORT_REGEX__: importRegex
        } )
    ]
}
// App.js
const req = require.context('./components', true, __IMPORT_REGEX__)

Lastly, Typescript users need to declare a type definition for __IMPORT_REGEX__.

// interface.d.ts
declare global {
    var __IMPORT_REGEX__: RegExp
}

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

Decoding SQS POST messages using node.js

I am faced with the challenge of setting up communication between a web server and a worker using an SQS. The process involves uploading an image to an S3 bucket through the server, which then sends a message to the SQS for the worker to retrieve, resize, ...

Using HTML to load an image is not possible, as it can only be done using CSS

I am currently dealing with a CSS issue in my project. Here is the code snippet from my stylesheet: .Img{ background: url('../assets/Trump.png'); } Now, let's take a look at the corresponding HTML code: <div class="Img"> However, ...

How to implement form modal binding using Laravel and Vue.js

There are two models named Tour.php public function Itinerary() { return $this->hasMany('App\Itinerary', 'tour_id'); } and Itinerary.php public function tour() { return $this->belongsTo('App\Tour', ...

Tips for showing data from Ajax responses on an HTML page

In my code, there are two JavaScript functions: The function fetch_items is responsible for returning data in the form of stringvalue. On the other hand, the function extract_items($arr) passes values to the fetch_items function. function fetch_items ...

Cease animation if the page has already reached its destination

In my current setup, I am using a JavaScript code snippet to navigate users to the specific location of the information they click on in a side navigation menu. However, one issue that arises is if they first click on one item and then another quickly, t ...

What is the best way to select or deselect all asp.net checkboxes with just one checkbox event?

I am looking for a way to control the checkboxes on my webpage using a checkbox named Select All, allowing me to check or uncheck all checkboxes within individual div sections. Since my checkboxes are asp.net controls with runat=server, I am unsure how to ...

Using Ajax to call a PHP function within a WordPress website

I am looking to trigger a PHP function using AJAX. Below is the code snippet of my form: <form class="woocommerce-form woocommerce-form-login login" method="post"> <p class="woocommerce-form-row woocommerce-form-row--wide form-row form-ro ...

Restructure an array of objects into a nested object structure

I have a list of task items that I need to organize into a structured object based on the ownerID var tasks = [ {taskID: "1", title: "task1", ownerID: "100", ownerName: "John", allocation: 80}, {taskID: "2", title: "task2", ownerID: "110", ownerNam ...

How can I bind the ID property of a child component from a parent component in Angular 2 using @Input?

I have a unique requirement in my parent component where I need to generate a child component with a distinct ID, and then pass this ID into the child component. The purpose of passing the unique ID is for the child component to use it within its template. ...

Provide Arguments to a Function in Express JS

How's everything going? I'm curious to find out the best way, and if it's possible to send a specific parameter to an express function in NodeJS. I want to pass the string ('admin') or any other string that I choose to the 'R ...

Authentication through Auth0 login

After successfully registering a user in Auth0 for login purposes (found in the Users section of the dashboard), I implemented the following code to authenticate the user using an HTML form with username and password fields: public login(username: string, ...

Using SailsJS to populate attributes transmitted through socket.io's publishUpdate event

Utilizing the built-in socket capabilities of SailsJS has proved to be quite effective for me so far. However, I've encountered a challenge that I haven't been able to find any information on. In my model, I have set it up to populate certain at ...

steps for signing in to garmin account with javascript

Attempting to set up an Oauth1 login for Garmin using Angular2 and standard http calls, but encountering a pre-flight OPTIONS call error on the initial request to oauth/request_token path. It seems like CORS is not enabled or something similar. Has anyone ...

The functionality of useMemo is compromised when changes are made to sessionStorage

I'm facing an issue with my app where the header contains an icon that should only be shown when the user is logged in. I store the login status in sessionStorage, but the component doesn't re-render when it changes. I attempted to use useEffect ...

Is it possible for me to automatically send the user's email and username through code without requiring any information from them while using the tawk.to chat widget?

I need assistance with automatically sending the user's email and name when they open a chat window. I have tried various methods to pre-fill the form data but it still appears empty. Please let me know if there is something I am missing. Thank you ta ...

Pressing the 'Enter' key within a textarea in a JQuery

This question seems fairly straightforward. I have a text area where hitting "enter" submits the content. Even though I reset the text to "Say something..." after submission, the cursor continues to blink. Is there a way to require the user to click on ...

Saving a complicated schema in Node using Mongoose fails to save or update when encountering an error

Greetings, I am facing challenges while trying to save a complex schema in MongoDB. const itemsSchema =new Schema({ cat: {type: String, required: true}, catItems: [{ items:{type: String}, isActive: {type: Boolean, default: true} }] }) ...

Encountering a ReferrenceError when utilizing jQuery with TypeScript

After transitioning from using JavaScript to TypeScript, I found myself reluctant to abandon jQuery. In my search for guidance on how to integrate the two, I came across several informative websites. Working with Visual Studio 2012, here is my initial atte ...

Update the section tag upon submission using jQuery on a jQuery Mobile HTML page

I have integrated a jquerymobile template into Dreamweaver 6.0 to create a mobile app interface. The home screen features four buttons - specifically, View, Create, Update, Delete. Upon clicking the Create button, a new screen is opened (each screen corres ...

Generate SVG components without displaying them

Is there a way to generate a custom SVG graphic through a function without the need to attach it to any element? Can I simply create an empty selection and return that instead? Here is my current implementation: function makeGraphic(svgParent) { retur ...