Why?
Why we need dynamic entries?
Assuming that we have a file structure for a project is something.
Project -- Modules | -- Modules_1 | -- Assets | -- Js | -- a.js | -- b.js | -- Module_2 | -- Assets | -- Js | -- c.js | -- d.js
We have to create entry for each of the Js file and every time we add any new file.
Solution
We can create a single entry in webpack.config.js
which will include every assets file.
We can create dynamic entries all because of the entry
property of Webpack config.entry
property can accept:
- String :
'./Modules/Modules_1/Assets/Js/a.js'
- Array of Strings:
[
'./Modules/Modules_1/Assets/Js/a.js',
'./Modules/Modules_1/Assets/Js/b.js'
] - Object:
{
'js/a': './Modules/Modules_1/Assets/Js/a.js',
'js/b': './Modules/Modules_1/Assets/Js/b.js'
}
Now, coming to the dynamic part
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
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 // the project 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 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; }, {}); // module.exports = Encore.getWebpackConfig(); const config = Encore.getWebpackConfig(); // Export the final configuration module.exports = config;
The above code is used for dynamic entry in symfony/webpack-encore
Similarly we can use in core webpack using below code for entry
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 }, {}),
Explanation
- Glob plays an important role here, we pass a string ‘./Modules/**/assets/js/**/*.js’ this string tells glob to search for
.js
file inassets/js
directory insideModules
- Glob return each matched file path.
- Then we replace
.js
extension as to define the path with the same name as our file name. - create entry.
That’s all to create dynamic entry with WebPack.