SoFunction
Updated on 2025-04-08

How to implement webpack dynamic batch loading files

background

Recently, the author encountered a small need at work:

To implement a component to play frame pictures

This requirement itself is not complicated, but it requires introducing ten images into the component at once, like the following:

// It's so willful, the subscript starts from 0~import frame0 from './assets/frame_0.png'
import frame1 from './assets/frame_1.png'
import frame2 from './assets/frame_2.png'
// ..Omit n piecesimport frame7 from './assets/frame_8.png'
import frame8 from './assets/frame_9.png'
import frame9 from './assets/frame_10.png'

As a programmer with a clean code, I don't allow this kind of repetitive code to exist, so I tried whether there is any simple method.

Method 1: Bypass webpack

Since the author uses vue-cli 3, familiar friends know that you can place the image in a fixed format under the public folder and then directly introduce it in the code with an absolute path. If you do this, you can construct an url array based on the file name, and the simple code is as follows:

const frames = []
_.times(10, v => {
  (`/images/frame_${v}.png`)
})
// Then you get an array of 10 urls

This method itself is an emergency measure provided by vue-cli, which has several disadvantages:

  • Unable to use webpack to process resources, unable to generate content hash, which is not conducive to cache updates
  • Unable to use url-loader to inline resources into base64 strings to reduce network requests

Method 2: require

Since import is a static keyword, if you want to load files in batches, you can use require, but it is not possible to write directly like the following:

const frames = []
_.times(10, v => {
  const path = `./assets/images/frame_${v}.png`
  (require(path))
}

The path in the above code can only be determined when the program is running, that is, it belongs to the runtime stage, while the requirement in webpack determines the file location during the construction stage, so webpack cannot infer where the path is.

But it can be written like this:

const frames = []
_.times(10, v => {
  (require(`./assets/images/frame_${v}.png`))
}
// The path with hash value is obtained in frames

Although there is no syntax difference between the two writing methods, the second writing method prompts webpack when building. webpack will add all files in ./assets/images to the bundle, so that you can find the corresponding files when you run it.

When using method 2, I try to extract the batch loaded logic to other modules for multiplexing:

export function loadAll (n, prefix, suffix) {
 const frames = []
 _.times(n, v => {
  (require('./' + prefix + v + suffix))
 })
 return frames
}

But it obviously failed because the extracted code and the running context belong to another module, so the file in the relative path cannot be found.

Method 3:

The above two methods are not very elegant, so I went through the webpack documentation and finally found this method:

(
 directory: String,
 includeSubdirs: Boolean /* Optional, the default value is true */,
 filter: RegExp /* Optional, the default value is /^\.\/.*$/, all files */,
 mode: String /* Optional, 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once', the default value is 'sync' */
)

Specifies a complete set of dependencies, which are introduced through a directory path, an includeSubdirs option, a filter with a finer granular control module and a mode definition of loading. The module can then be parsed easily.

Let's look at the above example:

const frames = []
const context = ('./assets/images', false, /frame_\d+.png/)
().forEach(k => {
  (context(k))
})

The code here creates a require context through .

  • The first parameter specifies the folder that needs to be loaded, that is, the ./assets/images folder in the component's current directory
  • The second parameter specifies whether subdirectories need to be included. Since there is no subdirectories, pass false
  • The third parameter specifies the matching rules for the files that need to be included, and we use a regular expression.

Then use () to get the file path list of the context, and context itself is also a method, which is equivalent to setting the context requirement. We put the file after requiring into the array. The path in the array is actually with a hash value. The following is the picture in my project:

["/static/img/frame_0.", "/static/img/frame_1.", "/static/img/frame_2.", "/static/img/frame_3.", "/static/img/frame_4.", "/static/img/frame_5.", "/static/img/frame_6.", "/static/img/frame_7.", "/static/img/frame_8.", "/static/img/frame_9."]

And if you set up inline pictures, there may be a base64 string of the pictures in the array.

Reconstruct it

Method 3 has solved our problem, and we can batch require files in a folder. However, the logic of the forEach is obviously repeated, so of course we extract it. In the future, multiple components need to be introduced:

Public module:

/**
  * Loading frame pictures in batches
  * @param {Function} context - Created function
  * @returns {Array<string>} All pictures returned
  */
function loadFrames (context) {
 const frames = []
 ().forEach(k =&gt; {
  (context(k))
 })
 return frames
}

In the component:

const context = ('./assets/images', false, /frame_\d+.png/)
const frames = loadFrames(context)

The mission is done! Interested friends can click the link at the end of the article to view the detailed documents~

Reference link

webpack dynamic require

This is the article about the implementation method of webpack dynamic batch loading files. For more related webpack dynamic batch loading content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!