webpack / webpack-dev-server

Serves a webpack app. Updates the browser on changes. Documentation https://webpack.js.org/configuration/dev-server/.
MIT License
7.78k stars 1.43k forks source link

ModuleNotFoundError with hard crash on file rename/move/delete #5256

Closed NathZ1 closed 3 weeks ago

NathZ1 commented 1 month ago

Bug report

I renamed a file in my project called Table.tsx to Table2.tsx file webpack-dev-server was running. This consistancy causes the crash to occur. Happens with rename/move/delete of any file within project src.

error from IDE console:

<e> [webpack-dev-middleware] ModuleNotFoundError: Module not found: Error: Can't resolve './Table' in 'C:\dev\shifts\shifts\src\pages\teamConfig\allocations'
<e>     at C:\dev\shifts\shifts\node_modules\webpack\lib\Compilation.js:2100:28
<e>     at C:\dev\shifts\shifts\node_modules\webpack\lib\NormalModuleFactory.js:904:13
<e>     at eval (eval at create (C:\dev\shifts\shifts\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:10:1)
<e>     at C:\dev\shifts\shifts\node_modules\webpack\lib\NormalModuleFactory.js:341:22
<e>     at eval (eval at create (C:\dev\shifts\shifts\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:9:1)
<e>     at C:\dev\shifts\shifts\node_modules\webpack\lib\NormalModuleFactory.js:518:22
<e>     at C:\dev\shifts\shifts\node_modules\webpack\lib\NormalModuleFactory.js:151:11
<e>     at C:\dev\shifts\shifts\node_modules\webpack\lib\NormalModuleFactory.js:776:25
<e>     at C:\dev\shifts\shifts\node_modules\webpack\lib\NormalModuleFactory.js:988:8
<e>     at C:\dev\shifts\shifts\node_modules\webpack\lib\NormalModuleFactory.js:1118:5
<e> resolve './Table' in 'C:\dev\shifts\shifts\src\pages\teamConfig\allocations'
<e>   using description file: C:\dev\shifts\shifts\package.json (relative path: ./src/pages/teamConfig/allocations)
<e>     Field 'browser' doesn't contain a valid alias configuration
<e>     using description file: C:\dev\shifts\shifts\package.json (relative path: ./src/pages/teamConfig/allocations/Table)
<e>       no extension
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table doesn't exist
<e>       .ts
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.ts doesn't exist
<e>       .tsx
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.tsx doesn't exist
<e>       .js
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.js doesn't exist
<e>       as directory
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table doesn't exist
<e>       .tsx
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.tsx doesn't exist
<e>       .js
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.js doesn't exist
<e>       .tsx
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.tsx doesn't exist
<e>       .js
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>       .tsx
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.tsx doesn't exist
<e>       .js
<e>       .tsx
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>       .tsx
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>       .tsx
<e>       .tsx
<e>       .tsx
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.tsx doesn't exist
<e>       .js
<e>         Field 'browser' doesn't contain a valid alias configuration
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table.js doesn't exist
<e>       as directory
<e>         C:\dev\shifts\shifts\src\pages\teamConfig\allocations\Table doesn't exist

Actual Behavior

Webpack-dev-server crashes when a file is renamed/deleted/moved etc. I'm not sure if this is a regression, but in a previous project it would throw an error in the console and the client but the server wouldn't crash.

Expected Behavior

It should throw an error saying the file is missing, but the server should continue to function without having to kill and restart.

How Do We Reproduce?

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "src",
    "target": "es2015",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "outDir": "dist",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": false, //need to emit as using fork-ts-checker-webpack-plugin
    "sourceMap": true,
    "jsx": "react-jsx"
  },
  "files": ["webpack.config.ts"],
  "include": [
    "src",
    "tests"  ],
  "ts-node": {
    "compilerOptions": {
      "module": "CommonJS"
    }
  }
}

webpack.config.ts:

import webpack from 'webpack'
import { relative, resolve } from 'path'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'
import TerserPlugin from 'terser-webpack-plugin'
import CopyWebpackPlugin from 'copy-webpack-plugin'
import ESLintPlugin from 'eslint-webpack-plugin'
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'
import ReactRefreshTypeScript from 'react-refresh-typescript'
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
import getPublicUrlOrPath from 'react-dev-utils/getPublicUrlOrPath'
import { WebpackManifestPlugin } from 'webpack-manifest-plugin'

module.exports = (env: { APP_BUILD?: string; FUNCTION_APP?: string }) => {
  //get PUBLIC_URL, which is needed for production builds where process (which is a Node server var), doesn't exist
  const publicUrlOrPath = getPublicUrlOrPath(process.env.NODE_ENV === 'development', undefined, process.env.PUBLIC_URL)

  //set whether are creating source maps with prod builds
  const genSourceMaps: boolean = true

  const prod = process.env.NODE_ENV === 'production'

  return {
    mode: prod ? 'production' : 'development',
    cache: { type: 'filesystem' },
    infrastructureLogging: { level: 'info' },
    stats: 'normal',
    devtool: !prod ? (genSourceMaps ? 'source-map' : false) : false, 
    bail: true,
    resolve: {
      modules: [resolve(__dirname, 'node_modules'), resolve(__dirname, './src')]
    },
    entry: './src/index.tsx',
    output: {
      path: resolve(__dirname, 'build'),
      publicPath: publicUrlOrPath,
      filename: prod ? '[name].[contenthash:8].js' : undefined,
      chunkFilename: prod ? '[name].[contenthash:8].chunk.js' : undefined,
      assetModuleFilename: 'media/[name].[hash][ext]',
      clean: true, //clears the output dir prior to building

      // Point sourcemap entries to original disk location (format as URL on Windows)
      devtoolModuleFilenameTemplate: (info: any) => {
        if (prod) return relative('./src', info.absoluteResourcePath).replace(/\\/g, '/')
        else return resolve(info.absoluteResourcePath).replace(/\\/g, '/')
      }
    },
    devServer: {
      port: '3000',
      static: ['./public'],
      open: true,
      hot: true,
      historyApiFallback: true,
      client: {
        overlay: {
          errors: true,
          warnings: false,
          runtimeErrors: true
        },
        reconnect: 5 //TEST ONLY
      },
      devMiddleware: {
        publicPath: publicUrlOrPath,
        writeToDisk: true //massively speeds up loading of dev server
      }
    },
    module: {
      rules: [
        //Typescript loader
        //NOTE: uses fork-ts-checker-webpack-plugin for TS checking in dev on a separate thread
        {
          test: /\.([cm]?ts|tsx)$/,
          exclude: /node_modules/,
          resolve: {
            extensions: ['.ts', '.tsx', '.js']
          },

          use: [
            {
              loader: require.resolve('ts-loader'),
              options: {
                getCustomTransformers: () => ({
                  before: [!prod && ReactRefreshTypeScript()].filter(Boolean)
                }),
                transpileOnly: !prod
              }
            }
          ]
        },

        //CSS loaders
        {
          test: /\.css$/,
          exclude: /node_modules/,
          use: [
            //In prod, MiniCSSExtractPlugin extract CSS to file(s), but in development "style" loader enables hot editing of CSS.
            prod && MiniCssExtractPlugin.loader,

            //style loader turns CSS into JS modules that inject <style> tags
            !prod && require.resolve('style-loader'),

            //css-loader resolves paths in CSS and adds assets as dependencies
            {
              loader: require.resolve('css-loader'),
              options: { sourceMap: genSourceMaps }
            },

            //postcss loader applies autoprefixer to CSS
            {
              loader: require.resolve('postcss-loader'),
              options: { sourceMap: genSourceMaps }
            }
          ].filter(Boolean),
          sideEffects: true //See https://github.com/webpack/webpack/issues/6571
        }
      ].filter(Boolean)
    },
    plugins: [
      //Generates an `index.html` file with the <script> injected.
      new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html' }),

      //Copies the public directory into the root of build directory
      new CopyWebpackPlugin({ patterns: [{ from: 'public' }] }),

      //Makes environment variables available to the build code
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: JSON.stringify(process.env.NODE_ENV),
          PUBLIC_URL: JSON.stringify(publicUrlOrPath.slice(0, -1)),
          APP_BUILD: JSON.stringify(env.APP_BUILD),
          FUNCTION_APP: JSON.stringify(env.FUNCTION_APP)
        }
      }),

      ...(prod
        ? [
            //Extracts CSS into separate files
            new MiniCssExtractPlugin({
              filename: '[name].[contenthash:8].css',
              chunkFilename: '[name].[contenthash:8].chunk.css'
            }),

            // Generate an asset manifest file
            new WebpackManifestPlugin({
              fileName: 'asset-manifest.json',
              publicPath: publicUrlOrPath,
              generate: (seed, files, entrypoints) => {
                const manifestFiles = files.reduce((manifest, file) => {
                  manifest[file.name] = file.path
                  return manifest
                }, seed)

                const entrypointFiles = entrypoints.main.filter(fileName => !fileName.endsWith('.map'))

                return {
                  files: manifestFiles,
                  entrypoints: entrypointFiles
                }
              }
            })
          ]
        : []),

      ...(!prod
        ? [
            //Checks code for issues with eslint
            new ESLintPlugin({ extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'] }),

            //Enables new React hot reloading in dev builds
            new ReactRefreshWebpackPlugin(),

            //Used for TS checking - does the checks on a separate process to the build
            //NOTE: This plugin uses TypeScript's, not Webpack's modules resolution (i.e. uses tsconfig.json)
            new ForkTsCheckerWebpackPlugin()
          ]
        : [])
    ],
    optimization: {
      nodeEnv: false, //do not modify/set the value of process.env.NODE_ENV as this is done by DefinePlugin
      minimizer: [
        //minimise JS
        new TerserPlugin({
          extractComments: false,
          terserOptions: {
            format: {
              comments: false
            }
          }
        }),

        //minimise CSS
        new CssMinimizerPlugin()
      ]
    }
  }
}

Please paste the results of npx webpack-cli info here, and mention other relevant information

System: OS: Windows 10 10.0.19045 CPU: (12) x64 12th Gen Intel(R) Core(TM) i7-1255U Memory: 2.40 GB / 15.59 GB Binaries: Node: 20.11.1 - C:\Program Files\nodejs\node.EXE npm: 10.2.4 - C:\Program Files\nodejs\npm.CMD Browsers: Edge: Chromium (127.0.2651.74) Internet Explorer: 11.0.19041.4355 Packages: copy-webpack-plugin: ^12.0.2 => 12.0.2 css-loader: ^7.1.1 => 7.1.2 css-minimizer-webpack-plugin: ^6.0.0 => 6.0.0 eslint-webpack-plugin: ^4.0.1 => 4.2.0 fork-ts-checker-webpack-plugin: ^9.0.0 => 9.0.2 html-webpack-plugin: ^5.5.1 => 5.6.0 postcss-loader: ^8.1.0 => 8.1.1 source-map-loader: ^5.0.0 => 5.0.0 style-loader: ^4.0.0 => 4.0.0 ts-loader: ^9.4.2 => 9.5.1 webpack: ^5.81.0 => 5.93.0 webpack-bundle-analyzer: ^4.9.0 => 4.10.2 webpack-cli: ^5.0.2 => 5.1.4 webpack-dev-server: ^5.0.4 => 5.0.4 webpack-manifest-plugin: ^5.0.0 => 5.0.0 workbox-webpack-plugin: ^7.0.0 => 7.1.0

alexander-akait commented 1 month ago

Sounds like a duplicate of https://github.com/webpack/enhanced-resolve/issues/395

NathZ1 commented 1 month ago

Hi @alexander-akait, thank you for your reply. I have reviewed the issue you linked, but I don't think it is the same issue. I am not using enhanced-resolve at all.

I have now created a small public repo where you can demo the issue -

https://github.com/NathZ1/webpack-dev-server-error-repo

Simply npm install, npm start, then rename the file 'src/FileToRename.tsx' and you should see the same webpack-dev-server crash as I am experiencing.

alexander-akait commented 3 weeks ago

Don't use bail: true https://webpack.js.org/configuration/other-options/#bail, we have a tip about it. Bail stop any other compilations when the first error happend.

Avoid using bail option in watch mode, as it will force webpack to exit as soon as possible when an error is found.

NathZ1 commented 3 weeks ago

Ahh of course!! Apologies for taking up your time. Cheers