shellscape / webpack-manifest-plugin

webpack plugin for generating asset manifests
MIT License
1.44k stars 184 forks source link

Different output on server and local machine when using multi-compiler #97

Closed ivancuric closed 3 years ago

ivancuric commented 6 years ago

I've been having a really weird issue where the manifest output is different when used locally vs on the server when using webpack's multi-compiler mode.

webpack.config.js ```js const fs = require('fs-extra'); const webpack = require('webpack'); const WebpackNotifierPlugin = require('webpack-notifier'); const CleanObsoleteChunks = require('webpack-clean-obsolete-chunks'); const InterpolateLoaderOptionsPlugin = require('interpolate-loader-options-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); const fixSvgDimensions = require('./_scripts/svg-dimension'); const paths = require('./_scripts/paths'); const nodeEnv = process.env.NODE_ENV || 'development'; const isProd = nodeEnv === 'production'; const getManifestPath = () => paths.dist.root + 'manifest.json'; if (isProd) { paths.dist = paths.temp; if (!fs.existsSync(getManifestPath())) { fs.outputJsonSync(getManifestPath(), {}); } } const getSvgoPlugins = () => [ { removeAttrs: { attrs: ['data-name'] } }, { removeTitle: true }, { removeXMLNS: true }, { addClassesToSVGElement: { classNames: ['svg', '[name]'] } }, { addAttributesToSVGElement: { attribute: 'aria-hidden="true"', }, }, ]; const configureSvgLoader = () => ({ test: /\.svg$/, use: [ { loader: 'raw-loader', }, { loader: 'skeleton-loader', options: { procedure(content) { return fixSvgDimensions(content); }, }, }, { loader: 'svgo-loader', options: { plugins: getSvgoPlugins(), }, }, ], }); const configureBabelLoader = browserlist => ({ test: /\.js$/, exclude: /(node_modules)/, use: { loader: 'babel-loader', options: { cacheDirectory: isProd ? false : true, presets: [ [ 'env', { debug: false, modules: false, useBuiltIns: true, targets: { browsers: browserlist, }, }, ], ], plugins: [ 'transform-object-rest-spread', 'transform-class-properties', 'syntax-dynamic-import', ], }, }, }); const basePlugins = () => [ !isProd && new CleanObsoleteChunks(), !isProd && new WebpackNotifierPlugin(), new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(nodeEnv) }, }), new InterpolateLoaderOptionsPlugin({ loaders: [ { name: 'svgo-loader', include: ['plugins.3.addClassesToSVGElement.classNames.1'], }, ], }), ].filter(Boolean); const prodPlugins = () => [ new ManifestPlugin({ fileName: getManifestPath(), cache: JSON.parse(fs.readFileSync(getManifestPath(), 'utf8')), }), new webpack.LoaderOptionsPlugin({ debug: true, minimize: true, }), new webpack.optimize.ModuleConcatenationPlugin(), new UglifyJSPlugin({ parallel: true, sourceMap: true, }), ]; const baseConfig = { resolve: { modules: ['node_modules', paths.src.svg, paths.src.js], }, devtool: isProd ? 'source-map' : 'cheap-module-source-map', plugins: isProd ? [...basePlugins(), ...prodPlugins()] : basePlugins(), performance: { hints: isProd ? 'warning' : false, }, }; const modernConfig = Object.assign({}, baseConfig, { name: 'modern', entry: { app: paths.src.js + 'app.js', }, output: { path: paths.dist.js, publicPath: paths.staticPath + '/js/', filename: isProd ? '[name]-[hash:7].js' : '[name].js', }, module: { rules: [ configureBabelLoader([ 'last 1 Chrome versions', 'last 1 Firefox versions', ]), configureSvgLoader(), ], }, }); const legacyConfig = Object.assign({}, baseConfig, { name: 'legacy', entry: { 'app-legacy': ['babel-polyfill', 'whatwg-fetch', paths.src.js + 'app.js'], }, output: { path: paths.dist.js + '/legacy/', publicPath: paths.staticPath + '/js/legacy/', filename: isProd ? '[name]-[hash:7].js' : '[name].js', }, module: { rules: [ configureBabelLoader([ '> 1%', 'last 2 versions', 'Firefox ESR', 'not ie < 11', ]), configureSvgLoader(), ], }, }); // module.exports = modernConfig; // module.exports = legacyConfig; module.exports = [modernConfig, legacyConfig]; ```
local build contents of manifest.json ```json { "main.css": "main-152b6c47d9.css", "0-d360947.js": "0-d360947.js", "0-d360947.js.map": "0-d360947.js.map", "1-d360947.js": "1-d360947.js", "1-d360947.js.map": "1-d360947.js.map", "10-d360947.js": "10-d360947.js", "10-d360947.js.map": "10-d360947.js.map", "11-d360947.js": "11-d360947.js", "11-d360947.js.map": "11-d360947.js.map", "12-d360947.js": "12-d360947.js", "12-d360947.js.map": "12-d360947.js.map", "2-d360947.js": "2-d360947.js", "2-d360947.js.map": "2-d360947.js.map", "3-d360947.js": "3-d360947.js", "3-d360947.js.map": "3-d360947.js.map", "4-d360947.js": "4-d360947.js", "4-d360947.js.map": "4-d360947.js.map", "5-d360947.js": "5-d360947.js", "5-d360947.js.map": "5-d360947.js.map", "6-d360947.js": "6-d360947.js", "6-d360947.js.map": "6-d360947.js.map", "7-d360947.js": "7-d360947.js", "7-d360947.js.map": "7-d360947.js.map", "8-d360947.js": "8-d360947.js", "8-d360947.js.map": "8-d360947.js.map", "9-d360947.js": "9-d360947.js", "9-d360947.js.map": "9-d360947.js.map", "app.js": "app-d360947.js", "app.js.map": "app-d360947.js.map", "0-fb8fef7.js": "0-fb8fef7.js", "0-fb8fef7.js.map": "0-fb8fef7.js.map", "1-fb8fef7.js": "1-fb8fef7.js", "1-fb8fef7.js.map": "1-fb8fef7.js.map", "10-fb8fef7.js": "10-fb8fef7.js", "10-fb8fef7.js.map": "10-fb8fef7.js.map", "11-fb8fef7.js": "11-fb8fef7.js", "11-fb8fef7.js.map": "11-fb8fef7.js.map", "12-fb8fef7.js": "12-fb8fef7.js", "12-fb8fef7.js.map": "12-fb8fef7.js.map", "2-fb8fef7.js": "2-fb8fef7.js", "2-fb8fef7.js.map": "2-fb8fef7.js.map", "3-fb8fef7.js": "3-fb8fef7.js", "3-fb8fef7.js.map": "3-fb8fef7.js.map", "4-fb8fef7.js": "4-fb8fef7.js", "4-fb8fef7.js.map": "4-fb8fef7.js.map", "5-fb8fef7.js": "5-fb8fef7.js", "5-fb8fef7.js.map": "5-fb8fef7.js.map", "6-fb8fef7.js": "6-fb8fef7.js", "6-fb8fef7.js.map": "6-fb8fef7.js.map", "7-fb8fef7.js": "7-fb8fef7.js", "7-fb8fef7.js.map": "7-fb8fef7.js.map", "8-fb8fef7.js": "8-fb8fef7.js", "8-fb8fef7.js.map": "8-fb8fef7.js.map", "9-fb8fef7.js": "9-fb8fef7.js", "9-fb8fef7.js.map": "9-fb8fef7.js.map", "app-legacy.js": "app-legacy-fb8fef7.js", "app-legacy.js.map": "app-legacy-fb8fef7.js.map" } ```
server build contents of manifest.json ``` { "main.css": "main-152b6c47d9.css", "0-fb8fef7.js": "0-fb8fef7.js", "0-fb8fef7.js.map": "0-fb8fef7.js.map", "1-fb8fef7.js": "1-fb8fef7.js", "1-fb8fef7.js.map": "1-fb8fef7.js.map", "10-fb8fef7.js": "10-fb8fef7.js", "10-fb8fef7.js.map": "10-fb8fef7.js.map", "11-fb8fef7.js": "11-fb8fef7.js", "11-fb8fef7.js.map": "11-fb8fef7.js.map", "12-fb8fef7.js": "12-fb8fef7.js", "12-fb8fef7.js.map": "12-fb8fef7.js.map", "2-fb8fef7.js": "2-fb8fef7.js", "2-fb8fef7.js.map": "2-fb8fef7.js.map", "3-fb8fef7.js": "3-fb8fef7.js", "3-fb8fef7.js.map": "3-fb8fef7.js.map", "4-fb8fef7.js": "4-fb8fef7.js", "4-fb8fef7.js.map": "4-fb8fef7.js.map", "5-fb8fef7.js": "5-fb8fef7.js", "5-fb8fef7.js.map": "5-fb8fef7.js.map", "6-fb8fef7.js": "6-fb8fef7.js", "6-fb8fef7.js.map": "6-fb8fef7.js.map", "7-fb8fef7.js": "7-fb8fef7.js", "7-fb8fef7.js.map": "7-fb8fef7.js.map", "8-fb8fef7.js": "8-fb8fef7.js", "8-fb8fef7.js.map": "8-fb8fef7.js.map", "9-fb8fef7.js": "9-fb8fef7.js", "9-fb8fef7.js.map": "9-fb8fef7.js.map", "app-legacy.js": "app-legacy-fb8fef7.js", "app-legacy.js.map": "app-legacy-fb8fef7.js.map" } ```

Not sure what else could be but something async-related, since the exact same build step on node v8.6 works locally, but gets bonkers a bit on the server.

I think that both processes are trying to write to the same file at once, even though I (think I?) specified it to work synchronously:

  new ManifestPlugin({
    fileName: getManifestPath(),
    cache: JSON.parse(fs.readFileSync(getManifestPath(), 'utf8')),
  }),

Any ideas what might be causing this issue and how to avoid it?

mastilver commented 6 years ago

Your issue is that your chunks have hashes in their names, I need to find out if it's an issue with webpack-manifest-plugin or if there is something else.

I don't have a lot of time currently so I will probably check it over the week-end

ivancuric commented 6 years ago

Thanks. I gotta admit I'm in way over my head when it comes to code splitting, hashing, multiple builds, etc. Was following along these two:

https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31 https://github.com/philipwalton/webpack-esnext-boilerplate

a-x- commented 6 years ago

is it may be a problem (it's little insane, I know):

  new UglifyJSPlugin({
    parallel: true,
shellscape commented 3 years ago

Hey all! I've taken over maintenance of the plugin and am doing some housecleaning. For Issues over a year old without a reproduction, we're going to go the route of closing them first. However, they're not dead! If the issue is still pending and still a problem, please reply with a reproduction and we'll reopen post-haste.

Please provide a reproduction by choosing one of the options below:

  1. Using the REPL.it plugin reproduction template at https://repl.it/@shellscape/manifest-plugin-repro
  2. Provide a minimal repository link (Read https://git.io/fNzHA for instructions). Please use NPM for installing dependencies! These may take more time to triage than the other options.

    ⚠️ ZIP Files are unsafe and maintainers will NOT download them.