Description of the problem
Using Webpack, I'm trying to use multiple entryfiles from the src directory to generate its counterpart in the dist directory.
Expected result :
│ │ │ ├─ dist
│ │ │ │ ├─ script.js
│ │ │ │ ├─ style.css
│ │ │ │ ├─ template-parts
│ │ │ │ │ ├─ blocks
│ │ │ │ │ │ ├─ moduleDemo
│ │ │ │ │ │ │ ├─ moduleDemo.css
│ │ │ │ │ │ ├─ moduleDemo2
│ │ │ │ │ │ │ ├─ moduleDemo2.css
│ │ │ │ │ │ │ ├─ moduleDemo2.js
│ │ │ │ │ │ ├─ moduleDemo3
│ │ │ │ │ │ │ ├─ moduleDemo3.js
│ │ │ │ │ ├─ component
│ │ │ │ │ │ ├─ componentTitle
│ │ │ │ │ │ │ ├─ componentTitle.css
│ │ │ │ │ │ │ ├─ componentTitle.js
│ │ │ │ │ │ └─ componentWysiwyg
│ │ │ │ │ │ ├─ componentWysiwyg.js
│ │ │ │ │ └─ patterns
│ │ │ │ │ ├─ demo-pattern-2.php
│ │ │ │ │ └─ demo-pattern.php
│ │ │ │ ├─ templates
│ │ │ │ │ ├─ 404.twig
│ │ │ │ │ ├─ archive.twig
│ │ │ │ │ ├─ etc ...
│ │ │ │ ├─ twig.css
│ │ │ │ ├─ twig.js
│ │ │ ├─ footer.php
│ │ │ ├─ functions.php
│ │ │ ├─ package-lock.json
│ │ │ ├─ package.json
│ │ │ ├─ etc ...
│ │ │ ├─ src
│ │ │ │ ├─ assets
│ │ │ │ ├─ js
│ │ │ │ │ ├─ app.js
│ │ │ │ │ └─ test.js
│ │ │ │ ├─ scss
│ │ │ │ │ ├─ abstracts
│ │ │ │ │ │ └─ \_variables.scss
│ │ │ │ │ ├─ base
│ │ │ │ │ │ └─ \_typography.scss
│ │ │ │ │ ├─ components
│ │ │ │ │ │ └─ \_button.scss
│ │ │ │ │ ├─ layout
│ │ │ │ │ │ └─ \_footer.scss
│ │ │ │ │ ├─ main.scss
│ │ │ │ │ ├─ pages
│ │ │ │ │ │ └─ \_404.scss
│ │ │ │ │ └─ themes
│ │ │ │ │ └─ \_theme.scss
│ │ │ │ ├─ template-parts
│ │ │ │ │ ├─ blocks
│ │ │ │ │ │ ├─ moduleDemo
│ │ │ │ │ │ │ ├─ moduleDemo.scss
│ │ │ │ │ │ ├─ moduleDemo2
│ │ │ │ │ │ │ ├─ moduleDemo2.scss
│ │ │ │ │ │ │ ├─ moduleDemo2.js
│ │ │ │ │ │ ├─ moduleDemo3
│ │ │ │ │ │ │ ├─ moduleDemo3.js
│ │ │ │ │ ├─ component
│ │ │ │ │ │ ├─ componentTitle
│ │ │ │ │ │ │ ├─ componentTitle.scss
│ │ │ │ │ │ │ ├─ componentTitle.js
│ │ │ │ │ │ └─ componentWysiwyg
│ │ │ │ │ │ ├─ componentWysiwyg.js
│ │ │ │ │ └─ patterns
│ │ │ │ │ ├─ demo-pattern-2.php
│ │ │ │ │ └─ demo-pattern.php
│ │ │ │ ├─ templates
│ │ │ │ │ ├─ 404.twig
│ │ │ │ │ ├─ archive.twig
│ │ │ │ │ ├─ etc ...
│ │ │ │ └─ twig.js
│ │ │ ├─ static
│ │ │ │ ├─ no-timber.html
│ │ │ │ └─ site.js
│ │ │ ├─ style.css
│ │ │ ├─ system
│ │ │ │ └─ inc
│ │ │ │ └─ utils.class.php
│ │ │ └─ webpack.config.js
For now, I'm using the glob plugin and the entryPlus plugin to find all of the folders and scss + js files related, that I return to the entry config :
const entryFiles = [
{
entryFiles: glob.sync('./src/template-parts/**/**/*.{scss,js}'),
outputName(item) {
let regex = /(\.scss)|(\.js)|(\.\/src\/)/g;
return item.replaceAll(regex, '');
},
},
];
console.log(entryFiles);
let blockConfig = Object.assign({}, config, {
entry: entryPlus(entryFiles),
output: {
filename: '[name].js',
chunkFilename: '[name].js?ver=[chunkhash]',
path: path.resolve(__dirname, 'dist'),
},
The console.log show the following entries :
[
{
entryFiles: [
'./src/template-parts/blocks/moduleDemo/moduleDemo.js',
'./src/template-parts/blocks/moduleDemo/moduleDemo.scss',
'./src/template-parts/blocks/moduleDemo2/moduleDemo2.scss',
'./src/template-parts/blocks/moduleDemo3/moduleDemo3.js',
'./src/template-parts/component/componentTitle/componentTitle.js',
'./src/template-parts/component/componentWysiwyg/componentWysiwyg.js'
],
outputName: [Function: outputName]
}
]
So technically, based on the src structure files, the right assets are passed through the entry config, but it's not properly working.
- First: if the original folder doesn't have a .js, it will still generate one in the corresponding dist folder.
- Second: if the original folder has both a .scss and a .js files, they will generate a .css file and a .js file, but while the first seems to work properly, the .js will not work as expected. Exemple with the moduleDemo folder that created a moduleDemo.js:
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ // The require scope
/******/ var __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
/*!**************************************************************!*\
!*** ./src/template-parts/blocks/moduleDemo/moduleDemo.scss ***!
\**************************************************************/
__webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
/******/ })()
;
//# sourceMappingURL=moduleDemo.js.map
Side note to take into account
The project has actually two configurations :
- One is basic, corresponding to the mainConfig - it needs one combined css and one combined js file outputed in the dist folder. This config works just fine excepted that it also generated a style.js file, which is not necessary. Here is the src directory :
│ │ │ ├─ src
│ │ │ │ ├─ assets
│ │ │ │ ├─ js
│ │ │ │ │ ├─ app.js
│ │ │ │ │ └─ test.js
│ │ │ │ ├─ scss
│ │ │ │ │ ├─ abstracts
│ │ │ │ │ │ ├─ \_functions.scss
│ │ │ │ │ │ ├─ \_mixins.scss
│ │ │ │ │ │ └─ \_variables.scss
│ │ │ │ │ ├─ base
│ │ │ │ │ │ └─ \_typography.scss
│ │ │ │ │ ├─ components
│ │ │ │ │ │ └─ \_button.scss
│ │ │ │ │ ├─ layout
│ │ │ │ │ │ ├─ \_footer.scss
│ │ │ │ │ │ └─ \_header.scss
│ │ │ │ │ ├─ main.scss
│ │ │ │ │ ├─ pages
│ │ │ │ │ │ └─ \_404.scss
│ │ │ │ │ └─ themes
│ │ │ │ │ ├─ \_admin.scss
│ │ │ │ │ └─ \_theme.scss
Here is the corresponding dist folder (I voluntary remove the .map generated files to make it more readable):
│ │ │ ├─ dist
│ │ │ │ ├─ script.js
│ │ │ │ ├─ style.css
│ │ │ │ ├─ style.js
- The second one correspond to the blockConfig, the main problem explained in this thread.
Current Webpack config
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// const WatchTimePlugin = require('webpack-watch-time-plugin');
const cssnano = require('cssnano');
const autoprefixer = require('autoprefixer');
// const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const entryPlus = require('webpack-entry-plus');
const glob = require('glob');
let config = {
module: {},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
};
let mainConfig = Object.assign({}, config, {
entry: {
twig: './src/twig.js',
style: './src/scss/main.scss',
script: './src/js/app.js',
},
output: {
filename: '[name].js',
chunkFilename: '[name].js?ver=[chunkhash]',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
extensions: ['*', '.js'],
},
mode: 'development',
performance: {
hints: false,
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.twig$/,
use: [
{
loader: 'file-loader',
options: {
context: 'src',
name: '[path][name].[ext]',
},
},
{ loader: 'extract-loader' },
{
loader: 'html-loader',
options: {
minimize: false,
sources: {
list: [
{
tag: 'img',
attribute: 'data-srcset',
type: 'srcset',
},
],
},
},
},
],
},
{
test: /\.php$/,
use: [
{
loader: 'file-loader',
options: {
context: 'src',
name: '[path][name].[ext]',
},
},
{ loader: 'extract-loader' },
{
loader: 'html-loader',
options: {
minimize: false,
},
},
],
},
{
test: /\.json$/,
type: 'javascript/auto',
use: [
{
loader: 'file-loader',
options: {
context: 'src',
name: '[path][name].[ext]',
},
},
{ loader: 'extract-loader' },
{
loader: 'html-loader',
options: {
minimize: false,
},
},
],
},
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/env'],
},
},
],
},
{
test: /\.(png|svg|jpg|jpeg|tiff|webp|gif|ico|woff|woff2|eot|ttf|otf|mp4|webm|wav|mp3|m4a|aac|oga)$/,
use: [
{
loader: 'file-loader',
options: {
context: 'src',
name: '[path][name].[ext]?ver=[md5:hash:8]',
},
},
],
},
],
},
});
const entryFiles = [
{
entryFiles: glob.sync('./src/template-parts/**/**/*.{scss,js}'),
outputName(item) {
let regex = /(\.scss)|(\.js)|(\.\/src\/)/g;
return item.replaceAll(regex, '');
},
},
];
console.log(entryFiles);
let blockConfig = Object.assign({}, config, {
entry: entryPlus(entryFiles),
output: {
filename: '[name].js',
chunkFilename: '[name].js?ver=[chunkhash]',
path: path.resolve(__dirname, 'dist'),
},
mode: 'development',
performance: {
hints: false,
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/env'],
},
},
],
},
],
},
});
mainConfig.module.rules.push({
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
});
blockConfig.module.rules.push({
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
});
module.exports = [mainConfig, blockConfig];
The file is definitely not very clean. There is a lot to make it look better and more efficient, so of course I'm open to suggestions as well.
Anyway, is there a way to achieve what I'm looking for and how ?