1

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 ?

  • Check out this thread where I had a similar problem and goal. https://stackoverflow.com/questions/22512813/using-variables-in-gulp-for-the-destination-file-name – Erik Pöhler Jul 02 '21 at 10:47

0 Answers0