Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin is incompatible with [hash] modifier in output.filename [v4-beta] #1346

Closed
BloodyAltair opened this issue Feb 20, 2020 · 4 comments
Closed

Comments

@BloodyAltair
Copy link

BloodyAltair commented Feb 20, 2020

Expected behaviour

The plugin should inject links to compiled .js files with, containing [hash] as the query string

Current behaviour

Plugin does not inject such files

Environment

Tell us which operating system you are using, as well as which versions of Node.js, npm, webpack, and html-webpack-plugin. Run the following to get it quickly:

Node.js v13.7.0
OS: linux 5.4.18-1-MANJARO
NPM: 6.13.6

my-app@0.0.1 /home/bloodyaltair/Web/My_App/frontend
└── webpack@4.41.6 

my-app@0.0.1 /home/bloodyaltair/Web/My_App/frontend
├─┬ favicons-webpack-plugin@3.0.1
│ └── html-webpack-plugin@4.0.0-beta.11  deduped
└── html-webpack-plugin@4.0.0-beta.11

Config

require('babel-register');

let webpack = require('webpack');
let path = require('path');
let glob = require('glob-all');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let MiniCssExtractPlugin = require('mini-css-extract-plugin');
let FaviconsWebpackPlugin = require('favicons-webpack-plugin');
let globImporter = require('node-sass-glob-importer');
let _ = require('lodash');
let TerserPlugin = require('terser-webpack-plugin');
let PurgeCSSPlugin = require('purgecss-webpack-plugin');

let packageJson = require('./package.json');

const isProduction = process.argv.some((arg) => arg === '-p');
process.env.NODE_ENV = isProduction ? 'production' : 'development';

/*
    Compile-time configuration
 */
let config = {};
try {
    config = require('./config/env.js');
} catch (err) {
    console.error('\n\n===\nCan not find config/env.js\n===\n\n', err);
    process.exit(-1);
}
/*
    Paths variables
 */
const rootPath = path.resolve('./src');
const outputPath = path.resolve('./dist');
const publicPath = config.publicPath || '/';
/*
    Common config
 */
let webpackConfig = {
    cache: true,
    devtool: 'cheap-module-source-map',
    devServer: {
        hot: true,
        host: '0.0.0.0',
        port: 3000,
        compress: false,
        overlay: true,
        proxy: {},
    },
    watch: true,
    watchOptions: {
        poll: 1000,
    },
    mode: isProduction ? 'production' : 'development',
    entry: [
        path.resolve(rootPath, 'index.js'),
    ],
    node: {
        __filename: true,
        __dirname: true,
    },
    output: {
        path: outputPath,
        publicPath: '/',
        filename: '[name].js?[hash]',
        pathinfo: !isProduction,
    },
    resolve: {
        modules: ['node_modules'],
        extensions: ['.js', '.css', '.scss'],
    },
    context: __dirname,
    optimization: {
        splitChunks: {
            chunks: 'all',
            minSize: 30000,
            maxSize: 0,
            minChunks: 1,
            maxAsyncRequests: 5,
            maxInitialRequests: 3,
            automaticNameDelimiter: '~',
            name: false,
            cacheGroups: {
                assets: {
                    name: 'assets',
                    test: /^src\/(.*)\.(css|gif|png|svg|jpe?g?|woff2?|eot|ttf)$/,
                    enforce: true,
                    reuseExistingChunk: true,
                },
                vendor: {
                    test: /node_modules/,
                    name: 'vendor',
                    enforce: true,
                },
                app: {
                    test: /^src\/(.*)\.(js|html)$/,
                    enforce: true,
                    name: 'app',
                    reuseExistingChunk: true,
                },
            },
        },
    },
    module: {
        rules: [
            {
                test: /\.(sc|c)ss$/,
                use: [
                    isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
                    `css-loader?${JSON.stringify({
                        importLoaders: 3,
                        url: true,
                        import: true,
                        localIdentName: isProduction ? '[hash:base64:5]' : '[path][name]-[local]',
                    })}`,
                    'postcss-loader',
                    'resolve-url-loader',
                    {
                        loader: 'sass-loader',
                        options: {
                            importer: globImporter(),
                            sourceMap: !isProduction,
                        },
                    },
                ],
            },
            {
                test: /\.js$/,
                loaders: [
                    'babel-loader?cacheDirectory=true',
                ],
                exclude: /node_modules[\\\/]+.*/,
            },
            {
                test: /\.(mp3|ogg|wav|gif|png|jpe?g|svg|eot|ttf|woff2?)/,
                use: [{
                    loader: 'file-loader',
                    options: {
                        name(file) {
                            let subdir = '';
                            switch (path.extname(file)) {
                                case '.mp3':
                                case '.ogg':
                                case '.wav':
                                    subdir = 'audio';
                                    break;
                                case '.gif':
                                case '.png':
                                case '.jpg':
                                case '.jpeg':
                                    subdir = 'images';
                                    break;
                                case '.eot':
                                case '.ttf':
                                case '.woff':
                                case '.woff2':
                                    subdir = 'fonts';
                                    break;
                                default:
                                    subdir = 'svg';
                                    break;
                            }

                            if (!isProduction) {
                                return "assets/" + subdir + "/[name].[ext]?[hash]";
                            }

                            return "assets/" + subdir + "/[hash].[ext]";
                        },
                    },
                }],
            },
            {
                test: /\.(html)$/,
                use: {
                    loader: 'html-loader',
                    options: {
                        attrs: ['object:data'],
                    },
                },
            },
        ],
    },
    plugins: [
        new webpack.DefinePlugin({
            'window.CLIENT_ID': config.clientId ? JSON.stringify(config.clientId) : undefined,
            'process.env': {
                NODE_ENV: JSON.stringify(process.env.NODE_ENV),
                APP_ENV: JSON.stringify(config.environment || process.env.NODE_ENV),
                __VERSION__: JSON.stringify(config.version || ''),
                __DEV__: !isProduction,
                __PROD__: isProduction,
            },
        }),
        new HtmlWebpackPlugin({
            template: path.resolve(rootPath, 'index.html'),
            filename: 'index.html',
            inject: 'body',
            minify: {
                quotes: isProduction,
                cdata: isProduction,
                removeComments: isProduction,
                collapseWhitespace: isProduction,
                conservativeCollapse: isProduction,
                preserveLineBreaks: !isProduction,
            },
        }),
        new PurgeCSSPlugin({
            paths: glob.sync(`${rootPath}/**/*`, {nodir: true}),
        }),
        new MiniCssExtractPlugin({
            filename: '[name].css?[hash]',
            chunkFilename: '[name].css?[hash]',
        }),
        new FaviconsWebpackPlugin({
            logo: path.join(rootPath, 'images/favicon.png'),
            prefix: 'assets/images/icons-[hash]/',
            emitStats: !isProduction,
            statsFilename: 'iconstats-[hash].json',
            persistentCache: true,
            inject: true,
            favicons: {
                background: '#f3ffe6',
                theme_color: '#005403',
                appleStatusBarStyle: 'black-translucent',

                display: 'fullscreen',
                orientation: 'portrait',
                logging: !isProduction,
                start_url: '/',
                version: packageJson.version,
                icons: {
                    android: true,
                    appleIcon: true,
                    appleStartup: true,
                    coast: true,
                    favicons: true,
                    firefox: true,
                    opengraph: true,
                    twitter: true,
                    yandex: true,
                    windows: true,
                },
            },
        }),
        new webpack.HotModuleReplacementPlugin(),
    ],
};

module.exports = webpackConfig;

...your template file if it is part of this issue: it doesn't matter, I can reproduce even on default template

Additional context

Hi. The plugin does not inject links to compiled js bundles if I specify [hash] as query string webpackConfig.output.filename (e.g. [hash].js - works, bundle.js?[hash] - does not work)
I know that there is HtmlWebpackPlugin() option named hash: <Boolean>, and I will use it as temporal workaround, but such way (I mean using [hash] in output.filename) also should work, as i understand (desired behavior was supported on v3)

UPD: This issue also affects MiniCssExtractPlugin
Example:

new MiniCssExtractPlugin({
            filename: '[name].css?[hash]',
            chunkFilename: '[name].css?[hash]',
        }),

[name]-[hash].css - works
[name].css?[hash] - doesn't work

UPD #⁠2: It seems that it doesn't work if I even add empty query (i.e. [name].css?)

@jantimon
Copy link
Owner

Not sure if that is a valid filename - it rather looks like a uri.

The html-webpack-plugin gets the filenames which are going to be written to disk - so probably there is no way to get this information about the query string.

But feel free to take a look at the code here:

const entryPointFiles = compilation.entrypoints.get(entryName).getFiles();

@jantimon
Copy link
Owner

same as:

#1367
#1355
#1374

@jantimon jantimon reopened this Mar 30, 2020
@jantimon
Copy link
Owner

I have reported this issue here: webpack/webpack#10638

@jantimon
Copy link
Owner

I will try to bring back the same behaviour as in 3.2 for details please see #1355

@lock lock bot locked as resolved and limited conversation to collaborators May 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants