vite-plugin-swc-react-refresh
Advanced tools
| import { PluginOption } from "vite"; | ||
| export declare const swcReactRefresh: () => PluginOption; |
+138
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/index.ts | ||
| var src_exports = {}; | ||
| __export(src_exports, { | ||
| swcReactRefresh: () => swcReactRefresh | ||
| }); | ||
| module.exports = __toCommonJS(src_exports); | ||
| var import_fs = require("fs"); | ||
| var import_path = require("path"); | ||
| var import_core = require("@swc/core"); | ||
| var runtimePublicPath = "/@react-refresh"; | ||
| var preambleCode = `import { injectIntoGlobalHook } from "${runtimePublicPath}"; | ||
| injectIntoGlobalHook(window); | ||
| window.$RefreshReg$ = () => {}; | ||
| window.$RefreshSig$ = () => (type) => type;`; | ||
| var importReactRE = /(^|\n)import\s+(\*\s+as\s+)?React(,|\s+)/; | ||
| var define; | ||
| var automaticRuntime = false; | ||
| var parserMap = /* @__PURE__ */ new Map([ | ||
| [".tsx", { syntax: "typescript", tsx: true }], | ||
| [".ts", { syntax: "typescript", tsx: false }], | ||
| [".jsx", { syntax: "ecmascript", jsx: true }], | ||
| [".js", { syntax: "ecmascript", jsx: false }] | ||
| ]); | ||
| var swcReactRefresh = () => ({ | ||
| name: "swc-react-refresh", | ||
| apply: "serve", | ||
| config: (config) => { | ||
| if (config.esbuild) { | ||
| define = config.esbuild.define; | ||
| automaticRuntime = config.esbuild.jsx === "automatic"; | ||
| } | ||
| return automaticRuntime ? { | ||
| esbuild: false, | ||
| optimizeDeps: { include: ["react/jsx-dev-runtime"] } | ||
| } : { esbuild: false }; | ||
| }, | ||
| resolveId: (id) => id === runtimePublicPath ? id : void 0, | ||
| load: (id) => id === runtimePublicPath ? (0, import_fs.readFileSync)((0, import_path.join)(__dirname, "refresh-runtime.js"), "utf-8") : void 0, | ||
| transformIndexHtml: () => [ | ||
| { tag: "script", attrs: { type: "module" }, children: preambleCode } | ||
| ], | ||
| async transform(code, id) { | ||
| if (id.includes("node_modules")) | ||
| return; | ||
| const parser = parserMap.get((0, import_path.extname)(id)); | ||
| if (!parser) | ||
| return; | ||
| let result; | ||
| try { | ||
| result = await (0, import_core.transform)(code, { | ||
| filename: id, | ||
| swcrc: false, | ||
| configFile: false, | ||
| sourceMaps: true, | ||
| jsc: { | ||
| target: "es2020", | ||
| parser, | ||
| transform: { | ||
| react: { | ||
| refresh: true, | ||
| development: true, | ||
| useBuiltins: true, | ||
| runtime: automaticRuntime ? "automatic" : void 0 | ||
| }, | ||
| optimizer: { globals: { vars: define } } | ||
| } | ||
| } | ||
| }); | ||
| } catch (e) { | ||
| const message = e.message; | ||
| const fileStartIndex = message.indexOf("\u256D\u2500["); | ||
| if (fileStartIndex !== -1) { | ||
| const match = message.slice(fileStartIndex).match(/:(\d+):(\d+)]/); | ||
| if (match) { | ||
| e.line = match[1]; | ||
| e.column = match[2]; | ||
| } | ||
| } | ||
| throw e; | ||
| } | ||
| let mappingPrefix = ""; | ||
| if (!automaticRuntime && result.code.includes("React.createElement") && !importReactRE.test(result.code)) { | ||
| result.code = `import React from "react"; | ||
| ${result.code}`; | ||
| mappingPrefix += ";"; | ||
| } | ||
| if (result.code.includes("$RefreshReg$")) { | ||
| mappingPrefix += ";;;;;;;;;;;;"; | ||
| result.code = `import * as RefreshRuntime from "${runtimePublicPath}"; | ||
| let prevRefreshReg; | ||
| let prevRefreshSig; | ||
| if (!window.$RefreshReg$) throw new Error("React refresh preamble was not loaded. Something is wrong."); | ||
| prevRefreshReg = window.$RefreshReg$; | ||
| prevRefreshSig = window.$RefreshSig$; | ||
| window.$RefreshReg$ = RefreshRuntime.getRefreshReg("${id}"); | ||
| window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform; | ||
| ${result.code} | ||
| window.$RefreshReg$ = prevRefreshReg; | ||
| window.$RefreshSig$ = prevRefreshSig; | ||
| import.meta.hot.accept(); | ||
| RefreshRuntime.enqueueUpdate(); | ||
| `; | ||
| } | ||
| if (!mappingPrefix) | ||
| return result; | ||
| const sourceMap = JSON.parse(result.map); | ||
| sourceMap.mappings = mappingPrefix + sourceMap.mappings; | ||
| return { code: result.code, map: sourceMap }; | ||
| } | ||
| }); | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| swcReactRefresh | ||
| }); |
| /** | ||
| * This is simplified pure-js version of https://github.com/facebook/react/blob/main/packages/react-refresh/src/ReactFreshRuntime.js | ||
| * without IE11 compatibility and functions for the babel plugin | ||
| * Copyright (c) Facebook, Inc. and its affiliates. | ||
| */ | ||
| const REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"); | ||
| const REACT_MEMO_TYPE = Symbol.for("react.memo"); | ||
| // We never remove these associations. | ||
| // It's OK to reference families, but use WeakMap/Set for types. | ||
| let allFamiliesByID = new Map(); | ||
| let allFamiliesByType = new WeakMap(); | ||
| let allSignaturesByType = new WeakMap(); | ||
| // This WeakMap is read by React, so we only put families | ||
| // that have actually been edited here. This keeps checks fast. | ||
| let updatedFamiliesByType = new WeakMap(); | ||
| // This is cleared on every performReactRefresh() call. | ||
| // It is an array of [Family, NextType] tuples. | ||
| let pendingUpdates = []; | ||
| // This is injected by the renderer via DevTools global hook. | ||
| let helpersByRendererID = new Map(); | ||
| let helpersByRoot = new Map(); | ||
| // We keep track of mounted roots so we can schedule updates. | ||
| let mountedRoots = new Set(); | ||
| // If a root captures an error, we remember it so we can retry on edit. | ||
| let failedRoots = new Set(); | ||
| // We also remember the last element for every root. | ||
| // It needs to be weak because we do this even for roots that failed to mount. | ||
| // If there is no WeakMap, we won't attempt to do retrying. | ||
| let rootElements = new WeakMap(); | ||
| let isPerformingRefresh = false; | ||
| function computeFullKey(signature) { | ||
| if (signature.fullKey !== null) { | ||
| return signature.fullKey; | ||
| } | ||
| let fullKey = signature.ownKey; | ||
| let hooks; | ||
| try { | ||
| hooks = signature.getCustomHooks(); | ||
| } catch (err) { | ||
| // This can happen in an edge case, e.g. if expression like Foo.useSomething | ||
| // depends on Foo which is lazily initialized during rendering. | ||
| // In that case just assume we'll have to remount. | ||
| signature.forceReset = true; | ||
| signature.fullKey = fullKey; | ||
| return fullKey; | ||
| } | ||
| for (let i = 0; i < hooks.length; i++) { | ||
| let hook = hooks[i]; | ||
| if (typeof hook !== "function") { | ||
| // Something's wrong. Assume we need to remount. | ||
| signature.forceReset = true; | ||
| signature.fullKey = fullKey; | ||
| return fullKey; | ||
| } | ||
| let nestedHookSignature = allSignaturesByType.get(hook); | ||
| if (nestedHookSignature === undefined) { | ||
| // No signature means Hook wasn't in the source code, e.g. in a library. | ||
| // We'll skip it because we can assume it won't change during this session. | ||
| continue; | ||
| } | ||
| let nestedHookKey = computeFullKey(nestedHookSignature); | ||
| if (nestedHookSignature.forceReset) { | ||
| signature.forceReset = true; | ||
| } | ||
| fullKey += "\n---\n" + nestedHookKey; | ||
| } | ||
| signature.fullKey = fullKey; | ||
| return fullKey; | ||
| } | ||
| function haveEqualSignatures(prevType, nextType) { | ||
| let prevSignature = allSignaturesByType.get(prevType); | ||
| let nextSignature = allSignaturesByType.get(nextType); | ||
| if (prevSignature === undefined && nextSignature === undefined) { | ||
| return true; | ||
| } | ||
| if (prevSignature === undefined || nextSignature === undefined) { | ||
| return false; | ||
| } | ||
| if (computeFullKey(prevSignature) !== computeFullKey(nextSignature)) { | ||
| return false; | ||
| } | ||
| if (nextSignature.forceReset) { | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| function isReactClass(type) { | ||
| return type.prototype && type.prototype.isReactComponent; | ||
| } | ||
| function canPreserveStateBetween(prevType, nextType) { | ||
| if (isReactClass(prevType) || isReactClass(nextType)) { | ||
| return false; | ||
| } | ||
| if (haveEqualSignatures(prevType, nextType)) { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| function resolveFamily(type) { | ||
| // Only check updated types to keep lookups fast. | ||
| return updatedFamiliesByType.get(type); | ||
| } | ||
| // This is a safety mechanism to protect against rogue getters and Proxies. | ||
| function getProperty(object, property) { | ||
| try { | ||
| return object[property]; | ||
| } catch (err) { | ||
| // Intentionally ignore. | ||
| return undefined; | ||
| } | ||
| } | ||
| function performReactRefresh() { | ||
| if (pendingUpdates.length === 0) { | ||
| return null; | ||
| } | ||
| if (isPerformingRefresh) { | ||
| return null; | ||
| } | ||
| isPerformingRefresh = true; | ||
| try { | ||
| let staleFamilies = new Set(); | ||
| let updatedFamilies = new Set(); | ||
| let updates = pendingUpdates; | ||
| pendingUpdates = []; | ||
| updates.forEach(function (_ref) { | ||
| let family = _ref[0], | ||
| nextType = _ref[1]; | ||
| // Now that we got a real edit, we can create associations | ||
| // that will be read by the React reconciler. | ||
| let prevType = family.current; | ||
| updatedFamiliesByType.set(prevType, family); | ||
| updatedFamiliesByType.set(nextType, family); | ||
| family.current = nextType; | ||
| // Determine whether this should be a re-render or a re-mount. | ||
| if (canPreserveStateBetween(prevType, nextType)) { | ||
| updatedFamilies.add(family); | ||
| } else { | ||
| staleFamilies.add(family); | ||
| } | ||
| }); | ||
| // TODO: rename these fields to something more meaningful. | ||
| let update = { | ||
| updatedFamilies: updatedFamilies, | ||
| // Families that will re-render preserving state | ||
| staleFamilies: staleFamilies, // Families that will be remounted | ||
| }; | ||
| helpersByRendererID.forEach(function (helpers) { | ||
| // Even if there are no roots, set the handler on first update. | ||
| // This ensures that if *new* roots are mounted, they'll use the resolve handler. | ||
| helpers.setRefreshHandler(resolveFamily); | ||
| }); | ||
| let didError = false; | ||
| let firstError = null; | ||
| // We snapshot maps and sets that are mutated during commits. | ||
| // If we don't do this, there is a risk they will be mutated while | ||
| // we iterate over them. For example, trying to recover a failed root | ||
| // may cause another root to be added to the failed list -- an infinite loop. | ||
| let failedRootsSnapshot = new Set(failedRoots); | ||
| let mountedRootsSnapshot = new Set(mountedRoots); | ||
| let helpersByRootSnapshot = new Map(helpersByRoot); | ||
| failedRootsSnapshot.forEach(function (root) { | ||
| let helpers = helpersByRootSnapshot.get(root); | ||
| if (helpers === undefined) { | ||
| throw new Error( | ||
| "Could not find helpers for a root. This is a bug in React Refresh.", | ||
| ); | ||
| } | ||
| if (!failedRoots.has(root)) { | ||
| // No longer failed. | ||
| } | ||
| if (!rootElements.has(root)) { | ||
| return; | ||
| } | ||
| let element = rootElements.get(root); | ||
| try { | ||
| helpers.scheduleRoot(root, element); | ||
| } catch (err) { | ||
| if (!didError) { | ||
| didError = true; | ||
| firstError = err; | ||
| } | ||
| // Keep trying other roots. | ||
| } | ||
| }); | ||
| mountedRootsSnapshot.forEach(function (root) { | ||
| let helpers = helpersByRootSnapshot.get(root); | ||
| if (helpers === undefined) { | ||
| throw new Error( | ||
| "Could not find helpers for a root. This is a bug in React Refresh.", | ||
| ); | ||
| } | ||
| if (!mountedRoots.has(root)) { | ||
| // No longer mounted. | ||
| } | ||
| try { | ||
| helpers.scheduleRefresh(root, update); | ||
| } catch (err) { | ||
| if (!didError) { | ||
| didError = true; | ||
| firstError = err; | ||
| } | ||
| // Keep trying other roots. | ||
| } | ||
| }); | ||
| if (didError) { | ||
| throw firstError; | ||
| } | ||
| return update; | ||
| } finally { | ||
| isPerformingRefresh = false; | ||
| } | ||
| } | ||
| function debounce(fn, delay) { | ||
| let handle; | ||
| return () => { | ||
| clearTimeout(handle); | ||
| handle = setTimeout(fn, delay); | ||
| }; | ||
| } | ||
| export const enqueueUpdate = debounce(performReactRefresh, 16); | ||
| function register(type, id) { | ||
| if (type === null) { | ||
| return; | ||
| } | ||
| if (typeof type !== "function" && typeof type !== "object") { | ||
| return; | ||
| } | ||
| // This can happen in an edge case, e.g. if we register | ||
| // return value of a HOC but it returns a cached component. | ||
| // Ignore anything but the first registration for each type. | ||
| if (allFamiliesByType.has(type)) { | ||
| return; | ||
| } | ||
| // Create family or remember to update it. | ||
| // None of this bookkeeping affects reconciliation | ||
| // until the first performReactRefresh() call above. | ||
| let family = allFamiliesByID.get(id); | ||
| if (family === undefined) { | ||
| family = { | ||
| current: type, | ||
| }; | ||
| allFamiliesByID.set(id, family); | ||
| } else { | ||
| pendingUpdates.push([family, type]); | ||
| } | ||
| allFamiliesByType.set(type, family); // Visit inner types because we might not have registered them. | ||
| if (typeof type === "object" && type !== null) { | ||
| switch (getProperty(type, "$$typeof")) { | ||
| case REACT_FORWARD_REF_TYPE: | ||
| register(type.render, id + "$render"); | ||
| break; | ||
| case REACT_MEMO_TYPE: | ||
| register(type.type, id + "$type"); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| export function getRefreshReg(filename) { | ||
| return (type, id) => register(type, filename + " " + id); | ||
| } | ||
| function setSignature(type, key, forceReset = false, getCustomHooks) { | ||
| if (!allSignaturesByType.has(type)) { | ||
| allSignaturesByType.set(type, { | ||
| forceReset: forceReset, | ||
| ownKey: key, | ||
| fullKey: null, | ||
| getCustomHooks: | ||
| getCustomHooks || | ||
| function () { | ||
| return []; | ||
| }, | ||
| }); | ||
| } | ||
| // Visit inner types because we might not have signed them. | ||
| if (typeof type === "object" && type !== null) { | ||
| switch (getProperty(type, "$$typeof")) { | ||
| case REACT_FORWARD_REF_TYPE: | ||
| setSignature(type.render, key, forceReset, getCustomHooks); | ||
| break; | ||
| case REACT_MEMO_TYPE: | ||
| setSignature(type.type, key, forceReset, getCustomHooks); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| // This is lazily called during first render for a type. | ||
| // It captures Hook list at that time so inline requires don't break comparisons. | ||
| function collectCustomHooksForSignature(type) { | ||
| let signature = allSignaturesByType.get(type); | ||
| if (signature !== undefined) { | ||
| computeFullKey(signature); | ||
| } | ||
| } | ||
| export function injectIntoGlobalHook(globalObject) { | ||
| // For React Native, the global hook will be set up by require('react-devtools-core'). | ||
| // That code will run before us. So we need to monkeypatch functions on existing hook. | ||
| // For React Web, the global hook will be set up by the extension. | ||
| // This will also run before us. | ||
| let hook = globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__; | ||
| if (hook === undefined) { | ||
| // However, if there is no DevTools extension, we'll need to set up the global hook ourselves. | ||
| // Note that in this case it's important that renderer code runs *after* this method call. | ||
| // Otherwise, the renderer will think that there is no global hook, and won't do the injection. | ||
| let nextID = 0; | ||
| globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = { | ||
| renderers: new Map(), | ||
| supportsFiber: true, | ||
| inject: function (injected) { | ||
| return nextID++; | ||
| }, | ||
| onScheduleFiberRoot: function (id, root, children) {}, | ||
| onCommitFiberRoot: function (id, root, maybePriorityLevel, didError) {}, | ||
| onCommitFiberUnmount: function () {}, | ||
| }; | ||
| } | ||
| if (hook.isDisabled) { | ||
| // This isn't a real property on the hook, but it can be set to opt out | ||
| // of DevTools integration and associated warnings and logs. | ||
| // Using console['warn'] to evade Babel and ESLint | ||
| console["warn"]( | ||
| "Something has shimmed the React DevTools global hook (__REACT_DEVTOOLS_GLOBAL_HOOK__). " + | ||
| "Fast Refresh is not compatible with this shim and will be disabled.", | ||
| ); | ||
| return; | ||
| } | ||
| // Here, we just want to get a reference to scheduleRefresh. | ||
| let oldInject = hook.inject; | ||
| hook.inject = function (injected) { | ||
| let id = oldInject.apply(this, arguments); | ||
| if ( | ||
| typeof injected.scheduleRefresh === "function" && | ||
| typeof injected.setRefreshHandler === "function" | ||
| ) { | ||
| // This version supports React Refresh. | ||
| helpersByRendererID.set(id, injected); | ||
| } | ||
| return id; | ||
| }; | ||
| // Do the same for any already injected roots. | ||
| // This is useful if ReactDOM has already been initialized. | ||
| // https://github.com/facebook/react/issues/17626 | ||
| hook.renderers.forEach(function (injected, id) { | ||
| if ( | ||
| typeof injected.scheduleRefresh === "function" && | ||
| typeof injected.setRefreshHandler === "function" | ||
| ) { | ||
| // This version supports React Refresh. | ||
| helpersByRendererID.set(id, injected); | ||
| } | ||
| }); | ||
| // We also want to track currently mounted roots. | ||
| let oldOnCommitFiberRoot = hook.onCommitFiberRoot; | ||
| let oldOnScheduleFiberRoot = hook.onScheduleFiberRoot || function () {}; | ||
| hook.onScheduleFiberRoot = function (id, root, children) { | ||
| if (!isPerformingRefresh) { | ||
| // If it was intentionally scheduled, don't attempt to restore. | ||
| // This includes intentionally scheduled unmounts. | ||
| failedRoots.delete(root); | ||
| rootElements.set(root, children); | ||
| } | ||
| return oldOnScheduleFiberRoot.apply(this, arguments); | ||
| }; | ||
| hook.onCommitFiberRoot = function (id, root, maybePriorityLevel, didError) { | ||
| let helpers = helpersByRendererID.get(id); | ||
| if (helpers !== undefined) { | ||
| helpersByRoot.set(root, helpers); | ||
| let current = root.current; | ||
| let alternate = current.alternate; | ||
| // We need to determine whether this root has just (un)mounted. | ||
| // This logic is copy-pasted from similar logic in the DevTools backend. | ||
| // If this breaks with some refactoring, you'll want to update DevTools too. | ||
| if (alternate !== null) { | ||
| let wasMounted = | ||
| alternate.memoizedState != null && | ||
| alternate.memoizedState.element != null; | ||
| let isMounted = | ||
| current.memoizedState != null && | ||
| current.memoizedState.element != null; | ||
| if (!wasMounted && isMounted) { | ||
| // Mount a new root. | ||
| mountedRoots.add(root); | ||
| failedRoots.delete(root); | ||
| } else if (wasMounted && isMounted) { | ||
| // Update an existing root. | ||
| // This doesn't affect our mounted root Set. | ||
| } else if (wasMounted && !isMounted) { | ||
| // Unmount an existing root. | ||
| mountedRoots.delete(root); | ||
| if (didError) { | ||
| // We'll remount it on future edits. | ||
| failedRoots.add(root); | ||
| } else { | ||
| helpersByRoot.delete(root); | ||
| } | ||
| } else if (!wasMounted && !isMounted) { | ||
| if (didError) { | ||
| // We'll remount it on future edits. | ||
| failedRoots.add(root); | ||
| } | ||
| } | ||
| } else { | ||
| // Mount a new root. | ||
| mountedRoots.add(root); | ||
| } | ||
| } | ||
| // Always call the decorated DevTools hook. | ||
| return oldOnCommitFiberRoot.apply(this, arguments); | ||
| }; | ||
| } | ||
| // This is a wrapper over more primitive functions for setting signature. | ||
| // Signatures let us decide whether the Hook order has changed on refresh. | ||
| // | ||
| // This function is intended to be used as a transform target, e.g.: | ||
| // let _s = createSignatureFunctionForTransform() | ||
| // | ||
| // function Hello() { | ||
| // const [foo, setFoo] = useState(0); | ||
| // const value = useCustomHook(); | ||
| // _s(); /* Call without arguments triggers collecting the custom Hook list. | ||
| // * This doesn't happen during the module evaluation because we | ||
| // * don't want to change the module order with inline requires. | ||
| // * Next calls are noops. */ | ||
| // return <h1>Hi</h1>; | ||
| // } | ||
| // | ||
| // /* Call with arguments attaches the signature to the type: */ | ||
| // _s( | ||
| // Hello, | ||
| // 'useState{[foo, setFoo]}(0)', | ||
| // () => [useCustomHook], /* Lazy to avoid triggering inline requires */ | ||
| // ); | ||
| export function createSignatureFunctionForTransform() { | ||
| let savedType; | ||
| let hasCustomHooks; | ||
| let didCollectHooks = false; | ||
| return function (type, key, forceReset, getCustomHooks) { | ||
| if (typeof key === "string") { | ||
| // We're in the initial phase that associates signatures | ||
| // with the functions. Note this may be called multiple times | ||
| // in HOC chains like _s(hoc1(_s(hoc2(_s(actualFunction))))). | ||
| if (!savedType) { | ||
| // We're in the innermost call, so this is the actual type. | ||
| savedType = type; | ||
| hasCustomHooks = typeof getCustomHooks === "function"; | ||
| } | ||
| // Set the signature for all types (even wrappers!) in case | ||
| // they have no signatures of their own. This is to prevent | ||
| // problems like https://github.com/facebook/react/issues/20417. | ||
| if ( | ||
| type != null && | ||
| (typeof type === "function" || typeof type === "object") | ||
| ) { | ||
| setSignature(type, key, forceReset, getCustomHooks); | ||
| } | ||
| return type; | ||
| } else { | ||
| // We're in the _s() call without arguments, which means | ||
| // this is the time to collect custom Hook signatures. | ||
| // Only do this once. This path is hot and runs *inside* every render! | ||
| if (!didCollectHooks && hasCustomHooks) { | ||
| didCollectHooks = true; | ||
| collectCustomHooksForSignature(savedType); | ||
| } | ||
| } | ||
| }; | ||
| } |
+7
-25
| { | ||
| "name": "vite-plugin-swc-react-refresh", | ||
| "description": "Use the versatility of swc for development and the maturity of esbuild for production", | ||
| "version": "2.1.0", | ||
| "description": "Use the versatility of SWC for development and the maturity of esbuild for production", | ||
| "version": "2.2.0", | ||
| "author": "Arnaud Barré (https://github.com/ArnaudBarre)", | ||
| "license": "MIT", | ||
| "author": "Arnaud Barré (https://github.com/ArnaudBarre)", | ||
| "main": "src/swc-react-refresh.js", | ||
| "files": [ | ||
| "src/*.js", | ||
| "src/*.d.ts" | ||
| ], | ||
| "repository": "github:ArnaudBarre/vite-plugin-swc-react-refresh", | ||
| "main": "index.js", | ||
| "keywords": [ | ||
@@ -21,22 +17,8 @@ "vite", | ||
| ], | ||
| "scripts": { | ||
| "build": "tsc", | ||
| "prettier": "yarn prettier-ci --write", | ||
| "prettier-ci": "prettier --check '**/*.{js,ts,json,md,yml}'" | ||
| }, | ||
| "prettier": { | ||
| "trailingComma": "all" | ||
| }, | ||
| "dependencies": { | ||
| "@swc/core": "^1.2.245" | ||
| }, | ||
| "peerDependencies": { | ||
| "vite": "^2 || ^3" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/node": "^18.0.6", | ||
| "prettier": "^2.7.1", | ||
| "typescript": "^4.7.4", | ||
| "vite": "^3.0.5" | ||
| "dependencies": { | ||
| "@swc/core": "^1.3.10" | ||
| } | ||
| } | ||
| } |
+1
-1
| # vite-plugin-swc-react-refresh [](https://www.npmjs.com/package/vite-plugin-swc-react-refresh) | ||
| Use the versatility of [swc](https://swc.rs/) for development and the maturity of [esbuild](https://esbuild.github.io/) for production. | ||
| Use the versatility of [SWC](https://swc.rs/) for development and the maturity of [esbuild](https://esbuild.github.io/) for production. | ||
@@ -5,0 +5,0 @@ - ✅ A fast Fast Refresh (~20x faster than Babel) |
| /** | ||
| * This is simplified pure-js version of https://github.com/facebook/react/blob/main/packages/react-refresh/src/ReactFreshRuntime.js | ||
| * without IE11 compatibility and functions for the babel plugin | ||
| * Copyright (c) Facebook, Inc. and its affiliates. | ||
| */ | ||
| const REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"); | ||
| const REACT_MEMO_TYPE = Symbol.for("react.memo"); | ||
| // We never remove these associations. | ||
| // It's OK to reference families, but use WeakMap/Set for types. | ||
| let allFamiliesByID = new Map(); | ||
| let allFamiliesByType = new WeakMap(); | ||
| let allSignaturesByType = new WeakMap(); | ||
| // This WeakMap is read by React, so we only put families | ||
| // that have actually been edited here. This keeps checks fast. | ||
| let updatedFamiliesByType = new WeakMap(); | ||
| // This is cleared on every performReactRefresh() call. | ||
| // It is an array of [Family, NextType] tuples. | ||
| let pendingUpdates = []; | ||
| // This is injected by the renderer via DevTools global hook. | ||
| let helpersByRendererID = new Map(); | ||
| let helpersByRoot = new Map(); | ||
| // We keep track of mounted roots so we can schedule updates. | ||
| let mountedRoots = new Set(); | ||
| // If a root captures an error, we remember it so we can retry on edit. | ||
| let failedRoots = new Set(); | ||
| // We also remember the last element for every root. | ||
| // It needs to be weak because we do this even for roots that failed to mount. | ||
| // If there is no WeakMap, we won't attempt to do retrying. | ||
| let rootElements = new WeakMap(); | ||
| let isPerformingRefresh = false; | ||
| function computeFullKey(signature) { | ||
| if (signature.fullKey !== null) { | ||
| return signature.fullKey; | ||
| } | ||
| let fullKey = signature.ownKey; | ||
| let hooks; | ||
| try { | ||
| hooks = signature.getCustomHooks(); | ||
| } catch (err) { | ||
| // This can happen in an edge case, e.g. if expression like Foo.useSomething | ||
| // depends on Foo which is lazily initialized during rendering. | ||
| // In that case just assume we'll have to remount. | ||
| signature.forceReset = true; | ||
| signature.fullKey = fullKey; | ||
| return fullKey; | ||
| } | ||
| for (let i = 0; i < hooks.length; i++) { | ||
| let hook = hooks[i]; | ||
| if (typeof hook !== "function") { | ||
| // Something's wrong. Assume we need to remount. | ||
| signature.forceReset = true; | ||
| signature.fullKey = fullKey; | ||
| return fullKey; | ||
| } | ||
| let nestedHookSignature = allSignaturesByType.get(hook); | ||
| if (nestedHookSignature === undefined) { | ||
| // No signature means Hook wasn't in the source code, e.g. in a library. | ||
| // We'll skip it because we can assume it won't change during this session. | ||
| continue; | ||
| } | ||
| let nestedHookKey = computeFullKey(nestedHookSignature); | ||
| if (nestedHookSignature.forceReset) { | ||
| signature.forceReset = true; | ||
| } | ||
| fullKey += "\n---\n" + nestedHookKey; | ||
| } | ||
| signature.fullKey = fullKey; | ||
| return fullKey; | ||
| } | ||
| function haveEqualSignatures(prevType, nextType) { | ||
| let prevSignature = allSignaturesByType.get(prevType); | ||
| let nextSignature = allSignaturesByType.get(nextType); | ||
| if (prevSignature === undefined && nextSignature === undefined) { | ||
| return true; | ||
| } | ||
| if (prevSignature === undefined || nextSignature === undefined) { | ||
| return false; | ||
| } | ||
| if (computeFullKey(prevSignature) !== computeFullKey(nextSignature)) { | ||
| return false; | ||
| } | ||
| if (nextSignature.forceReset) { | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| function isReactClass(type) { | ||
| return type.prototype && type.prototype.isReactComponent; | ||
| } | ||
| function canPreserveStateBetween(prevType, nextType) { | ||
| if (isReactClass(prevType) || isReactClass(nextType)) { | ||
| return false; | ||
| } | ||
| if (haveEqualSignatures(prevType, nextType)) { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| function resolveFamily(type) { | ||
| // Only check updated types to keep lookups fast. | ||
| return updatedFamiliesByType.get(type); | ||
| } | ||
| // This is a safety mechanism to protect against rogue getters and Proxies. | ||
| function getProperty(object, property) { | ||
| try { | ||
| return object[property]; | ||
| } catch (err) { | ||
| // Intentionally ignore. | ||
| return undefined; | ||
| } | ||
| } | ||
| function performReactRefresh() { | ||
| if (pendingUpdates.length === 0) { | ||
| return null; | ||
| } | ||
| if (isPerformingRefresh) { | ||
| return null; | ||
| } | ||
| isPerformingRefresh = true; | ||
| try { | ||
| let staleFamilies = new Set(); | ||
| let updatedFamilies = new Set(); | ||
| let updates = pendingUpdates; | ||
| pendingUpdates = []; | ||
| updates.forEach(function (_ref) { | ||
| let family = _ref[0], | ||
| nextType = _ref[1]; | ||
| // Now that we got a real edit, we can create associations | ||
| // that will be read by the React reconciler. | ||
| let prevType = family.current; | ||
| updatedFamiliesByType.set(prevType, family); | ||
| updatedFamiliesByType.set(nextType, family); | ||
| family.current = nextType; | ||
| // Determine whether this should be a re-render or a re-mount. | ||
| if (canPreserveStateBetween(prevType, nextType)) { | ||
| updatedFamilies.add(family); | ||
| } else { | ||
| staleFamilies.add(family); | ||
| } | ||
| }); | ||
| // TODO: rename these fields to something more meaningful. | ||
| let update = { | ||
| updatedFamilies: updatedFamilies, | ||
| // Families that will re-render preserving state | ||
| staleFamilies: staleFamilies, // Families that will be remounted | ||
| }; | ||
| helpersByRendererID.forEach(function (helpers) { | ||
| // Even if there are no roots, set the handler on first update. | ||
| // This ensures that if *new* roots are mounted, they'll use the resolve handler. | ||
| helpers.setRefreshHandler(resolveFamily); | ||
| }); | ||
| let didError = false; | ||
| let firstError = null; | ||
| // We snapshot maps and sets that are mutated during commits. | ||
| // If we don't do this, there is a risk they will be mutated while | ||
| // we iterate over them. For example, trying to recover a failed root | ||
| // may cause another root to be added to the failed list -- an infinite loop. | ||
| let failedRootsSnapshot = new Set(failedRoots); | ||
| let mountedRootsSnapshot = new Set(mountedRoots); | ||
| let helpersByRootSnapshot = new Map(helpersByRoot); | ||
| failedRootsSnapshot.forEach(function (root) { | ||
| let helpers = helpersByRootSnapshot.get(root); | ||
| if (helpers === undefined) { | ||
| throw new Error( | ||
| "Could not find helpers for a root. This is a bug in React Refresh.", | ||
| ); | ||
| } | ||
| if (!failedRoots.has(root)) { | ||
| // No longer failed. | ||
| } | ||
| if (!rootElements.has(root)) { | ||
| return; | ||
| } | ||
| let element = rootElements.get(root); | ||
| try { | ||
| helpers.scheduleRoot(root, element); | ||
| } catch (err) { | ||
| if (!didError) { | ||
| didError = true; | ||
| firstError = err; | ||
| } | ||
| // Keep trying other roots. | ||
| } | ||
| }); | ||
| mountedRootsSnapshot.forEach(function (root) { | ||
| let helpers = helpersByRootSnapshot.get(root); | ||
| if (helpers === undefined) { | ||
| throw new Error( | ||
| "Could not find helpers for a root. This is a bug in React Refresh.", | ||
| ); | ||
| } | ||
| if (!mountedRoots.has(root)) { | ||
| // No longer mounted. | ||
| } | ||
| try { | ||
| helpers.scheduleRefresh(root, update); | ||
| } catch (err) { | ||
| if (!didError) { | ||
| didError = true; | ||
| firstError = err; | ||
| } | ||
| // Keep trying other roots. | ||
| } | ||
| }); | ||
| if (didError) { | ||
| throw firstError; | ||
| } | ||
| return update; | ||
| } finally { | ||
| isPerformingRefresh = false; | ||
| } | ||
| } | ||
| function debounce(fn, delay) { | ||
| let handle; | ||
| return () => { | ||
| clearTimeout(handle); | ||
| handle = setTimeout(fn, delay); | ||
| }; | ||
| } | ||
| export const enqueueUpdate = debounce(performReactRefresh, 16); | ||
| function register(type, id) { | ||
| if (type === null) { | ||
| return; | ||
| } | ||
| if (typeof type !== "function" && typeof type !== "object") { | ||
| return; | ||
| } | ||
| // This can happen in an edge case, e.g. if we register | ||
| // return value of a HOC but it returns a cached component. | ||
| // Ignore anything but the first registration for each type. | ||
| if (allFamiliesByType.has(type)) { | ||
| return; | ||
| } | ||
| // Create family or remember to update it. | ||
| // None of this bookkeeping affects reconciliation | ||
| // until the first performReactRefresh() call above. | ||
| let family = allFamiliesByID.get(id); | ||
| if (family === undefined) { | ||
| family = { | ||
| current: type, | ||
| }; | ||
| allFamiliesByID.set(id, family); | ||
| } else { | ||
| pendingUpdates.push([family, type]); | ||
| } | ||
| allFamiliesByType.set(type, family); // Visit inner types because we might not have registered them. | ||
| if (typeof type === "object" && type !== null) { | ||
| switch (getProperty(type, "$$typeof")) { | ||
| case REACT_FORWARD_REF_TYPE: | ||
| register(type.render, id + "$render"); | ||
| break; | ||
| case REACT_MEMO_TYPE: | ||
| register(type.type, id + "$type"); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| export function getRefreshReg(filename) { | ||
| return (type, id) => register(type, filename + " " + id); | ||
| } | ||
| function setSignature(type, key, forceReset = false, getCustomHooks) { | ||
| if (!allSignaturesByType.has(type)) { | ||
| allSignaturesByType.set(type, { | ||
| forceReset: forceReset, | ||
| ownKey: key, | ||
| fullKey: null, | ||
| getCustomHooks: | ||
| getCustomHooks || | ||
| function () { | ||
| return []; | ||
| }, | ||
| }); | ||
| } | ||
| // Visit inner types because we might not have signed them. | ||
| if (typeof type === "object" && type !== null) { | ||
| switch (getProperty(type, "$$typeof")) { | ||
| case REACT_FORWARD_REF_TYPE: | ||
| setSignature(type.render, key, forceReset, getCustomHooks); | ||
| break; | ||
| case REACT_MEMO_TYPE: | ||
| setSignature(type.type, key, forceReset, getCustomHooks); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| // This is lazily called during first render for a type. | ||
| // It captures Hook list at that time so inline requires don't break comparisons. | ||
| function collectCustomHooksForSignature(type) { | ||
| let signature = allSignaturesByType.get(type); | ||
| if (signature !== undefined) { | ||
| computeFullKey(signature); | ||
| } | ||
| } | ||
| export function injectIntoGlobalHook(globalObject) { | ||
| // For React Native, the global hook will be set up by require('react-devtools-core'). | ||
| // That code will run before us. So we need to monkeypatch functions on existing hook. | ||
| // For React Web, the global hook will be set up by the extension. | ||
| // This will also run before us. | ||
| let hook = globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__; | ||
| if (hook === undefined) { | ||
| // However, if there is no DevTools extension, we'll need to set up the global hook ourselves. | ||
| // Note that in this case it's important that renderer code runs *after* this method call. | ||
| // Otherwise, the renderer will think that there is no global hook, and won't do the injection. | ||
| let nextID = 0; | ||
| globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = { | ||
| renderers: new Map(), | ||
| supportsFiber: true, | ||
| inject: function (injected) { | ||
| return nextID++; | ||
| }, | ||
| onScheduleFiberRoot: function (id, root, children) {}, | ||
| onCommitFiberRoot: function (id, root, maybePriorityLevel, didError) {}, | ||
| onCommitFiberUnmount: function () {}, | ||
| }; | ||
| } | ||
| if (hook.isDisabled) { | ||
| // This isn't a real property on the hook, but it can be set to opt out | ||
| // of DevTools integration and associated warnings and logs. | ||
| // Using console['warn'] to evade Babel and ESLint | ||
| console["warn"]( | ||
| "Something has shimmed the React DevTools global hook (__REACT_DEVTOOLS_GLOBAL_HOOK__). " + | ||
| "Fast Refresh is not compatible with this shim and will be disabled.", | ||
| ); | ||
| return; | ||
| } | ||
| // Here, we just want to get a reference to scheduleRefresh. | ||
| let oldInject = hook.inject; | ||
| hook.inject = function (injected) { | ||
| let id = oldInject.apply(this, arguments); | ||
| if ( | ||
| typeof injected.scheduleRefresh === "function" && | ||
| typeof injected.setRefreshHandler === "function" | ||
| ) { | ||
| // This version supports React Refresh. | ||
| helpersByRendererID.set(id, injected); | ||
| } | ||
| return id; | ||
| }; | ||
| // Do the same for any already injected roots. | ||
| // This is useful if ReactDOM has already been initialized. | ||
| // https://github.com/facebook/react/issues/17626 | ||
| hook.renderers.forEach(function (injected, id) { | ||
| if ( | ||
| typeof injected.scheduleRefresh === "function" && | ||
| typeof injected.setRefreshHandler === "function" | ||
| ) { | ||
| // This version supports React Refresh. | ||
| helpersByRendererID.set(id, injected); | ||
| } | ||
| }); | ||
| // We also want to track currently mounted roots. | ||
| let oldOnCommitFiberRoot = hook.onCommitFiberRoot; | ||
| let oldOnScheduleFiberRoot = hook.onScheduleFiberRoot || function () {}; | ||
| hook.onScheduleFiberRoot = function (id, root, children) { | ||
| if (!isPerformingRefresh) { | ||
| // If it was intentionally scheduled, don't attempt to restore. | ||
| // This includes intentionally scheduled unmounts. | ||
| failedRoots.delete(root); | ||
| rootElements.set(root, children); | ||
| } | ||
| return oldOnScheduleFiberRoot.apply(this, arguments); | ||
| }; | ||
| hook.onCommitFiberRoot = function (id, root, maybePriorityLevel, didError) { | ||
| let helpers = helpersByRendererID.get(id); | ||
| if (helpers !== undefined) { | ||
| helpersByRoot.set(root, helpers); | ||
| let current = root.current; | ||
| let alternate = current.alternate; | ||
| // We need to determine whether this root has just (un)mounted. | ||
| // This logic is copy-pasted from similar logic in the DevTools backend. | ||
| // If this breaks with some refactoring, you'll want to update DevTools too. | ||
| if (alternate !== null) { | ||
| let wasMounted = | ||
| alternate.memoizedState != null && | ||
| alternate.memoizedState.element != null; | ||
| let isMounted = | ||
| current.memoizedState != null && | ||
| current.memoizedState.element != null; | ||
| if (!wasMounted && isMounted) { | ||
| // Mount a new root. | ||
| mountedRoots.add(root); | ||
| failedRoots.delete(root); | ||
| } else if (wasMounted && isMounted) { | ||
| // Update an existing root. | ||
| // This doesn't affect our mounted root Set. | ||
| } else if (wasMounted && !isMounted) { | ||
| // Unmount an existing root. | ||
| mountedRoots.delete(root); | ||
| if (didError) { | ||
| // We'll remount it on future edits. | ||
| failedRoots.add(root); | ||
| } else { | ||
| helpersByRoot.delete(root); | ||
| } | ||
| } else if (!wasMounted && !isMounted) { | ||
| if (didError) { | ||
| // We'll remount it on future edits. | ||
| failedRoots.add(root); | ||
| } | ||
| } | ||
| } else { | ||
| // Mount a new root. | ||
| mountedRoots.add(root); | ||
| } | ||
| } | ||
| // Always call the decorated DevTools hook. | ||
| return oldOnCommitFiberRoot.apply(this, arguments); | ||
| }; | ||
| } | ||
| // This is a wrapper over more primitive functions for setting signature. | ||
| // Signatures let us decide whether the Hook order has changed on refresh. | ||
| // | ||
| // This function is intended to be used as a transform target, e.g.: | ||
| // let _s = createSignatureFunctionForTransform() | ||
| // | ||
| // function Hello() { | ||
| // const [foo, setFoo] = useState(0); | ||
| // const value = useCustomHook(); | ||
| // _s(); /* Call without arguments triggers collecting the custom Hook list. | ||
| // * This doesn't happen during the module evaluation because we | ||
| // * don't want to change the module order with inline requires. | ||
| // * Next calls are noops. */ | ||
| // return <h1>Hi</h1>; | ||
| // } | ||
| // | ||
| // /* Call with arguments attaches the signature to the type: */ | ||
| // _s( | ||
| // Hello, | ||
| // 'useState{[foo, setFoo]}(0)', | ||
| // () => [useCustomHook], /* Lazy to avoid triggering inline requires */ | ||
| // ); | ||
| export function createSignatureFunctionForTransform() { | ||
| let savedType; | ||
| let hasCustomHooks; | ||
| let didCollectHooks = false; | ||
| return function (type, key, forceReset, getCustomHooks) { | ||
| if (typeof key === "string") { | ||
| // We're in the initial phase that associates signatures | ||
| // with the functions. Note this may be called multiple times | ||
| // in HOC chains like _s(hoc1(_s(hoc2(_s(actualFunction))))). | ||
| if (!savedType) { | ||
| // We're in the innermost call, so this is the actual type. | ||
| savedType = type; | ||
| hasCustomHooks = typeof getCustomHooks === "function"; | ||
| } | ||
| // Set the signature for all types (even wrappers!) in case | ||
| // they have no signatures of their own. This is to prevent | ||
| // problems like https://github.com/facebook/react/issues/20417. | ||
| if ( | ||
| type != null && | ||
| (typeof type === "function" || typeof type === "object") | ||
| ) { | ||
| setSignature(type, key, forceReset, getCustomHooks); | ||
| } | ||
| return type; | ||
| } else { | ||
| // We're in the _s() call without arguments, which means | ||
| // this is the time to collect custom Hook signatures. | ||
| // Only do this once. This path is hot and runs *inside* every render! | ||
| if (!didCollectHooks && hasCustomHooks) { | ||
| didCollectHooks = true; | ||
| collectCustomHooksForSignature(savedType); | ||
| } | ||
| } | ||
| }; | ||
| } |
| import { PluginOption } from "vite"; | ||
| export declare const swcReactRefresh: () => PluginOption; |
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.swcReactRefresh = void 0; | ||
| const fs_1 = __importDefault(require("fs")); | ||
| const path_1 = __importDefault(require("path")); | ||
| const core_1 = require("@swc/core"); | ||
| const runtimePublicPath = "/@react-refresh"; | ||
| const preambleCode = `import { injectIntoGlobalHook } from "${runtimePublicPath}"; | ||
| injectIntoGlobalHook(window); | ||
| window.$RefreshReg$ = () => {}; | ||
| window.$RefreshSig$ = () => (type) => type;`; | ||
| const importReactRE = /(^|\n)import\s+(\*\s+as\s+)?React(,|\s+)/; | ||
| let define; | ||
| let automaticRuntime = false; | ||
| const swcReactRefresh = () => ({ | ||
| name: "react-refresh", | ||
| apply: "serve", | ||
| config: (config) => { | ||
| if (config.esbuild) { | ||
| define = config.esbuild.define; | ||
| automaticRuntime = config.esbuild.jsx === "automatic"; | ||
| } | ||
| return automaticRuntime | ||
| ? { | ||
| esbuild: false, | ||
| optimizeDeps: { include: ["react/jsx-dev-runtime"] }, | ||
| } | ||
| : { esbuild: false }; | ||
| }, | ||
| resolveId: (id) => (id === runtimePublicPath ? id : undefined), | ||
| load: (id) => id === runtimePublicPath | ||
| ? fs_1.default.readFileSync(path_1.default.join(__dirname, "refresh-runtime.js"), "utf-8") | ||
| : undefined, | ||
| transformIndexHtml: () => [ | ||
| { tag: "script", attrs: { type: "module" }, children: preambleCode }, | ||
| ], | ||
| async transform(code, id) { | ||
| if (id.includes("node_modules")) | ||
| return; | ||
| if (!/\.[jt]sx?$/.test(id)) | ||
| return; | ||
| const result = await (0, core_1.transform)(code, { | ||
| filename: id, | ||
| swcrc: false, | ||
| configFile: false, | ||
| sourceMaps: true, | ||
| jsc: { | ||
| target: "es2020", | ||
| transform: { | ||
| react: { | ||
| refresh: true, | ||
| development: true, | ||
| useBuiltins: true, | ||
| runtime: automaticRuntime ? "automatic" : undefined, | ||
| }, | ||
| optimizer: { globals: { vars: define } }, | ||
| }, | ||
| }, | ||
| }); | ||
| let mappingPrefix = ""; | ||
| if (!automaticRuntime && | ||
| result.code.includes("React.createElement") && | ||
| !importReactRE.test(result.code)) { | ||
| result.code = `import React from "react";\n${result.code}`; | ||
| mappingPrefix += ";"; | ||
| } | ||
| if (result.code.includes("$RefreshReg$")) { | ||
| mappingPrefix += ";;;;;;;;;;;;"; | ||
| result.code = `import * as RefreshRuntime from "${runtimePublicPath}"; | ||
| let prevRefreshReg; | ||
| let prevRefreshSig; | ||
| if (!window.$RefreshReg$) throw new Error("React refresh preamble was not loaded. Something is wrong."); | ||
| prevRefreshReg = window.$RefreshReg$; | ||
| prevRefreshSig = window.$RefreshSig$; | ||
| window.$RefreshReg$ = RefreshRuntime.getRefreshReg("${id}"); | ||
| window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform; | ||
| ${result.code} | ||
| window.$RefreshReg$ = prevRefreshReg; | ||
| window.$RefreshSig$ = prevRefreshSig; | ||
| import.meta.hot.accept(); | ||
| RefreshRuntime.enqueueUpdate(); | ||
| `; | ||
| } | ||
| if (!mappingPrefix) | ||
| return result; | ||
| const sourceMap = JSON.parse(result.map); | ||
| sourceMap.mappings = mappingPrefix + sourceMap.mappings; | ||
| return { code: result.code, map: sourceMap }; | ||
| }, | ||
| }); | ||
| exports.swcReactRefresh = swcReactRefresh; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
25237
2.71%0
-100%600
6.76%1
Infinity%Updated