stephencookdev / speed-measure-webpack-plugin

⏱ See how fast (or not) your plugins and loaders are, so you can optimise your builds
MIT License
2.4k stars 80 forks source link

It doesn't work with CRA. But I found a tweak ! #185

Open Ricola3D opened 2 years ago

Ricola3D commented 2 years ago

Unfortunately the default SpeedMeasurePlugin does not work with CRA.

Indeed I found the following issues:

But after several hours of research, and disabling the features that provokes bugs, I made an overload that works with CRA ! I measures almost all the build and works.

See the code below:

/* eslint-disable no-param-reassign */
/* eslint-disable import/no-extraneous-dependencies */
const webpack = require('webpack')

const ProgressBarPlugin = require('progress-bar-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const { WrappedPlugin } = require('speed-measure-webpack-plugin/WrappedPlugin')

// const HtmlWebpackPlugin = require('html-webpack-plugin')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ManifestPlugin = require('webpack-manifest-plugin')
// const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin')
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin')

/**
 * Measure build speed (override of the Github project working with CRA)
 * Documentation: https://github.com/stephencookdev/speed-measure-webpack-plugin
 */
class SpeedMeasurePluginForReactScripts extends SpeedMeasurePlugin {
  constructor(options) {
    super(options)

    this.wrap = this.wrap.bind(this)
  }

  wrap(config) {
    if (this.options.disable) return config
    if (Array.isArray(config)) return config.map(this.wrap)
    if (typeof config === 'function')
      return (...args) => this.wrap(config(...args))

    config.plugins = (config.plugins || []).map((plugin) => {
      const pluginName =
        Object.keys(this.options.pluginNames || {}).find(
          (name) => plugin === this.options.pluginNames[name]
        ) ||
        (plugin.constructor && plugin.constructor.name) ||
        '(unable to deduce plugin name)'

      if (
        plugin instanceof InlineChunkHtmlPlugin ||
        plugin instanceof ModuleNotFoundPlugin ||
        plugin instanceof webpack.DefinePlugin ||
        plugin instanceof webpack.HotModuleReplacementPlugin ||
        plugin instanceof CaseSensitivePathsPlugin ||
        plugin instanceof MiniCssExtractPlugin ||
        plugin instanceof ManifestPlugin ||
        plugin instanceof webpack.IgnorePlugin ||
        plugin instanceof WorkboxWebpackPlugin.InjectManifest ||
        plugin instanceof ESLintPlugin ||
        plugin instanceof UglifyJsPlugin ||
        plugin instanceof ProgressBarPlugin
      ) {
        return new WrappedPlugin(plugin, pluginName, this)
      }

      // ForkTsCheckerWebpackPlugin - STRANGE BEHAVIOUR WITH CRA: build seems ok, but console output stays stuck on "Files successfully emitted, waiting for typecheck results..."
      // ReactRefreshWebpackPlugin - NOT SURE IF IT WORKS WITH CRA
      // HtmlWebpackPlugin - DOES NOT WORK WITH CRA: "URIError: Failed to decode param '/%PUBLIC_URL%/*** */.js'"
      // InterpolateHtmlPlugin - DOES NOT WORK WITH CRA: "URIError: Failed to decode param '/%PUBLIC_URL%/*** */.js'"

      // By default all other plugins are not wrapped for measure
      return plugin
    })

    if (config.optimization && config.optimization.minimizer) {
      config.optimization.minimizer = config.optimization.minimizer.map(
        (plugin) => {
          return new WrappedPlugin(plugin, plugin.constructor.name, this)
        }
      )
    }

    // DOES NOT WORK WITH CRA: "./src/index.css Module build failed: Error: Final loader (./node_modules/speed-measure-webpack-plugin/loader.js) didn't return a Buffer or String"
    // if (config.module && this.options.granularLoaderData) {
    //   config.module = prependLoader(config.module)
    // }

    if (!this.smpPluginAdded) {
      config.plugins = config.plugins.concat(this)
      this.smpPluginAdded = true
    }

    return config
  }
}

/**
 * Measure build speed
 * Documentation: https://github.com/stephencookdev/speed-measure-webpack-plugin
 */
module.exports = new SpeedMeasurePluginForReactScripts({
  // If you want to compare deviation from previous builds
  // compareLoadersBuild: {
  //   filePath: './buildInfo.json',
  // },
  disable: process.env.MEASURE_WEBPACK_SPEED === 'false',
  // If you want granular loader data
  granularLoaderData: true,
  // If you want to see the top longest files to load
  loaderTopFiles: 10,
  outputFormat: 'humanVerbose',
})
jackykwandesign commented 1 year ago

i tried with CRA, react rewire and this config will disable react hot reload feature or should i add back the hot reload manually ?