webpack / webpack

A bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.
https://webpack.js.org
MIT License
64.64k stars 8.8k forks source link

Consecutive Build output differs -> 1. build broken, 2. build works #12479

Closed DeadIine closed 3 years ago

DeadIine commented 3 years ago

Bug report

What is the current behavior?

I've upgraded an existing Project from Webpack 4.44.2 to 5.17.

When I run a build script using the webpack CLI: "build": "cross-env NODE_ENV=production TENANT=CLIENT1 webpack --config webpack/prod.config.js",

Webpack builds several functions into the desired output folder. (I'm exporting 5 configs from my webpack.config.js... currently trying to reduce this but I think it should still work properly)

So when I run the script for the first time, webpack finishes without errors and all files are at the desired output path. When I open the website though, I'm getting errors like cannot read default of undefined. This error is caused in an async function with loads components using await

When running the script again, the error is gone and the website works properly.

I've found out why I'm getting these errors. When I open the minified entry file, at the very bottom I can find a switch case statement where the chunks should be listed:

image

The odd thing about it is, that the store entries are empty.. So no scripts are loaded on the website when a chunk is required.

After building a second time, all entries are listed as expected:

image

I'm thinking this might be a race condition or some kind of internal caching which causes this behavior. It's 100% reproducible. First build broken, second build works.

If the current behavior is a bug, please provide the steps to reproduce.

My configuration is pretty standard I'd say:

Config:

const prodConfig = {
    mode: "production",
    plugins: [
        new webpack.DefinePlugin({
            STORE_MANIFEST: JSON.stringify(
                env.getManifest(paths.storeManifest)
            ),
            COMMON_MANIFEST: JSON.stringify(
                env.getManifest(paths.commonManifest)
            ),
            COMPONENT_MANIFEST: JSON.stringify(
                env.getManifest(paths.componentManifest)
            ),
            ENV_MODE: JSON.stringify(process.env.NODE_ENV),
            TENANT: JSON.stringify(process.env.TENANT),
        }),
        new WebpackManifestPlugin({
            fileName: "asset-manifest.json",
            publicPath: "",
        }),
    ]
    // allow absolute imports from "src/"
    resolve: {
        modules: [
            path.resolve(process.cwd(), 'redesign/packages/shop/src'),
            path.resolve(process.cwd(), 'redesign/packages/frontend/client1/src'),
            path.resolve(process.cwd(), 'redesign/packages/frontend/client2/src'),
            'node_modules'
        ],
        alias: {
            svgs: svgsPath,
        },
    },
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif|eot|ttf|woff|woff2|otf)$/,
                use: ['file-loader'],
            },
            {
                test: /\.svg$/,
                use: ['@svgr/webpack'],
            },
            {
                test: /\.(sa|sc|c)ss$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: { esModule: false, url: false },
                    },
                    {
                        loader: 'sass-loader', // transform scss to cs
                        options: {
                            additionalData: `$tenant: ${ process.env.TENANT };`,
                            sassOptions: {
                                includePaths: [
                                    path.resolve(process.cwd(),'node_modules'),
                                    path.resolve(process.cwd(),'redesign/node_modules')
                                ],
                            },
                        }
                    }
                ],
            },
            {
                test: /\.m?js$/,
                exclude: /node_modules\/(?!(@mm)\/).*/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        rootMode: 'upward'
                    },
                },
            },
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            }
        ],
    },
    externals: {
        react: 'React',
        'react-dom': 'ReactDom',
        redux: 'Redux',
        'react-redux': 'ReactRedux',
        'redux-subspace': 'ReduxSubspace',
        '@redux-dynostore/core': 'ReduxDynostoreCore',
        '@redux-dynostore/react-redux': 'ReduxDynostoreReactRedux',
        '@redux-dynostore/react-redux-subspace':
        'ReduxDynostoreReactReduxSubspace',
        '@redux-dynostore/redux-subspace': 'ReduxDynostoreReduxSubspace',
        'styled-components': 'StyledComponents',
    }
};

Export with multiple functions:

module.exports = [
    {
        ...prodConfig,
        entry: entrypoints.stores,  // entrypoints ist an object with key: value (string) pairs
        output: {
            path: paths.appStores,
            filename: '[name].[chunkhash].js',
            publicPath
        }
    },
    {
        ...prodConfig,
        entry: entrypoints.bundles,  // entrypoints ist an object with key: value (string) pairs
        output: {
            path: paths.appBundles,
            filename: '[name].[chunkhash].js',
            publicPath,
        }
    },
    {
        ...omit(prodConfig, ['externals']),
        entry: entrypoints.acp,  // entrypoints ist an object with key: value (string) pairs
        output: {
            path: paths.acpBuild,
            filename: '[name].[chunkhash].js',
            publicPath,
        }
    },
];

What is the expected behavior?

I'd think that the output should be the same with every build. Building twice and getting different results should not be normal. So I'd expect the entries to be properly listed also on the first build.

Other relevant information: webpack version: 5.17 Node.js version: 12.16.3 Operating System: MacOS Catalina Additional tools: yarn, shell

alexander-akait commented 3 years ago

Something creates after first build, please provide reproducible test repo

alexander-akait commented 3 years ago

I think here concurrency problem, one compiler depend on files from other compiler, so you need to run builds in series, no magic we have here, I see STORE_MANIFEST in your configuration, so when you run firstly STORE_MANIFEST is empty, in second run you have STORE_MANIFEST from previous run, feel free to feedback