TypeStrong/fork-ts-checker-webpack-plugin

Getting ERROR in compiler.getInfrastructureLogger is not a function

urig-40seas opened this issue · 3 comments

Current behavior

I have a React application that exists within a monorepo managed by NX. I build the application using the command npx webpack --config webpack.browser.config.js, and I have attached my webpack.browser.config.js file below.

The build process works smoothly, but when I tried to add ForkTsCheckerWebpackPlugin, the build failed with the error message: ERROR in compiler.getInfrastructureLogger is not a function. I searched the web and found that this issue may be related to having multiple webpacks installed, but since webpack is installed by NX and is also needed for other projects, I am not sure how to proceed.

Has anyone else experienced this issue? Do you have any ideas for remediation?

Environment

  • fork-ts-checker-webpack-plugin: 8.0.0

  • (btw, seems like I have several more installed)
    ├─┬ @nrwl/cypress@14.5.10
    │ └── fork-ts-checker-webpack-plugin@7.2.13
    ├─┬ @nrwl/node@14.4.3
    │ └── fork-ts-checker-webpack-plugin@6.2.10
    ├─┬ @nrwl/web@14.5.10
    │ └── fork-ts-checker-webpack-plugin@7.2.13
    └── fork-ts-checker-webpack-plugin@8.0.0

  • typescript: 4.7.4

  • os: Mac Os Ventura 13.2.1

  • webpack: 5.74.0

  • webpack-cli: 4.10.0

  • webpack-dev-server 4.15.0

webpack config

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { StatsWriterPlugin } = require('webpack-stats-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const { HotModuleReplacementPlugin } = require('webpack');

module.exports = (env) => {
    const isOffline = env?.production ? env?.production === false : true;

    return {
        entry: {
            main: path.join(__dirname, 'src/browser/index.tsx'),
        },
        target: 'web',
        mode: isOffline ? 'development' : 'production',
        node: {
            __dirname: true,
            __filename: true,
        },
        devServer: {
            port: 5050,
            hot: true,
            headers: {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
                'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
            },
            watchFiles: {
                paths: ['**/*'],
                options: {
                    ignored: ['**/node_modules', '**/dist', '**/.webpack', '**/.serverless'],
                },
            },
            devMiddleware: {
                writeToDisk: (filePath) => {
                    // Always write the stats.json to disk, so we can load it in code
                    return /\bstats\.json$/.test(filePath);
                },
            },
        },
        performance: {
            // Turn off size warnings for entry points
            hints: false,
        },
        optimization: {
            runtimeChunk: 'single',
            splitChunks: {
                cacheGroups: {
                    // TODO: Customize code splitting to your needs
                    vendor: {
                        name: 'vendor',
                        test: /[\\/]node_modules[\\/]/,
                        chunks: 'all',
                    },
                    components: {
                        name: 'components',
                        test: /[\\/]src[\\/]components[\\/]/,
                        chunks: 'all',
                        minSize: 0,
                    },
                },
            },
        },
        // React recommends `cheap-module-source-map` for development
        devtool: isOffline ? 'cheap-module-source-map' : 'nosources-source-map',
        plugins: [
            new CleanWebpackPlugin(),
            new CopyWebpackPlugin({
                patterns: [
                    {
                        // Copy content from `./public/` folder to our output directory
                        context: './public/',
                        from: '**/*',
                    },
                ],
            }),
            new MiniCssExtractPlugin({
                filename: isOffline ? '[name].css' : '[name].[contenthash:8].css',
            }),
            new StatsWriterPlugin({
                filename: 'stats.json',
                transform(data, _opts) {
                    const assets = data.assetsByChunkName;
                    const stats = JSON.stringify(
                        {
                            scripts: Object.entries(assets).flatMap(([_asset, files]) => {
                                return files.filter((filename) => filename.endsWith('.js') && !/\.hot-update\./.test(filename));
                            }),
                            styles: Object.entries(assets).flatMap(([_asset, files]) => {
                                return files.filter((filename) => filename.endsWith('.css') && !/\.hot-update\./.test(filename));
                            }),
                        },
                        null,
                        2,
                    );
                    return stats;
                },
            }),
            isOffline && new HotModuleReplacementPlugin(),
        ].filter(Boolean),
        module: {
            rules: [
                {
                    test: /\.(ts|js)x?$/,
                    loader: 'esbuild-loader',
                    options: {
                        target: 'es2015', // Syntax to compile to (see options below for possible values)
                    },
                },
                {
                    test: /\.css$/,
                    use: [MiniCssExtractPlugin.loader, 'css-loader'],
                },
                {
                    test: /\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: { limit: 8192 },
                        },
                    ],
                },
            ],
        },
        resolve: {
            // TsconfigPathsPlugin applies the path aliases defined in `.tsconfig.json`
             // 🚨 with new ForkTsCheckerWebpackPlugin() we fail with 'ERROR in compiler.getInfrastructureLogger is not a function'
             // 🚨 when removing it the build works
            plugins: [new TsconfigPathsPlugin(), new ForkTsCheckerWebpackPlugin()],
            extensions: ['.browser.tsx', '.browser.ts', '.browser.jsx', '.browser.js', '.tsx', '.ts', '.jsx', '.js'],
        },
        output: {
            path: path.join(__dirname, 'dist'),
            filename: isOffline ? '[name].js' : '[name].[contenthash:8].js',
            crossOriginLoading: 'anonymous', // enable cross-origin loading of chunks
        },
    };
};

same issue, the mini re-product is :

node -v
v18.15.0
yarn -v
3.6.1

{
  "name": "AAAAA",
  "private": true,
  "scripts": {
    "build:watch": "tsc --watch",
    "webpack:watch": "webpack --watch"
  },
  "packageManager": "yarn@3.6.1",
  "dependencies": {
    "fork-ts-checker-webpack-plugin": "^8.0.0",
    "ts-loader": "^9.4.4",
    "tsconfig-paths-webpack-plugin": "^4.1.0",
    "typescript": "^5.1.6",
    "webpack": "^5.88.2",
    "webpack-cli": "^5.1.4"
  }
}
const path = require('path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  mode: "development",
  devtool: "inline-source-map",
  entry: {
    server: './src/server/0.ts',
    web: './src/web/1.ts',
  },
  output: {
    filename: './dist/[name]/[name].js',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    // Add `.ts` and `.tsx` as a resolvable extension.
    extensions: [".ts", ".tsx", ".js"],
    plugins: [
      // new TsconfigPathsPlugin({configFile: "./tsconfig.json"}),
      new ForkTsCheckerWebpackPlugin(),
    ],
  },
  module: {
    rules: [
      // all files with a `.ts`, `.cts`, `.mts` or `.tsx` extension will be handled by `ts-loader`
      {
        test: /\.([cm]?ts|tsx)$/, loader: "ts-loader" ,
        // use: [
        //   {
        //     loader: 'ts-loader',
        //     options: {
        //       transpileOnly: true
        //     }
        //   }
        // ]
      }
    ]
  },
  // watchOptions: {
  //   // for some systems, watching many files can result in a lot of CPU or memory usage
  //   // https://webpack.js.org/configuration/watch/#watchoptionsignored
  //   // don't use this pattern, if you have a monorepo with linked packages
  //   ignored: /node_modules/,
  // },
};

You are including ForkTsCheckerWebpackPlugin in the wrong place. It needs to be outside the "resolve" property, as seen in the docs examples: https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/blob/main/examples/babel-loader/webpack.config.js

WRONG:

module.exports = {
  mode: "development",
  devtool: "inline-source-map",
  resolve: {
    // Add `.ts` and `.tsx` as a resolvable extension.
    extensions: [".ts", ".tsx", ".js"],
    plugins: [
      new ForkTsCheckerWebpackPlugin(),
    ],
  },
};

GOOD:

module.exports = {
  mode: "development",
  devtool: "inline-source-map",
  resolve: {
    // Add `.ts` and `.tsx` as a resolvable extension.
    extensions: [".ts", ".tsx", ".js"],
    plugins: [],
  },
  plugins: [
      new ForkTsCheckerWebpackPlugin(),
    ]
};

Thanks @AlesioSinopoli for the answer 👍