@@ -3,14 +3,25 @@ const webpack = require('webpack');
33const { createRefreshTemplate, injectRefreshEntry } = require ( './helpers' ) ;
44const { refreshUtils } = require ( './runtime/globals' ) ;
55
6+ /**
7+ * @typedef {Object } ReactRefreshPluginOptions
8+ * @property {boolean } [disableRefreshCheck] A flag to disable detection of the react-refresh Babel plugin.
9+ * @property {boolean } [forceEnable] A flag to enable the plugin forcefully.
10+ */
11+
12+ /** @type {ReactRefreshPluginOptions } */
13+ const defaultOptions = {
14+ disableRefreshCheck : false ,
15+ forceEnable : false ,
16+ } ;
17+
618class ReactRefreshPlugin {
719 /**
8- * @param {* } [options] Options for react-refresh-plugin.
9- * @param {boolean } [options.forceEnable] A flag to enable the plugin forcefully.
20+ * @param {ReactRefreshPluginOptions } [options] Options for react-refresh-plugin.
1021 * @returns {void }
1122 */
1223 constructor ( options ) {
13- this . options = options || { } ;
24+ this . options = Object . assign ( defaultOptions , options ) ;
1425 }
1526
1627 /**
@@ -59,11 +70,14 @@ class ReactRefreshPlugin {
5970 / \. ( [ j t ] s x ? | f l o w ) $ / . test ( data . resource ) &&
6071 // Skip all files from node_modules
6172 ! / n o d e _ m o d u l e s / . test ( data . resource ) &&
62- // Skip runtime refresh utilities (to prevent self-referencing)
73+ // Skip files related to refresh runtime (to prevent self-referencing)
6374 // This is useful when using the plugin as a direct dependency
64- data . resource !== path . join ( __dirname , './runtime/utils.js' )
75+ ! data . resource . includes ( path . join ( __dirname , './runtime' ) )
6576 ) {
66- data . loaders . unshift ( require . resolve ( './loader' ) ) ;
77+ data . loaders . unshift ( {
78+ loader : require . resolve ( './loader' ) ,
79+ options : undefined ,
80+ } ) ;
6781 }
6882
6983 return data ;
@@ -76,6 +90,33 @@ class ReactRefreshPlugin {
7690 // Constructs the correct module template for react-refresh
7791 createRefreshTemplate
7892 ) ;
93+
94+ compilation . hooks . finishModules . tap ( this . constructor . name , modules => {
95+ if ( ! this . options . disableRefreshCheck ) {
96+ const refreshPluginInjection = / \$ R e f r e s h R e g \$ / ;
97+ const RefreshDetectionModule = modules . find (
98+ module => module . resource === require . resolve ( './runtime/BabelDetectComponent.js' )
99+ ) ;
100+
101+ // In most cases, if we cannot find the injected detection module,
102+ // there are other compilation instances injected by other plugins.
103+ // We will have to bail out in those cases.
104+ if ( ! RefreshDetectionModule ) {
105+ return ;
106+ }
107+
108+ // Check for the function transform by the Babel plugin.
109+ if ( ! refreshPluginInjection . test ( RefreshDetectionModule . _source . source ( ) ) ) {
110+ throw new Error (
111+ [
112+ 'The plugin is unable to detect transformed code from react-refresh.' ,
113+ 'Did you forget to include "react-refresh/babel" in your list of Babel plugins?' ,
114+ 'Note: you can disable this check by setting "disableRefreshCheck: true".' ,
115+ ] . join ( ' ' )
116+ ) ;
117+ }
118+ }
119+ } ) ;
79120 } ) ;
80121 }
81122}
0 commit comments