Tuesday, 14 December 2021

Why does this webpack 4 config not work with webpack 5 and how do I fix it?

I have the following config that works perfectly for webpack 4. I had to upgrade to webpack 5 for reasons outside of my control and now I can't get some of the files loaded. I think there may be something wrong between the CopyWebpackPlugin and whatever resolves urls and such for scss files.

If you want to have a go yourselves, be my guests: https://github.com/isaacphysics/isaac-react-app/tree/update-dependencies I found multiple deps conflicts while updating some dependencies so I figured I'd rebuild the whole list from scratch and see if I could optimize it.

Anyway, here's the config:

webpack.config.common.js

/* eslint-disable */
const path = require('path');
const BASE_DIRECTORY = path.resolve(__dirname, "..");
const resolve = (p) => path.resolve(BASE_DIRECTORY, p);
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');

// Read in the .env file and put into `process.env`:
require('dotenv').config();

module.exports = (isProd) => {

    return {
        stats: {
            errorDetails: true
        },
        
        mode: isProd ? "production" : "development",

        devServer: {
            headers: {
                "Content-Security-Policy-Report-Only": "default-src 'self' https://cdn.isaacphysics.org https://cdn.isaaccomputerscience.org localhost:8080 ws://localhost:8080 https://www.google-analytics.com https://maps.googleapis.com; object-src 'none'; frame-src 'self' https://anvil.works https://*.anvil.app https://www.youtube-nocookie.com; img-src 'self' localhost:8080 data: https://cdn.isaacphysics.org https://cdn.isaaccomputerscience.org https://www.google-analytics.com https://i.ytimg.com https://maps.googleapis.com https://maps.gstatic.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://cdn.isaacphysics.org https://cdn.isaaccomputerscience.org https://fonts.gstatic.com;",
                "Feature-Policy": "geolocation 'none'; camera 'none'; microphone 'none'; accelerometer 'none';",
                "X-Clacks-Overhead": "GNU Terry Pratchett",
            },
        },

        output: {
            publicPath: "/",
            pathinfo: !isProd,
            filename: isProd ? 'static/js/[name].[contenthash:8].js' : 'static/js/[name].js',
            chunkFilename: isProd ? 'static/js/[name].[contenthash:8].chunk.js' : 'static/js/[name].chunk.js',
        },

        resolve: {
            modules: [path.resolve(__dirname), 'node_modules'],
            extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs'],
            alias: {
                'p5': 'p5/lib/p5.min.js'
            }
        },

        module: {
            rules: [
                {
                    oneOf: [
                        {
                            test: /\.mjs$/,
                            include: /node_modules/,
                            type: 'javascript/auto'
                        },
                        {
                            test: /\.[jt]sx?$/,
                            exclude: /node_modules/,
                            use: [
                                {
                                    loader: 'babel-loader',
                                    options: {
                                        presets: ["@babel/preset-env", "@babel/preset-react"],
                                        plugins: [
                                          "@babel/plugin-proposal-class-properties",
                                          "@babel/plugin-transform-classes"
                                        ]
                                    }
                                },
                                {
                                    loader: 'ts-loader',
                                    options: {
                                        compilerOptions: {
                                            noEmit: false,
                                            jsx: "react",
                                        },
                                    },
                                }
                            ],
                        },
                        {
                            test: /node_modules[\/\\](query-string|split-on-first|strict-uri-encode|d3.*)[\/\\].*\.js$/,
                            use: [
                                {
                                    loader: 'babel-loader',
                                    options: {
                                        presets: ["@babel/preset-env"],
                                        plugins: ["@babel/plugin-transform-modules-commonjs"]
                                    }
                                },
                            ],
                        },
                        {
                            test: /\.scss$/,
                            use: [
                                'style-loader',
                                isProd ? { loader: MiniCssExtractPlugin.loader, options: { esModule: false } } : null,
                                'css-loader',
                                'sass-loader',
                            ].filter(Boolean),
                        },
                        {
                            include: [/\.ttf$/, /\.woff2?$/,],
                            use: {
                                loader: 'file-loader',
                                options: {
                                    name: isProd ? 'static/fonts/[name].[contenthash:8].[ext]' : 'static/fonts/[name].[ext]',
                                },
                            },
                        },
                    ],
                },
            ],
        },

        optimization: {
            splitChunks: {
                chunks: "all",
            },
            runtimeChunk: true,
            minimizer: [
                new TerserPlugin({
                    terserOptions: {
                        safari10: true,
                    },
                }),
            ],
        },

        devtool : "source-map",

        plugins: [
            isProd ? new CleanWebpackPlugin() : null, // Clear the build directory before writing output of a successful build.
            new MiniCssExtractPlugin({
                filename: isProd ? 'static/css/[name].[contenthash:8].css' : 'static/css/[name].css',
                chunkFilename: isProd ? 'static/css/[name].[contenthash:8].chunk.css' : 'static/css/[name].chunk.css',
            }),
            new CopyWebpackPlugin({
                patterns: [{
                    from: resolve('public/assets'),
                    to: 'assets',
                }
            ]}),
            new webpack.DefinePlugin({
                REACT_APP_API_VERSION: `"${process.env.REACT_APP_API_VERSION}"`,
                ENV_QUIZ_FEATURE_FLAG: process.env.QUIZ_FEATURE && process.env.QUIZ_FEATURE.trim() === "true",
            }),
        ].filter(Boolean),
    };
};

webpack.config.cs.js

/* eslint-disable */
const path = require('path');
const BASE_DIRECTORY = path.resolve(__dirname, "..");
const resolve = (p) => path.resolve(BASE_DIRECTORY, p);
const HtmlWebpackPlugin = require('html-webpack-plugin');
const configCommon = require('./webpack.config.common');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { merge } = require('webpack-merge');
const webpack = require('webpack');

module.exports = env => {

    let isProd = env === "prod";

    let configCS = {
        entry: {
            'isaac-cs': [resolve('src/index-cs')],
        },

        output: {
            path: resolve(`build-cs`),
        },

        plugins: [
            new HtmlWebpackPlugin({
                template: 'public/index-cs.html',
            }),
            new webpack.DefinePlugin({
                ISAAC_SITE: '"cs"',
            }),
            new CopyWebpackPlugin({
                patterns: [{
                    from: resolve('public/manifest-cs.json'),
                    to: 'manifest-cs.json',
                }, {
                    from: resolve('public/unsupported_browsers/unsupported-cs.html'),
                    to: 'unsupported_browser.html',
                }, {
                    from: resolve('public/unsupported_browsers/unsupported-cs.js'),
                    to: 'unsupported_browser.js',
                }]
            }),
        ],
    };

    return merge(configCommon(isProd), configCS);
};

Whenever I run

$ webpack-dev-server --hot --port 8004 --history-api-fallback --config config/webpack.config.cs.js --allowed-hosts=true

or build

webpack --env prod --config config/webpack.config.cs.js

I end up with loads of errors such this:

ERROR in ./src/scss/cs/isaac.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/scss/cs/isaac.scss) 19:37-109
Module not found: Error: Can't resolve '/assets/google-login-sprite-dark-pressed.png' in '/Users/morpheu5/src/isaac/isaac-react-app/src/scss/cs'
resolve '/assets/google-login-sprite-dark-pressed.png' in '/Users/morpheu5/src/isaac/isaac-react-app/src/scss/cs'
  using description file: /Users/morpheu5/src/isaac/isaac-react-app/package.json (relative path: ./src/scss/cs)
    No description file found in /assets or above
    no extension
      /assets/google-login-sprite-dark-pressed.png doesn't exist
    .ts
      /assets/google-login-sprite-dark-pressed.png.ts doesn't exist
    .tsx
      /assets/google-login-sprite-dark-pressed.png.tsx doesn't exist
    .js
      /assets/google-login-sprite-dark-pressed.png.js doesn't exist
    .jsx
      /assets/google-login-sprite-dark-pressed.png.jsx doesn't exist
    .mjs
      /assets/google-login-sprite-dark-pressed.png.mjs doesn't exist
    as directory
      /assets/google-login-sprite-dark-pressed.png doesn't exist
    root path /Users/morpheu5/src/isaac/isaac-react-app
      using description file: /Users/morpheu5/src/isaac/isaac-react-app/package.json (relative path: ./assets/google-login-sprite-dark-pressed.png)
        no extension
          /Users/morpheu5/src/isaac/isaac-react-app/assets/google-login-sprite-dark-pressed.png doesn't exist
        .ts
          /Users/morpheu5/src/isaac/isaac-react-app/assets/google-login-sprite-dark-pressed.png.ts doesn't exist
        .tsx
          /Users/morpheu5/src/isaac/isaac-react-app/assets/google-login-sprite-dark-pressed.png.tsx doesn't exist
        .js
          /Users/morpheu5/src/isaac/isaac-react-app/assets/google-login-sprite-dark-pressed.png.js doesn't exist
        .jsx
          /Users/morpheu5/src/isaac/isaac-react-app/assets/google-login-sprite-dark-pressed.png.jsx doesn't exist
        .mjs
          /Users/morpheu5/src/isaac/isaac-react-app/assets/google-login-sprite-dark-pressed.png.mjs doesn't exist
        as directory
          /Users/morpheu5/src/isaac/isaac-react-app/assets/google-login-sprite-dark-pressed.png doesn't exist
 @ ./src/scss/cs/isaac.scss 8:6-152 22:17-24 26:7-21 58:25-39 59:36-47 59:50-64 63:6-73:7 64:54-65 64:68-82 70:42-53 70:56-70 72:21-28 83:0-122 83:0-122 84:22-29 84:33-47 84:50-64 61:4-74:5
 @ ./src/index-cs.tsx 3:0-30

Those assets are loaded through url(/assets/...) statements in scss files. I'm using sass (the Dart version) in case it may be relevant.



from Why does this webpack 4 config not work with webpack 5 and how do I fix it?

No comments:

Post a Comment