codinggames

How Webpack handles dynamic imports with variable paths

It's not magic, I promise

Written in April 11, 2022 - 🕒 3 min. read

Webpack is the most popular module bundler for JavaScript, it’s a tool for bundling modules together into a single file and more.

One thing that always bugged me was how it handles dynamic imports with variable paths, I mean, I knew it was not magic, but I didn’t know how it works, and I always forgot to research it… until now.

Magic?
Magic?

How file imports work

Whenever you import a file in your code, Webpack will look for it in the project directory and copy it to the build folder with a new name, then Webpack replaces the import code in your bundled JavaScript file with the path to the newly copied file.

Here is a super simplified example:

// import on your app.js file
import utils from './helpers/utils.js';

// import on the bundled file
import utils from './build/09wdj0wjd.bundle.0.js';

What is a dynamic import?

Sometimes you don’t want the browser to download the file immediately, you want to load it only when it’s needed, and for that, you can use a dynamic import.

const button = document.createElement('button');
button.innerHTML = 'Click me';
// when the button is clicked, a dynamic import will happen
button.onclick = () => import('./helpers/utils.js').then(() => console.log('Dynamic import'));

It’s possible to use dynamic imports with pretty much any type of file, so it’s quite useful for large images or audio files, for example.

But what happens when you want to import a file with a variable path?

const fileName = 'image.jpg';
const button = document.createElement('button');
button.innerHTML = 'Click me';
button.onclick = () => import(`./assets/images/${fileName}`);

How does Webpack know which file to copy to the build folder? Well, there is a way to tell Webpack to ignore the import, and let the browser resolve it as it wants with the comment /* webpackIgnore: true */.

const path = 'assets/images/image.jpg';
// the browser will resolve this import and fail if the file doesn't exist
const module = await import(/*webpackIgnore: true*/ path);

That’s nice, but somehow it’s also possible to not do that and let Webpack figure out the path to the file. But how?

Magic

The magic trick

It’s really not that complicated, but it comes with some caveats. For example, if you import a file with a variable path, at least some part of that path needs to be explicit in the string, for example:

// this works
const fileName = 'image.jpg';
let module = await import(`./assets/images/${fileName}`);

// this doesn't work
const path = './assets/images/image.jpg';
module = await import(path);

Why is that? The way Webpack does it is by analyzing the interpolated string path during the build process, then getting the explicit path part from the string, in this example assets/images/, and then copy all the files from that folder to the build folder.

Webpack does it in a very smart way too, if the import statement includes the file extension, it will only copy the files with that extension, for example import(`./assets/images/${fileName}.png`) will only copy PNG files.

Since Webpack does that by analyzing string in the import statement, it’s not able to know which files to copy when the whole path is a variable without an explicit string part.

Conclusion

Webpack might have a cumbersome configuration, and sometimes it might seem like dark sorcery, but it’s a very powerful tool with lots of features, and if you dig deep enough, you’ll find that its implementation is really not that complicated.

If you want to know more about Webpack, you can check out the official Webpack documentation, and you can read more about Module Methods here and Dynamic Imports here.

Tags:


Post a comment

Comments

RG on 9/18/22

const module = await import(/*webpackIgnore: true*/ path); This does not work for me, at least some part of that path needs to be explicit in the string. I'd prefer to use a variable. Also, const module = await import(/*webpackIgnore: true*/ `${path}'); does not work either. Please advise. Thanks.