diff --git a/lib/index.js b/lib/index.js index 98ca41f9..db5196ef 100644 --- a/lib/index.js +++ b/lib/index.js @@ -63,14 +63,12 @@ class ReactRefreshPlugin { } = webpack; // Inject react-refresh context to all Webpack entry points. - // This should create `EntryDependency` objects when available, - // and fallback to patching the `entry` object for legacy workflows. - const addEntries = getAdditionalEntries(this.options); + const { overlayEntries, prependEntries } = getAdditionalEntries(this.options); // Prepended entries does not care about injection order, // so we can utilise EntryPlugin for simpler logic. - addEntries.prependEntries.forEach((entry) => { + for (const entry of prependEntries) { new EntryPlugin(compiler.context, entry, { name: undefined }).apply(compiler); - }); + } const integrationEntry = getIntegrationEntry(this.options.overlay.sockIntegration); const socketEntryData = []; @@ -93,11 +91,11 @@ class ReactRefreshPlugin { // Overlay entries need to be injected AFTER integration's entry, // so we will loop through everything in `finishMake` instead of `make`. // This ensures we can traverse all entry points and inject stuff with the correct order. - for (const [idx, entry] of addEntries.overlayEntries.entries()) { + for (const [idx, entry] of overlayEntries.entries()) { compiler.hooks.finishMake.tapPromise( { name: this.constructor.name, - stage: Number.MIN_SAFE_INTEGER + (addEntries.overlayEntries.length - idx - 1), + stage: Number.MIN_SAFE_INTEGER + (overlayEntries.length - idx - 1), }, (compilation) => { // Only hook into the current compiler diff --git a/lib/utils/getRefreshGlobal.js b/lib/utils/getRefreshGlobal.js deleted file mode 100644 index b61c4e0c..00000000 --- a/lib/utils/getRefreshGlobal.js +++ /dev/null @@ -1,96 +0,0 @@ -const { getRefreshGlobalScope } = require('../globals'); - -/** - * @typedef {Object} RuntimeTemplate - * @property {function(string, string[]): string} basicFunction - * @property {function(): boolean} supportsConst - * @property {function(string, string=): string} returningFunction - */ - -/** - * Generates the refresh global runtime template. - * @param {import('webpack').Template} Template The template helpers. - * @param {Record} [RuntimeGlobals] The runtime globals. - * @param {RuntimeTemplate} [RuntimeTemplate] The runtime template helpers. - * @returns {string} The refresh global runtime template. - */ -function getRefreshGlobal( - Template, - RuntimeGlobals = {}, - RuntimeTemplate = { - basicFunction(args, body) { - return `function(${args}) {\n${Template.indent(body)}\n}`; - }, - supportsConst() { - return false; - }, - returningFunction(returnValue, args = '') { - return `function(${args}) { return ${returnValue}; }`; - }, - } -) { - const declaration = RuntimeTemplate.supportsConst() ? 'const' : 'var'; - const refreshGlobal = getRefreshGlobalScope(RuntimeGlobals); - return Template.asString([ - `${refreshGlobal} = {`, - Template.indent([ - // Lifecycle methods - They should be specific per module and restored after module execution. - // These stubs ensure unwanted calls (e.g. unsupported patterns, broken transform) would not error out. - // If the current module is processed by our loader, - // they will be swapped in place during module initialisation by the `setup` method below. - `register: ${RuntimeTemplate.returningFunction('undefined')},`, - `signature: ${RuntimeTemplate.returningFunction( - RuntimeTemplate.returningFunction('type', 'type') - )},`, - // Runtime - This should be a singleton and persist throughout the lifetime of the app. - // This stub ensures calls to `runtime` would not error out. - // If any module within the bundle is processed by our loader, - // it will be swapped in place via an injected import. - 'runtime: {', - Template.indent([ - `createSignatureFunctionForTransform: ${RuntimeTemplate.returningFunction( - RuntimeTemplate.returningFunction('type', 'type') - )},`, - `register: ${RuntimeTemplate.returningFunction('undefined')}`, - ]), - '},', - // Setup - This handles initialisation of the global runtime. - // It should never be touched throughout the lifetime of the app. - `setup: ${RuntimeTemplate.basicFunction('currentModuleId', [ - // Store all previous values for fields on `refreshGlobal` - - // this allows proper restoration in the `cleanup` phase. - `${declaration} prevModuleId = ${refreshGlobal}.moduleId;`, - `${declaration} prevRegister = ${refreshGlobal}.register;`, - `${declaration} prevSignature = ${refreshGlobal}.signature;`, - `${declaration} prevCleanup = ${refreshGlobal}.cleanup;`, - '', - `${refreshGlobal}.moduleId = currentModuleId;`, - '', - `${refreshGlobal}.register = ${RuntimeTemplate.basicFunction('type, id', [ - `${declaration} typeId = currentModuleId + " " + id;`, - `${refreshGlobal}.runtime.register(type, typeId);`, - ])}`, - '', - `${refreshGlobal}.signature = ${RuntimeTemplate.returningFunction( - `${refreshGlobal}.runtime.createSignatureFunctionForTransform()` - )};`, - '', - `${refreshGlobal}.cleanup = ${RuntimeTemplate.basicFunction('cleanupModuleId', [ - // Only cleanup if the module IDs match. - // In rare cases, it might get called in another module's `cleanup` phase. - 'if (currentModuleId === cleanupModuleId) {', - Template.indent([ - `${refreshGlobal}.moduleId = prevModuleId;`, - `${refreshGlobal}.register = prevRegister;`, - `${refreshGlobal}.signature = prevSignature;`, - `${refreshGlobal}.cleanup = prevCleanup;`, - ]), - '}', - ])}`, - ])}`, - ]), - '};', - ]); -} - -module.exports = getRefreshGlobal; diff --git a/lib/utils/index.js b/lib/utils/index.js index 1001544c..ebe6a367 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -1,8 +1,6 @@ const getAdditionalEntries = require('./getAdditionalEntries'); const getIntegrationEntry = require('./getIntegrationEntry'); -const getRefreshGlobal = require('./getRefreshGlobal'); const getSocketIntegration = require('./getSocketIntegration'); -const injectRefreshEntry = require('./injectRefreshEntry'); const injectRefreshLoader = require('./injectRefreshLoader'); const makeRefreshRuntimeModule = require('./makeRefreshRuntimeModule'); const normalizeOptions = require('./normalizeOptions'); @@ -10,9 +8,7 @@ const normalizeOptions = require('./normalizeOptions'); module.exports = { getAdditionalEntries, getIntegrationEntry, - getRefreshGlobal, getSocketIntegration, - injectRefreshEntry, injectRefreshLoader, makeRefreshRuntimeModule, normalizeOptions, diff --git a/lib/utils/injectRefreshEntry.js b/lib/utils/injectRefreshEntry.js deleted file mode 100644 index 66470237..00000000 --- a/lib/utils/injectRefreshEntry.js +++ /dev/null @@ -1,98 +0,0 @@ -/** @typedef {string | string[] | import('webpack').Entry} StaticEntry */ -/** @typedef {StaticEntry | import('webpack').EntryFunc} WebpackEntry */ - -const EntryParseError = new Error( - [ - '[ReactRefreshPlugin]', - 'Failed to parse the Webpack `entry` object!', - 'Please ensure the `entry` option in your Webpack config is specified.', - ].join(' ') -); - -/** - * Webpack entries related to socket integrations. - * They have to run before any code that sets up the error overlay. - * @type {string[]} - */ -const socketEntries = [ - 'webpack-dev-server/client', - 'webpack-hot-middleware/client', - 'webpack-plugin-serve/client', - 'react-dev-utils/webpackHotDevClient', -]; - -/** - * Checks if a Webpack entry string is related to socket integrations. - * @param {string} entry A Webpack entry string. - * @returns {boolean} Whether the entry is related to socket integrations. - */ -function isSocketEntry(entry) { - return socketEntries.some((socketEntry) => entry.includes(socketEntry)); -} - -/** - * Injects an entry to the bundle for react-refresh. - * @param {WebpackEntry} [originalEntry] A Webpack entry object. - * @param {import('./getAdditionalEntries').AdditionalEntries} additionalEntries An object that contains the Webpack entries for prepending and the overlay feature - * @returns {WebpackEntry} An injected entry object. - */ -function injectRefreshEntry(originalEntry, additionalEntries) { - const { prependEntries, overlayEntries } = additionalEntries; - - // Single string entry point - if (typeof originalEntry === 'string') { - if (isSocketEntry(originalEntry)) { - return [...prependEntries, originalEntry, ...overlayEntries]; - } - - return [...prependEntries, ...overlayEntries, originalEntry]; - } - // Single array entry point - if (Array.isArray(originalEntry)) { - if (originalEntry.length === 0) { - throw EntryParseError; - } - - const socketEntryIndex = originalEntry.findIndex(isSocketEntry); - - let socketAndPrecedingEntries = []; - if (socketEntryIndex !== -1) { - socketAndPrecedingEntries = originalEntry.splice(0, socketEntryIndex + 1); - } - - return [...prependEntries, ...socketAndPrecedingEntries, ...overlayEntries, ...originalEntry]; - } - // Multiple entry points - if (typeof originalEntry === 'object') { - const entries = Object.entries(originalEntry); - if (entries.length === 0) { - throw EntryParseError; - } - - return entries.reduce( - (acc, [curKey, curEntry]) => ({ - ...acc, - [curKey]: - typeof curEntry === 'object' && curEntry.import - ? { - ...curEntry, - import: injectRefreshEntry(curEntry.import, additionalEntries), - } - : injectRefreshEntry(curEntry, additionalEntries), - }), - {} - ); - } - // Dynamic entry points - if (typeof originalEntry === 'function') { - return (...args) => - Promise.resolve(originalEntry(...args)).then((resolvedEntry) => - injectRefreshEntry(resolvedEntry, additionalEntries) - ); - } - - throw EntryParseError; -} - -module.exports = injectRefreshEntry; -module.exports.socketEntries = socketEntries; diff --git a/lib/utils/makeRefreshRuntimeModule.js b/lib/utils/makeRefreshRuntimeModule.js index 2a4a36c0..a4a63032 100644 --- a/lib/utils/makeRefreshRuntimeModule.js +++ b/lib/utils/makeRefreshRuntimeModule.js @@ -18,15 +18,15 @@ function makeRefreshRuntimeModule(webpack) { */ generate() { const { runtimeTemplate } = this.compilation; - const declareVar = runtimeTemplate.supportsConst() ? 'const' : 'var'; + const constDeclaration = runtimeTemplate.supportsConst() ? 'const' : 'var'; return webpack.Template.asString([ - `${declareVar} setup = ${runtimeTemplate.basicFunction('moduleId', [ - `${declareVar} refresh = {`, + `${constDeclaration} setup = ${runtimeTemplate.basicFunction('moduleId', [ + `${constDeclaration} refresh = {`, webpack.Template.indent([ `moduleId: moduleId,`, `register: ${runtimeTemplate.basicFunction('type, id', [ - `${declareVar} typeId = moduleId + " " + id;`, - `refresh.runtime.register(type, typeId);`, + `${constDeclaration} typeId = moduleId + ' ' + id;`, + 'refresh.runtime.register(type, typeId);', ])},`, `signature: ${runtimeTemplate.returningFunction( 'refresh.runtime.createSignatureFunctionForTransform()' @@ -42,36 +42,41 @@ function makeRefreshRuntimeModule(webpack) { ]), `};`, `return refresh;`, - ])}`, + ])};`, '', `${webpack.RuntimeGlobals.interceptModuleExecution}.push(${runtimeTemplate.basicFunction( 'options', [ - `${declareVar} originalFactory = options.factory;`, + `${constDeclaration} originalFactory = options.factory;`, `options.factory = ${runtimeTemplate.basicFunction( - ['moduleObject', 'moduleExports', 'webpackRequire'], + 'moduleObject, moduleExports, webpackRequire', [ // Our require function delegates to the original require function - `${declareVar} hotRequire = ${runtimeTemplate.returningFunction( + `${constDeclaration} hotRequire = ${runtimeTemplate.returningFunction( 'webpackRequire(request)', 'request' )};`, - // The propery descriptor factory below ensures that all properties but $Refresh$ are proxied through to the original require function - `${declareVar} createPropertyDescriptor = ${runtimeTemplate.basicFunction('name', [ - `return {`, - webpack.Template.indent([ - `configurable: true,`, - `enumerable: true,`, - `get: ${runtimeTemplate.returningFunction('webpackRequire[name]')},`, - `set: ${runtimeTemplate.basicFunction('value', [ - 'webpackRequire[name] = value;', - ])},`, - ]), - `};`, - ])};`, - `for (${declareVar} name in webpackRequire) {`, + // The propery descriptor factory below + // ensures all properties but $Refresh$ are proxied through to the original require function + `${constDeclaration} createPropertyDescriptor = ${runtimeTemplate.basicFunction( + 'name', + [ + `return {`, + webpack.Template.indent([ + `configurable: true,`, + `enumerable: true,`, + `get: ${runtimeTemplate.returningFunction('webpackRequire[name]')},`, + `set: ${runtimeTemplate.basicFunction('value', [ + 'webpackRequire[name] = value;', + ])},`, + ]), + `};`, + ] + )};`, + `for (${constDeclaration} name in webpackRequire) {`, webpack.Template.indent([ - `if (Object.prototype.hasOwnProperty.call(webpackRequire, name) && name !== "$Refresh$") {`, + 'if (name === "$Refresh$") continue;', + 'if (Object.prototype.hasOwnProperty.call(webpackRequire, name)) {', webpack.Template.indent([ `Object.defineProperty(hotRequire, name, createPropertyDescriptor(name));`, ]), diff --git a/test/unit/getRefreshGlobal.test.js b/test/unit/getRefreshGlobal.test.js deleted file mode 100644 index a2148e93..00000000 --- a/test/unit/getRefreshGlobal.test.js +++ /dev/null @@ -1,123 +0,0 @@ -const { RuntimeGlobals, Template } = require('webpack'); -const getRefreshGlobal = require('../../lib/utils/getRefreshGlobal'); - -describe('getRefreshGlobal', () => { - beforeEach(() => { - global.__webpack_require__ = {}; - }); - - afterAll(() => { - delete global.__webpack_require__; - }); - - it('should return working refresh global without providing runtime template', () => { - const refreshGlobalTemplate = getRefreshGlobal(Template); - expect(refreshGlobalTemplate).toMatchInlineSnapshot(` - "__webpack_require__.$Refresh$ = { - register: function() { return undefined; }, - signature: function() { return function(type) { return type; }; }, - runtime: { - createSignatureFunctionForTransform: function() { return function(type) { return type; }; }, - register: function() { return undefined; } - }, - setup: function(currentModuleId) { - var prevModuleId = __webpack_require__.$Refresh$.moduleId; - var prevRegister = __webpack_require__.$Refresh$.register; - var prevSignature = __webpack_require__.$Refresh$.signature; - var prevCleanup = __webpack_require__.$Refresh$.cleanup; - - __webpack_require__.$Refresh$.moduleId = currentModuleId; - - __webpack_require__.$Refresh$.register = function(type, id) { - var typeId = currentModuleId + " " + id; - __webpack_require__.$Refresh$.runtime.register(type, typeId); - } - - __webpack_require__.$Refresh$.signature = function() { return __webpack_require__.$Refresh$.runtime.createSignatureFunctionForTransform(); }; - - __webpack_require__.$Refresh$.cleanup = function(cleanupModuleId) { - if (currentModuleId === cleanupModuleId) { - __webpack_require__.$Refresh$.moduleId = prevModuleId; - __webpack_require__.$Refresh$.register = prevRegister; - __webpack_require__.$Refresh$.signature = prevSignature; - __webpack_require__.$Refresh$.cleanup = prevCleanup; - } - } - } - };" - `); - expect(() => { - eval(refreshGlobalTemplate); - }).not.toThrow(); - - const refreshGlobal = global.__webpack_require__.$Refresh$; - expect(() => { - refreshGlobal.setup('1'); - }).not.toThrow(); - expect(refreshGlobal.moduleId).toBe('1'); - expect(typeof refreshGlobal.runtime).toBe('object'); - expect(typeof refreshGlobal.runtime.createSignatureFunctionForTransform).toBe('function'); - expect(typeof refreshGlobal.runtime.register).toBe('function'); - expect(typeof refreshGlobal.cleanup).toBe('function'); - expect(typeof refreshGlobal.register).toBe('function'); - expect(typeof refreshGlobal.signature).toBe('function'); - }); - - it('should return working refresh global with provided runtime globals and runtime template', () => { - const RuntimeTemplate = require('webpack/lib/RuntimeTemplate'); - const refreshGlobalTemplate = getRefreshGlobal( - Template, - RuntimeGlobals, - new RuntimeTemplate({}, { environment: { arrowFunction: true, const: true } }, (i) => i) - ); - expect(refreshGlobalTemplate).toMatchInlineSnapshot(` - "__webpack_require__.$Refresh$ = { - register: () => (undefined), - signature: () => ((type) => (type)), - runtime: { - createSignatureFunctionForTransform: () => ((type) => (type)), - register: () => (undefined) - }, - setup: (currentModuleId) => { - const prevModuleId = __webpack_require__.$Refresh$.moduleId; - const prevRegister = __webpack_require__.$Refresh$.register; - const prevSignature = __webpack_require__.$Refresh$.signature; - const prevCleanup = __webpack_require__.$Refresh$.cleanup; - - __webpack_require__.$Refresh$.moduleId = currentModuleId; - - __webpack_require__.$Refresh$.register = (type, id) => { - const typeId = currentModuleId + " " + id; - __webpack_require__.$Refresh$.runtime.register(type, typeId); - } - - __webpack_require__.$Refresh$.signature = () => (__webpack_require__.$Refresh$.runtime.createSignatureFunctionForTransform()); - - __webpack_require__.$Refresh$.cleanup = (cleanupModuleId) => { - if (currentModuleId === cleanupModuleId) { - __webpack_require__.$Refresh$.moduleId = prevModuleId; - __webpack_require__.$Refresh$.register = prevRegister; - __webpack_require__.$Refresh$.signature = prevSignature; - __webpack_require__.$Refresh$.cleanup = prevCleanup; - } - } - } - };" - `); - expect(() => { - eval(refreshGlobalTemplate); - }).not.toThrow(); - - const refreshGlobal = global.__webpack_require__.$Refresh$; - expect(() => { - refreshGlobal.setup('1'); - }).not.toThrow(); - expect(refreshGlobal.moduleId).toBe('1'); - expect(typeof refreshGlobal.runtime).toBe('object'); - expect(typeof refreshGlobal.runtime.createSignatureFunctionForTransform).toBe('function'); - expect(typeof refreshGlobal.runtime.register).toBe('function'); - expect(typeof refreshGlobal.cleanup).toBe('function'); - expect(typeof refreshGlobal.register).toBe('function'); - expect(typeof refreshGlobal.signature).toBe('function'); - }); -}); diff --git a/test/unit/injectRefreshEntry.test.js b/test/unit/injectRefreshEntry.test.js deleted file mode 100644 index b12c7e78..00000000 --- a/test/unit/injectRefreshEntry.test.js +++ /dev/null @@ -1,145 +0,0 @@ -const injectRefreshEntry = require('../../lib/utils/injectRefreshEntry'); - -const ErrorOverlayEntry = require.resolve('../../client/ErrorOverlayEntry'); -const ReactRefreshEntry = require.resolve('../../client/ReactRefreshEntry'); - -const DEFAULT_ENTRIES = { - overlayEntries: [ErrorOverlayEntry], - prependEntries: [ReactRefreshEntry], -}; - -describe('injectRefreshEntry', () => { - it('should add entries to a string', () => { - expect(injectRefreshEntry('test.js', DEFAULT_ENTRIES)).toStrictEqual([ - ReactRefreshEntry, - ErrorOverlayEntry, - 'test.js', - ]); - }); - - it('should add entries to an array', () => { - expect(injectRefreshEntry(['test.js'], DEFAULT_ENTRIES)).toStrictEqual([ - ReactRefreshEntry, - ErrorOverlayEntry, - 'test.js', - ]); - }); - - it('should add entries to an object', () => { - expect( - injectRefreshEntry( - { - main: 'test.js', - vendor: ['react', 'react-dom'], - }, - DEFAULT_ENTRIES - ) - ).toStrictEqual({ - main: [ReactRefreshEntry, ErrorOverlayEntry, 'test.js'], - vendor: [ReactRefreshEntry, ErrorOverlayEntry, 'react', 'react-dom'], - }); - }); - - it('should add entries to an object using entry description', () => { - expect( - injectRefreshEntry( - { - main: { - dependOn: 'vendors', - import: 'test.js', - }, - vendor: ['react', 'react-dom'], - }, - DEFAULT_ENTRIES - ) - ).toStrictEqual({ - main: { - dependOn: 'vendors', - import: [ReactRefreshEntry, ErrorOverlayEntry, 'test.js'], - }, - vendor: [ReactRefreshEntry, ErrorOverlayEntry, 'react', 'react-dom'], - }); - }); - - it('should add entries to a synchronous function', () => { - const returnedEntry = injectRefreshEntry(() => 'test.js', DEFAULT_ENTRIES); - expect(typeof returnedEntry).toBe('function'); - expect(returnedEntry()).resolves.toStrictEqual([ - ReactRefreshEntry, - ErrorOverlayEntry, - 'test.js', - ]); - }); - - it('should add entries to an asynchronous function', () => { - const returnedEntry = injectRefreshEntry(() => Promise.resolve('test.js'), DEFAULT_ENTRIES); - expect(typeof returnedEntry).toBe('function'); - expect(returnedEntry()).resolves.toStrictEqual([ - ReactRefreshEntry, - ErrorOverlayEntry, - 'test.js', - ]); - }); - - it('should add entries to a function returning an object', () => { - const returnedEntry = injectRefreshEntry( - () => ({ - main: 'test.js', - vendor: ['react', 'react-dom'], - }), - DEFAULT_ENTRIES - ); - expect(typeof returnedEntry).toBe('function'); - expect(returnedEntry()).resolves.toStrictEqual({ - main: [ReactRefreshEntry, ErrorOverlayEntry, 'test.js'], - vendor: [ReactRefreshEntry, ErrorOverlayEntry, 'react', 'react-dom'], - }); - }); - - it('should not append overlay entry when unused', () => { - expect( - injectRefreshEntry('test.js', { - prependEntries: [], - overlayEntries: [], - }) - ).toStrictEqual(['test.js']); - }); - - it('should append overlay entry for a string after socket-related entries', () => { - expect(injectRefreshEntry('webpack-dev-server/client', DEFAULT_ENTRIES)).toStrictEqual([ - ReactRefreshEntry, - 'webpack-dev-server/client', - ErrorOverlayEntry, - ]); - }); - - it('should append overlay entry for an array after socket-related entries while keeping original relative order', () => { - expect( - injectRefreshEntry(['setup-env.js', 'webpack-dev-server/client', 'test.js'], DEFAULT_ENTRIES) - ).toStrictEqual([ - ReactRefreshEntry, - 'setup-env.js', - 'webpack-dev-server/client', - ErrorOverlayEntry, - 'test.js', - ]); - }); - - it('should throw when empty array entry is received', () => { - expect(() => injectRefreshEntry([], DEFAULT_ENTRIES)).toThrowErrorMatchingInlineSnapshot( - `"[ReactRefreshPlugin] Failed to parse the Webpack \`entry\` object! Please ensure the \`entry\` option in your Webpack config is specified."` - ); - }); - - it('should throw when empty object entry is received', () => { - expect(() => injectRefreshEntry({}, DEFAULT_ENTRIES)).toThrowErrorMatchingInlineSnapshot( - `"[ReactRefreshPlugin] Failed to parse the Webpack \`entry\` object! Please ensure the \`entry\` option in your Webpack config is specified."` - ); - }); - - it('should throw when invalid entry is received', () => { - expect(() => injectRefreshEntry(1, DEFAULT_ENTRIES)).toThrowErrorMatchingInlineSnapshot( - `"[ReactRefreshPlugin] Failed to parse the Webpack \`entry\` object! Please ensure the \`entry\` option in your Webpack config is specified."` - ); - }); -}); diff --git a/test/unit/makeRefreshRuntimeModule.test.js b/test/unit/makeRefreshRuntimeModule.test.js index 367df804..49844139 100644 --- a/test/unit/makeRefreshRuntimeModule.test.js +++ b/test/unit/makeRefreshRuntimeModule.test.js @@ -38,46 +38,47 @@ describe('makeRefreshRuntimeModule', () => { const runtime = instance.generate(); expect(runtime).toMatchInlineSnapshot(` - "var setup = function(moduleId) { - var refresh = { - moduleId: moduleId, - register: function(type, id) { - var typeId = moduleId + " " + id; - refresh.runtime.register(type, typeId); - }, - signature: function() { return refresh.runtime.createSignatureFunctionForTransform(); }, - runtime: { - createSignatureFunctionForTransform: function() { return function(type) { return type; }; }, - register: function() {} +"var setup = function(moduleId) { + var refresh = { + moduleId: moduleId, + register: function(type, id) { + var typeId = moduleId + ' ' + id; + refresh.runtime.register(type, typeId); + }, + signature: function() { return refresh.runtime.createSignatureFunctionForTransform(); }, + runtime: { + createSignatureFunctionForTransform: function() { return function(type) { return type; }; }, + register: function() {} + }, + }; + return refresh; +}; + +__webpack_require__.i.push(function(options) { + var originalFactory = options.factory; + options.factory = function(moduleObject, moduleExports, webpackRequire) { + var hotRequire = function(request) { return webpackRequire(request); }; + var createPropertyDescriptor = function(name) { + return { + configurable: true, + enumerable: true, + get: function() { return webpackRequire[name]; }, + set: function(value) { + webpackRequire[name] = value; }, }; - return refresh; + }; + for (var name in webpackRequire) { + if (name === "$Refresh$") continue; + if (Object.prototype.hasOwnProperty.call(webpackRequire, name)) { + Object.defineProperty(hotRequire, name, createPropertyDescriptor(name)); + } } - - __webpack_require__.i.push(function(options) { - var originalFactory = options.factory; - options.factory = function(moduleObject,moduleExports,webpackRequire) { - var hotRequire = function(request) { return webpackRequire(request); }; - var createPropertyDescriptor = function(name) { - return { - configurable: true, - enumerable: true, - get: function() { return webpackRequire[name]; }, - set: function(value) { - webpackRequire[name] = value; - }, - }; - }; - for (var name in webpackRequire) { - if (Object.prototype.hasOwnProperty.call(webpackRequire, name) && name !== "$Refresh$") { - Object.defineProperty(hotRequire, name, createPropertyDescriptor(name)); - } - } - hotRequire.$Refresh$ = setup(options.id); - originalFactory.call(this, moduleObject, moduleExports, hotRequire); - }; - });" - `); + hotRequire.$Refresh$ = setup(options.id); + originalFactory.call(this, moduleObject, moduleExports, hotRequire); + }; +});" +`); expect(() => { eval(runtime); }).not.toThrow(); @@ -99,46 +100,47 @@ describe('makeRefreshRuntimeModule', () => { const runtime = instance.generate(); expect(runtime).toMatchInlineSnapshot(` - "const setup = (moduleId) => { - const refresh = { - moduleId: moduleId, - register: (type, id) => { - const typeId = moduleId + " " + id; - refresh.runtime.register(type, typeId); - }, - signature: () => (refresh.runtime.createSignatureFunctionForTransform()), - runtime: { - createSignatureFunctionForTransform: () => ((type) => (type)), - register: x => {} +"const setup = (moduleId) => { + const refresh = { + moduleId: moduleId, + register: (type, id) => { + const typeId = moduleId + ' ' + id; + refresh.runtime.register(type, typeId); + }, + signature: () => (refresh.runtime.createSignatureFunctionForTransform()), + runtime: { + createSignatureFunctionForTransform: () => ((type) => (type)), + register: x => {} + }, + }; + return refresh; +}; + +__webpack_require__.i.push((options) => { + const originalFactory = options.factory; + options.factory = (moduleObject, moduleExports, webpackRequire) => { + const hotRequire = (request) => (webpackRequire(request)); + const createPropertyDescriptor = (name) => { + return { + configurable: true, + enumerable: true, + get: () => (webpackRequire[name]), + set: (value) => { + webpackRequire[name] = value; }, }; - return refresh; + }; + for (const name in webpackRequire) { + if (name === "$Refresh$") continue; + if (Object.prototype.hasOwnProperty.call(webpackRequire, name)) { + Object.defineProperty(hotRequire, name, createPropertyDescriptor(name)); + } } - - __webpack_require__.i.push((options) => { - const originalFactory = options.factory; - options.factory = (moduleObject,moduleExports,webpackRequire) => { - const hotRequire = (request) => (webpackRequire(request)); - const createPropertyDescriptor = (name) => { - return { - configurable: true, - enumerable: true, - get: () => (webpackRequire[name]), - set: (value) => { - webpackRequire[name] = value; - }, - }; - }; - for (const name in webpackRequire) { - if (Object.prototype.hasOwnProperty.call(webpackRequire, name) && name !== "$Refresh$") { - Object.defineProperty(hotRequire, name, createPropertyDescriptor(name)); - } - } - hotRequire.$Refresh$ = setup(options.id); - originalFactory.call(this, moduleObject, moduleExports, hotRequire); - }; - });" - `); + hotRequire.$Refresh$ = setup(options.id); + originalFactory.call(this, moduleObject, moduleExports, hotRequire); + }; +});" +`); expect(() => { eval(runtime); }).not.toThrow();