ReferenceError: $RefreshReg$ 未定义

Mik*_*hke 10 reactjs babeljs

在基于 CRA 的 React 应用程序中,当我导入也由普通应用程序代码(正常 === 非工作程序)导入的文件并使用 babel dev 运行应用程序时,我在 webworker 文件(所有代码都使用 Typescript)中收到此错误服务器处于调试模式。

搜索此错误将我带到各种模块特定问题报告/解决方案,但是我无法使用它们。但很明显,这是一个 React 热重载问题,我想知道如何解决它,因为它使我无法在 Web Worker 中使用我的应用程序代码。

我的开发依赖项是:

    "devDependencies": {
        "@babel/core": "^7.12.10",
        "@babel/preset-env": "^7.11.11",
        "@babel/preset-typescript": "^7.12.7",
        "@testing-library/react": "^11.2.3",
        "@types/classnames": "^2.2.11",
        "@types/color": "^3.0.1",
        "@types/d3": "^6.2.0",
        "@types/history": "4.7.8",
        "@types/jest": "^26.0.20",
        "@types/lodash": "^4.14.168",
        "@types/node": "^14.14.22",
        "@types/react": "^17.0.0",
        "@types/react-dom": "^17.0.0",
        "@types/react-test-renderer": "^17.0.0",
        "@types/react-window": "^1.8.2",
        "@types/resize-observer-browser": "^0.1.5",
        "@types/selenium-webdriver": "^4.0.11",
        "@types/topojson": "^3.2.2",
        "@types/uuid": "^8.3.0",
        "@types/ws": "^7.4.0",
        "@typescript-eslint/eslint-plugin-tslint": "^4.14.0",
        "acorn": "^8.0.5",
        "antlr4ts-cli": "^0.5.0-alpha.4",
        "eslint": "^7.18.0",
        "eslint-plugin-flowtype": "^5.2.0",
        "eslint-plugin-import": "^2.22.1",
        "eslint-plugin-jsdoc": "^31.3.3",
        "eslint-plugin-jsx-a11y": "^6.4.1",
        "eslint-plugin-prefer-arrow": "^1.2.2",
        "eslint-plugin-react": "^7.22.0",
        "eslint-plugin-react-hooks": "^4.2.0",
        "identity-obj-proxy": "^3.0.0",
        "jest": "26.6.0",
        "jest-transform-stub": "^2.0.0",
        "jest-websocket-mock": "^2.2.0",
        "mock-socket": "^9.0.3",
        "monaco-editor-webpack-plugin": "^1.9.1",
        "monaco-typescript": "^4.2.0",
        "raw-loader": "^4.0.2",
        "react-app-rewired": "^2.1.8",
        "react-scripts": "^4.0.3",
        "react-test-renderer": "^17.0.1",
        "selenium-webdriver": "^4.0.0-beta.1",
        "ts-jest": "^26.5.2",
        "tslint": "^6.1.3",
        "typescript": "^4.1.3",
        "typescript-eslint-parser": "22.0.0",
        "webdriver-manager": "^12.1.8",
        "webpack": "4.44.2",
        "webpack-bundle-analyzer": "^4.4.0",
        "worker-loader": "^3.0.8",
        "ws": "^7.4.3"
    },
Run Code Online (Sandbox Code Playgroud)

我也可以应用的唯一有前途的解决方案是:https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/176#issuecomment-683150213,但它没有帮助。我仍然遇到同样的错误。我的网络工作者代码是:

/* eslint-disable no-restricted-globals */
/* eslint-disable no-eval */
/* eslint-disable @typescript-eslint/no-unused-vars */

(window as any).$RefreshReg$ = () => {/**/};
(window as any).$RefreshSig$ = () => () => {/**/};

import { ShellInterfaceSqlEditor } from "../../supplement/ShellInterface";
import { PrivateWorker, ExecutionResultType, IConsoleWorkerData } from "./console.worker-types";

const backend = new ShellInterfaceSqlEditor();
const ctx: PrivateWorker = self as any;

Run Code Online (Sandbox Code Playgroud)

不幸的是,关于更改 babel 加载器配置的进一步讨论超出了我的范围,因为我自己没有配置它(但是,我正在使用react-app-rewired 来配置一些自定义加载器)。

我还可以尝试什么来解决这个问题?

小智 2

我尝试了这个答案和各种 Github 问题中的许多解决方案,但没有一个为我解决问题。最终我通过WebpacksideEffects优化和配置找到了解决方案!

\n

长话短说:

\n
    \n
  • 确保您的 Webpack 配置有一个对象optimization集,并且该optimization对象的属性sideEffects设置为 true。似乎nx并且可能cra或craco默认为 false,如果未使用的 React 组件作为“桶”文件的一部分导出,则会将其导入到 WebWorker 包中
  • \n
  • 如果您要导入自己的共享 ui 包,该包导出 React 组件和一些非 React 组件,那么您需要sideEffects在包的package.json文件中指定配置,以确保 React 组件被标记为“纯”且安全修剪。请参阅下面的更多细节
  • \n
\n

在检查了我的 WebWorker 的包之后,我意识到一些 React 组件被捆绑到了工作包中worker-loader,即使它们没有在工作程序中使用。至少其中一种情况发生在我们的应用程序中,因为我们有一个共享包,其中包含一些 React 组件和其他普通的 TS 实用程序。

\n

我们的 WebWorker 正在从此包中导入一个值(名为导出),并且由于某种原因,整个包被包含在 WebWorker \xe2\x80\x93 中,包括未在任何地方使用的 React 组件!然后,React Fast Refresh 插件(默认情况下由 CRA 安装/使用)通过支持热刷新/重新加载(调用 和$RefreshReg$co)所需的更改来增强我们的 WebWorker 包。

\n

有关此问题的一些 Github 问题引用了名为 的 Webpack tree shake 优化sideEffects,您可以在https://webpack.js.org/guides/tree-shaking/阅读更多相关信息。这是相关的部分:

\n
\n

新的 webpack 4 版本扩展了此功能,通过“sideEffects”package.json 属性向编译器提供提示,以指示项目中的哪些文件是“纯粹的”,因此如果未使用,可以安全地修剪。

\n
\n

在您的包中 package.json,您可以指定"sideEffects": false将整个包标记为“纯”并且在未使用时可以安全地修剪,或者您可以指定确实有副作用的特定导出/路径,例如对我们来说:

\n
  "sideEffects": [\n    "./src/styles/*"\n  ],\n
Run Code Online (Sandbox Code Playgroud)\n

然而,设置这个值并不能立即对我们的应用程序起作用,这令人困惑。最终,我遇到了一个关于此问题的线程,nx其中一条非常有用的评论指出他们的 Webpack 配置禁用了sideEffectsWebpack 的优化:(https://github.com/nrwl/nx/issues/9717#issuecomment-1163533981)

\n
\n

我发现 Nx 正在将 optimization: { sideEffects: false } 传递给 webpack,这会显式关闭 tree shake,无论你的 package.json 内容如何。在我最初的问题(lodash-es)中没有进行树摇动的库已经有了自己的 package.json,它指定了促进最佳树摇动所需的设置,但是 Nx 正在全局关闭 Webpack 中的树摇动,这样对于项目中的任何库或任何代码都不会发生这种情况。

\n
\n

我尝试webpackConfig.optimization.sideEffects = true在我的应用程序中明确设置,然后繁荣!问题已解决,React 组件已从 WebWorker 捆绑包中排除。

\n

  • 我从 CRA 转向了 preact、vite.js、esbuild 和 rollup,所以我无法评估你的答案。但从您投入的努力以及阅读给定链接中的描述来看,这似乎是一个很好的答案,所以我将接受这个答案。 (2认同)