To create dynamic entries in Webpack by making use of glob.
If you are in hurry then check the below code otherwise you are most welcome to read the complete article for every aspects.
// dynamic entry
glob.sync('./directory-to-search-in/**/assets/js/**/*.js').reduce((acc, item) => {
/**
* The "[name]" placeholder in the "output" property will be replaced
* with each key name in our "name" object. We replace .js so that we can use
* our js file with its name. ex path/a.js as path/a
*/
var name = item.replace(/\.\/Modules\/|\.js/gi, '');
acc[name] = item;
// add entry for each js file
Encore.addEntry(name, item);
return acc;
}, {});
Why we need dynamic entries?
In general we have a huge file structure and in case we have a modular structure or something like plugins based system then how can we manage assets of each plugin, any number of plugins can be installed. we are not going to add entry manually for each plugin installed.
Assuming that we have a file structure for a project is something.
Project
-- Modules
| -- Module-abc
| -- Assets
| -- Js
| -- app.js
| -- app-vue.js
| -- Module-xyz
| -- Assets
| -- Js
| -- xyz.js
| -- style.js
As per above file structure, in general we need to create entry for each of the Js file and every time we add any new module to our project which is not a good solution.
Creating Dynamic Entries in Webpack
Types of entries in Webpack Config
We can create a single entry in webpack.config.js which will include every assets file. The entry property of Webpack config allow us to do so. entry property can accept:
- String :
‘./Modules/Modules-abc/Assets/Js/app.js’ - Array of Strings:
[
‘./Modules/Module-abc/Assets/Js/app.js’,
‘./Modules/Module-abc/Assets/Js/app-vue.js’
] - Object:
{
‘js/app’: ‘./Modules/Modules-abc/Assets/Js/app.js’,
‘js/app-vue’: ‘./Modules/Modules-abc/Assets/Js/app-vue.js’
}
Adding Dynamic enteries to config file
We use ‘glob‘ for this, When passed a string, Glob will attempt to find each file that matches the path given and return each path to the file as string array.webpack.config.js
we are considering the example for Symfony but the process is same in any framework.
var Encore = require('@symfony/webpack-encore');
/**
* When passed a string, Glob will attempt to find each file that matches the
* path given and return each path to the file as string[]
*/
const glob = require('glob')
Encore
// directory where compiled assets will be stored
.setOutputPath('public/resource/')
.setPublicPath('/resource')
.enableSourceMaps(!Encore.isProduction())
// dynamic entry
glob.sync('./Modules/**/assets/js/**/*.js').reduce((acc, item) => {
/**
* The "[name]" placeholder in the "output" property will be replaced
* with each key name in our "name" object. We replace .js so that we can use
* our js file with its name. ex Module-abc/assets/js/a.js as Module-abc/assets/js/a
*/
var name = item.replace(/\.\/Modules\/|\.js/gi, '');
acc[name] = item;
// add entry for each js file
Encore.addEntry(name, item);
return acc;
}, {});
// module.exports = Encore.getWebpackConfig();
const config = Encore.getWebpackConfig();
// Export the final configuration
module.exports = config;
Adding dynamic entries in core Webpack
entry: glob.sync('./Modules/**/assets/js/**/*.js').reduce((acc, path) => {
/**
* The "[name]" placeholder in the "output" property will be replaced
* with each key name in our "name" object. We replace .js so that we can use
* our js file with its name. ex path/a.js as path/a
*/
var name = item.replace(/\.\/Modules\/|\.js/gi, '');
/**
* each js file in the directory will be added to object
*/
acc[name] = item;
return acc
}, {}),
Elucidation
- Glob plays an important role here, we pass a string ‘./Modules/**/assets/js/**/*.js’ this string tells glob to search for
.jsfile inassets/jsdirectory insideModules - Glob return each matched file path.
- Then we replace
.jsextension as to define the path with the same name as our file name.

I spend a day and then found this, it really helps me. Thank you @anjaneya