pmmmwh / react-refresh-webpack-plugin

A Webpack plugin to enable "Fast Refresh" (also previously known as Hot Reloading) for React components.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Integration problem when using with ts-loader and any loader ahead of it

RoB8080 opened this issue · comments

This problem is related to ts-loader's watch run logic.

If there is any loader runs before ts-loader when HMR, it will call loader.loaderModule to manually load file and process it. This is the source code, you can also refer to fragment below.

Then this plugin will inject a loader in afterResolve hook, which makes the final loaders be like [refreshLoader, stringifyLoader, loaderBeforeTsLoader].

The result is a JSON string wrapped by refresh code, which ts-loader can't handle.

I think add a check logic can solve this problem, but not sure if there is any performance or compatibility concern.

if (
  // current conditions
  // this will make sure it's not triggered by ts-loader watch-run
  && !moduleData.loaders.some(({ loader }) => loader.endsWith('ts-loader/dist/stringify-loader.js'))
) {
  moduleData.loaders.unshift({
    loader: resolvedLoader,
    options,
  });
}

ts-loader source code

function updateFile(
  instance: TSInstance,
  key: FilePathKey,
  filePath: string,
  loader: webpack.LoaderContext<LoaderOptions>,
  loaderIndex: number
) {
  return new Promise<void>((resolve, reject) => {
    // When other loaders are specified after ts-loader
    // (e.g. `{ test: /\.ts$/, use: ['ts-loader', 'other-loader'] }`),
    // manually apply them to TypeScript files.
    // Otherwise, files not 'preprocessed' by them may cause complication errors (#1111).
    if (
      loaderIndex + 1 < loader.loaders.length &&
      instance.rootFileNames.has(path.normalize(filePath))
    ) {
      let request = `!!${path.resolve(__dirname, 'stringify-loader.js')}!`;
      for (let i = loaderIndex + 1; i < loader.loaders.length; ++i) {
        request += loader.loaders[i].request + '!';
      }
      request += filePath;
      loader.loadModule(request, (err, source) => {
        if (err) {
          reject(err);
        } else {
          const text = JSON.parse(source);
          updateFileWithText(instance, key, filePath, () => text);
          resolve();
        }
      });
    } else {
      updateFileWithText(
        instance,
        key,
        filePath,
        nFilePath => fsReadFile(nFilePath) || ''
      );
      resolve();
    }
  });
}

@RoB8080 Can you create small reproducible test repo? Maybe it will be better to improve on ts-loader side

Issue seems to be resolved with the latest versions of ts-loader