Do you want to request a feature or report a bug?
Bug
What is the current behavior?
I’m finding that the chunkhash varies between builds in v4. Using the diff utility between the the different files shows no differences. Attempting to narrow the codebase down reduces the frequency of different hashes.
If the current behavior is a bug, please provide the steps to reproduce.
I’ve been unsuccessful in creating a small test case as it’s just too inconsistent and would take such an enormous amount of time for me to figure out by slicing and dicing our codebase.
I’m happy to help as much as I can to find a repro, but I’d need some information about diagnostics I can turn on to figure out what’s happening.
What is the expected behavior?
The chunkhash should be consistent, as does in version 3.
If this is a feature request, what is motivation or use case for changing the behavior?
Please mention other relevant information such as the browser version, Node.js version, webpack version, and Operating System.
Webpack 4.6.0, Node 8.9.4, OS X 10.13.4
Here’s our webpack.config.js
const path = require('path');
const webpack = require('webpack');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const childProcess = require('child_process');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const AssetsPlugin = require('assets-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const WebpackBuildNotifierPlugin = require('webpack-build-notifier');
const root = path.resolve(__dirname, './src');
const webappPath = path.resolve(__dirname, '..');
const deployPath = path.resolve(webappPath, './public/assets');
const dev = !process.env.NODE_ENV;
const ci = process.env.NODE_ENV === 'ci';
const prod = process.env.NODE_ENV === 'production';
if (prod) {
console.log('PRODUCTION MODE ENABLED');
}
// don't hash the filename unless we're building for prod or staging. Hashed filenames interfere with karma tests.
const outputFilename = dev || ci ? '[name].bundle.js' : '[name].[chunkhash].bundle.js';
const excludedMapSources = dev ? [/vendor.*bundle.js/, /manifest.*bundle.js/] : [/manifest.*bundle.js/];
function getPlugins() {
let plugins = [
new CleanWebpackPlugin(['public/assets/*'], {
allowExternal: true,
root: webappPath
}),
new webpack.SourceMapDevToolPlugin({
filename: "[file].map",
exclude: excludedMapSources
}),
new AssetsPlugin({
includeManifest: true,
path: deployPath,
prettyPrint: true
})
];
plugins.push(new webpack.NamedModulesPlugin());
plugins.push(new webpack.optimize.ModuleConcatenationPlugin());
return plugins;
}
module.exports = {
context: root,
mode: prod ? 'production' : 'development',
devtool: false, // rely on SourceMapDevToolPlugin
cache: dev,
stats: {
chunks: false,
chunkModules: false,
entrypoints: false,
modules: false,
version: false,
hash: false,
timings: false,
},
entry: {
app: './core-app/bootstrap.ts',
embed: './core-embed/bootstrap.ts'
},
watchOptions: {
aggregateTimeout: 300,
ignored: /node_modules/
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
alias: {
handsontable: 'handsontable/dist/handsontable.full.js'
}
},
output: {
filename: outputFilename,
path: path.resolve(__dirname, '../public/assets'),
},
optimization: {
runtimeChunk: {
name: "manifest",
},
splitChunks: {
cacheGroups: {
// default: false,
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "initial",
enforce: true
}
},
},
},
externals: {
nvd3: 'window.nv',
highcharts: "window.Highcharts",
angular: 'window.angular',
jquery: 'window.jQuery',
lodash: 'window._',
moment: 'window.moment',
ace: 'window.ace',
d3: 'window.d3',
chiliPiper: 'window.ChiliPiper',
},
plugins: getPlugins(),
module: {
rules: [
{
test: /\.ts(x?)$/,
exclude: [/\.(spec|e2e)\.ts$/],
use: [{
loader: 'ts-loader',
options: {
experimentalWatchApi: true // seems to work ok atm, but performance improvement varies
}
}]
}, {
test: /\.(html|css)$/,
loader: 'raw-loader',
exclude: /\.async\.(html|css)$/
}, {
test: /\.svg$/,
loader: 'url-loader?' + JSON.stringify({
name: '[name]_[hash]'
})
}
]
}
};
I changed it to contenthash, but I still get different hashes and they have the same content. I even took out the sourcemap output to make sure they are exactly the same.
Experiencing the same issue, did you resolve it?
EDIT: This plugin fixed my issue:
https://www.npmjs.com/package/webpack-plugin-hash-output
it happens for me too and I do use😢 (it seems that chunk’s content is different per build)
contenthash
but they are changed per my buildI also have this issue with chunkhash but I am seeing a pattern:
I should have come back and posted an update.
Short answer, Webpack’s hashing algorithm is deterministic. But the content being sent to it may not be. I discovered a whole slew of issues:
I found the easiest way to debug this issue was to override the webpack hashing algorithm and add a little script to detect for my local absolute path. Here is approximately what I used:
https://gist.github.com/halfnibble/c9f0c3b8d61e7002c799b5d24ae05643
And then in webpack config:
@halfnibble re: #7179 (comment)
fantastic comment, thanks to it I revisited the topic and found that it was indeed
script-loader
that was breaking hashing in our project (due to the usage ofpath.join
andrequire.resolve
which both output absolute paths). I migrated away from it toraw-loader
instead, and submitted the PR to deprecatescript-loader
.The info about not using absolute paths is documented in “writing a loader” doc:
https://webpack.js.org/contribute/writing-a-loader/#absolute-paths