Showing preview only (335K chars total). Download the full file or copy to clipboard to get everything.
Repository: pmmmwh/react-refresh-webpack-plugin
Branch: main
Commit: 5e4ce91c63e1
Files: 194
Total size: 293.4 KB
Directory structure:
gitextract_f1f9g2an/
├── .babelrc.json
├── .eslintignore
├── .eslintrc.json
├── .gitattributes
├── .github/
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── client/
│ ├── ErrorOverlayEntry.js
│ ├── ReactRefreshEntry.js
│ ├── package.json
│ └── utils/
│ ├── errorEventHandlers.js
│ ├── formatWebpackErrors.js
│ └── retry.js
├── docs/
│ ├── API.md
│ └── TROUBLESHOOTING.md
├── examples/
│ ├── flow-with-babel/
│ │ ├── .flowconfig
│ │ ├── babel.config.js
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── index.html
│ │ ├── src/
│ │ │ ├── App.jsx
│ │ │ ├── ArrowFunction.jsx
│ │ │ ├── ClassDefault.jsx
│ │ │ ├── ClassNamed.jsx
│ │ │ ├── FunctionDefault.jsx
│ │ │ ├── FunctionNamed.jsx
│ │ │ ├── LazyComponent.jsx
│ │ │ └── index.js
│ │ └── webpack.config.js
│ ├── typescript-with-babel/
│ │ ├── babel.config.js
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── index.html
│ │ ├── src/
│ │ │ ├── App.tsx
│ │ │ ├── ArrowFunction.tsx
│ │ │ ├── ClassDefault.tsx
│ │ │ ├── ClassNamed.tsx
│ │ │ ├── FunctionDefault.tsx
│ │ │ ├── FunctionNamed.tsx
│ │ │ ├── LazyComponent.tsx
│ │ │ └── index.tsx
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ ├── typescript-with-swc/
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── index.html
│ │ ├── src/
│ │ │ ├── App.tsx
│ │ │ ├── ArrowFunction.tsx
│ │ │ ├── ClassDefault.tsx
│ │ │ ├── ClassNamed.tsx
│ │ │ ├── FunctionDefault.tsx
│ │ │ ├── FunctionNamed.tsx
│ │ │ ├── LazyComponent.tsx
│ │ │ └── index.tsx
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ ├── typescript-with-tsc/
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── index.html
│ │ ├── src/
│ │ │ ├── App.tsx
│ │ │ ├── ArrowFunction.tsx
│ │ │ ├── ClassDefault.tsx
│ │ │ ├── ClassNamed.tsx
│ │ │ ├── FunctionDefault.tsx
│ │ │ ├── FunctionNamed.tsx
│ │ │ ├── LazyComponent.tsx
│ │ │ └── index.tsx
│ │ ├── tsconfig.dev.json
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ ├── webpack-dev-server/
│ │ ├── babel.config.js
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── index.html
│ │ ├── src/
│ │ │ ├── App.jsx
│ │ │ ├── ArrowFunction.jsx
│ │ │ ├── ClassDefault.jsx
│ │ │ ├── ClassNamed.jsx
│ │ │ ├── FunctionDefault.jsx
│ │ │ ├── FunctionNamed.jsx
│ │ │ ├── LazyComponent.jsx
│ │ │ └── index.js
│ │ └── webpack.config.js
│ ├── webpack-hot-middleware/
│ │ ├── babel.config.js
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── index.html
│ │ ├── server.js
│ │ ├── src/
│ │ │ ├── App.jsx
│ │ │ ├── ArrowFunction.jsx
│ │ │ ├── ClassDefault.jsx
│ │ │ ├── ClassNamed.jsx
│ │ │ ├── FunctionDefault.jsx
│ │ │ ├── FunctionNamed.jsx
│ │ │ ├── LazyComponent.jsx
│ │ │ └── index.js
│ │ └── webpack.config.js
│ └── webpack-plugin-serve/
│ ├── babel.config.js
│ ├── package.json
│ ├── public/
│ │ └── index.html
│ ├── src/
│ │ ├── App.jsx
│ │ ├── ArrowFunction.jsx
│ │ ├── ClassDefault.jsx
│ │ ├── ClassNamed.jsx
│ │ ├── FunctionDefault.jsx
│ │ ├── FunctionNamed.jsx
│ │ ├── LazyComponent.jsx
│ │ └── index.js
│ └── webpack.config.js
├── jest.config.js
├── lib/
│ ├── globals.js
│ ├── index.js
│ ├── options.json
│ ├── runtime/
│ │ └── RefreshUtils.js
│ ├── types.js
│ └── utils/
│ ├── getAdditionalEntries.js
│ ├── getIntegrationEntry.js
│ ├── getSocketIntegration.js
│ ├── index.js
│ ├── injectRefreshLoader.js
│ ├── makeRefreshRuntimeModule.js
│ └── normalizeOptions.js
├── loader/
│ ├── index.js
│ ├── options.json
│ ├── types.js
│ └── utils/
│ ├── getIdentitySourceMap.js
│ ├── getModuleSystem.js
│ ├── getRefreshModuleRuntime.js
│ ├── index.js
│ ├── normalizeOptions.js
│ └── webpackGlobal.js
├── options/
│ └── index.js
├── overlay/
│ ├── components/
│ │ ├── CompileErrorTrace.js
│ │ ├── PageHeader.js
│ │ ├── RuntimeErrorFooter.js
│ │ ├── RuntimeErrorHeader.js
│ │ ├── RuntimeErrorStack.js
│ │ └── Spacer.js
│ ├── containers/
│ │ ├── CompileErrorContainer.js
│ │ └── RuntimeErrorContainer.js
│ ├── index.js
│ ├── package.json
│ ├── theme.js
│ └── utils.js
├── package.json
├── scripts/
│ └── test.js
├── sockets/
│ ├── WDSSocket.js
│ ├── WHMEventSource.js
│ ├── WPSSocket.js
│ └── package.json
├── test/
│ ├── conformance/
│ │ ├── ReactRefresh.test.js
│ │ └── environment.js
│ ├── helpers/
│ │ ├── compilation/
│ │ │ ├── fixtures/
│ │ │ │ └── source-map-loader.js
│ │ │ ├── index.js
│ │ │ └── normalizeErrors.js
│ │ └── sandbox/
│ │ ├── aliasWDSv4.js
│ │ ├── configs.js
│ │ ├── fixtures/
│ │ │ └── hmr-notifier.js
│ │ ├── index.js
│ │ └── spawn.js
│ ├── jest-environment.js
│ ├── jest-global-setup.js
│ ├── jest-global-teardown.js
│ ├── jest-resolver.js
│ ├── jest-test-setup.js
│ ├── loader/
│ │ ├── fixtures/
│ │ │ ├── auto/
│ │ │ │ └── package.json
│ │ │ ├── cjs/
│ │ │ │ ├── esm/
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── package.json
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ └── esm/
│ │ │ ├── cjs/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── loader.test.js
│ │ ├── unit/
│ │ │ ├── getIdentitySourceMap.test.js
│ │ │ ├── getModuleSystem.test.js
│ │ │ ├── getRefreshModuleRuntime.test.js
│ │ │ └── normalizeOptions.test.js
│ │ └── validateOptions.test.js
│ ├── mocks/
│ │ └── fetch.js
│ └── unit/
│ ├── fixtures/
│ │ └── socketIntegration.js
│ ├── getAdditionalEntries.test.js
│ ├── getIntegrationEntry.test.js
│ ├── getSocketIntegration.test.js
│ ├── globals.test.js
│ ├── makeRefreshRuntimeModule.test.js
│ ├── normalizeOptions.test.js
│ └── validateOptions.test.js
├── tsconfig.json
├── types/
│ ├── lib/
│ │ ├── index.d.ts
│ │ └── types.d.ts
│ ├── loader/
│ │ ├── index.d.ts
│ │ └── types.d.ts
│ └── options/
│ └── index.d.ts
└── webpack.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc.json
================================================
{
"env": {
"test": {
"plugins": ["@babel/plugin-transform-modules-commonjs"]
}
}
}
================================================
FILE: .eslintignore
================================================
*dist/
*node_modules/
*umd/
*__tmp__
# Ignore examples because they might have custom ESLint configurations
examples/*
================================================
FILE: .eslintrc.json
================================================
{
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
"parserOptions": {
"ecmaVersion": 2022
},
"env": {
"commonjs": true,
"es2022": true,
"node": true
},
"overrides": [
{
"files": ["client/**/*.js", "overlay/**/*.js", "lib/runtime/**/*.js", "sockets/**/*.js"],
"parserOptions": {
"ecmaVersion": 2015
},
"env": {
"browser": true,
"es6": true
}
},
{
"files": [
"scripts/test.mjs",
"test/jest-test-setup.js",
"test/helpers/{,!(fixtures)*/}*.js",
"test/mocks/**/*.js",
"test/**/*.test.js"
],
"env": {
"jest": true
},
"globals": {
"__DEBUG__": true,
"WDS_VERSION": true,
"browser": true,
"window": true
},
"parserOptions": {
"sourceType": "module"
}
},
{
"files": ["test/helpers/**/fixtures/*.js", "test/conformance/**/*.test.js"],
"env": {
"browser": true
}
},
{
"files": ["test/**/fixtures/esm/*.js"],
"parserOptions": {
"ecmaVersion": 2015,
"sourceType": "module"
},
"env": {
"commonjs": false,
"es6": true
}
},
{
"files": ["test/**/fixtures/cjs/esm/*.js"],
"parserOptions": {
"ecmaVersion": 2015,
"sourceType": "module"
},
"env": {
"commonjs": false,
"es6": true
}
},
{
"files": ["test/**/fixtures/esm/cjs/*.js"],
"env": {
"commonjs": true,
"es6": true
}
}
]
}
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
lint-and-format:
name: Lint and Format
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: yarn
node-version: 22
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Check Linting
run: yarn lint
- name: Check Formatting
run: yarn format:check
test:
name: Tests (Node ${{ matrix.node-version }} - WDS ${{ matrix.wds-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version:
- '18'
- '20'
- '22'
wds-version:
- '4'
- '5'
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: yarn
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Run Tests
run: yarn test --testPathIgnorePatterns conformance
env:
BROWSER: false
WDS_VERSION: ${{ matrix.wds-version }}
conformance:
name: Conformance (Node ${{ matrix.node-version }} - WDS ${{ matrix.wds-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version:
- '18'
- '20'
- '22'
wds-version:
- '4'
- '5'
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: yarn
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Disable AppArmor
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
- name: Run Conformance Tests
run: yarn test conformance
env:
WDS_VERSION: ${{ matrix.wds-version }}
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
*node_modules
# distribution
*dist
*umd
# misc
.DS_Store
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# editor config
.idea
.vscode
# test artifacts
*__tmp__
================================================
FILE: .prettierignore
================================================
*dist/
*node_modules/
*umd/
*__tmp__
================================================
FILE: .prettierrc.json
================================================
{
"printWidth": 100,
"singleQuote": true,
"trailingComma": "es5"
}
================================================
FILE: CHANGELOG.md
================================================
## 0.6.2 (26 Nov 2025)
### Fixes
- Relaxed peer dependency requirement on `type-fest` to allow v5.x
([#934](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/934))
## 0.6.1 (26 Jun 2025)
### Fixes
- Ensure `this` propagates into module factory properly
([#921](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/921))
## 0.6.0 (28 Apr 2025)
### BREAKING
- Minimum required Node.js version has been bumped to `18.12.0`.
- Minimum required `webpack` version has been bumped to `5.2.0`.
- Minimum supported `webpack-dev-server` version has been bumped to `4.8.0`.
- Minimum supported `webpack-plugin-serve` version has been bumped to `1.0.0`.
- `overlay.sockHost`, `overlay.sockPath`, `overlay.sockPort`, `overlay.sockProtocol` and `overlay.useURLPolyfill` have all been removed.
([#850](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/850))
It was necessary to support WDS below `4.8.0` (published in April 2022).
It is no-longer necessary as a direct integration with WDS is now possible.
### Features
- Added helper script to better support use cases where React and/or React-DOM are externalized
([#852](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/852))
### Fixes
- Ensure plugin injected entries are no-op in production
([#900](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/900))
### Internal
- Dropped support for Webpack 4 / WDS 3
([#850](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/850),
[#904](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/904))
- Migrated from `ansi-html` to `anser` in error overlay
([#854](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/854))
- Bumped all development dependencies
([#905](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/905))
## 0.5.17 (26 Jun 2025)
### Fixes
- Ensure `this` propagates into module factory properly
([#922](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/922))
## 0.5.16 (31 Mar 2025)
### Fixes
- Fixed out of order cleanup when using top-level await
([#898](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/898))
## 0.5.15 (3 Jun 2024)
### Fixes
- Fixed wrong import in error overlay for `ansi-html`
([#853](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/853))
## 0.5.14 (1 Jun 2024)
### Fixes
- Moved to `ansi-html` `v0.0.9` and `schema-utils` `v4.x`
([#848](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/848))
### Internal
- Run tests on latest versions of Node.js 18, 20 and 22
([#848](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/848))
- Bumped `jest` to v29 and some other development dependencies
([#848](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/848))
- Removed `yalc`
([#849](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/849))
## 0.5.13 (28 Apr 2024)
### Fixes
- Fixed module system inferring (ESM vs CJS) to start from the point of each file
([#771](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/771))
## 0.5.12 (27 Apr 2024)
### Fixes
- Fixed incorrect `sockProtocol` override
([#835](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/835))
- Relaxed peer dependency requirement on `webpack-dev-server` to allow v5.x
([#837](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/837))
## 0.5.11 (15 Aug 2023)
### Features
- Added support to exclude dynamically generated modules from other loaders
([#769](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/769))
### Fixes
- Fixed unnecessary memory leaks due to `prevExports`
([#766](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/766))
- Relaxed peer dependency requirement on `type-fest` to allow v4.x
([#767](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/767))
- Fixed module type resolution when there is difference across contexts
([#768](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/768))
## 0.5.10 (24 Nov 2022)
### Fixes
- Bumped `loader-utils` to fix security vulnerability
([#700](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/700))
## 0.5.9 (10 Nov 2022)
### Fixes
- Bumped `loader-utils` to fix security vulnerability
([#685](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/685))
## 0.5.8 (9 Oct 2022)
### Fixes
- Fixed performance issue regarding `require.resolve` in loader injection
([#669](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/669))
- Bumped `core-js-pure` to not depend on deprecated versions
([#674](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/674))
## 0.5.7 (23 May 2022)
### Fixes
- Removed debug `console.log` statement
([#631](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/631))
### Internal
- Run tests on Node.js 18
([#631](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/631))
## 0.5.6 (10 May 2022)
### Fixes
- Fixed faulty `this` type import in loader
([#624](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/624))
- Made current script detection more robust for edge cases
([#630](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/630))
### Internal
- Swapped to new `ReactDOM.createRoot` API in examples
([#626](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/626))
## 0.5.5 (4 April 2022)
### Fixes
- Handle unknown `moduleId` for dynamically generated modules
([#547](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/547))
- Handle WDS `auto` value on `port`
([#574](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/574))
- Fixed `react-refresh@0.12.0` compatibility
([#576](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/576))
- Fixed crash when parsing compile errors in overlay
([#577](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/577))
- Respect virtual modules when injecting loader
([#593](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/593))
- Allow `port` to be missing for WDS, also some general refactoring
([#623](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/623))
### Internal
- A couple documentation changes in README
([#575](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/575),
[8c39623](https://github.com/pmmmwh/react-refresh-webpack-plugin/commit/8c39623dac237aa15795b60820babcffebb28c64),
[#597](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/597))
- Bumped dependencies for testing infrastructure
([#526](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/526),
[#564](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/564),
[#567](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/567),
[#581](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/581),
[#588](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/588),
[#591](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/591),
[#594](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/594),
[#616](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/616))
## 0.5.4 (22 December 2021)
### Fixes
- Skip loader injection for files referenced as assets
([#545](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/545))
- Changed failures of `exports` capturing to warn instead of throw
([#546](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/546))
## 0.5.3 (28 November 2021)
### Fixes
- Updated overlay for unsafe area in Safari
([#528](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/528))
- Fixed performance in large projects due to memory leak in loader
([#537](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/537))
## 0.5.2 (19 November 2021)
### Features
- Added support for WDS v4 `client.webSocketURL`
([#529](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/529))
### Fixes
- Fixed lost module context due to interceptor by always using regular functions
([#531](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/531))
- Relaxed peer dependency requirement on `react-refresh`
([#534](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/534))
## 0.5.1 (15 September 2021)
### Fixes
- Relaxed peer dependency requirement on `type-fest` to allow v2.x
([#507](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/507),
[#508](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/508))
### Internal
- Fixed typos in README
([#509](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/509))
## 0.5.0 (14 September 2021)
### BREAKING
- While most of the public API did not change,
we've re-written a large chunk of the runtime code to support a wider range of use cases.
This is likely to provide more stability, but if `0.4.x` works in your setup but `0.5.x` doesn't,
please file us an issue - we would love to address it!
- The `disableRefreshCheck` option have been removed.
([#285](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/285))
It has long been effect-less and deprecated since `0.3.x`.
- The `overlay.useLegacyWDSSockets` have been removed.
([#498](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/498))
It is aimed to support WDS below `3.6.0` (published in June 2019),
but looking at current usage and download stats,
we've decided it is best to drop support for the old socket format moving forward.
- Handling of port `0` have been removed.
([#337](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/337))
- `html-entities` have been bumped to `2.x`.
([#321](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/321))
- `react-refresh` have been bumped to `0.10.0`.
([#353](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/353))
### Features
- Added WDS v4 support with new socket defaults through Webpack config
([#241](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/241),
[#286](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/286),
[#392](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/392),
[#413](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/413),
[#479](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/479))
- Added the `overlay.sockProtocol` option
([#242](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/242))
- Added monorepo compatibility via the the `library` option
([#273](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/273))
- Rewritten URL handling using WHATWG `URL` APIs with automatic pony-filling
([#278](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/278),
[#332](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/332),
[#378](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/378))
- Rewritten Webpack 5 compatibility using new APIs and hooks
([#319](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/319),
[#372](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/372),
[#434](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/434),
[#483](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/483))
- Rewritten refresh runtime to be fully module system aware
([#337](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/337),
[#461](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/461),
[#482](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/482),
[#492](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/492))
- Rewritten Webpack 4 and 5 checks using feature detection on compiler
([#415](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/415))
- Added support for `experiments.topLevelAwait`
([#435](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/435),
[#447](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/447),
[#493](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/493))
- Added retry logic when socket initialisation fails
([#446](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/446))
### Fixes
- Relaxed peer dependency requirement on `type-fest`
([#257](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/257),
[c02018a](https://github.com/pmmmwh/react-refresh-webpack-plugin/commit/c02018a853f58341d44ea9f1b56a9568ffe7b657),
[#484](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/484))
- Relaxed requirement on the `overlay` option to accept relative paths
([#284](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/284))
- Patched unstable initialisation of global scope across module boundaries
([#290](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/290),
[#369](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/369),
[#464](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/464),
[#505](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/505))
- Patched quote escaping in injected runtime code
([#306](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/306))
- Invalidate updates outside of Refresh boundary for consistency
([#307](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/307))
- Properly throw when an ambiguous entrypoint is received while using Webpack 4
([#320](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/320))
- Fixed overlay script source detection for WDS when no `src` is found
([#331](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/331))
- Fixed possible Stack Overflow through self-referencing
([#370](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/370),
[#380](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/380))
- Relaxed errors on HMR not found to not crash JS parsing
([#371](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/371))
- Ensure overlay code won't run if disabled
([#374](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/374))
- Relaxed peer dependency requirement on `@types/webpack`
([#414](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/414))
- Fixed compiler error overlay crashes when messages are empty
([#462](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/462))
- Swapped `ansi-html` to `ansi-html-community` to fix ReDoS vulnerability
([#501](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/501))
### Internal
- More stable testing infrastructure
([#234](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/234))
- Run tests by default on Webpack 5
([#440](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/440))
- Rewrite documentation and fix outstanding issues
([#283](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/283),
[#291](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/291),
[#311](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/311),
[#376](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/376),
[#480](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/480),
[#497](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/497),
[#499](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/499))
- Added documentation on community plugins: `react-refresh-typescript` and `swc`
([#248](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/248),
[fbe1f27](https://github.com/pmmmwh/react-refresh-webpack-plugin/commit/fbe1f270de46c4a308d996a4487653a95aebfc25),
[#450](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/450))
## 0.4.3 (2 November 2020)
### Fixes
- Fixed Yarn 2 PnP compatibility with absolute `react-refresh/runtime` imports
([#230](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/230))
- Fixed Webpack 5 compatibility by requiring `__webpack_require__`
([#233](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/233))
- Fixed IE 11 compatibility in socket code
([4033e6af](https://github.com/pmmmwh/react-refresh-webpack-plugin/commit/4033e6af279f5f50396ff24fb1ec89c41fc2df32))
- Relaxed peer dependency requirement for `react-refresh` to allow `0.9.x`
([747c19ba](https://github.com/pmmmwh/react-refresh-webpack-plugin/commit/747c19ba43d81f19a042d44922d0518c6403528c))
## 0.4.2 (3 September 2020)
### Fixes
- Patched loader to use with Node.js global `fetch` polyfills
([#193](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/193))
- Patched default `include` and `exclude` options to be case-insensitive
([#194](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/194))
## 0.4.1 (28 July 2020)
### Fixes
- Fixed accidental use of testing alias `webpack.next` in published plugin code
([#167](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/167))
## 0.4.0 (28 July 2020)
### BREAKING
- Minimum required Node.js version have been bumped to 10 as Node.js 8 is EOL now.
- Minimum required Webpack version is now `v4.43.0` or later as we adopted the new `module.hot.invalidate` API.
([#89](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/89))
The new API enabled us to bail out of the HMR loop less frequently and provide a better experience.
If you really cannot upgrade, you can stay on `0.3.3` for the time being.
- While most of our public API did not change, this release is closer to a rewrite than a refactor.
A lot of files have moved to provide easier access for advanced users and frameworks.
([#122](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/122))
You can check the difference in the PR to see what have moved and where they are now.
- The `useLegacyWDSSockets` option is now scoped under the `overlay` option.
([#153](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/153))
### Features
- Adopted the `module.hot.invalidate()` API, which means we will now bail out less often
([#89](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/89))
- Attach runtime on Webpack's global scope instead of `window`, making the plugin platform-agnostic
([#102](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/102))
- Added stable support for **Webpack 5** and beta support for **Module Federation**
([#123](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/123),
[#132](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/132),
[#164](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/164))
- Socket integration URL detection via `document.currentScript`
([#133](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/133))
- Relaxed requirements for "required" `overlay` options to receive `false` as value
([#154](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/154))
- Prefixed all errors thrown by the plugin
([#161](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/161))
- Eliminated use of soon-to-be-deprecated `lodash.debounce` package
([#163](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/163))
### Fixes
- Fixed circular references for `__react_refresh_error_overlay__` and `__react_refresh_utils`
([#116](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/116))
- Fixed IE11 compatibility
([#106](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/106),
[#121](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/121))
- Rearranged directories to provide more ergonomic imports
([#122](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/122))
- Fixed issues with Babel/ESLint/Flow regarding loader ordering and runtime cleanup
([#129](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/129),
[#140](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/140))
- Correctly detecting the HMR plugin
([#130](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/130),
[#160](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/160))
- Fixed unwanted injection of error overlay in non-browser environment
([#146](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/146))
- Scoped the `useLegacyWDSSockets` options under `overlay` to reflect its true use
([#153](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/153))
- Fixed non-preserved relative ordering of Webpack entries
([#165](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/165))
### Internal
- Full HMR test suite - we are confident the plugin works!
([#93](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/93),
[#96](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/96))
- Unit tests for all plugin-related Node.js code
([#127](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/127))
## 0.3.3 (29 May 2020)
### Fixes
- Removed unrecoverable React errors check and its corresponding bail out logic on hot dispose
([#104](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/104))
## 0.3.2 (22 May 2020)
### Fixes
- Fixed error in overlay when stack trace is unavailable
([#91](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/91))
- Fixed IE11 compatibility
([#98](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/98))
## 0.3.1 (11 May 2020)
### Fixes
- Relaxed peer dependency requirements for `webpack-plugin-serve`
([64bb6b8](https://github.com/pmmmwh/react-refresh-webpack-plugin/commit/64bb6b8c26bbf9e51484ef7a109c0921be7889ff))
## 0.3.0 (10 May 2020)
### BREAKING
- Deprecated the `disableRefreshCheck` flag
([#60](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/60))
### Features
- Added custom error overlay support
([#44](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/44))
- Added example project to use TypeScript without usual Babel settings
([#46](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/46))
- Added custom socket parameters for WDS
([#52](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/52))
- Added TypeScript definition files
([#65](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/65))
- Added stricter options validation rules
([#62](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/62))
- Added option to configure socket runtime to support more hot integrations
([#64](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/64))
- Added support for `webpack-plugin-serve`
([#74](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/74))
### Fixes
- Fixed non-dismissible overlay for build warnings
([#57](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/57))
- Fixed electron compatibility
([#58](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/58))
- Fixed optional peer dependencies to be truly optional
([#59](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/59))
- Fixed compatibility issues caused by `node-url`
([#61](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/61))
- Removed check for `react` import for compatibility
([#69](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/69))
## 0.2.0 (2 March 2020)
### Features
- Added `webpack-hot-middleware` support
([#23](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/23))
### Fixes
- Fixed dependency on a global `this` variable to better support web workers
([#29](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/29))
## 0.1.3 (19 December 2019)
### Fixes
- Fixed runtime template injection when the `runtimeChunks` optimization is used in Webpack
([#26](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/26))
## 0.1.2 (18 December 2019)
### Fixes
- Fixed caching of Webpack loader to significantly improve performance
([#22](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/22))
## 0.1.1 (13 December 2019)
### Fixes
- Fixed usage of WDS SockJS fallback
([#17](https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/17))
## 0.1.0 (7 December 2019)
- Initial public release
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 Michael Mok
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# React Refresh Webpack Plugin
[actions]: https://github.com/pmmmwh/react-refresh-webpack-plugin/actions/workflows/ci.yml
[actions:badge]: https://img.shields.io/github/actions/workflow/status/pmmmwh/react-refresh-webpack-plugin/ci.yml?branch=main
[license:badge]: https://img.shields.io/github/license/pmmmwh/react-refresh-webpack-plugin
[npm:latest]: https://www.npmjs.com/package/@pmmmwh/react-refresh-webpack-plugin/v/latest
[npm:latest:badge]: https://img.shields.io/npm/v/@pmmmwh/react-refresh-webpack-plugin/latest
[npm:next]: https://www.npmjs.com/package/@pmmmwh/react-refresh-webpack-plugin/v/next
[npm:next:badge]: https://img.shields.io/npm/v/@pmmmwh/react-refresh-webpack-plugin/next
[![GitHub Actions][actions:badge]][actions]
[![License][license:badge]](./LICENSE)
[![Latest Version][npm:latest:badge]][npm:latest]
[![Next Version][npm:next:badge]][npm:next]
A Webpack plugin to enable "Fast Refresh" (also known as _Hot Reloading_) for React components.
> We're hoping to land a v1 release soon - please help us by reporting any issues you've encountered!
## Getting Started
### Prerequisites
Ensure that you are using at least the minimum supported versions of this plugin's peer dependencies -
older versions unfortunately do not contain code to orchestrate "Fast Refresh",
and thus cannot be made compatible.
We recommend using the following versions:
| Dependency | Version |
| --------------- | ------------------------------------ |
| `Node.js` | `18.12.0`+, `20.x`, `22.x` |
| `react` | `16.13.0`+, `17.x`, `18.x` or `19.x` |
| `react-dom` | `16.13.0`+, `17.x`, `18.x` or `19.x` |
| `react-refresh` | `0.10.0`+ |
| `webpack` | `5.2.0`+ |
<details>
<summary>Minimum requirements</summary>
<br />
| Dependency | Version |
| --------------- | --------- |
| `Node.js` | `18.12.0` |
| `react` | `16.9.0` |
| `react-dom` | `16.9.0` |
| `react-refresh` | `0.10.0` |
| `webpack` | `5.2.0` |
</details>
<details>
<summary>Using custom renderers (e.g. <code>react-three-fiber</code>, <code>react-pdf</code>, <code>ink</code>)</summary>
<br />
To ensure full support of "Fast Refresh" with components rendered by custom renderers,
you should ensure the renderer you're using depends on a recent version of `react-reconciler`.
We recommend version `0.25.0` or above, but any versions above `0.22.0` should work.
If the renderer is not compatible, please file them an issue instead.
</details>
### Installation
With all prerequisites met, you can install this plugin using your package manager of choice:
```sh
# if you prefer npm
npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
# if you prefer yarn
yarn add -D @pmmmwh/react-refresh-webpack-plugin react-refresh
# if you prefer pnpm
pnpm add -D @pmmmwh/react-refresh-webpack-plugin react-refresh
```
The `react-refresh` package (from the React team) is a required peer dependency of this plugin.
We recommend using version `0.10.0` or above.
<details>
<summary>Support for TypeScript</summary>
<br />
TypeScript support is available out-of-the-box for those who use `webpack.config.ts`.
Our exported types however depends on `type-fest`, so you'll have to add it as a `devDependency`:
```sh
# if you prefer npm
npm install -D type-fest
# if you prefer yarn
yarn add -D type-fest
# if you prefer pnpm
pnpm add -D type-fest
```
> **:memo: Note**:
>
> `type-fest@4.x` only supports Node.js v16 or above,
> `type-fest@3.x` only supports Node.js v14.16 or above,
> and `type-fest@2.x` only supports Node.js v12.20 or above.
> If you're using an older version of Node.js, please install `type-fest@1.x`.
</details>
### Usage
For most setups, we recommend integrating with `babel-loader`.
It covers the most use cases and is officially supported by the React team.
The example below will assume you're using `webpack-dev-server`.
If you haven't done so, set up your development Webpack configuration for Hot Module Replacement (HMR).
```js
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
devServer: {
hot: true,
},
};
```
<details>
<summary>Using <code>webpack-hot-middleware</code></summary>
<br />
```js
const webpack = require('webpack');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
plugins: [isDevelopment && new webpack.HotModuleReplacementPlugin()].filter(Boolean),
};
```
</details>
<details>
<summary>Using <code>webpack-plugin-serve</code></summary>
<br />
```js
const { WebpackPluginServe } = require('webpack-plugin-serve');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
plugins: [isDevelopment && new WebpackPluginServe()].filter(Boolean),
};
```
</details>
Then, add the `react-refresh/babel` plugin to your Babel configuration and this plugin to your Webpack configuration.
```js
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean),
},
},
],
},
],
},
plugins: [isDevelopment && new ReactRefreshWebpackPlugin()].filter(Boolean),
};
```
> **:memo: Note**:
>
> Ensure both the Babel transform (`react-refresh/babel`) and this plugin are enabled only in `development` mode!
<details>
<summary>Using <code>ts-loader</code></summary>
<br />
> **:warning: Warning**:
> This is an un-official integration maintained by the community.
Install [`react-refresh-typescript`](https://github.com/Jack-Works/react-refresh-transformer/tree/main/typescript).
Ensure your TypeScript version is at least 4.0.
```sh
# if you prefer npm
npm install -D react-refresh-typescript
# if you prefer yarn
yarn add -D react-refresh-typescript
# if you prefer pnpm
pnpm add -D react-refresh-typescript
```
Then, instead of wiring up `react-refresh/babel` via `babel-loader`,
you can wire-up `react-refresh-typescript` with `ts-loader`:
```js
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const ReactRefreshTypeScript = require('react-refresh-typescript');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('ts-loader'),
options: {
getCustomTransformers: () => ({
before: [isDevelopment && ReactRefreshTypeScript()].filter(Boolean),
}),
transpileOnly: isDevelopment,
},
},
],
},
],
},
plugins: [isDevelopment && new ReactRefreshWebpackPlugin()].filter(Boolean),
};
```
> It is recommended to run `ts-loader` with `transpileOnly` is set to `true`.
> You can use `ForkTsCheckerWebpackPlugin` as an alternative if you need typechecking during development.
</details>
<details>
<summary>Using <code>swc-loader</code></summary>
<br />
> **:warning: Warning**:
> This is an un-official integration maintained by the community.
Ensure your `@swc/core` version is at least `1.2.86`.
It is also recommended to use `swc-loader` version `0.1.13` or above.
Then, instead of wiring up `react-refresh/babel` via `babel-loader`,
you can wire-up `swc-loader` and use the `refresh` transform:
```js
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('swc-loader'),
options: {
jsc: {
transform: {
react: {
development: isDevelopment,
refresh: isDevelopment,
},
},
},
},
},
],
},
],
},
plugins: [isDevelopment && new ReactRefreshWebpackPlugin()].filter(Boolean),
};
```
> Starting from version `0.1.13`, `swc-loader` will set the `development` option based on Webpack's `mode` option.
> `swc` won't enable fast refresh when `development` is `false`.
</details>
For more information on how to set up "Fast Refresh" with different integrations,
please check out [our examples](examples).
### Overlay Integration
This plugin integrates with the most common Webpack HMR solutions to surface errors during development -
in the form of an error overlay.
By default, `webpack-dev-server` is used,
but you can set the [`overlay.sockIntegration`](docs/API.md#sockintegration) option to match what you're using.
The supported versions are as follows:
| Dependency | Version |
| ------------------------ | ----------------- |
| `webpack-dev-server` | `4.8.0`+ or `5.x` |
| `webpack-hot-middleware` | `2.x` |
| `webpack-plugin-serve` | `1.x` |
## API
Please refer to [the API docs](docs/API.md) for all available options.
## FAQs and Troubleshooting
Please refer to [the Troubleshooting guide](docs/TROUBLESHOOTING.md) for FAQs and resolutions to common issues.
## License
This project is licensed under the terms of the [MIT License](/LICENSE).
## Special Thanks
<a href="https://jb.gg/OpenSource?from=ReactRefreshWebpackPlugin" target="_blank">
<img
alt="JetBrains Logo"
src="https://user-images.githubusercontent.com/9338255/132110580-61d3dba5-f5c7-4479-bd8e-39cd65b42fc5.png"
width="120"
/>
</a>
================================================
FILE: client/ErrorOverlayEntry.js
================================================
/* global __react_refresh_error_overlay__, __react_refresh_socket__ */
if (process.env.NODE_ENV !== 'production') {
const events = require('./utils/errorEventHandlers.js');
const formatWebpackErrors = require('./utils/formatWebpackErrors.js');
const runWithRetry = require('./utils/retry.js');
// Setup error states
let isHotReload = false;
let hasRuntimeErrors = false;
/**
* Try dismissing the compile error overlay.
* This will also reset runtime error records (if any),
* because we have new source to evaluate.
* @returns {void}
*/
const tryDismissErrorOverlay = function () {
__react_refresh_error_overlay__.clearCompileError();
__react_refresh_error_overlay__.clearRuntimeErrors(!hasRuntimeErrors);
hasRuntimeErrors = false;
};
/**
* A function called after a compile success signal is received from Webpack.
* @returns {void}
*/
const handleCompileSuccess = function () {
isHotReload = true;
if (isHotReload) {
tryDismissErrorOverlay();
}
};
/**
* A function called after a compile errored signal is received from Webpack.
* @param {string[]} errors
* @returns {void}
*/
const handleCompileErrors = function (errors) {
isHotReload = true;
const formattedErrors = formatWebpackErrors(errors);
// Only show the first error
__react_refresh_error_overlay__.showCompileError(formattedErrors[0]);
};
/**
* Handles compilation messages from Webpack.
* Integrates with a compile error overlay.
* @param {*} message A Webpack HMR message sent via WebSockets.
* @returns {void}
*/
const compileMessageHandler = function (message) {
switch (message.type) {
case 'ok':
case 'still-ok':
case 'warnings': {
// TODO: Implement handling for warnings
handleCompileSuccess();
break;
}
case 'errors': {
handleCompileErrors(message.data);
break;
}
default: {
// Do nothing.
}
}
};
// Only register if no other overlay have been registered
if (
typeof window !== 'undefined' &&
!window.__reactRefreshOverlayInjected &&
__react_refresh_socket__
) {
// Registers handlers for compile errors with retry -
// This is to prevent mismatching injection order causing errors to be thrown
runWithRetry(
function initSocket() {
__react_refresh_socket__.init(compileMessageHandler);
},
3,
'Failed to set up the socket connection.'
);
// Registers handlers for runtime errors
events.handleError(function handleError(error) {
hasRuntimeErrors = true;
__react_refresh_error_overlay__.handleRuntimeError(error);
});
events.handleUnhandledRejection(function handleUnhandledPromiseRejection(error) {
hasRuntimeErrors = true;
__react_refresh_error_overlay__.handleRuntimeError(error);
});
// Mark overlay as injected to prevent double-injection
window.__reactRefreshOverlayInjected = true;
}
}
================================================
FILE: client/ReactRefreshEntry.js
================================================
/* global __react_refresh_library__ */
if (process.env.NODE_ENV !== 'production') {
const safeThis = require('core-js-pure/features/global-this');
const RefreshRuntime = require('react-refresh/runtime');
if (typeof safeThis !== 'undefined') {
var $RefreshInjected$ = '__reactRefreshInjected';
// Namespace the injected flag (if necessary) for monorepo compatibility
if (typeof __react_refresh_library__ !== 'undefined' && __react_refresh_library__) {
$RefreshInjected$ += '_' + __react_refresh_library__;
}
// Only inject the runtime if it hasn't been injected
if (!safeThis[$RefreshInjected$]) {
// Inject refresh runtime into global scope
RefreshRuntime.injectIntoGlobalHook(safeThis);
// Mark the runtime as injected to prevent double-injection
safeThis[$RefreshInjected$] = true;
}
}
}
================================================
FILE: client/package.json
================================================
{
"type": "commonjs"
}
================================================
FILE: client/utils/errorEventHandlers.js
================================================
/**
* @callback EventCallback
* @param {string | Error | null} context
* @returns {void}
*/
/**
* @callback EventHandler
* @param {Event} event
* @returns {void}
*/
/**
* A function that creates an event handler for the `error` event.
* @param {EventCallback} callback A function called to handle the error context.
* @returns {EventHandler} A handler for the `error` event.
*/
function createErrorHandler(callback) {
return function errorHandler(event) {
if (!event || !event.error) {
return callback(null);
}
if (event.error instanceof Error) {
return callback(event.error);
}
// A non-error was thrown, we don't have a trace. :(
// Look in your browser's devtools for more information
return callback(new Error(event.error));
};
}
/**
* A function that creates an event handler for the `unhandledrejection` event.
* @param {EventCallback} callback A function called to handle the error context.
* @returns {EventHandler} A handler for the `unhandledrejection` event.
*/
function createRejectionHandler(callback) {
return function rejectionHandler(event) {
if (!event || !event.reason) {
return callback(new Error('Unknown'));
}
if (event.reason instanceof Error) {
return callback(event.reason);
}
// A non-error was rejected, we don't have a trace :(
// Look in your browser's devtools for more information
return callback(new Error(event.reason));
};
}
/**
* Creates a handler that registers an EventListener on window for a valid type
* and calls a callback when the event fires.
* @param {string} eventType A valid DOM event type.
* @param {function(EventCallback): EventHandler} createHandler A function that creates an event handler.
* @returns {register} A function that registers the EventListener given a callback.
*/
function createWindowEventHandler(eventType, createHandler) {
/**
* @type {EventHandler | null} A cached event handler function.
*/
let eventHandler = null;
/**
* Unregisters an EventListener if it has been registered.
* @returns {void}
*/
function unregister() {
if (eventHandler === null) {
return;
}
window.removeEventListener(eventType, eventHandler);
eventHandler = null;
}
/**
* Registers an EventListener if it hasn't been registered.
* @param {EventCallback} callback A function called after the event handler to handle its context.
* @returns {unregister | void} A function to unregister the registered EventListener if registration is performed.
*/
function register(callback) {
if (eventHandler !== null) {
return;
}
eventHandler = createHandler(callback);
window.addEventListener(eventType, eventHandler);
return unregister;
}
return register;
}
const handleError = createWindowEventHandler('error', createErrorHandler);
const handleUnhandledRejection = createWindowEventHandler(
'unhandledrejection',
createRejectionHandler
);
module.exports = {
handleError: handleError,
handleUnhandledRejection: handleUnhandledRejection,
};
================================================
FILE: client/utils/formatWebpackErrors.js
================================================
/**
* @typedef {Object} WebpackErrorObj
* @property {string} moduleIdentifier
* @property {string} moduleName
* @property {string} message
*/
const friendlySyntaxErrorLabel = 'Syntax error:';
/**
* Checks if the error message is for a syntax error.
* @param {string} message The raw Webpack error message.
* @returns {boolean} Whether the error message is for a syntax error.
*/
function isLikelyASyntaxError(message) {
return message.indexOf(friendlySyntaxErrorLabel) !== -1;
}
/**
* Cleans up Webpack error messages.
*
* This implementation is based on the one from [create-react-app](https://github.com/facebook/create-react-app/blob/edc671eeea6b7d26ac3f1eb2050e50f75cf9ad5d/packages/react-dev-utils/formatWebpackMessages.js).
* @param {string} message The raw Webpack error message.
* @returns {string} The formatted Webpack error message.
*/
function formatMessage(message) {
let lines = message.split('\n');
// Strip Webpack-added headers off errors/warnings
// https://github.com/webpack/webpack/blob/master/lib/ModuleError.js
lines = lines.filter(function (line) {
return !/Module [A-z ]+\(from/.test(line);
});
// Remove leading newline
if (lines.length > 2 && lines[1].trim() === '') {
lines.splice(1, 1);
}
// Remove duplicated newlines
lines = lines.filter(function (line, index, arr) {
return index === 0 || line.trim() !== '' || line.trim() !== arr[index - 1].trim();
});
// Clean up the file name
lines[0] = lines[0].replace(/^(.*) \d+:\d+-\d+$/, '$1');
// Cleans up verbose "module not found" messages for files and packages.
if (lines[1] && lines[1].indexOf('Module not found: ') === 0) {
lines = [
lines[0],
lines[1]
.replace('Error: ', '')
.replace('Module not found: Cannot find file:', 'Cannot find file:'),
];
}
message = lines.join('\n');
// Clean up syntax errors
message = message.replace('SyntaxError:', friendlySyntaxErrorLabel);
// Internal stacks are generally useless, so we strip them -
// except the stacks containing `webpack:`,
// because they're normally from user code generated by webpack.
message = message.replace(/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm, ''); // at ... ...:x:y
message = message.replace(/^\s*at\s((?!webpack:).)*<anonymous>[\s)]*(\n|$)/gm, ''); // at ... <anonymous>
message = message.replace(/^\s*at\s<anonymous>(\n|$)/gm, ''); // at <anonymous>
return message.trim();
}
/**
* Formats Webpack error messages into a more readable format.
* @param {Array<string | WebpackErrorObj>} errors An array of Webpack error messages.
* @returns {string[]} The formatted Webpack error messages.
*/
function formatWebpackErrors(errors) {
let formattedErrors = errors.map(function (errorObjOrMessage) {
// Webpack 5 compilation errors are in the form of descriptor objects,
// so we have to join pieces to get the format we want.
if (typeof errorObjOrMessage === 'object') {
return formatMessage([errorObjOrMessage.moduleName, errorObjOrMessage.message].join('\n'));
}
// Webpack 4 compilation errors are strings
return formatMessage(errorObjOrMessage);
});
if (formattedErrors.some(isLikelyASyntaxError)) {
// If there are any syntax errors, show just them.
formattedErrors = formattedErrors.filter(isLikelyASyntaxError);
}
return formattedErrors;
}
module.exports = formatWebpackErrors;
================================================
FILE: client/utils/retry.js
================================================
function runWithRetry(callback, maxRetries, message) {
function executeWithRetryAndTimeout(currentCount) {
try {
if (currentCount > maxRetries - 1) {
console.warn('[React Refresh]', message);
return;
}
callback();
} catch (err) {
setTimeout(
function () {
executeWithRetryAndTimeout(currentCount + 1);
},
Math.pow(10, currentCount)
);
}
}
executeWithRetryAndTimeout(0);
}
module.exports = runWithRetry;
================================================
FILE: docs/API.md
================================================
# API
## Directives
The `react-refresh/babel` plugin provide support to directive comments out of the box.
### `reset`
```js
/* @refresh reset */
```
This directive tells React Refresh to force reset state on every refresh (current file only).
This can be useful, for example, to reset error boundary components' state,
so it doesn't persist when new code is executed.
## Options
This plugin accepts a few options to tweak its behaviour.
In usual scenarios, you probably wouldn't have to reach for them -
they exist specifically to enable integration in more advanced/complicated setups.
### `ReactRefreshPluginOptions`
```ts
interface ReactRefreshPluginOptions {
forceEnable?: boolean;
exclude?: string | RegExp | Array<string | RegExp>;
include?: string | RegExp | Array<string | RegExp>;
library?: string;
esModule?: boolean | ESModuleOptions;
overlay?: boolean | ErrorOverlayOptions;
}
```
#### `forceEnable`
Type: `boolean`
Default: `undefined`
Enables the plugin forcefully.
It is useful if you want to:
- Use the plugin in production;
- Use the plugin with the `none` mode in Webpack without setting `NODE_ENV`;
- Use the plugin in environments we do not support, such as `electron-prerender`
(**WARNING: Proceed at your own risk!**).
#### `exclude`
Type: `string | RegExp | Array<string | RegExp>`
Default: `/node_modules/`
Exclude files from being processed by the plugin.
This is similar to the `module.rules` option in Webpack.
#### `include`
Type: `string | RegExp | Array<string | RegExp>`
Default: `/\.([jt]sx?|flow)$/i`
Include files to be processed by the plugin.
This is similar to the `module.rules` option in Webpack.
#### `library`
Type: `string`
Default: `''`, or `output.uniqueName` in Webpack 5, or `output.library` for both Webpack 4/5 if set
Sets a namespace for the React Refresh runtime.
This is similar to the `output.uniqueName` in Webpack 5 or the `output.library` option in Webpack 4/5.
It is most useful when multiple instances of React Refresh is running together simultaneously.
#### `esModule`
Type: `boolean | ESModuleOptions`
Default: `undefined` (auto-detection)
Enables strict ES Modules compatible runtime.
By default, the plugin will try to infer the module system same as Webpack 5,
either via the `type` property in `package.json` (`commonjs` and `module`),
or via the file extension (`.cjs` and `.mjs`).
It is most useful when you want to enforce output of native ESM code.
See the [`ESModuleOptions`](#esmoduleoptions) section below for more details on the object API.
#### `overlay`
Type: `boolean | ErrorOverlayOptions`
Default:
```json5
{
entry: '@pmmmwh/react-refresh-webpack-plugin/client/ErrorOverlayEntry',
module: '@pmmmwh/react-refresh-webpack-plugin/overlay',
sockIntegration: 'wds',
}
```
Modifies behaviour of the plugin's error overlay integration:
- If `overlay` is not provided or `true`, the **DEFAULT** behaviour will be used;
- If `overlay` is `false`, the error overlay integration will be **DISABLED**;
- If `overlay` is an object (`ErrorOverlayOptions`), it will act with respect to what is provided
(\*NOTE: This is targeted for ADVANCED use cases.).
See the [`ErrorOverlayOptions`](#erroroverlayoptions) section below for more details on the object API.
### `ESModuleOptions`
```ts
interface ESModuleOptions {
exclude?: string | RegExp | Array<string | RegExp>;
include?: string | RegExp | Array<string | RegExp>;
}
```
#### `exclude`
Type: `string | RegExp | Array<string | RegExp>`
Default: `/node_modules/`
Exclude files from being processed as ESM.
This is similar to the `module.rules` option in Webpack.
#### `include`
Type: `string | RegExp | Array<string | RegExp>`
Default: `/\.([jt]sx?|flow)$/i`
Include files to be processed as ESM.
This is similar to the `module.rules` option in Webpack.
### `ErrorOverlayOptions`
```ts
interface ErrorOverlayOptions {
entry?: string | false;
module?: string | false;
sockIntegration?: 'wds' | 'whm' | 'wps' | false | string;
}
```
#### `entry`
Type: `string | false`
Default: `'@pmmmwh/react-refresh-webpack-plugin/client/ErrorOverlayEntry'`
The **PATH** to a file/module that sets up the error overlay integration.
Both **ABSOLUTE** and **RELATIVE** paths are acceptable, but it is recommended to use the **FORMER**.
When set to `false`, no code will be injected for this stage.
#### `module`
Type: `string | false`
Default: `'@pmmmwh/react-refresh-webpack-plugin/overlay'`
The **PATH** to a file/module to be used as an error overlay (e.g. `react-error-overlay`).
Both **ABSOLUTE** and **RELATIVE** paths are acceptable, but it is recommended to use the **FORMER**.
The provided file should contain two **NAMED** exports:
```ts
function handleRuntimeError(error: Error) {}
function clearRuntimeErrors() {}
```
- `handleRuntimeError` is invoked when a **RUNTIME** error is **CAUGHT** (e.g. during module initialisation or execution);
- `clearRuntimeErrors` is invoked when a module is **RE-INITIALISED** via "Fast Refresh".
If the default `entry` is used, the file should contain two more **NAMED** exports:
```ts
function showCompileError(webpackErrorMessage: string) {}
function clearCompileError() {}
```
- `showCompileError` is invoked when an error occurred during a Webpack compilation
(NOTE: `webpackErrorMessage` might be ANSI encoded depending on the integration);
- `clearCompileError` is invoked when a new Webpack compilation is started (i.e. HMR rebuild).
> Note: if you want to use `react-error-overlay` as a value to this option,
> you should instead use `react-dev-utils/refreshOverlayInterop` or implement a similar interop.
> The APIs expected by this plugin is slightly different from what `react-error-overlay` provides out-of-the-box.
#### `sockIntegration`
Default: `wds`
Type: `wds`, `whm`, `wps`, `false` or `string`
The HMR integration that the error overlay will interact with -
it can either be a short form name of the integration (`wds`, `whm`, `wps`),
or a **PATH** to a file/module that sets up a connection to receive Webpack build messages.
Both **ABSOLUTE** and **RELATIVE** paths are acceptable, but it is recommended to use the **FORMER**.
Common HMR integrations (for Webpack) are support by this plugin out-of-the-box:
- For `webpack-dev-server`, you can skip this option or set it to `wds`;
- For `webpack-hot-middleware`, set this option to `whm`;
- For `webpack-plugin-serve`, set this option to `wps`.
If you use any other HMR integrations (e.g. custom ones), or if you want to customise how the connection is being setup,
you will need to implement a message client in the provided file/module.
You can reference implementations inside the [`sockets`](https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/main/sockets) directory.
================================================
FILE: docs/TROUBLESHOOTING.md
================================================
# Troubleshooting
## Coming from `react-hot-loader`
If you are coming from `react-hot-loader`, before using the plugin,
you have to ensure that you've completely erased the integration of RHL from your app:
- Removed the `react-hot-loader/babel` Babel plugin (from Babel config variants or Webpack config)
- Removed the `react-hot-loader/patch` Webpack entry
- Removed the `react-hot-loader/webpack` Webpack loader
- Removed the alias of `react-dom` to `@hot-loader/react-dom` (from `package.json` or Webpack config)
- Removed imports and their usages from `react-hot-loader`
This has to be done because, internally,
`react-hot-loader` intercepts and reconciles the React tree before React can try to re-render it.
That in turn breaks mechanisms the plugin depends on to deliver the experience.
## Compatibility with `npm@7`
`npm@7` have brought back the behaviour of auto-installing peer dependencies with new semantics,
but their support for optional peer dependencies,
used by this plugin to provide support to multiple integrations without bundling them all,
are known to be a bit lacking.
If you encounter the `ERESOLVE` error code while running `npm install` -
you can fallback to use the legacy dependency resolution algorithm and it should resolve the issue:
```sh
npm install --legacy-peer-deps
```
## Usage with CSS Files/Imports
This plugin does not provide HMR for CSS.
To achieve that,
you should be using [`style-loader`](https://github.com/webpack-contrib/style-loader) or [`mini-css-extract-plugin`](https://github.com/webpack-contrib/mini-css-extract-plugin).
Both provides HMR capabilities out of the box for Webpack 5 -
if are still on Webpack 4 and uses `mini-css-extract-plugin`, you might have to [do some setup](https://github.com/webpack-contrib/mini-css-extract-plugin/#hot-module-reloading-hmr).
## Usage with Indirection (like Workers and JS Templates)
If you share the Babel config for files in an indirect code path (e.g. Web Workers, JS Templates with partial pre-render) and all your other source files,
you might experience this error:
```
Uncaught ReferenceError: $RefreshReg$ is not defined
```
The reason is that when using child compilers (e.g. `html-webpack-plugin`, `worker-plugin`), plugins are usually not applied (but loaders are).
This means that code processed by `react-refresh/babel` is not further transformed by this plugin and will lead to broken builds.
To solve this issue, you can choose one of the following workarounds:
**Sloppy**
In the entry of your indirect code path (e.g. some `index.js`), add the following two lines:
```js
self.$RefreshReg$ = () => {};
self.$RefreshSig$ = () => () => {};
```
This basically acts as a "polyfill" for helpers expected by `react-refresh/babel`, so the worker can run properly.
**Simple**
Ensure all exports within the indirect code path are not named in `PascalCase`.
This will tell the Babel plugin to do nothing when it hits those files.
In general, the `PascalCase` naming scheme should be reserved for React components only,
and it doesn't really make sense for them to exist within non-React-rendering contexts.
**Robust but complex**
In your Webpack configuration, alter the Babel setup as follows:
```js
{
rules: [
// JS-related rules only
{
oneOf: [
{
test: /\.[jt]s$/,
include: '<Your indirection files here>',
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
// Your Babel config here
},
},
},
{
test: /\.[jt]sx?$/,
include: '<Your files here>',
exclude: ['<Your indirection files here>', /node_modules/],
use: {
loader: 'babel-loader',
options: {
// Your Babel config here
plugins: [isDevelopment && 'react-refresh/babel'].filter(Boolean),
},
},
},
],
},
// Any other rules, such as CSS
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
];
}
```
This would ensure that your indirect code path will not be processed by `react-refresh/babel`,
thus eliminating the problem completely.
## Hot Module Replacement (HMR) is not enabled
This means that you have not enabled HMR for Webpack, or we are unable to detect a working HMR implementation from the compilation context.
**Using `webpack-dev-server`**
Set the `hot` or `hotOnly` options to `true`.
**Using `webpack-hot-middleware`**
Add `HotModuleReplacementPlugin` to your list of plugins to use in development mode.
**Using `webpack-plugin-serve`**
Set the `hmr` option to `true`.
## State not preserved for class components
This is intended behaviour.
If you're coming from [react-hot-loader](https://github.com/gaearon/react-hot-loader), this might be the biggest surprise for you.
The main rationale behind this is listed in [this wish list for hot reloading](https://overreacted.io/my-wishlist-for-hot-reloading/):
> It is better to lose local state than to behave incorrectly.
>
> It is better to lose local state than use an old version.
The truth is, historically, hot reloading for class components was never reliable and maintainable.
It was implemented based on workarounds like wrapping components with Proxies.
While these workarounds made hot reloading "work" on the surface, they led to inconsistencies in other departments:
- Lifecycle methods will fire randomly at random times;
- Type checks will fail randomly (`<Component />.type === Component` is `false`); and
- Mutation of React's internals, which is difficult to manage and will need to play catch up with React as we move into the future (a-la Concurrent Mode).
Thus, to keep fast refresh reliable and resilient to errors (with recovery for most cases), class components will always be re-mounted on a hot update.
## Edits always lead to full reload
In most cases, if the plugin is applied correctly, it would mean that we weren't able to set up boundaries to stop update propagation.
It can be narrowed down to a few unsupported patterns:
1. Un-named/non-pascal-case-named components
See [this tweet](https://twitter.com/dan_abramov/status/1255229440860262400) for drawbacks of not giving component proper names.
They are impossible to support because we have no ways to statically determine they are React-related.
This issue also exist for other React developer tools, like the [hooks ESLint plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks).
Internal components in HOCs also have to conform to this rule.
```jsx
// won't work
export default () => <div />;
export default function () {
return <div />;
}
export default function divContainer() {
return <div />;
}
```
2. Chain of files leading to root with none containing React-related content only
This pattern cannot be supported because we cannot ensure non-React-related content are free of side effects.
Usually with this error you will see something like this in the browser console:
```
Ignored an update to unaccepted module ... [a very long path]
```
3. `export * from 'namespace'` (TypeScript only)
This only affect users using TypeScript on Babel.
This pattern is only supported when you don't mix normal exports with type exports, or when all your exports conform to the `PascalCase` rule.
This is because we cannot statically analyse the exports from the namespace to determine whether we can set up a boundary and stop update propagation.
## Component not updating with bundle splitting techniques
Webpack allows various bundle splitting techniques to improve performance and cacheability.
However, these techniques often result in a shuffled execution order, which will break fast refresh.
To make fast refresh work properly, make sure your Webpack configuration comply to the following rules:
1. All React-related packages (including custom reconcilers) should be in the same chunk with `react-refresh/runtime`
Because fast refresh internally uses the React DevTools protocol and have to be registered before any React code runs,
all React-related stuff needs to be in the same chunk to ensure execution order and object equality in the form of `WeakMap` keys.
**Using DLL plugin**
Ensure the entries for the DLL include `react-refresh/runtime`,
and the `mode` option is set to `development`.
```js
module.exports = {
mode: 'development',
entry: ['react', 'react-dom', 'react-refresh/runtime'],
};
```
**Using multiple entries**
Ensure the `react` chunk includes `react-refresh/runtime`.
```js
module.exports = {
entry: {
main: 'index.js',
vendors: ['react', 'react-dom', 'react-refresh/runtime'],
},
};
```
2. Only one copy of both the HMR runtime and the plugin's runtime should be embedded for one Webpack app
This concern only applies when you have multiple entry points.
You can use Webpack's `optimization.runtimeChunk` option to enforce this.
```js
module.exports = {
optimization: {
runtimeChunk: 'single',
},
};
```
## Externalising React
Fast refresh relies on initialising code before **ANY** React code is ran.
If you externalise React, however, it is likely that this plugin cannot inject the necessary runtime code before it.
You can deal with this in a few ways (also see [#334](https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/334) for relevant discussion).
**Production-only externalisation**
The simplest solution to this issue is to simply not externalise React in development.
This would guarantee any code injected by this plugin run before any React code,
and would require the least manual tweaking.
**Use React DevTools**
If the execution environment is something you can control, and you wanted to externalise React in development,
you can use React DevTools which would inject hooks to the environment for React to attach to.
React Refresh should be able to hook into copies of React connected this way even it runs afterwards,
but do note that React DevTools does not inject hooks over a frame boundary (`iframe`).
**Externalise React Refresh**
If all solutions above are not applicable, you can also externalise `react-refresh/runtime` together with React.
We provide an entrypoint to easily achieve this - `@pmmmwh/react-refresh-webpack-plugin/umd/client.min.js`.
If you would like to use the provided script, ensure that it is loaded before React and/or React-DOM.
You can load this script via any CDN for `npm`, such as `jsDelivr` and `unpkg`:
```html
<!-- if you prefer jsDelivr -->
<script src=" https://cdn.jsdelivr.net/npm/@pmmmwh/react-refresh-webpack-plugin@^0.6.2/umd/client.min.js "></script>
<!-- if you prefer unpkg -->
<script src="https://unpkg.com/@pmmmwh/react-refresh-webpack-plugin@^0.6.2/umd/client.min.js"></script>
```
If you don't want to use the provided script,
you can check out [this sandbox](https://codesandbox.io/s/react-refresh-externals-14fpn) for an example on how this could be done manually.
## Running multiple instances of React Refresh simultaneously
If you are running on a micro-frontend architecture (e.g. Module Federation in Webpack 5),
you should set the `library` output to ensure proper namespacing in the runtime injection script.
**Using Webpack's `output.uniqueName` option (Webpack 5 only)**
```js
module.exports = {
output: {
uniqueName: 'YourLibrary',
},
};
```
**Using Webpack's `output.library` option**
```js
module.exports = {
output: {
library: 'YourLibrary',
},
};
```
**Using the plugin's `library` option**
```js
module.exports = {
plugins: [
new ReactRefreshPlugin({
library: 'YourLibrary',
}),
],
};
```
================================================
FILE: examples/flow-with-babel/.flowconfig
================================================
[ignore]
[include]
[libs]
[lints]
[options]
[strict]
================================================
FILE: examples/flow-with-babel/babel.config.js
================================================
module.exports = (api) => {
// This caches the Babel config
api.cache.using(() => process.env.NODE_ENV);
return {
presets: [
'@babel/preset-env',
'@babel/preset-flow',
// Enable development transform of React with new automatic runtime
['@babel/preset-react', { development: !api.env('production'), runtime: 'automatic' }],
],
// Applies the react-refresh Babel plugin on non-production modes only
...(!api.env('production') && { plugins: ['react-refresh/babel'] }),
};
};
================================================
FILE: examples/flow-with-babel/package.json
================================================
{
"name": "using-flow-with-babel",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-flow": "^7.25.9",
"@babel/preset-react": "^7.26.3",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
"babel-loader": "^10.0.0",
"cross-env": "^7.0.3",
"flow-bin": "^0.266.1",
"html-webpack-plugin": "^5.6.3",
"react-refresh": "^0.17.0",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.1"
},
"scripts": {
"start": "webpack serve --hot",
"build": "cross-env NODE_ENV=production webpack"
}
}
================================================
FILE: examples/flow-with-babel/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Flow React App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: examples/flow-with-babel/src/App.jsx
================================================
// @flow
import { lazy, Suspense } from 'react';
import { ArrowFunction } from './ArrowFunction';
import ClassDefault from './ClassDefault';
import { ClassNamed } from './ClassNamed';
import FunctionDefault from './FunctionDefault';
import { FunctionNamed } from './FunctionNamed';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<ClassDefault />
<ClassNamed />
<FunctionDefault />
<FunctionNamed />
<ArrowFunction />
<Suspense fallback={<h1>Loading</h1>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
================================================
FILE: examples/flow-with-babel/src/ArrowFunction.jsx
================================================
// @flow
export const ArrowFunction = () => <h1>Arrow Function</h1>;
================================================
FILE: examples/flow-with-babel/src/ClassDefault.jsx
================================================
// @flow
import { Component } from 'react';
class ClassDefault extends Component<{}> {
render() {
return <h1>Default Export Class</h1>;
}
}
export default ClassDefault;
================================================
FILE: examples/flow-with-babel/src/ClassNamed.jsx
================================================
// @flow
import { Component } from 'react';
export class ClassNamed extends Component<{}> {
render() {
return <h1>Named Export Class</h1>;
}
}
================================================
FILE: examples/flow-with-babel/src/FunctionDefault.jsx
================================================
// @flow
function FunctionDefault() {
return <h1>Default Export Function</h1>;
}
export default FunctionDefault;
================================================
FILE: examples/flow-with-babel/src/FunctionNamed.jsx
================================================
// @flow
export function FunctionNamed() {
return <h1>Named Export Function</h1>;
}
================================================
FILE: examples/flow-with-babel/src/LazyComponent.jsx
================================================
// @flow
function LazyComponent() {
return <h1>Lazy Component</h1>;
}
export default LazyComponent;
================================================
FILE: examples/flow-with-babel/src/index.js
================================================
// @flow
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
================================================
FILE: examples/flow-with-babel/webpack.config.js
================================================
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
devServer: {
client: { overlay: false },
},
entry: {
main: './src/index.js',
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.join(__dirname, 'src'),
use: 'babel-loader',
},
],
},
plugins: [
isDevelopment && new ReactRefreshPlugin(),
new HtmlWebpackPlugin({
filename: './index.html',
template: './public/index.html',
}),
].filter(Boolean),
resolve: {
extensions: ['.js', '.jsx'],
},
};
================================================
FILE: examples/typescript-with-babel/babel.config.js
================================================
module.exports = (api) => {
// This caches the Babel config
api.cache.using(() => process.env.NODE_ENV);
return {
presets: [
'@babel/preset-env',
'@babel/preset-typescript',
// Enable development transform of React with new automatic runtime
['@babel/preset-react', { development: !api.env('production'), runtime: 'automatic' }],
],
// Applies the react-refresh Babel plugin on non-production modes only
...(!api.env('production') && { plugins: ['react-refresh/babel'] }),
};
};
================================================
FILE: examples/typescript-with-babel/package.json
================================================
{
"name": "using-typescript-with-babel",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.27.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"babel-loader": "^10.0.0",
"cross-env": "^7.0.3",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"html-webpack-plugin": "^5.6.3",
"react-refresh": "^0.17.0",
"typescript": "~5.8.3",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.1"
},
"scripts": {
"start": "webpack serve --hot",
"build": "cross-env NODE_ENV=production webpack"
}
}
================================================
FILE: examples/typescript-with-babel/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TS React App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: examples/typescript-with-babel/src/App.tsx
================================================
import { lazy, Suspense } from 'react';
import { ArrowFunction } from './ArrowFunction';
import ClassDefault from './ClassDefault';
import { ClassNamed } from './ClassNamed';
import FunctionDefault from './FunctionDefault';
import { FunctionNamed } from './FunctionNamed';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<ClassDefault />
<ClassNamed />
<FunctionDefault />
<FunctionNamed />
<ArrowFunction />
<Suspense fallback={<h1>Loading</h1>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
================================================
FILE: examples/typescript-with-babel/src/ArrowFunction.tsx
================================================
export const ArrowFunction = () => <h1>Arrow Function</h1>;
================================================
FILE: examples/typescript-with-babel/src/ClassDefault.tsx
================================================
import { Component } from 'react';
class ClassDefault extends Component {
render() {
return <h1>Default Export Class</h1>;
}
}
export default ClassDefault;
================================================
FILE: examples/typescript-with-babel/src/ClassNamed.tsx
================================================
import { Component } from 'react';
export class ClassNamed extends Component {
render() {
return <h1>Named Export Class</h1>;
}
}
================================================
FILE: examples/typescript-with-babel/src/FunctionDefault.tsx
================================================
function FunctionDefault() {
return <h1>Default Export Function</h1>;
}
export default FunctionDefault;
================================================
FILE: examples/typescript-with-babel/src/FunctionNamed.tsx
================================================
export function FunctionNamed() {
return <h1>Named Export Function</h1>;
}
================================================
FILE: examples/typescript-with-babel/src/LazyComponent.tsx
================================================
function LazyComponent() {
return <h1>Lazy Component</h1>;
}
export default LazyComponent;
================================================
FILE: examples/typescript-with-babel/src/index.tsx
================================================
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('app');
const root = createRoot(container!);
root.render(<App />);
================================================
FILE: examples/typescript-with-babel/tsconfig.json
================================================
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "ESNext",
"moduleResolution": "node",
"outDir": "dist",
"target": "ESNext",
"sourceMap": true
},
"include": ["src"]
}
================================================
FILE: examples/typescript-with-babel/webpack.config.js
================================================
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
devServer: {
client: { overlay: false },
},
entry: {
main: './src/index.tsx',
},
module: {
rules: [
{
test: /\.tsx?$/,
include: path.join(__dirname, 'src'),
use: 'babel-loader',
},
],
},
plugins: [
isDevelopment && new ReactRefreshPlugin(),
new ForkTsCheckerWebpackPlugin(),
new HtmlWebpackPlugin({
filename: './index.html',
template: './public/index.html',
}),
].filter(Boolean),
resolve: {
extensions: ['.js', '.ts', '.tsx'],
},
};
================================================
FILE: examples/typescript-with-swc/package.json
================================================
{
"name": "using-typescript-with-swc",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
"@swc/core": "^1.11.16",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"core-js": "^3.41.0",
"cross-env": "^7.0.3",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"html-webpack-plugin": "^5.6.3",
"react-refresh": "^0.17.0",
"swc-loader": "^0.2.6",
"typescript": "~5.8.3",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.1"
},
"scripts": {
"start": "webpack serve --hot",
"build": "cross-env NODE_ENV=production webpack"
}
}
================================================
FILE: examples/typescript-with-swc/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>swc React App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: examples/typescript-with-swc/src/App.tsx
================================================
import { lazy, Suspense } from 'react';
import { ArrowFunction } from './ArrowFunction';
import ClassDefault from './ClassDefault';
import { ClassNamed } from './ClassNamed';
import FunctionDefault from './FunctionDefault';
import { FunctionNamed } from './FunctionNamed';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<ClassDefault />
<ClassNamed />
<FunctionDefault />
<FunctionNamed />
<ArrowFunction />
<Suspense fallback={<h1>Loading</h1>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
================================================
FILE: examples/typescript-with-swc/src/ArrowFunction.tsx
================================================
export const ArrowFunction = () => <h1>Arrow Function</h1>;
================================================
FILE: examples/typescript-with-swc/src/ClassDefault.tsx
================================================
import { Component } from 'react';
class ClassDefault extends Component {
render() {
return <h1>Default Export Class</h1>;
}
}
export default ClassDefault;
================================================
FILE: examples/typescript-with-swc/src/ClassNamed.tsx
================================================
import { Component } from 'react';
export class ClassNamed extends Component {
render() {
return <h1>Named Export Class</h1>;
}
}
================================================
FILE: examples/typescript-with-swc/src/FunctionDefault.tsx
================================================
function FunctionDefault() {
return <h1>Default Export Function</h1>;
}
export default FunctionDefault;
================================================
FILE: examples/typescript-with-swc/src/FunctionNamed.tsx
================================================
export function FunctionNamed() {
return <h1>Named Export Function</h1>;
}
================================================
FILE: examples/typescript-with-swc/src/LazyComponent.tsx
================================================
function LazyComponent() {
return <h1>Lazy Component</h1>;
}
export default LazyComponent;
================================================
FILE: examples/typescript-with-swc/src/index.tsx
================================================
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('app');
const root = createRoot(container!);
root.render(<App />);
================================================
FILE: examples/typescript-with-swc/tsconfig.json
================================================
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "ESNext",
"moduleResolution": "node",
"outDir": "dist",
"target": "ESNext",
"sourceMap": true
},
"include": ["src"]
}
================================================
FILE: examples/typescript-with-swc/webpack.config.js
================================================
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
devServer: {
client: { overlay: false },
},
entry: {
main: './src/index.tsx',
},
module: {
rules: [
{
test: /\.tsx?$/,
include: path.join(__dirname, 'src'),
use: [
{
loader: 'swc-loader',
options: {
env: { mode: 'usage' },
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
dynamicImport: true,
},
transform: {
react: {
// swc-loader will check whether webpack mode is 'development'
// and set this automatically starting from 0.1.13. You could also set it yourself.
// swc won't enable fast refresh when development is false
runtime: 'automatic',
refresh: isDevelopment,
},
},
},
},
},
],
},
],
},
plugins: [
isDevelopment && new ReactRefreshPlugin(),
new ForkTsCheckerWebpackPlugin(),
new HtmlWebpackPlugin({
filename: './index.html',
template: './public/index.html',
}),
].filter(Boolean),
resolve: {
extensions: ['.js', '.ts', '.tsx'],
},
};
================================================
FILE: examples/typescript-with-tsc/package.json
================================================
{
"name": "using-typescript-with-tsc",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"cross-env": "^7.0.3",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"html-webpack-plugin": "^5.6.3",
"react-refresh": "^0.17.0",
"react-refresh-typescript": "^2.0.10",
"ts-loader": "^9.5.2",
"typescript": "~5.8.3",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.1"
},
"scripts": {
"start": "webpack serve --hot",
"build": "cross-env NODE_ENV=production webpack"
}
}
================================================
FILE: examples/typescript-with-tsc/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TSC React App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: examples/typescript-with-tsc/src/App.tsx
================================================
import { lazy, Suspense } from 'react';
import { ArrowFunction } from './ArrowFunction';
import ClassDefault from './ClassDefault';
import { ClassNamed } from './ClassNamed';
import FunctionDefault from './FunctionDefault';
import { FunctionNamed } from './FunctionNamed';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<ClassDefault />
<ClassNamed />
<FunctionDefault />
<FunctionNamed />
<ArrowFunction />
<Suspense fallback={<h1>Loading</h1>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
================================================
FILE: examples/typescript-with-tsc/src/ArrowFunction.tsx
================================================
export const ArrowFunction = () => <h1>Arrow Function</h1>;
================================================
FILE: examples/typescript-with-tsc/src/ClassDefault.tsx
================================================
import { Component } from 'react';
class ClassDefault extends Component {
render() {
return <h1>Default Export Class</h1>;
}
}
export default ClassDefault;
================================================
FILE: examples/typescript-with-tsc/src/ClassNamed.tsx
================================================
import { Component } from 'react';
export class ClassNamed extends Component {
render() {
return <h1>Named Export Class</h1>;
}
}
================================================
FILE: examples/typescript-with-tsc/src/FunctionDefault.tsx
================================================
function FunctionDefault() {
return <h1>Default Export Function</h1>;
}
export default FunctionDefault;
================================================
FILE: examples/typescript-with-tsc/src/FunctionNamed.tsx
================================================
export function FunctionNamed() {
return <h1>Named Export Function</h1>;
}
================================================
FILE: examples/typescript-with-tsc/src/LazyComponent.tsx
================================================
function LazyComponent() {
return <h1>Lazy Component</h1>;
}
export default LazyComponent;
================================================
FILE: examples/typescript-with-tsc/src/index.tsx
================================================
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('app');
const root = createRoot(container!);
root.render(<App />);
================================================
FILE: examples/typescript-with-tsc/tsconfig.dev.json
================================================
{
"extends": "./tsconfig.json",
"compilerOptions": {
"jsx": "react-jsxdev"
},
"include": ["src"]
}
================================================
FILE: examples/typescript-with-tsc/tsconfig.json
================================================
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "ESNext",
"moduleResolution": "node",
"outDir": "dist",
"target": "ESNext",
"sourceMap": true
},
"include": ["src"]
}
================================================
FILE: examples/typescript-with-tsc/webpack.config.js
================================================
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshTypeScript = require('react-refresh-typescript');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
devServer: {
client: { overlay: false },
},
entry: {
main: './src/index.tsx',
},
module: {
rules: [
{
test: /\.tsx?$/,
include: path.join(__dirname, 'src'),
use: [
{
loader: 'ts-loader',
options: {
configFile: isDevelopment ? 'tsconfig.dev.json' : 'tsconfig.json',
transpileOnly: isDevelopment,
...(isDevelopment && {
getCustomTransformers: () => ({
before: [ReactRefreshTypeScript()],
}),
}),
},
},
],
},
],
},
plugins: [
isDevelopment && new ReactRefreshPlugin(),
new ForkTsCheckerWebpackPlugin(),
new HtmlWebpackPlugin({
filename: './index.html',
template: './public/index.html',
}),
].filter(Boolean),
resolve: {
extensions: ['.js', '.ts', '.tsx'],
},
};
================================================
FILE: examples/webpack-dev-server/babel.config.js
================================================
module.exports = (api) => {
// This caches the Babel config
api.cache.using(() => process.env.NODE_ENV);
return {
presets: [
'@babel/preset-env',
// Enable development transform of React with new automatic runtime
['@babel/preset-react', { development: !api.env('production'), runtime: 'automatic' }],
],
// Applies the react-refresh Babel plugin on non-production modes only
...(!api.env('production') && { plugins: ['react-refresh/babel'] }),
};
};
================================================
FILE: examples/webpack-dev-server/package.json
================================================
{
"name": "using-webpack-dev-server",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
"babel-loader": "^10.0.0",
"cross-env": "^7.0.3",
"html-webpack-plugin": "^5.6.3",
"react-refresh": "^0.17.0",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.1"
},
"scripts": {
"start": "webpack serve --hot",
"build": "cross-env NODE_ENV=production webpack"
}
}
================================================
FILE: examples/webpack-dev-server/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WDS React App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: examples/webpack-dev-server/src/App.jsx
================================================
import { lazy, Suspense } from 'react';
import { ArrowFunction } from './ArrowFunction';
import ClassDefault from './ClassDefault';
import { ClassNamed } from './ClassNamed';
import FunctionDefault from './FunctionDefault';
import { FunctionNamed } from './FunctionNamed';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<ClassDefault />
<ClassNamed />
<FunctionDefault />
<FunctionNamed />
<ArrowFunction />
<Suspense fallback={<h1>Loading</h1>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
================================================
FILE: examples/webpack-dev-server/src/ArrowFunction.jsx
================================================
export const ArrowFunction = () => <h1>Arrow Function</h1>;
================================================
FILE: examples/webpack-dev-server/src/ClassDefault.jsx
================================================
import { Component } from 'react';
class ClassDefault extends Component {
render() {
return <h1>Default Export Class</h1>;
}
}
export default ClassDefault;
================================================
FILE: examples/webpack-dev-server/src/ClassNamed.jsx
================================================
import { Component } from 'react';
export class ClassNamed extends Component {
render() {
return <h1>Named Export Class</h1>;
}
}
================================================
FILE: examples/webpack-dev-server/src/FunctionDefault.jsx
================================================
function FunctionDefault() {
return <h1>Default Export Function</h1>;
}
export default FunctionDefault;
================================================
FILE: examples/webpack-dev-server/src/FunctionNamed.jsx
================================================
export function FunctionNamed() {
return <h1>Named Export Function</h1>;
}
================================================
FILE: examples/webpack-dev-server/src/LazyComponent.jsx
================================================
function LazyComponent() {
return <h1>Lazy Component</h1>;
}
export default LazyComponent;
================================================
FILE: examples/webpack-dev-server/src/index.js
================================================
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
================================================
FILE: examples/webpack-dev-server/webpack.config.js
================================================
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
devServer: {
client: { overlay: false },
},
entry: {
main: './src/index.js',
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.join(__dirname, 'src'),
use: 'babel-loader',
},
],
},
plugins: [
isDevelopment && new ReactRefreshPlugin(),
new HtmlWebpackPlugin({
filename: './index.html',
template: './public/index.html',
}),
].filter(Boolean),
resolve: {
extensions: ['.js', '.jsx'],
},
};
================================================
FILE: examples/webpack-hot-middleware/babel.config.js
================================================
module.exports = (api) => {
// This caches the Babel config
api.cache.using(() => process.env.NODE_ENV);
return {
presets: [
'@babel/preset-env',
// Enable development transform of React with new automatic runtime
['@babel/preset-react', { development: !api.env('production'), runtime: 'automatic' }],
],
// Applies the react-refresh Babel plugin on non-production modes only
...(!api.env('production') && { plugins: ['react-refresh/babel'] }),
};
};
================================================
FILE: examples/webpack-hot-middleware/package.json
================================================
{
"name": "using-webpack-hot-middleware",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
"babel-loader": "^10.0.0",
"cross-env": "^7.0.3",
"express": "^5.2.0",
"html-webpack-plugin": "^5.6.3",
"react-refresh": "^0.17.0",
"webpack": "^5.98.0",
"webpack-dev-middleware": "^7.4.2",
"webpack-hot-middleware": "^2.26.1"
},
"scripts": {
"start": "node ./server.js",
"build": "cross-env NODE_ENV=production webpack"
}
}
================================================
FILE: examples/webpack-hot-middleware/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WHM React App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: examples/webpack-hot-middleware/server.js
================================================
const path = require('path');
const express = require('express');
const webpack = require('webpack');
const config = require('./webpack.config.js');
const app = express();
const compiler = webpack(config);
app.use(
require('webpack-dev-middleware')(compiler, {
publicPath: config.output.publicPath,
})
);
app.use(
require(`webpack-hot-middleware`)(compiler, {
log: false,
path: `/__webpack_hmr`,
heartbeat: 10 * 1000,
})
);
app.get('*', (req, res, next) => {
const filename = path.join(compiler.outputPath, 'index.html');
compiler.outputFileSystem.readFile(filename, (err, result) => {
if (err) {
return next(err);
}
res.set('content-type', 'text/html');
res.send(result);
res.end();
});
});
app.listen(8080, () => console.log('App is listening on port 8080!'));
================================================
FILE: examples/webpack-hot-middleware/src/App.jsx
================================================
import { lazy, Suspense } from 'react';
import { ArrowFunction } from './ArrowFunction';
import ClassDefault from './ClassDefault';
import { ClassNamed } from './ClassNamed';
import FunctionDefault from './FunctionDefault';
import { FunctionNamed } from './FunctionNamed';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<ClassDefault />
<ClassNamed />
<FunctionDefault />
<FunctionNamed />
<ArrowFunction />
<Suspense fallback={<h1>Loading</h1>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
================================================
FILE: examples/webpack-hot-middleware/src/ArrowFunction.jsx
================================================
export const ArrowFunction = () => <h1>Arrow Function</h1>;
================================================
FILE: examples/webpack-hot-middleware/src/ClassDefault.jsx
================================================
import { Component } from 'react';
class ClassDefault extends Component {
render() {
return <h1>Default Export Class</h1>;
}
}
export default ClassDefault;
================================================
FILE: examples/webpack-hot-middleware/src/ClassNamed.jsx
================================================
import { Component } from 'react';
export class ClassNamed extends Component {
render() {
return <h1>Named Export Class</h1>;
}
}
================================================
FILE: examples/webpack-hot-middleware/src/FunctionDefault.jsx
================================================
function FunctionDefault() {
return <h1>Default Export Function</h1>;
}
export default FunctionDefault;
================================================
FILE: examples/webpack-hot-middleware/src/FunctionNamed.jsx
================================================
export function FunctionNamed() {
return <h1>Named Export Function</h1>;
}
================================================
FILE: examples/webpack-hot-middleware/src/LazyComponent.jsx
================================================
function LazyComponent() {
return <h1>Lazy Component</h1>;
}
export default LazyComponent;
================================================
FILE: examples/webpack-hot-middleware/src/index.js
================================================
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
================================================
FILE: examples/webpack-hot-middleware/webpack.config.js
================================================
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
entry: {
main: ['webpack-hot-middleware/client', './src/index.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.join(__dirname, 'src'),
use: 'babel-loader',
},
],
},
plugins: [
isDevelopment && new webpack.HotModuleReplacementPlugin(),
isDevelopment &&
new ReactRefreshPlugin({
overlay: {
sockIntegration: 'whm',
},
}),
new HtmlWebpackPlugin({
filename: './index.html',
template: './public/index.html',
}),
].filter(Boolean),
resolve: {
extensions: ['.js', '.jsx'],
},
};
================================================
FILE: examples/webpack-plugin-serve/babel.config.js
================================================
module.exports = (api) => {
// This caches the Babel config
api.cache.using(() => process.env.NODE_ENV);
return {
presets: [
'@babel/preset-env',
// Enable development transform of React with new automatic runtime
['@babel/preset-react', { development: !api.env('production'), runtime: 'automatic' }],
],
// Applies the react-refresh Babel plugin on non-production modes only
...(!api.env('production') && { plugins: ['react-refresh/babel'] }),
};
};
================================================
FILE: examples/webpack-plugin-serve/package.json
================================================
{
"name": "using-webpack-plugin-serve",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
"babel-loader": "^10.0.0",
"cross-env": "^7.0.3",
"html-webpack-plugin": "^5.6.3",
"react-refresh": "^0.17.0",
"webpack": "^5.104.1",
"webpack-cli": "^6.0.1",
"webpack-plugin-serve": "^1.6.0"
},
"scripts": {
"start": "webpack --watch",
"build": "cross-env NODE_ENV=production webpack"
}
}
================================================
FILE: examples/webpack-plugin-serve/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WPS React App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: examples/webpack-plugin-serve/src/App.jsx
================================================
import { lazy, Suspense } from 'react';
import { ArrowFunction } from './ArrowFunction';
import ClassDefault from './ClassDefault';
import { ClassNamed } from './ClassNamed';
import FunctionDefault from './FunctionDefault';
import { FunctionNamed } from './FunctionNamed';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<ClassDefault />
<ClassNamed />
<FunctionDefault />
<FunctionNamed />
<ArrowFunction />
<Suspense fallback={<h1>Loading</h1>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
================================================
FILE: examples/webpack-plugin-serve/src/ArrowFunction.jsx
================================================
export const ArrowFunction = () => <h1>Arrow Function</h1>;
================================================
FILE: examples/webpack-plugin-serve/src/ClassDefault.jsx
================================================
import { Component } from 'react';
class ClassDefault extends Component {
render() {
return <h1>Default Export Class</h1>;
}
}
export default ClassDefault;
================================================
FILE: examples/webpack-plugin-serve/src/ClassNamed.jsx
================================================
import { Component } from 'react';
export class ClassNamed extends Component {
render() {
return <h1>Named Export Class</h1>;
}
}
================================================
FILE: examples/webpack-plugin-serve/src/FunctionDefault.jsx
================================================
function FunctionDefault() {
return <h1>Default Export Function</h1>;
}
export default FunctionDefault;
================================================
FILE: examples/webpack-plugin-serve/src/FunctionNamed.jsx
================================================
export function FunctionNamed() {
return <h1>Named Export Function</h1>;
}
================================================
FILE: examples/webpack-plugin-serve/src/LazyComponent.jsx
================================================
function LazyComponent() {
return <h1>Lazy Component</h1>;
}
export default LazyComponent;
================================================
FILE: examples/webpack-plugin-serve/src/index.js
================================================
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
================================================
FILE: examples/webpack-plugin-serve/webpack.config.js
================================================
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { WebpackPluginServe: ServePlugin } = require('webpack-plugin-serve');
const isDevelopment = process.env.NODE_ENV !== 'production';
const outputPath = path.resolve(__dirname, 'dist');
module.exports = {
mode: isDevelopment ? 'development' : 'production',
entry: {
main: ['webpack-plugin-serve/client', './src/index.js'],
},
output: {
filename: 'bundle.js',
path: outputPath,
publicPath: '/',
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.join(__dirname, 'src'),
use: 'babel-loader',
},
],
},
plugins: [
isDevelopment &&
new ServePlugin({
port: 8080,
static: outputPath,
status: false,
}),
isDevelopment &&
new ReactRefreshPlugin({
overlay: {
sockIntegration: 'wps',
},
}),
new HtmlWebpackPlugin({
filename: './index.html',
template: './public/index.html',
}),
].filter(Boolean),
resolve: {
extensions: ['.js', '.jsx'],
},
};
================================================
FILE: jest.config.js
================================================
module.exports = {
globalSetup: '<rootDir>/jest-global-setup.js',
globalTeardown: '<rootDir>/jest-global-teardown.js',
prettierPath: null,
resolver: '<rootDir>/jest-resolver.js',
rootDir: 'test',
setupFilesAfterEnv: ['<rootDir>/jest-test-setup.js'],
testEnvironment: '<rootDir>/jest-environment.js',
testMatch: ['<rootDir>/**/*.test.js'],
};
================================================
FILE: lib/globals.js
================================================
/**
* Gets current bundle's global scope identifier for React Refresh.
* @param {Record<string, string>} runtimeGlobals The Webpack runtime globals.
* @returns {string} The React Refresh global scope within the Webpack bundle.
*/
module.exports.getRefreshGlobalScope = (runtimeGlobals) => {
return `${runtimeGlobals.require || '__webpack_require__'}.$Refresh$`;
};
================================================
FILE: lib/index.js
================================================
const { validate: validateOptions } = require('schema-utils');
const { getRefreshGlobalScope } = require('./globals');
const {
getAdditionalEntries,
getIntegrationEntry,
getSocketIntegration,
injectRefreshLoader,
makeRefreshRuntimeModule,
normalizeOptions,
} = require('./utils');
const schema = require('./options.json');
class ReactRefreshPlugin {
/**
* @param {import('./types').ReactRefreshPluginOptions} [options] Options for react-refresh-plugin.
*/
constructor(options = {}) {
validateOptions(schema, options, {
name: 'React Refresh Plugin',
baseDataPath: 'options',
});
/**
* @readonly
* @type {import('./types').NormalizedPluginOptions}
*/
this.options = normalizeOptions(options);
}
/**
* Applies the plugin.
* @param {import('webpack').Compiler} compiler A webpack compiler object.
* @returns {void}
*/
apply(compiler) {
// Skip processing in non-development mode, but allow manual force-enabling
if (
// Webpack do not set process.env.NODE_ENV, so we need to check for mode.
// Ref: https://github.com/webpack/webpack/issues/7074
(compiler.options.mode !== 'development' ||
// We also check for production process.env.NODE_ENV,
// in case it was set and mode is non-development (e.g. 'none')
(process.env.NODE_ENV && process.env.NODE_ENV === 'production')) &&
!this.options.forceEnable
) {
return;
}
const logger = compiler.getInfrastructureLogger(this.constructor.name);
// Get Webpack imports from compiler instance (if available) -
// this allow mono-repos to use different versions of Webpack without conflicts.
const webpack = compiler.webpack || require('webpack');
const {
DefinePlugin,
EntryDependency,
EntryPlugin,
ModuleFilenameHelpers,
NormalModule,
ProvidePlugin,
RuntimeGlobals,
Template,
} = webpack;
// Inject react-refresh context to all Webpack entry points.
const { overlayEntries, prependEntries } = getAdditionalEntries(this.options);
// Prepended entries does not care about injection order,
// so we can utilise EntryPlugin for simpler logic.
for (const entry of prependEntries) {
new EntryPlugin(compiler.context, entry, { name: undefined }).apply(compiler);
}
const integrationEntry = getIntegrationEntry(this.options.overlay.sockIntegration);
const socketEntryData = [];
compiler.hooks.make.tap(
{ name: this.constructor.name, stage: Number.POSITIVE_INFINITY },
(compilation) => {
// Exhaustively search all entries for `integrationEntry`.
// If found, mark those entries and the index of `integrationEntry`.
for (const [name, entryData] of compilation.entries.entries()) {
const index = entryData.dependencies.findIndex(
(dep) => dep.request && dep.request.includes(integrationEntry)
);
if (index !== -1) {
socketEntryData.push({ name, index });
}
}
}
);
// 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 overlayEntries.entries()) {
compiler.hooks.finishMake.tapPromise(
{
name: this.constructor.name,
stage: Number.MIN_SAFE_INTEGER + (overlayEntries.length - idx - 1),
},
(compilation) => {
// Only hook into the current compiler
if (compilation.compiler !== compiler) {
return Promise.resolve();
}
const injectData = socketEntryData.length ? socketEntryData : [{ name: undefined }];
return Promise.all(
injectData.map(({ name, index }) => {
return new Promise((resolve, reject) => {
const options = { name };
const dep = EntryPlugin.createDependency(entry, options);
compilation.addEntry(compiler.context, dep, options, (err) => {
if (err) return reject(err);
// If the entry is not a global one,
// and we have registered the index for integration entry,
// we will reorder all entry dependencies to our desired order.
// That is, to have additional entries DIRECTLY behind integration entry.
if (name && typeof index !== 'undefined') {
const entryData = compilation.entries.get(name);
entryData.dependencies.splice(
index + 1,
0,
entryData.dependencies.splice(entryData.dependencies.length - 1, 1)[0]
);
}
resolve();
});
});
})
);
}
);
}
// Inject necessary modules and variables to bundle's global scope
const refreshGlobal = getRefreshGlobalScope(RuntimeGlobals || {});
/** @type {Record<string, string | boolean>}*/
const definedModules = {
// Mapping of react-refresh globals to Webpack runtime globals
$RefreshReg$: `${refreshGlobal}.register`,
$RefreshSig$: `${refreshGlobal}.signature`,
'typeof $RefreshReg$': 'function',
'typeof $RefreshSig$': 'function',
// Library mode
__react_refresh_library__: JSON.stringify(
Template.toIdentifier(
this.options.library ||
compiler.options.output.uniqueName ||
compiler.options.output.library
)
),
};
/** @type {Record<string, string>} */
const providedModules = {
__react_refresh_utils__: require.resolve('./runtime/RefreshUtils'),
};
if (this.options.overlay === false) {
// Stub errorOverlay module so their calls can be erased
definedModules.__react_refresh_error_overlay__ = false;
definedModules.__react_refresh_socket__ = false;
} else {
if (this.options.overlay.module) {
providedModules.__react_refresh_error_overlay__ = require.resolve(
this.options.overlay.module
);
}
if (this.options.overlay.sockIntegration) {
providedModules.__react_refresh_socket__ = getSocketIntegration(
this.options.overlay.sockIntegration
);
}
}
new DefinePlugin(definedModules).apply(compiler);
new ProvidePlugin(providedModules).apply(compiler);
const match = ModuleFilenameHelpers.matchObject.bind(undefined, this.options);
let loggedHotWarning = false;
compiler.hooks.compilation.tap(
this.constructor.name,
(compilation, { normalModuleFactory }) => {
// Only hook into the current compiler
if (compilation.compiler !== compiler) {
return;
}
// Set factory for EntryDependency which is used to initialise the module
compilation.dependencyFactories.set(EntryDependency, normalModuleFactory);
const ReactRefreshRuntimeModule = makeRefreshRuntimeModule(webpack);
compilation.hooks.additionalTreeRuntimeRequirements.tap(
this.constructor.name,
// Setup react-refresh globals with a Webpack runtime module
(chunk, runtimeRequirements) => {
runtimeRequirements.add(RuntimeGlobals.interceptModuleExecution);
runtimeRequirements.add(RuntimeGlobals.moduleCache);
runtimeRequirements.add(refreshGlobal);
compilation.addRuntimeModule(chunk, new ReactRefreshRuntimeModule());
}
);
normalModuleFactory.hooks.afterResolve.tap(
this.constructor.name,
// Add react-refresh loader to process files that matches specified criteria
(resolveData) => {
injectRefreshLoader(resolveData.createData, {
match,
options: {
const: compilation.runtimeTemplate.supportsConst(),
esModule: this.options.esModule,
},
});
}
);
NormalModule.getCompilationHooks(compilation).loader.tap(
// `Infinity` ensures this check will run only after all other taps
{ name: this.constructor.name, stage: Infinity },
// Check for existence of the HMR runtime -
// it is the foundation to this plugin working correctly
(context) => {
if (!context.hot && !loggedHotWarning) {
logger.warn(
[
'Hot Module Replacement (HMR) is not enabled!',
'React Refresh requires HMR to function properly.',
].join(' ')
);
loggedHotWarning = true;
}
}
);
}
);
}
}
module.exports.ReactRefreshPlugin = ReactRefreshPlugin;
module.exports = ReactRefreshPlugin;
================================================
FILE: lib/options.json
================================================
{
"additionalProperties": false,
"type": "object",
"definitions": {
"Path": { "type": "string" },
"MatchCondition": {
"anyOf": [{ "instanceof": "RegExp" }, { "$ref": "#/definitions/Path" }]
},
"MatchConditions": {
"type": "array",
"items": { "$ref": "#/definitions/MatchCondition" },
"minItems": 1
},
"ESModuleOptions": {
"additionalProperties": false,
"type": "object",
"properties": {
"exclude": {
"anyOf": [
{ "$ref": "#/definitions/MatchCondition" },
{ "$ref": "#/definitions/MatchConditions" }
]
},
"include": {
"anyOf": [
{ "$ref": "#/definitions/MatchCondition" },
{ "$ref": "#/definitions/MatchConditions" }
]
}
}
},
"OverlayOptions": {
"additionalProperties": false,
"type": "object",
"properties": {
"entry": {
"anyOf": [{ "const": false }, { "$ref": "#/definitions/Path" }]
},
"module": {
"anyOf": [{ "const": false }, { "$ref": "#/definitions/Path" }]
},
"sockIntegration": {
"anyOf": [
{ "const": false },
{ "enum": ["wds", "whm", "wps"] },
{ "$ref": "#/definitions/Path" }
]
}
}
}
},
"properties": {
"esModule": {
"anyOf": [{ "type": "boolean" }, { "$ref": "#/definitions/ESModuleOptions" }]
},
"exclude": {
"anyOf": [
{ "$ref": "#/definitions/MatchCondition" },
{ "$ref": "#/definitions/MatchConditions" }
]
},
"forceEnable": { "type": "boolean" },
"include": {
"anyOf": [
{ "$ref": "#/definitions/MatchCondition" },
{ "$ref": "#/definitions/MatchConditions" }
]
},
"library": { "type": "string" },
"overlay": {
"anyOf": [{ "type": "boolean" }, { "$ref": "#/definitions/OverlayOptions" }]
}
}
}
================================================
FILE: lib/runtime/RefreshUtils.js
================================================
/* global __webpack_require__ */
var Refresh = require('react-refresh/runtime');
/**
* Extracts exports from a webpack module object.
* @param {string} moduleId A Webpack module ID.
* @returns {*} An exports object from the module.
*/
function getModuleExports(moduleId) {
if (typeof moduleId === 'undefined') {
// `moduleId` is unavailable, which indicates that this module is not in the cache,
// which means we won't be able to capture any exports,
// and thus they cannot be refreshed safely.
// These are likely runtime or dynamically generated modules.
return {};
}
var maybeModule = __webpack_require__.c[moduleId];
if (typeof maybeModule === 'undefined') {
// `moduleId` is available but the module in cache is unavailable,
// which indicates the module is somehow corrupted (e.g. broken Webpacak `module` globals).
// We will warn the user (as this is likely a mistake) and assume they cannot be refreshed.
console.warn('[React Refresh] Failed to get exports for module: ' + moduleId + '.');
return {};
}
var exportsOrPromise = maybeModule.exports;
if (typeof Promise !== 'undefined' && exportsOrPromise instanceof Promise) {
return exportsOrPromise.then(function (exports) {
return exports;
});
}
return exportsOrPromise;
}
/**
* Calculates the signature of a React refresh boundary.
* If this signature changes, it's unsafe to accept the boundary.
*
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/907d6af22ac6ebe58572be418e9253a90665ecbd/packages/metro/src/lib/polyfills/require.js#L795-L816).
* @param {*} moduleExports A Webpack module exports object.
* @returns {string[]} A React refresh boundary signature array.
*/
function getReactRefreshBoundarySignature(moduleExports) {
var signature = [];
signature.push(Refresh.getFamilyByType(moduleExports));
if (moduleExports == null || typeof moduleExports !== 'object') {
// Exit if we can't iterate over exports.
return signature;
}
for (var key in moduleExports) {
if (key === '__esModule') {
continue;
}
signature.push(key);
signature.push(Refresh.getFamilyByType(moduleExports[key]));
}
return signature;
}
/**
* Creates a data object to be retained across refreshes.
* This object should not transtively reference previous exports,
* which can form infinite chain of objects across refreshes, which can pressure RAM.
*
* @param {*} moduleExports A Webpack module exports object.
* @returns {*} A React refresh boundary signature array.
*/
function getWebpackHotData(moduleExports) {
return {
signature: getReactRefreshBoundarySignature(moduleExports),
isReactRefreshBoundary: isReactRefreshBoundary(moduleExports),
};
}
/**
* Creates a helper that performs a delayed React refresh.
* @returns {function(function(): void): void} A debounced React refresh function.
*/
function createDebounceUpdate() {
/**
* A cached setTimeout handler.
* @type {number | undefined}
*/
var refreshTimeout;
/**
* Performs react refresh on a delay and clears the error overlay.
* @param {function(): void} callback
* @returns {void}
*/
function enqueueUpdate(callback) {
if (typeof refreshTimeout === 'undefined') {
refreshTimeout = setTimeout(function () {
refreshTimeout = undefined;
Refresh.performReactRefresh();
callback();
}, 30);
}
}
return enqueueUpdate;
}
/**
* Checks if all exports are likely a React component.
*
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/febdba2383113c88296c61e28e4ef6a7f4939fda/packages/metro/src/lib/polyfills/require.js#L748-L774).
* @param {*} moduleExports A Webpack module exports object.
* @returns {boolean} Whether the exports are React component like.
*/
function isReactRefreshBoundary(moduleExports) {
if (Refresh.isLikelyComponentType(moduleExports)) {
return true;
}
if (moduleExports === undefined || moduleExports === null || typeof moduleExports !== 'object') {
// Exit if we can't iterate over exports.
return false;
}
var hasExports = false;
var areAllExportsComponents = true;
for (var key in moduleExports) {
hasExports = true;
// This is the ES Module indicator flag
if (key === '__esModule') {
continue;
}
// We can (and have to) safely execute getters here,
// as Webpack manually assigns harmony exports to getters,
// without any side-effects attached.
// Ref: https://github.com/webpack/webpack/blob/b93048643fe74de2a6931755911da1212df55897/lib/MainTemplate.js#L281
var exportValue = moduleExports[key];
if (!Refresh.isLikelyComponentType(exportValue)) {
areAllExportsComponents = false;
}
}
return hasExports && areAllExportsComponents;
}
/**
* Checks if exports are likely a React component and registers them.
*
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/febdba2383113c88296c61e28e4ef6a7f4939fda/packages/metro/src/lib/polyfills/require.js#L818-L835).
* @param {*} moduleExports A Webpack module exports object.
* @param {string} moduleId A Webpack module ID.
* @returns {void}
*/
function registerExportsForReactRefresh(moduleExports, moduleId) {
if (Refresh.isLikelyComponentType(moduleExports)) {
// Register module.exports if it is likely a component
Refresh.register(moduleExports, moduleId + ' %exports%');
}
if (moduleExports === undefined || moduleExports === null || typeof moduleExports !== 'object') {
// Exit if we can't iterate over the exports.
return;
}
for (var key in moduleExports) {
// Skip registering the ES Module indicator
if (key === '__esModule') {
continue;
}
var exportValue = moduleExports[key];
if (Refresh.isLikelyComponentType(exportValue)) {
var typeID = moduleId + ' %exports% ' + key;
Refresh.register(exportValue, typeID);
}
}
}
/**
* Compares previous and next module objects to check for mutated boundaries.
*
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/907d6af22ac6ebe58572be418e9253a90665ecbd/packages/metro/src/lib/polyfills/require.js#L776-L792).
* @param {*} prevSignature The signature of the current Webpack module exports object.
* @param {*} nextSignature The signature of the next Webpack module exports object.
* @returns {boolean} Whether the React refresh boundary should be invalidated.
*/
function shouldInvalidateReactRefreshBoundary(prevSignature, nextSignature) {
if (prevSignature.length !== nextSignature.length) {
return true;
}
for (var i = 0; i < nextSignature.length; i += 1) {
if (prevSignature[i] !== nextSignature[i]) {
return true;
}
}
return false;
}
var enqueueUpdate = createDebounceUpdate();
function executeRuntime(moduleExports, moduleId, webpackHot, refreshOverlay, isTest) {
registerExportsForReactRefresh(moduleExports, moduleId);
if (webpackHot) {
var isHotUpdate = !!webpackHot.data;
var prevData;
if (isHotUpdate) {
prevData = webpackHot.data.prevData;
}
if (isReactRefreshBoundary(moduleExports)) {
webpackHot.dispose(
/**
* A callback to performs a full refresh if React has unrecoverable errors,
* and also caches the to-be-disposed module.
* @param {*} data A hot module data object from Webpack HMR.
* @returns {void}
*/
function hotDisposeCallback(data) {
// We have to mutate the data object to get data registered and cached
data.prevData = getWebpackHotData(moduleExports);
}
);
webpackHot.accept(
/**
* An error handler to allow self-recovering behaviours.
* @param {Error} error An error occurred during evaluation of a module.
* @returns {void}
*/
function hotErrorHandler(error) {
if (typeof refreshOverlay !== 'undefined' && refreshOverlay) {
refreshOverlay.handleRuntimeError(error);
}
if (typeof isTest !== 'undefined' && isTest) {
if (window.onHotAcceptError) {
window.onHotAcceptError(error.message);
}
}
__webpack_require__.c[moduleId].hot.accept(hotErrorHandler);
}
);
if (isHotUpdate) {
if (
prevData &&
prevData.isReactRefreshBoundary &&
shouldInvalidateReactRefreshBoundary(
prevData.signature,
getReactRefreshBoundarySignature(moduleExports)
)
) {
webpackHot.invalidate();
} else {
enqueueUpdate(
/**
* A function to dismiss the error overlay after performing React refresh.
* @returns {void}
*/
function updateCallback() {
if (typeof refreshOverlay !== 'undefined' && refreshOverlay) {
refreshOverlay.clearRuntimeErrors();
}
}
);
}
}
} else {
if (isHotUpdate && typeof prevData !== 'undefined') {
webpackHot.invalidate();
}
}
}
}
module.exports = Object.freeze({
enqueueUpdate: enqueueUpdate,
executeRuntime: executeRuntime,
getModuleExports: getModuleExports,
isReactRefreshBoundary: isReactRefreshBoundary,
registerExportsForReactRefresh: registerExportsForReactRefresh,
});
================================================
FILE: lib/types.js
================================================
/**
* @typedef {Object} ErrorOverlayOptions
* @property {string | false} [entry] Path to a JS file that sets up the error overlay integration.
* @property {string | false} [module] The error overlay module to use.
* @property {import('type-fest').LiteralUnion<'wds' | 'whm' | 'wps' | false, string>} [sockIntegration] Path to a JS file that sets up the Webpack socket integration.
*/
/**
* @typedef {import('type-fest').SetRequired<ErrorOverlayOptions, 'entry' | 'module' | 'sockIntegration'>} NormalizedErrorOverlayOptions
*/
/**
* @typedef {Object} ReactRefreshPluginOptions
* @property {boolean | import('../loader/types').ESModuleOptions} [esModule] Enables strict ES Modules compatible runtime.
* @property {string | RegExp | Array<string | RegExp>} [exclude] Files to explicitly exclude from processing.
* @property {boolean} [forceEnable] Enables the plugin forcefully.
* @property {string | RegExp | Array<string | RegExp>} [include] Files to explicitly include for processing.
* @property {string} [library] Name of the library bundle.
* @property {boolean | ErrorOverlayOptions} [overlay] Modifies how the error overlay integration works in the plugin.
*/
/**
* @typedef {Object} OverlayOverrides
* @property {false | NormalizedErrorOverlayOptions} overlay Modifies how the error overlay integration works in the plugin.
*/
/**
* @typedef {import('type-fest').SetRequired<import('type-fest').Except<ReactRefreshPluginOptions, 'overlay'>, 'exclude' | 'include'> & OverlayOverrides} NormalizedPluginOptions
*/
module.exports = {};
================================================
FILE: lib/utils/getAdditionalEntries.js
================================================
/**
* @typedef {Object} AdditionalEntries
* @property {string[]} prependEntries
* @property {string[]} overlayEntries
*/
/**
* Creates an object that contains two entry arrays: the prependEntries and overlayEntries
* @param {import('../types').NormalizedPluginOptions} options Configuration options for this plugin.
* @returns {AdditionalEntries} An object that contains the Webpack entries for prepending and the overlay feature
*/
function getAdditionalEntries(options) {
const prependEntries = [
// React-refresh runtime
require.resolve('../../client/ReactRefreshEntry'),
];
const overlayEntries = [
// Error overlay runtime
options.overlay && options.overlay.entry && require.resolve(options.overlay.entry),
].filter(Boolean);
return { prependEntries, overlayEntries };
}
module.exports = getAdditionalEntries;
================================================
FILE: lib/utils/getIntegrationEntry.js
================================================
/**
* Gets entry point of a supported socket integration.
* @param {'wds' | 'whm' | 'wps' | string} integrationType A valid socket integration type or a path to a module.
* @returns {string | undefined} Path to the resolved integration entry point.
*/
function getIntegrationEntry(integrationType) {
let resolvedEntry;
switch (integrationType) {
case 'whm': {
resolvedEntry = 'webpack-hot-middleware/client';
break;
}
case 'wps': {
resolvedEntry = 'webpack-plugin-serve/client';
break;
}
}
return resolvedEntry;
}
module.exports = getIntegrationEntry;
================================================
FILE: lib/utils/getSocketIntegration.js
================================================
/**
* Gets the socket integration to use for Webpack messages.
* @param {'wds' | 'whm' | 'wps' | string} integrationType A valid socket integration type or a path to a module.
* @returns {string} Path to the resolved socket integration module.
*/
function getSocketIntegration(integrationType) {
let resolvedSocketIntegration;
switch (integrationType) {
case 'wds': {
resolvedSocketIntegration = require.resolve('../../sockets/WDSSocket');
break;
}
case 'whm': {
resolvedSocketIntegration = require.resolve('../../sockets/WHMEventSource');
break;
}
case 'wps': {
resolvedSocketIntegration = require.resolve('../../sockets/WPSSocket');
break;
}
default: {
resolvedSocketIntegration = require.resolve(integrationType);
break;
}
}
return resolvedSocketIntegration;
}
module.exports = getSocketIntegration;
================================================
FILE: lib/utils/index.js
================================================
const getAdditionalEntries = require('./getAdditionalEntries');
const getIntegrationEntry = require('./getIntegrationEntry');
const getSocketIntegration = require('./getSocketIntegration');
const injectRefreshLoader = require('./injectRefreshLoader');
const makeRefreshRuntimeModule = require('./makeRefreshRuntimeModule');
const normalizeOptions = require('./normalizeOptions');
module.exports = {
getAdditionalEntries,
getIntegrationEntry,
getSocketIntegration,
injectRefreshLoader,
makeRefreshRuntimeModule,
normalizeOptions,
};
================================================
FILE: lib/utils/injectRefreshLoader.js
================================================
const path = require('node:path');
/**
* @callback MatchObject
* @param {string} [str]
* @returns {boolean}
*/
/**
* @typedef {Object} InjectLoaderOptions
* @property {MatchObject} match A function to include/exclude files to be processed.
* @property {import('../../loader/types').ReactRefreshLoaderOptions} [options] Options passed to the loader.
*/
const resolvedLoader = require.resolve('../../loader');
const reactRefreshPath = path.dirname(require.resolve('react-refresh'));
const refreshUtilsPath = path.join(__dirname, '../runtime/RefreshUtils');
/**
* Injects refresh loader to all JavaScript-like and user-specified files.
* @param {*} moduleData Module factory creation data.
* @param {InjectLoaderOptions} injectOptions Options to alter how the loader is injected.
* @returns {*} The injected module factory creation data.
*/
function injectRefreshLoader(moduleData, injectOptions) {
const { match, options } = injectOptions;
// Include and exclude user-specified files
if (!match(moduleData.matchResource || moduleData.resource)) return moduleData;
// Include and exclude dynamically generated modules from other loaders
if (moduleData.matchResource && !match(moduleData.request)) return moduleData;
// Exclude files referenced as assets
if (moduleData.type.includes('asset')) return moduleData;
// Check to prevent double injection
if (moduleData.loaders.find(({ loader }) => loader === resolvedLoader)) return moduleData;
// Skip react-refresh and the plugin's runtime utils to prevent self-referencing -
// this is useful when using the plugin as a direct dependency,
// or when node_modules are specified to be processed.
if (
moduleData.resource.includes(reactRefreshPath) ||
moduleData.resource.includes(refreshUtilsPath)
) {
return moduleData;
}
// As we inject runtime code for each module,
// it is important to run the injected loader after everything.
// This way we can ensure that all code-processing have been done,
// and we won't risk breaking tools like Flow or ESLint.
moduleData.loaders.unshift({
loader: resolvedLoader,
options,
});
return moduleData;
}
module.exports = injectRefreshLoader;
================================================
FILE: lib/utils/makeRefreshRuntimeModule.js
================================================
/**
* Makes a runtime module to intercept module execution for React Refresh.
* This module creates an isolated `__webpack_require__` function for each module,
* and injects a `$Refresh$` object into it for use by React Refresh.
* @param {import('webpack')} webpack The Webpack exports.
* @returns {typeof import('webpack').RuntimeModule} The runtime module class.
*/
function makeRefreshRuntimeModule(webpack) {
return class ReactRefreshRuntimeModule extends webpack.RuntimeModule {
constructor() {
// Second argument is the `stage` for this runtime module -
// we'll use the same stage as Webpack's HMR runtime module for safety.
super('react refresh', webpack.RuntimeModule.STAGE_BASIC);
}
/**
* @returns {string} runtime code
*/
generate() {
if (!this.compilation) throw new Error('Webpack compilation missing!');
const { runtimeTemplate } = this.compilation;
const constDeclaration = runtimeTemplate.supportsConst() ? 'const' : 'var';
return webpack.Template.asString([
`${constDeclaration} setup = ${runtimeTemplate.basicFunction('moduleId', [
`${constDeclaration} refresh = {`,
webpack.Template.indent([
`moduleId: moduleId,`,
`register: ${runtimeTemplate.basicFunction('type, id', [
`${constDeclaration} typeId = moduleId + ' ' + id;`,
'refresh.runtime.register(type, typeId);',
])},`,
`signature: ${runtimeTemplate.returningFunction(
'refresh.runtime.createSignatureFunctionForTransform()'
)},`,
`runtime: {`,
webpack.Template.indent([
`createSignatureFunctionForTransform: ${runtimeTemplate.returningFunction(
runtimeTemplate.returningFunction('type', 'type')
)},`,
`register: ${runtimeTemplate.emptyFunction()}`,
]),
`},`,
]),
`};`,
`return refresh;`,
])};`,
'',
`${webpack.RuntimeGlobals.interceptModuleExecution}.push(${runtimeTemplate.basicFunction(
'options',
[
`${constDeclaration} originalFactory = options.factory;`,
// Using a function declaration -
// ensures `this` would propagate for modules relying on it
`options.factory = function(moduleObject, moduleExports, webpackRequire) {`,
webpack.Template.indent([
// Our require function delegates to the original require function
`${constDeclaration} hotRequire = ${runtimeTemplate.returningFunction(
'webpackRequire(request)',
'request'
)};`,
// 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 (name === "$Refresh$") continue;',
'if (Object.prototype.hasOwnProperty.call(webpackRequire, name)) {',
webpack.Template.indent([
`Object.defineProperty(hotRequire, name, createPropertyDescriptor(name));`,
]),
`}`,
]),
`}`,
`hotRequire.$Refresh$ = setup(options.id);`,
`originalFactory.call(this, moduleObject, moduleExports, hotRequire);`,
]),
'};',
]
)});`,
]);
}
};
}
module.exports = makeRefreshRuntimeModule;
================================================
FILE: lib/utils/normalizeOptions.js
================================================
const { d, n } = require('../../options');
/**
* Normalizes the options for the plugin.
* @param {import('../types').ReactRefreshPluginOptions} options Non-normalized plugin options.
* @returns {import('../types').NormalizedPluginOptions} Normalized plugin options.
*/
const normalizeOptions = (options) => {
d(options, 'exclude', /node_modules/i);
d(options, 'include', /\.([cm]js|[jt]sx?|flow)$/i);
d(options, 'forceEnable');
d(options, 'library');
n(options, 'overlay', (overlay) => {
/** @type {import('../types').NormalizedErrorOverlayOptions} */
const defaults = {
entry: require.resolve('../../client/ErrorOverlayEntry'),
module: require.resolve('../../overlay'),
sockIntegration: 'wds',
};
if (overlay === false) {
return false;
}
if (typeof overlay === 'undefined' || overlay === true) {
return defaults;
}
d(overlay, 'entry', defaults.entry);
d(overlay, 'module', defaults.module);
d(overlay, 'sockIntegration', defaults.sockIntegration);
return overlay;
});
return options;
};
module.exports = normalizeOptions;
================================================
FILE: loader/index.js
================================================
// This is a patch for mozilla/source-map#349 -
// internally, it uses the existence of the `fetch` global to toggle browser behaviours.
// That check, however, will break when `fetch` polyfills are used for SSR setups.
// We "reset" the polyfill here to ensure it won't interfere with source-map generation.
const originalFetch = global.fetch;
delete global.fetch;
const { validate: validateOptions } = require('schema-utils');
const { SourceMapConsumer, SourceNode } = require('source-map');
const {
getIdentitySourceMap,
getModuleSystem,
getRefreshModuleRuntime,
normalizeOptions,
webpackGlobal,
} = require('./utils');
const schema = require('./options.json');
const RefreshRuntimePath = require
.resolve('react-refresh')
.replace(/\\/g, '/')
.replace(/'/g, "\\'");
/**
* A simple Webpack loader to inject react-refresh HMR code into modules.
*
* [Reference for Loader API](https://webpack.js.org/api/loaders/)
* @this {import('webpack').LoaderContext<import('./types').ReactRefreshLoaderOptions>}
* @param {string} source The original module source code.
* @param {import('source-map').RawSourceMap} [inputSourceMap] The source map of the module.
* @param {*} [meta] The loader metadata passed in.
* @returns {void}
*/
function ReactRefreshLoader(source, inputSourceMap, meta) {
let options = this.getOptions();
validateOptions(schema, options, {
baseDataPath: 'options',
name: 'React Refresh Loader',
});
options = normalizeOptions(options);
const callback = this.async();
const { ModuleFilenameHelpers, Template } = this._compiler.webpack || require('webpack');
const RefreshSetupRuntimes = {
cjs: Template.asString(
`${webpackGlobal}.$Refresh$.runtime = require('${RefreshRuntimePath}');`
),
esm: Template.asString([
`import * as __react_refresh_runtime__ from '${RefreshRuntimePath}';`,
`${webpackGlobal}.$Refresh$.runtime = __react_refresh_runtime__;`,
]),
};
/**
* @this {import('webpack').LoaderContext<import('./types').ReactRefreshLoaderOptions>}
* @param {string} source
* @param {import('source-map').RawSourceMap} [inputSourceMap]
* @returns {Promise<[string, import('source-map').RawSourceMap]>}
*/
async function _loader(source, inputSourceMap) {
/** @type {'esm' | 'cjs'} */
const moduleSystem = await getModuleSystem.call(this, ModuleFilenameHelpers, options);
const RefreshSetupRuntime = RefreshSetupRuntimes[moduleSystem];
const RefreshModuleRuntime = getRefreshModuleRuntime(Template, {
const: options.const,
moduleSystem,
});
if (this.sourceMap) {
let originalSourceMap = inputSourceMap;
if (!originalSourceMap) {
originalSourceMap = getIdentitySourceMap(source, this.resourcePath);
}
return SourceMapConsumer.with(originalSourceMap, undefined, (consumer) => {
const node = SourceNode.fromStringWithSourceMap(source, consumer);
node.prepend([RefreshSetupRuntime, '\n\n']);
node.add(['\n\n', RefreshModuleRuntime]);
const { code, map } = node.toStringWithSourceMap();
return [code, map.toJSON()];
});
} else {
return [[RefreshSetupRuntime, source, RefreshModuleRuntime].join('\n\n'), inputSourceMap];
}
}
_loader.call(this, source, inputSourceMap).then(
([code, map]) => {
callback(null, code, map, meta);
},
(error) => {
callback(error);
}
);
}
module.exports = ReactRefreshLoader;
// Restore the original value of the `fetch` global, if it exists
if (originalFetch) {
global.fetch = originalFetch;
}
================================================
FILE: loader/options.json
================================================
{
"additionalProperties": false,
"type": "object",
"definitions": {
"MatchCondition": {
"anyOf": [{ "instanceof": "RegExp", "tsType": "RegExp" }, { "$ref": "#/definitions/Path" }]
},
"MatchConditions": {
"type": "array",
"items": { "$ref": "#/definitions/MatchCondition" },
"minItems": 1
},
"Path": { "type": "string" },
"ESModuleOptions": {
"additionalProperties": false,
"type": "object",
"properties": {
"exclude": {
"anyOf": [
{ "$ref": "#/definitions/MatchCondition" },
{ "$ref": "#/definitions/MatchConditions" }
]
},
"include": {
"anyOf": [
{ "$ref": "#/definitions/MatchCondition" },
{ "$ref": "#/definitions/MatchConditions" }
]
}
}
}
},
"properties": {
"const": { "type": "boolean" },
"esModule": { "anyOf": [{ "type": "boolean" }, { "$ref": "#/definitions/ESModuleOptions" }] }
}
}
================================================
FILE: loader/types.js
================================================
/**
* @typedef {Object} ESModuleOptions
* @property {string | RegExp | Array<string | RegExp>} [exclude] Files to explicitly exclude from flagged as ES Modules.
* @property {string | RegExp | Array<string | RegExp>} [include] Files to explicitly include for flagged as ES Modules.
*/
/**
* @typedef {Object} ReactRefreshLoaderOptions
* @property {boolean} [const] Enables usage of ES6 `const` and `let` in generated runtime code.
* @property {boolean | ESModuleOptions} [esModule] Enables strict ES Modules compatible runtime.
*/
/**
* @typedef {import('type-fest').SetRequired<ReactRefreshLoaderOptions, 'const'>} NormalizedLoaderOptions
*/
module.exports = {};
================================================
FILE: loader/utils/getIdentitySourceMap.js
================================================
const { SourceMapGenerator } = require('source-map');
/**
* Generates an identity source map from a source file.
* @param {string} source The content of the source file.
* @param {string} resourcePath The name of the source file.
* @returns {import('source-map').RawSourceMap} The identity source map.
*/
function getIdentitySourceMap(source, resourcePath) {
const sourceMap = new SourceMapGenerator();
sourceMap.setSourceContent(resourcePath, source);
source.split('\n').forEach((_, index) => {
sourceMap.addMapping({
source: resourcePath,
original: {
line: index + 1,
column: 0,
},
generated: {
line: index + 1,
column: 0,
},
});
});
return sourceMap.toJSON();
}
module.exports = getIdentitySourceMap;
================================================
FILE: loader/utils/getModuleSystem.js
================================================
const fs = require('node:fs/promises');
const path = require('node:path');
/** @type {Map<string, string | undefined>} */
let packageJsonTypeMap = new Map();
/**
* Infers the current active module system from loader context and options.
* @this {import('webpack').loader.LoaderContext}
* @param {import('webpack').ModuleFilenameHelpers} ModuleFilenameHelpers Webpack's module filename helpers.
* @param {import('../types').NormalizedLoaderOptions} options The normalized loader options.
* @return {Promise<'esm' | 'cjs'>} The inferred module system.
*/
async function getModuleSystem(ModuleFilenameHelpers, options) {
// Check loader options -
// if `esModule` is set we don't have to do extra guess work.
switch (typeof options.esModule) {
case 'boolean': {
return options.esModule ? 'esm' : 'cjs';
}
case 'object': {
if (
options.esModule.include &&
ModuleFilenameHelpers.matchPart(this.resourcePath, options.esModule.include)
) {
return 'esm';
}
if (
options.esModule.exclude &&
ModuleFilenameHelpers.matchPart(this.resourcePath, options.esModule.exclude)
) {
return 'cjs';
}
break;
}
default: // Do nothing
}
// Check current resource's extension
if (/\.mjs$/.test(this.resourcePath)) return 'esm';
if (/\.cjs$/.test(this.resourcePath)) return 'cjs';
if (typeof this.addMissingDependency !== 'function') {
// This is Webpack 4 which does not support `import.meta`.
// We assume `.js` files are CommonJS because the output cannot be ESM anyway.
return 'cjs';
}
// We will assume CommonJS if we cannot determine otherwise
let packageJsonType = '';
// We begin our search for relevant `package.json` files,
// at the directory of the resource being loaded.
// These paths should already be resolved,
// but we resolve them again to ensure we are dealing with an aboslute path.
const resourceContext = path.dirname(this.resourcePath);
let searchPath = resourceContext;
let previousSearchPath = '';
// We start our search just above the root context of the webpack compilation
const stopPath = path.dirname(this.rootContext);
// If the module context is a resolved symlink outside the `rootContext` path,
// then we will never find the `stopPath` - so we also halt when we hit the root.
// Note that there is a potential that the wrong `package.json` is found in some pathalogical cases,
// such as a folder that is conceptually a package + does not have an ancestor `package.json`,
// but there exists a `package.json` higher up.
// This might happen if you have a folder of utility JS files that you symlink but did not organize as a package.
// We consider this an unsupported edge case for now.
while (searchPath !== stopPath && searchPath !== previousSearchPath) {
// If we have already determined the `package.json` type for this path we can stop searching.
// We do however still need to cache the found value,
// from the `resourcePath` folder up to the matching `searchPath`,
// to avoid retracing these steps when processing sibling resources.
if (packageJsonTypeMap.has(searchPath)) {
packageJsonType = packageJsonTypeMap.get(searchPath);
let currentPath = resourceContext;
while (currentPath !== searchPath) {
// We set the found type at least level from `resourcePath` folder up to the matching `searchPath`
packageJsonTypeMap.set(currentPath, packageJsonType);
currentPath = path.dirname(currentPath);
}
break;
}
let packageJsonPath = path.join(searchPath, 'package.json');
try {
const packageSource = await fs.readFile(packageJsonPath, 'utf-8');
try {
const packageObject = JSON.parse(packageSource);
// Any package.json is sufficient as long as it can be parsed.
// If it does not explicitly have a `type: "module"` it will be assumed to be CommonJS.
packageJsonType = typeof packageObject.type === 'string' ? packageObject.type : '';
packageJsonTypeMap.set(searchPath, packageJsonType);
// We set the type in the cache for all paths from the `resourcePath` folder,
// up to the matching `searchPath` to avoid retracing these steps when processing sibling resources.
let currentPath = resourceContext;
while (currentPath !== searchPath) {
packageJsonTypeMap.set(currentPath, packageJsonType);
currentPath = path.dirname(currentPath);
}
} catch (e) {
// `package.json` exists but could not be parsed.
// We track it as a dependency so we can reload if this file changes.
}
this.addDependency(packageJsonPath);
break;
} catch (e) {
// `package.json` does not exist.
// We track it as a missing dependency so we can reload if this file is added.
this.addMissingDependency(packageJsonPath);
}
// Try again at the next level up
previousSearchPath = searchPath;
searchPath = path.dirname(searchPath);
}
// Check `package.json` for the `type` field -
// fallback to use `cjs` for anything ambiguous.
return packageJsonType === 'module' ? 'esm' : 'cjs';
}
module.exports = getModuleSystem;
================================================
FILE: loader/utils/getRefreshModuleRuntime.js
================================================
const webpackGlobal = require('./webpackGlobal');
/**
* @typedef ModuleRuntimeOptions {Object}
* @property {boolean} const Use ES6 `const` and `let` in generated runtime code.
* @property {'cjs' | 'esm'} moduleSystem The module system to be used.
*/
/**
* Generates code appended to each JS-like module for react-refresh capabilities.
*
* `__react_refresh_utils__` will be replaced with actual utils during source parsing by `webpack.ProvidePlugin`.
*
* [Reference for Runtime Injection](https://github.com/webpack/webpack/blob/b07d3b67d2252f08e4bb65d354a11c9b69f8b434/lib/HotModuleReplacementPlugin.js#L419)
* [Reference for HMR Error Recovery](https://github.com/webpack/webpack/issues/418#issuecomment-490296365)
*
* @param {import('webpack').Template} Webpack's templating helpers.
* @param {ModuleRuntimeOptions} options The refresh module runtime options.
* @returns {string} The refresh module runtime template.
*/
function getRefreshModuleRuntime(Template, options) {
const constDeclaration = options.const ? 'const' : 'var';
const letDeclaration = options.const ? 'let' : 'var';
const webpackHot = options.moduleSystem === 'esm' ? 'import.meta.webpackHot' : 'module.hot';
return Template.asString([
`${constDeclaration} $ReactRefreshModuleId$ = ${webpackGlobal}.$Refresh$.moduleId;`,
`${constDeclaration} $ReactRefreshCurrentExports$ = __react_refresh_utils__.getModuleExports(`,
Template.indent('$ReactRefreshModuleId$'),
');',
'',
'function $ReactRefreshModuleRuntime$(exports) {',
Template.indent([
`if (${webpackHot}) {`,
Template.indent([
`${letDeclaration} errorOverlay;`,
"if (typeof __react_refresh_error_overlay__ !== 'undefined') {",
Template.indent('errorOverlay = __react_refresh_error_overlay__;'),
'}',
`${letDeclaration} testMode;`,
"if (typeof __react_refresh_test__ !== 'undefined') {",
Template.indent('testMode = __react_refresh_test__;'),
'}',
'return __react_refresh_utils__.executeRuntime(',
Template.indent([
'exports,',
'$ReactRefreshModuleId$,',
`${webpackHot},`,
'errorOverlay,',
'testMode',
]),
');',
]),
'}',
]),
'}',
'',
"if (typeof Promise !== 'undefined' && $ReactRefreshCurrentExports$ instanceof Promise) {",
Template.indent('$ReactRefreshCurrentExports$.then($ReactRefreshModuleRuntime$);'),
'} else {',
Template.indent('$ReactRefreshModuleRuntime$($ReactRefreshCurrentExports$);'),
'}',
]);
}
module.exports = getRefreshModuleRuntime;
================================================
FILE: loader/utils/index.js
================================================
const getIdentitySourceMap = require('./getIdentitySourceMap');
const getModuleSystem = require('./getModuleSystem');
const getRefreshModuleRuntime = require('./getRefreshModuleRuntime');
const normalizeOptions = require('./normalizeOptions');
const webpackGlobal = require('./webpackGlobal');
module.exports = {
getIdentitySourceMap,
getModuleSystem,
getRefreshModuleRuntime,
normalizeOptions,
webpackGlobal,
};
================================================
FILE: loader/utils/normalizeOptions.js
================================================
const { d, n } = require('../../options');
/**
* Normalizes the options for the loader.
* @param {import('../types').ReactRefreshLoaderOptions} options Non-normalized loader options.
* @returns {import('../types').NormalizedLoaderOptions} Normalized loader options.
*/
const normalizeOptions = (options) => {
d(options, 'const', false);
n(options, 'esModule', (esModule) => {
if (typeof esModule === 'boolean' || typeof esModule === 'undefined') {
return esModule;
}
d(esModule, 'include');
d(esModule, 'exclude');
return esModule;
});
return options;
};
module.exports = normalizeOptions;
================================================
FILE: loader/utils/webpackGlobal.js
================================================
// When available, use `__webpack_global__` which is a stable runtime function to use `__webpack_require__` in this compilation
// See: https://github.com/webpack/webpack/issues/20139
const webpackGlobal = `(typeof __webpack_global__ !== 'undefined' ? __webpack_global__ : __webpack_require__)`;
module.exports = webpackGlobal;
================================================
FILE: options/index.js
================================================
/**
* Sets a constant default value for the property when it is undefined.
* @template T
* @template {keyof T} Property
* @param {T} object An object.
* @param {Property} property A property of the provided object.
* @param {T[Property]} [defaultValue] The default value to set for the property.
* @returns {T[Property]} The defaulted property value.
*/
const d = (object, property, defaultValue) => {
if (typeof object[property] === 'undefined' && typeof defaultValue !== 'undefined') {
object[property] = defaultValue;
}
return object[property];
};
/**
* Resolves the value for a nested object option.
* @template T
* @template {keyof T} Property
* @template Result
* @param {T} object An object.
* @param {Property} property A property of the provided object.
* @param {function(T | undefined): Result} fn The handler to resolve the property's value.
* @returns {Result} The resolved option value.
*/
const n = (object, property, fn) => {
object[property] = fn(object[property]);
return object[property];
};
module.exports = { d, n };
================================================
FILE: overlay/components/CompileErrorTrace.js
================================================
const Anser = require('anser');
const entities = require('html-entities');
const utils = require('../utils.js');
/**
* @typedef {Object} CompileErrorTraceProps
* @property {string} errorMessage
*/
/**
* A formatter that turns Webpack compile error messages into highlighted HTML source traces.
* @param {Document} document
* @param {HTMLElement} root
* @param {CompileErrorTraceProps} props
* @returns {void}
*/
function CompileErrorTrace(document, root, props) {
const errorParts = props.errorMessage.split('\n');
if (errorParts.length) {
if (errorParts[0]) {
errorParts[0] = utils.formatFilename(errorParts[0]);
}
const errorMessage = errorParts.splice(1, 1)[0];
if (errorMessage) {
// Strip filename from the error message
errorParts.unshift(errorMessage.replace(/^(.*:)\s.*:(\s.*)$/, '$1$2'));
}
}
const stackContainer = document.createElement('pre');
stackContainer.style.fontFamily = [
'"SFMono-Regular"',
'Consolas',
'Liberation Mono',
'Menlo',
'Courier',
'monospace',
].join(', ');
stackContainer.style.margin = '0';
stackContainer.style.whiteSpace = 'pre-wrap';
const entries = Anser.ansiToJson(
entities.encode(errorParts.join('\n'), { level: 'html5', mode: 'nonAscii' }),
{
json: true,
remove_empty: true,
use_classes: true,
}
);
for (let i = 0; i < entries.length; i += 1) {
const entry = entries[i];
const elem = document.createElement('span');
elem.innerHTML = entry.content;
elem.style.color = entry.fg ? `var(--color-${entry.fg})` : undefined;
elem.style.wordBreak = 'break-word';
switch (entry.decoration) {
case 'bold':
elem.style.fontWeight = 800;
break;
case 'italic':
elem.style.fontStyle = 'italic';
break;
}
stackContainer.appendChild(elem);
}
root.appendChild(stackContainer);
}
module.exports = CompileErrorTrace;
================================================
FILE: overlay/components/PageHeader.js
================================================
const Spacer = require('./Spacer.js');
const theme = require('../theme.js');
/**
* @typedef {Object} PageHeaderProps
* @property {string} [message]
* @property {string} title
* @property {string} [topOffset]
*/
/**
* The header of the overlay.
* @param {Document} document
* @param {HTMLElement} root
* @param {PageHeaderProps} props
* @returns {void}
*/
function PageHeader(document, root, props) {
const pageHeaderContainer = document.createElement('div');
pageHeaderContainer.style.background = theme['dark-background'];
pageHeaderContainer.style.boxShadow = '0 1px 4px rgba(0, 0, 0, 0.3)';
pageHeaderContainer.style.color = theme.white;
pageHeaderContainer.style.left = '0';
pageHeaderContainer.style.right = '0';
pageHeaderContainer.style.padding = '1rem 1.5rem';
pageHeaderContainer.style.paddingLeft = 'max(1.5rem, env(safe-area-inset-left))';
pageHeaderContainer.style.paddingRight = 'max(1.5rem, env(safe-area-inset-right))';
pageHeaderContainer.style.position = 'fixed';
pageHeaderContainer.style.top = props.topOffset || '0';
const title = document.createElement('h3');
title.innerText = props.title;
title.style.color = theme.red;
title.style.fontSize = '1.125rem';
title.style.lineHeight = '1.3';
title.style.margin = '0';
pageHeaderContainer.appendChild(title);
if (props.message) {
title.style.margin = '0 0 0.5rem';
const message = document.createElement('span');
message.innerText = props.message;
message.style.color = theme.white;
message.style.wordBreak = 'break-word';
pageHeaderContainer.appendChild(message);
}
root.appendChild(pageHeaderContainer);
// This has to run after appending elements to root
// because we need to actual mounted height.
Spacer(document, root, {
space: pageHeaderContainer.offsetHeight.toString(10),
});
}
module.exports = PageHeader;
================================================
FILE: overlay/components/RuntimeErrorFooter.js
================================================
const Spacer = require('./Spacer.js');
const theme = require('../theme.js');
/**
* @typedef {Object} RuntimeErrorFooterProps
* @property {string} [initialFocus]
* @property {boolean} multiple
* @property {function(MouseEvent): void} onClickCloseButton
* @property {function(MouseEvent): void} onClickNextButton
* @property {function(MouseEvent): void} onClickPrevButton
*/
/**
* A fixed footer that handles pagination of runtime errors.
* @param {Document} document
* @param {HTMLElement} root
* @param {RuntimeErrorFooterProps} props
* @returns {void}
*/
function RuntimeErrorFooter(document, root, props) {
const footer = document.createElement('div');
footer.style.backgroundColor = theme['dark-background'];
footer.style.bottom = '0';
footer.style.boxShadow = '0 -1px 4px rgba(0, 0, 0, 0.3)';
footer.style.height = '2.5rem';
footer.style.left = '0';
footer.style.right = '0';
footer.style.lineHeight = '2.5rem';
footer.style.paddingBottom = '0';
footer.style.paddingBottom = 'env(safe-area-inset-bottom)';
footer.style.position = 'fixed';
footer.style.textAlign = 'center';
footer.style.zIndex = '2';
const BUTTON_CONFIGS = {
prev: {
id: 'prev',
label: '◀ Prev',
onClick: props.onClickPrevButton,
},
close: {
id: 'close',
label: '× Close',
onClick: props.onClickCloseButton,
},
next: {
id: 'next',
label: 'Next ▶',
onClick: props.onClickNextButton,
},
};
let buttons = [BUTTON_CONFIGS.close];
if (props.multiple) {
buttons = [BUTTON_CONFIGS.prev, BUTTON_CONFIGS.close, BUTTON_CONFIGS.next];
}
/** @type {HTMLButtonElement | undefined} */
let initialFocusButton;
for (let i = 0; i < buttons.length; i += 1) {
const buttonConfig = buttons[i];
const button = document.createElement('button');
button.id = buttonConfig.id;
button.innerHTML = buttonConfig.label;
button.tabIndex = 1;
button.style.backgroundColor = theme['dark-background'];
button.style.border = 'none';
button.style.color = theme.white;
button.style.cursor = 'pointer';
button.style.fontSize = 'inherit';
button.style.height = '100%';
button.style.padding = '0.5rem 0.75rem';
button.style.width = `${(100 / buttons.length).toString(10)}%`;
button.addEventListener('click', buttonConfig.onClick);
if (buttonConfig.id === props.initialFocus) {
initialFocusButton = button;
}
footer.appendChild(button);
}
root.appendChild(footer);
Spacer(document, root, { space: '2.5rem' });
if (initialFocusButton) {
initialFocusButton.focus();
}
}
module.exports = RuntimeErrorFooter;
================================================
FILE: overlay/components/RuntimeErrorHeader.js
================================================
const Spacer = require('./Spacer.js');
const theme = require('../theme.js');
/**
* @typedef {Object} RuntimeErrorHeaderProps
* @property {number} currentErrorIndex
* @property {number} totalErrors
*/
/**
* A fixed header that shows the total runtime error count.
* @param {Document} document
* @param {HTMLElement} root
* @param {RuntimeErrorHeaderProps} props
* @returns {void}
*/
function RuntimeErrorHeader(document, root, props) {
const header = document.createElement('div');
header.innerText = `Error ${props.currentErrorIndex + 1} of ${props.totalErrors}`;
header.style.backgroundColor = theme.red;
header.style.color = theme.white;
header.style.fontWeight = '500';
header.style.height = '2.5rem';
header.style.left = '0';
header.style.lineHeight = '2.5rem';
header.style.position = 'fixed';
header.style.textAlign = 'center';
header.style.top = '0';
header.style.width = '100vw';
header.style.zIndex = '2';
root.appendChild(header);
Spacer(document, root, { space: '2.5rem' });
}
module.exports = RuntimeErrorHeader;
================================================
FILE: overlay/components/RuntimeErrorStack.js
================================================
const ErrorStackParser = require('error-stack-parser');
const theme = require('../theme.js');
const utils = require('../utils.js');
/**
* @typedef {Object} RuntimeErrorStackProps
* @property {Error} error
*/
/**
* A formatter that turns runtime error stacks into highlighted HTML stacks.
* @param {Document} document
* @param {HTMLElement} root
* @param {RuntimeErrorStackProps} props
* @returns {void}
*/
function RuntimeErrorStack(document, root, props) {
const stackTitle = document.createElement('h4');
stackTitle.innerText = 'Call Stack';
stackTitle.style.color = theme.white;
stackTitle.style.fontSize = '1.0625rem';
stackTitle.style.fontWeight = '500';
stackTitle.style.lineHeight = '1.3';
stackTitle.style.margin = '0 0 0.5rem';
const stackContainer = document.createElement('div');
stackContainer.style.fontSize = '0.8125rem';
stackContainer.style.lineHeight = '1.3';
stackContainer.style.whiteSpace = 'pre-wrap';
let errorStacks;
try {
errorStacks = ErrorStackParser.parse(props.error);
} catch (e) {
errorStacks = [];
stackContainer.innerHTML = 'No stack trace is available for this error!';
}
for (let i = 0; i < Math.min(errorStacks.length, 10); i += 1) {
const currentStack = errorStacks[i];
const functionName = document.createElement('code');
functionName.innerHTML = ` ${currentStack.functionName || '(anonymous function)'}`;
functionName.style.color = theme.yellow;
functionName.style.fontFamily = [
'"SFMono-Regular"',
'Consolas',
'Liberation Mono',
'Menlo',
'Courier',
'monospace',
].join(', ');
const fileName = document.createElement('div');
fileName.innerHTML =
'  ' +
utils.formatFilename(currentStack.fileName) +
':' +
currentStack.lineNumber +
':' +
currentStack.columnNumber;
fileName.style.color = theme.white;
fileName.style.fontSize = '0.6875rem';
fileName.style.marginBottom = '0.25rem';
stackContainer.appendChild(functionName);
stackContainer.appendChild(fileName);
}
root.appendChild(stackTitle);
root.appendChild(stackContainer);
}
module.exports = RuntimeErrorStack;
================================================
FILE: overlay/components/Spacer.js
================================================
/**
* @typedef {Object} SpacerProps
* @property {string} space
*/
/**
* An empty element to add spacing manually.
* @param {Document} document
* @param {HTMLElement} root
* @param {SpacerProps} props
* @returns {void}
*/
function Spacer(document, root, props) {
const spacer = document.createElement('div');
spacer.style.paddingBottom = props.space;
root.appendChild(spacer);
}
module.exports = Spacer;
================================================
FILE: overlay/containers/CompileErrorContainer.js
================================================
const CompileErrorTrace = require('../components/CompileErrorTrace.js');
const PageHeader = require('../components/PageHeader.js');
const Spacer = require('../components/Spacer.js');
/**
* @typedef {Object} CompileErrorContainerProps
* @property {string} errorMessage
*/
/**
* A container to render Webpack compilation error messages with source trace.
* @param {Document} document
* @param {HTMLElement} root
* @param {CompileErrorContainerProps} props
* @returns {void}
*/
function CompileErrorContainer(document, root, props) {
PageHeader(document, root, {
title: 'Failed to compile.',
});
CompileErrorTrace(document, root, { errorMessage: props.errorMessage });
Spacer(document, root, { space: '1rem' });
}
module.exports = CompileErrorContainer;
================================================
FILE: overlay/containers/RuntimeErrorContainer.js
================================================
const PageHeader = require('../components/PageHeader.js');
const RuntimeErrorStack = require('../components/RuntimeErrorStack.js');
const Spacer = require('../components/Spacer.js');
/**
* @typedef {Object} RuntimeErrorContainerProps
* @property {Error} currentError
*/
/**
* A container to render runtime error messages with stack trace.
* @param {Document} document
* @param {HTMLElement} root
* @param {RuntimeErrorContainerProps} props
* @returns {void}
*/
function RuntimeErrorContainer(document, root, props) {
PageHeader(document, root, {
message: props.currentError.message,
title: props.currentError.name,
topOffset: '2.5rem',
});
RuntimeErrorStack(document, root, {
error: props.currentError,
});
Spacer(document, root, { space: '1rem' });
}
module.exports = RuntimeErrorContainer;
================================================
FILE: overlay/index.js
================================================
const RuntimeErrorFooter = require('./components/RuntimeErrorFooter.js');
const RuntimeErrorHeader = require('./components/RuntimeErrorHeader.js');
const CompileErrorContainer = require('./containers/CompileErrorContainer.js');
const RuntimeErrorContainer = require('./containers/RuntimeErrorContainer.js');
const theme = require('./theme.js');
const utils = require('./utils.js');
/**
* @callback RenderFn
* @returns {void}
*/
/* ===== Cached elements for DOM manipulations ===== */
/**
* The iframe that contains the overlay.
* @type {HTMLIFrameElement}
*/
let iframeRoot = null;
/**
* The document object from the iframe root, used to create and render elements.
* @type {Document}
*/
let rootDocument = null;
/**
* The root div elements will attach to.
* @type {HTMLDivElement}
*/
let root = null;
/**
* A Cached function to allow deferred render.
* @type {RenderFn | null}
*/
let scheduledRenderFn = null;
/* ===== Overlay State ===== */
/**
* The latest error message from Webpack compilation.
* @type {string}
*/
let currentCompileErrorMessage = '';
/**
* Index of the error currently shown by the overlay.
* @type {number}
*/
let currentRuntimeErrorIndex = 0;
/**
* The latest runtime error objects.
* @type {Error[]}
*/
let currentRuntimeErrors = [];
/**
* The render mode the overlay is currently in.
* @type {'compileError' | 'runtimeError' | null}
*/
let currentMode = null;
/**
* @typedef {Object} IframeProps
* @property {function(): void} onIframeLoad
*/
/**
* Creates the main `iframe` the overlay will attach to.
* Accepts a callback to be ran after iframe is initialized.
* @param {Document} document
* @param {HTMLElement} root
* @param {IframeProps} props
* @returns {HTMLIFrameElement}
*/
function IframeRoot(document, root, props) {
const iframe = document.createElement('iframe');
iframe.id = 'react-refresh-overlay';
iframe.src = 'about:blank';
iframe.style.border = 'none';
iframe.style.height = '100%';
iframe.style.left = '0';
iframe.style.minHeight = '100vh';
iframe.style.minHeight = '-webkit-fill-available';
iframe.style.position = 'fixed';
iframe.style.top = '0';
iframe.style.width = '100vw';
iframe.style.zIndex = '2147483647';
iframe.addEventListener('load', function onLoad() {
// Reset margin of iframe body
iframe.contentDocument.body.style.margin = '0';
props.onIframeLoad();
});
// We skip mounting and returns as we need to ensure
// the load event is fired after we setup the global variable
return iframe;
}
/**
* Creates the main `div` element for the overlay to render.
* @param {Document} document
* @param {HTMLElement} root
* @returns {HTMLDivElement}
*/
function OverlayRoot(document, root) {
const div = document.createElement('div');
div.id = 'react-refresh-overlay-error';
// Apply ANSI theme
div.style.setProperty('--color-ansi-selection', theme.selection);
div.style.setProperty('--color-ansi-bg', theme.background);
div.style.setProperty('--color-ansi-fg', theme.white);
div.style.setProperty('--color-ansi-white', theme.white);
div.style.setProperty('--color-ansi-black', theme.black);
div.style.setProperty('--color-ansi-blue', theme.blue);
div.style.setProperty('--color-ansi-cyan', theme.cyan);
div.style.setProperty('--color-ansi-green', theme.green);
div.style.setProperty('--color-ansi-magenta', theme.magenta);
div.style.setProperty('--color-ansi-red', theme.red);
div.style.setProperty('--color-ansi-yellow', theme.yellow);
div.style.setProperty('--color-ansi-bright-white', theme['bright-white']);
div.style.setProperty('--color-ansi-bright-black', theme['bright-black']);
div.style.setProperty('--color-ansi-bright-blue', theme['bright-blue']);
div.style.setProperty('--color-ansi-bright-cyan', theme['bright-cyan']);
div.style.setProperty('--color-ansi-bright-green', theme['bright-green']);
div.style.setProperty('--color-ansi-bright-magenta', theme['bright-magenta']);
div.style.setProperty('--color-ansi-bright-red', theme['bright-red']);
div.style.setProperty('--color-ansi-bright-yellow', theme['bright-yellow']);
// Style the contents container
div.style.backgroundColor = theme.background;
div.style.boxSizing = 'border-box';
div.style.color = theme.white;
div.style.fontFamily = ['-apple-system', '"Source Sans Pro"', 'sans-serif'].join(', ');
div.style.fontSize = '0.875rem';
div.style.height = '100%';
div.style.lineHeight = '1.3';
div.style.overflow = 'auto';
div.style.padding = '1rem 1.5rem 0';
div.style.paddingTop = 'max(1rem, env(safe-area-inset-top))';
div.style.paddingRight = 'max(1.5rem, env(safe-area-inset-right))';
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
div.style.paddingLeft = 'max(1.5rem, env(safe-area-inset-left))';
div.style.width = '100vw';
root.appendChild(div);
return div;
}
/**
* Ensures the iframe root and the overlay root are both initialized before render.
* If check fails, render will be deferred until both roots are initialized.
* @param {RenderFn} renderFn A function that triggers a DOM render.
* @returns {void}
*/
function ensureRootExists(renderFn) {
if (root) {
// Overlay root is ready, we can render right away.
renderFn();
return;
}
// Creating an iframe may be asynchronous so we'll defer render.
// In case of multiple calls, function from the last call will be used.
scheduledRenderFn = renderFn;
if (iframeRoot) {
// Iframe is already ready, it will fire the load event.
return;
}
// Create the iframe root, and, the overlay root inside it when it is ready.
iframeRoot = IframeRoot(document, document.body, {
onIframeLoad: function onIframeLoad() {
rootDocument = iframeRoot.contentDocument;
root = OverlayRoot(rootDocument, rootDocument.body);
scheduledRenderFn();
},
});
// We have to mount here to ensure `iframeRoot` is set when `onIframeLoad` fires.
// This is because onIframeLoad() will be called synchronously
// or asynchronously depending on the browser.
document.body.appendChild(iframeRoot);
}
/**
* Creates the main `div` element for the overlay to render.
* @returns {void}
*/
function render() {
ensureRootExists(function () {
const currentFocus = rootDocument.activeElement;
let currentFocusId;
if (currentFocus.localName === 'button' && currentFocus.id) {
currentFocusId = currentFocus.id;
}
utils.removeAllChildren(root);
if (currentCompileErrorMessage) {
currentMode = 'compileError';
CompileErrorContainer(rootDocument, root, {
errorMessage: currentCompileErrorMessage,
});
} else if (currentRuntimeErrors.length) {
currentMode = 'runtimeError';
RuntimeErrorHeader(rootDocument, root, {
currentErrorIndex: currentRuntimeErrorIndex,
totalErrors: currentRuntimeErrors.length,
});
RuntimeErrorContainer(rootDocument, root, {
currentError: currentRuntimeErrors[currentRuntimeErrorIndex],
});
RuntimeErrorFooter(rootDocument, root, {
initialFocus: currentFocusId,
multiple: currentRuntimeErrors.length > 1,
onClickCloseButton: function onClose() {
clearRuntimeErrors();
},
onClickNextButton: function onNext() {
if (currentRuntimeErrorIndex === currentRuntimeErrors.length - 1) {
return;
}
currentRuntimeErrorIndex += 1;
ensureRootExists(render);
},
onClickPrevButton: function onPrev() {
if (currentRuntimeErrorIndex === 0) {
return;
}
currentRuntimeErrorIndex -= 1;
ensureRootExists(render);
},
});
}
});
}
/**
* Destroys the state of the overlay.
* @returns {void}
*/
function cleanup() {
// Clean up and reset all internal state.
document.body.removeChild(iframeRoot);
scheduledRenderFn = null;
root = null;
iframeRoot = null;
}
/**
* Clears Webpack compilation errors and dismisses the compile error overlay.
* @returns {void}
*/
function clearCompileError() {
if (!root || currentMode !== 'compileError') {
return;
}
currentCompileErrorMessage = '';
currentMode = null;
cleanup();
}
/**
* Clears runtime error records and dismisses the runtime error overlay.
* @param {boolean} [dismissOverlay] Whether to dismiss the overlay or not.
* @returns {void}
*/
function clearRuntimeErrors(dismissOverlay) {
if (!root || currentMode !== 'runtimeError') {
return;
}
currentRuntimeErrorIndex = 0;
currentRuntimeErrors = [];
if (typeof dismissOverlay === 'undefined' || dismissOverlay) {
currentMode = null;
cleanup();
}
}
/**
* Shows the compile error overlay with the specific Webpack error message.
* @param {string} message
* @returns {void}
*/
function showCompileError(message) {
if (!message) {
return;
}
currentCompileErrorMessage = message;
render();
}
/**
* Shows the runtime error overlay with the specific error records.
* @param {Error[]} errors
* @returns {void}
*/
function showRuntimeErrors(errors) {
if (!errors || !errors.length) {
return;
}
currentRuntimeErrors = errors;
render();
}
/**
* The debounced version of `showRuntimeErrors` to prevent frequent renders
* due to rapid firing listeners.
* @param {Error[]} errors
* @returns {void}
*/
const debouncedShowRuntimeErrors = utils.debounce(showRuntimeErrors, 30);
/**
* Detects if an error is a Webpack compilation error.
* @param {Error} error The error of interest.
* @returns {boolean} If the error is a Webpack compilation error.
*/
function isWebpackCompileError(error) {
return /Module [A-z ]+\(from/.test(error.message) || /Cannot find module/.test(error.message);
}
/**
* Handles runtime error contexts captured with EventListeners.
* Integrates with a runtime error overlay.
* @param {Error} error A valid error object.
* @returns {void}
*/
function handleRuntimeError(error) {
if (error && !isWebpackCompileError(error) && currentRuntimeErrors.indexOf(error) === -1) {
currentRuntimeErrors = currentRuntimeErrors.concat(error);
}
debouncedShowRuntimeErrors(currentRuntimeErrors);
}
module.exports = Object.freeze({
clearCompileError: clearCompileError,
clearRuntimeErrors: clearRuntimeErrors,
handleRuntimeError: handleRuntimeError,
showCompileError: showCompileError,
showRuntimeErrors: showRuntimeErrors,
});
================================================
FILE: overlay/package.json
================================================
{
"type": "commonjs"
}
================================================
FILE: overlay/theme.js
================================================
/**
* @typedef {Object} Theme
* @property {string} black
* @property {string} bright-black
* @property {string} red
* @property {string} bright-red
* @property {string} green
* @property {string} bright-green
* @property {string} yellow
* @property {string} bright-yellow
* @property {string} blue
* @property {string} bright-blue
* @property {string} magenta
* @property {string} bright-magenta
* @property {string} cyan
* @property {string} bright-cyan
* @property {string} white
* @property {string} bright-white
* @property {string} lightgrey
* @property {string} darkgrey
* @property {string} grey
* @property {string} dimgrey
*/
/**
* @type {Theme} theme
* A collection of colors to be used by the overlay.
* Partially adopted from Tomorrow Night Bright.
*/
const theme = {
black: '#000000',
'bright-black': '#474747',
red: '#D34F56',
'bright-red': '#dd787d',
green: '#B9C954',
'bright-green': '#c9d57b',
yellow: '#E6C452',
'bright-yellow': '#ecd37f',
blue: '#7CA7D8',
'bright-blue': '#a3c1e4',
magenta: '#C299D6',
'bright-magenta': '#d8bde5',
cyan: '#73BFB1',
'bright-cyan': '#96cfc5',
white: '#FFFFFF',
'bright-white': '#FFFFFF',
background: '#474747',
'dark-background': '#343434',
selection: 'rgba(234, 234, 234, 0.5)',
};
module.exports = theme;
================================================
FILE: overlay/utils.js
================================================
/**
* Debounce a function to delay invoking until wait (ms) have elapsed since the last invocation.
* @param {function(...*): *} fn The function to be debounced.
* @param {number} wait Milliseconds to wait before invoking again.
* @return {function(...*): void} The debounced function.
*/
function debounce(fn, wait) {
/**
* A cached setTimeout handler.
* @type {number | undefined}
*/
let timer;
/**
* @returns {void}
*/
function debounced() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
return fn.apply(context, args);
}, wait);
}
return debounced;
}
/**
* Prettify a filename from error stacks into the desired format.
* @param {string} filename The filename to be formatted.
* @returns {string} The formatted filename.
*/
function formatFilename(filename) {
// Strip away protocol and domain for compiled files
const htmlMatch = /^https?:\/\/(.*)\/(.*)/.exec(filename);
if (htmlMatch && htmlMatch[1] && htmlMatch[2]) {
return htmlMatch[2];
}
// Strip everything before the first directory for source files
const sourceMatch = /\/.*?([^./]+[/|\\].*)$/.exec(filename);
if (sourceMatch && sourceMatch[1]) {
return sourceMatch[1].replace(/\?$/, '');
}
// Unknown filename type, use it as is
return filename;
}
/**
* Remove all children of an element.
* @param {HTMLElement} element A valid HTML element.
* @param {number} [skip] Number of elements to skip removing.
* @returns {void}
*/
function removeAllChildren(element, skip) {
/** @type {Node[]} */
const childList = Array.prototype.slice.call(
element.childNodes,
typeof skip !== 'undefined' ? skip : 0
);
for (let i = 0; i < childList.length; i += 1) {
element.removeChild(childList[i]);
}
}
module.exports = {
debounce: debounce,
formatFilename: formatFilename,
removeAllChildren: removeAllChildren,
};
================================================
FILE: package.json
================================================
{
"name": "@pmmmwh/react-refresh-webpack-plugin",
"version": "0.6.2",
"description": "An **EXPERIMENTAL** Webpack plugin to enable \"Fast Refresh\" (also previously known as _Hot Reloading_) for React components.",
"keywords": [
"react",
"javascript",
"webpack",
"refresh",
"hmr",
"hotreload",
"livereload",
"live",
"edit",
"hot",
"reload"
],
"homepage": "https://github.com/pmmmwh/react-refresh-webpack-plugin#readme",
"bugs": {
"url": "https://github.com/pmmmwh/react-refresh-webpack-plugin/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/pmmmwh/react-refresh-webpack-plugin.git"
},
"license": "MIT",
"author": "Michael Mok",
"main": "lib/index.js",
"types": "types/lib/index.d.ts",
"files": [
"client",
"lib",
"loader",
"options",
"overlay",
"sockets",
"types",
"umd"
],
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610",
"scripts": {
"test": "run-s -c test:pre \"test:exec {@}\" test:post --",
"test:wds-4": "cross-env WDS_VERSION=4 yarn test",
"test:exec": "node --experimental-vm-modules scripts/test.js",
"test:pre": "run-s -c test:pre:*",
"test:pre:0": "yarn link",
"test:pre:1": "yarn link @pmmmwh/react-refresh-webpack-plugin",
"test:post": "run-s -c test:post:*",
"test:post:0": "yarn unlink @pmmmwh/react-refresh-webpack-plugin",
"test:post:1": "yarn unlink",
"lint": "eslint --report-unused-disable-directives --ext .js,.jsx .",
"lint:fix": "yarn lint --fix",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,md}\"",
"types:clean": "del types",
"types:compile": "tsc",
"types:prune-private": "del \"types/*/*\" \"!types/{lib,loader,options}/{index,types}.d.ts\"",
"generate:client-external": "webpack",
"generate:types": "run-s types:clean types:compile types:prune-private \"format --log-level=silent\"",
"prepublishOnly": "run-p generate:*"
},
"dependencies": {
"anser": "^2.1.1",
"core-js-pure": "^3.23.3",
"error-stack-parser": "^2.0.6",
"html-entities": "^2.1.0",
"schema-utils": "^4.2.0",
"source-map": "^0.7.3"
},
"devDependencies": {
"@babel/core": "^7.24.6",
"@babel/plugin-transform-modules-commonjs": "^7.24.6",
"@types/cross-spawn": "^6.0.6",
"@types/fs-extra": "^11.0.4",
"@types/jest": "^29.5.12",
"@types/json-schema": "^7.0.15",
"@types/module-alias": "^2.0.4",
"@types/node": "^24.10.1",
"@types/webpack": "^5.28.5",
"babel-loader": "^10.0.0",
"cross-env": "^7.0.3",
"cross-spawn": "^7.0.5",
"del-cli": "^6.0.0",
"eslint": "^8.6.0",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-prettier": "^5.1.3",
"fs-extra": "^11.2.0",
"get-port": "^7.1.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-environment-node": "^29.7.0",
"jest-junit": "^16.0.0",
"jest-location-mock": "^2.0.0",
"memfs": "^4.9.2",
"module-alias": "^2.2.3",
"nanoid": "^3.3.8",
"npm-run-all2": "^7.0.2",
"prettier": "^3.3.0",
"puppeteer": "^24.4.0",
"react-refresh": "^0.18.0",
"sourcemap-validator": "^2.1.0",
"terser-webpack-plugin": "^5.3.10",
"type-fest": "^4.41.0",
"typescript": "~5.9.3",
"webpack": "^5.94.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.0.4",
"webpack-dev-server-v4": "npm:webpack-dev-server@^4.8.0",
"webpack-hot-middleware": "^2.26.1",
"webpack-plugin-serve": "^1.6.0",
"yn": "^4.0.0"
},
"peerDependencies": {
"@types/webpack": "5.x",
"react-refresh": ">=0.10.0 <1.0.0",
"sockjs-client": "^1.4.0",
"type-fest": ">=0.17.0 <6.0.0",
"webpack": "^5.0.0",
"webpack-dev-server": "^4.8.0 || 5.x",
"webpack-hot-middleware": "2.x",
"webpack-plugin-serve": "1.x"
},
"peerDependenciesMeta": {
"@types/webpack": {
"optional": true
},
"sockjs-client": {
"optional": true
},
"type-fest": {
"optional": true
},
"webpack-dev-server": {
"optional": true
},
"webpack-hot-middleware": {
"optional": true
},
"webpack-plugin-serve": {
"optional": true
}
},
"resolutions": {
"memfs": "^4.0.0",
"rimraf": "^5.0.0",
"type-fest": "^4.41.0"
},
"engines": {
"node": ">=18.12"
}
}
================================================
FILE: scripts/test.js
================================================
// Setup environment before any code -
// this makes sure everything coming after will run in the correct env.
process.env.NODE_ENV = 'test';
// Crash on unhandled rejections instead of failing silently.
process.on('unhandledRejection', (reason) => {
throw reason;
});
const jest = require('jest');
const yn = require('yn');
let argv = process.argv.slice(2);
if (yn(process.env.CI)) {
// Use CI mode
argv.push('--ci');
// Parallelized puppeteer tests have high memory overhead in CI environments.
// Fall back to run in series so tests could run faster.
arg
gitextract_f1f9g2an/ ├── .babelrc.json ├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .github/ │ └── workflows/ │ └── ci.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── client/ │ ├── ErrorOverlayEntry.js │ ├── ReactRefreshEntry.js │ ├── package.json │ └── utils/ │ ├── errorEventHandlers.js │ ├── formatWebpackErrors.js │ └── retry.js ├── docs/ │ ├── API.md │ └── TROUBLESHOOTING.md ├── examples/ │ ├── flow-with-babel/ │ │ ├── .flowconfig │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── public/ │ │ │ └── index.html │ │ ├── src/ │ │ │ ├── App.jsx │ │ │ ├── ArrowFunction.jsx │ │ │ ├── ClassDefault.jsx │ │ │ ├── ClassNamed.jsx │ │ │ ├── FunctionDefault.jsx │ │ │ ├── FunctionNamed.jsx │ │ │ ├── LazyComponent.jsx │ │ │ └── index.js │ │ └── webpack.config.js │ ├── typescript-with-babel/ │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── public/ │ │ │ └── index.html │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── ArrowFunction.tsx │ │ │ ├── ClassDefault.tsx │ │ │ ├── ClassNamed.tsx │ │ │ ├── FunctionDefault.tsx │ │ │ ├── FunctionNamed.tsx │ │ │ ├── LazyComponent.tsx │ │ │ └── index.tsx │ │ ├── tsconfig.json │ │ └── webpack.config.js │ ├── typescript-with-swc/ │ │ ├── package.json │ │ ├── public/ │ │ │ └── index.html │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── ArrowFunction.tsx │ │ │ ├── ClassDefault.tsx │ │ │ ├── ClassNamed.tsx │ │ │ ├── FunctionDefault.tsx │ │ │ ├── FunctionNamed.tsx │ │ │ ├── LazyComponent.tsx │ │ │ └── index.tsx │ │ ├── tsconfig.json │ │ └── webpack.config.js │ ├── typescript-with-tsc/ │ │ ├── package.json │ │ ├── public/ │ │ │ └── index.html │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── ArrowFunction.tsx │ │ │ ├── ClassDefault.tsx │ │ │ ├── ClassNamed.tsx │ │ │ ├── FunctionDefault.tsx │ │ │ ├── FunctionNamed.tsx │ │ │ ├── LazyComponent.tsx │ │ │ └── index.tsx │ │ ├── tsconfig.dev.json │ │ ├── tsconfig.json │ │ └── webpack.config.js │ ├── webpack-dev-server/ │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── public/ │ │ │ └── index.html │ │ ├── src/ │ │ │ ├── App.jsx │ │ │ ├── ArrowFunction.jsx │ │ │ ├── ClassDefault.jsx │ │ │ ├── ClassNamed.jsx │ │ │ ├── FunctionDefault.jsx │ │ │ ├── FunctionNamed.jsx │ │ │ ├── LazyComponent.jsx │ │ │ └── index.js │ │ └── webpack.config.js │ ├── webpack-hot-middleware/ │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── public/ │ │ │ └── index.html │ │ ├── server.js │ │ ├── src/ │ │ │ ├── App.jsx │ │ │ ├── ArrowFunction.jsx │ │ │ ├── ClassDefault.jsx │ │ │ ├── ClassNamed.jsx │ │ │ ├── FunctionDefault.jsx │ │ │ ├── FunctionNamed.jsx │ │ │ ├── LazyComponent.jsx │ │ │ └── index.js │ │ └── webpack.config.js │ └── webpack-plugin-serve/ │ ├── babel.config.js │ ├── package.json │ ├── public/ │ │ └── index.html │ ├── src/ │ │ ├── App.jsx │ │ ├── ArrowFunction.jsx │ │ ├── ClassDefault.jsx │ │ ├── ClassNamed.jsx │ │ ├── FunctionDefault.jsx │ │ ├── FunctionNamed.jsx │ │ ├── LazyComponent.jsx │ │ └── index.js │ └── webpack.config.js ├── jest.config.js ├── lib/ │ ├── globals.js │ ├── index.js │ ├── options.json │ ├── runtime/ │ │ └── RefreshUtils.js │ ├── types.js │ └── utils/ │ ├── getAdditionalEntries.js │ ├── getIntegrationEntry.js │ ├── getSocketIntegration.js │ ├── index.js │ ├── injectRefreshLoader.js │ ├── makeRefreshRuntimeModule.js │ └── normalizeOptions.js ├── loader/ │ ├── index.js │ ├── options.json │ ├── types.js │ └── utils/ │ ├── getIdentitySourceMap.js │ ├── getModuleSystem.js │ ├── getRefreshModuleRuntime.js │ ├── index.js │ ├── normalizeOptions.js │ └── webpackGlobal.js ├── options/ │ └── index.js ├── overlay/ │ ├── components/ │ │ ├── CompileErrorTrace.js │ │ ├── PageHeader.js │ │ ├── RuntimeErrorFooter.js │ │ ├── RuntimeErrorHeader.js │ │ ├── RuntimeErrorStack.js │ │ └── Spacer.js │ ├── containers/ │ │ ├── CompileErrorContainer.js │ │ └── RuntimeErrorContainer.js │ ├── index.js │ ├── package.json │ ├── theme.js │ └── utils.js ├── package.json ├── scripts/ │ └── test.js ├── sockets/ │ ├── WDSSocket.js │ ├── WHMEventSource.js │ ├── WPSSocket.js │ └── package.json ├── test/ │ ├── conformance/ │ │ ├── ReactRefresh.test.js │ │ └── environment.js │ ├── helpers/ │ │ ├── compilation/ │ │ │ ├── fixtures/ │ │ │ │ └── source-map-loader.js │ │ │ ├── index.js │ │ │ └── normalizeErrors.js │ │ └── sandbox/ │ │ ├── aliasWDSv4.js │ │ ├── configs.js │ │ ├── fixtures/ │ │ │ └── hmr-notifier.js │ │ ├── index.js │ │ └── spawn.js │ ├── jest-environment.js │ ├── jest-global-setup.js │ ├── jest-global-teardown.js │ ├── jest-resolver.js │ ├── jest-test-setup.js │ ├── loader/ │ │ ├── fixtures/ │ │ │ ├── auto/ │ │ │ │ └── package.json │ │ │ ├── cjs/ │ │ │ │ ├── esm/ │ │ │ │ │ ├── index.js │ │ │ │ │ └── package.json │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ └── esm/ │ │ │ ├── cjs/ │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── loader.test.js │ │ ├── unit/ │ │ │ ├── getIdentitySourceMap.test.js │ │ │ ├── getModuleSystem.test.js │ │ │ ├── getRefreshModuleRuntime.test.js │ │ │ └── normalizeOptions.test.js │ │ └── validateOptions.test.js │ ├── mocks/ │ │ └── fetch.js │ └── unit/ │ ├── fixtures/ │ │ └── socketIntegration.js │ ├── getAdditionalEntries.test.js │ ├── getIntegrationEntry.test.js │ ├── getSocketIntegration.test.js │ ├── globals.test.js │ ├── makeRefreshRuntimeModule.test.js │ ├── normalizeOptions.test.js │ └── validateOptions.test.js ├── tsconfig.json ├── types/ │ ├── lib/ │ │ ├── index.d.ts │ │ └── types.d.ts │ ├── loader/ │ │ ├── index.d.ts │ │ └── types.d.ts │ └── options/ │ └── index.d.ts └── webpack.config.js
SYMBOL INDEX (141 symbols across 85 files)
FILE: client/utils/errorEventHandlers.js
function createErrorHandler (line 17) | function createErrorHandler(callback) {
function createRejectionHandler (line 36) | function createRejectionHandler(callback) {
function createWindowEventHandler (line 57) | function createWindowEventHandler(eventType, createHandler) {
FILE: client/utils/formatWebpackErrors.js
function isLikelyASyntaxError (line 15) | function isLikelyASyntaxError(message) {
function formatMessage (line 26) | function formatMessage(message) {
function formatWebpackErrors (line 78) | function formatWebpackErrors(errors) {
FILE: client/utils/retry.js
function runWithRetry (line 1) | function runWithRetry(callback, maxRetries, message) {
FILE: examples/flow-with-babel/src/App.jsx
function App (line 12) | function App() {
FILE: examples/flow-with-babel/src/ClassDefault.jsx
method render (line 6) | render() {
FILE: examples/flow-with-babel/src/ClassNamed.jsx
method render (line 6) | render() {
FILE: examples/flow-with-babel/src/FunctionDefault.jsx
function FunctionDefault (line 3) | function FunctionDefault() {
FILE: examples/flow-with-babel/src/FunctionNamed.jsx
function FunctionNamed (line 3) | function FunctionNamed() {
FILE: examples/flow-with-babel/src/LazyComponent.jsx
function LazyComponent (line 3) | function LazyComponent() {
FILE: examples/typescript-with-babel/src/App.tsx
function App (line 10) | function App() {
FILE: examples/typescript-with-babel/src/ClassDefault.tsx
class ClassDefault (line 3) | class ClassDefault extends Component {
method render (line 4) | render() {
FILE: examples/typescript-with-babel/src/ClassNamed.tsx
class ClassNamed (line 3) | class ClassNamed extends Component {
method render (line 4) | render() {
FILE: examples/typescript-with-babel/src/FunctionDefault.tsx
function FunctionDefault (line 1) | function FunctionDefault() {
FILE: examples/typescript-with-babel/src/FunctionNamed.tsx
function FunctionNamed (line 1) | function FunctionNamed() {
FILE: examples/typescript-with-babel/src/LazyComponent.tsx
function LazyComponent (line 1) | function LazyComponent() {
FILE: examples/typescript-with-swc/src/App.tsx
function App (line 10) | function App() {
FILE: examples/typescript-with-swc/src/ClassDefault.tsx
class ClassDefault (line 3) | class ClassDefault extends Component {
method render (line 4) | render() {
FILE: examples/typescript-with-swc/src/ClassNamed.tsx
class ClassNamed (line 3) | class ClassNamed extends Component {
method render (line 4) | render() {
FILE: examples/typescript-with-swc/src/FunctionDefault.tsx
function FunctionDefault (line 1) | function FunctionDefault() {
FILE: examples/typescript-with-swc/src/FunctionNamed.tsx
function FunctionNamed (line 1) | function FunctionNamed() {
FILE: examples/typescript-with-swc/src/LazyComponent.tsx
function LazyComponent (line 1) | function LazyComponent() {
FILE: examples/typescript-with-tsc/src/App.tsx
function App (line 10) | function App() {
FILE: examples/typescript-with-tsc/src/ClassDefault.tsx
class ClassDefault (line 3) | class ClassDefault extends Component {
method render (line 4) | render() {
FILE: examples/typescript-with-tsc/src/ClassNamed.tsx
class ClassNamed (line 3) | class ClassNamed extends Component {
method render (line 4) | render() {
FILE: examples/typescript-with-tsc/src/FunctionDefault.tsx
function FunctionDefault (line 1) | function FunctionDefault() {
FILE: examples/typescript-with-tsc/src/FunctionNamed.tsx
function FunctionNamed (line 1) | function FunctionNamed() {
FILE: examples/typescript-with-tsc/src/LazyComponent.tsx
function LazyComponent (line 1) | function LazyComponent() {
FILE: examples/webpack-dev-server/src/App.jsx
function App (line 10) | function App() {
FILE: examples/webpack-dev-server/src/ClassDefault.jsx
class ClassDefault (line 3) | class ClassDefault extends Component {
method render (line 4) | render() {
FILE: examples/webpack-dev-server/src/ClassNamed.jsx
class ClassNamed (line 3) | class ClassNamed extends Component {
method render (line 4) | render() {
FILE: examples/webpack-dev-server/src/FunctionDefault.jsx
function FunctionDefault (line 1) | function FunctionDefault() {
FILE: examples/webpack-dev-server/src/FunctionNamed.jsx
function FunctionNamed (line 1) | function FunctionNamed() {
FILE: examples/webpack-dev-server/src/LazyComponent.jsx
function LazyComponent (line 1) | function LazyComponent() {
FILE: examples/webpack-hot-middleware/src/App.jsx
function App (line 10) | function App() {
FILE: examples/webpack-hot-middleware/src/ClassDefault.jsx
class ClassDefault (line 3) | class ClassDefault extends Component {
method render (line 4) | render() {
FILE: examples/webpack-hot-middleware/src/ClassNamed.jsx
class ClassNamed (line 3) | class ClassNamed extends Component {
method render (line 4) | render() {
FILE: examples/webpack-hot-middleware/src/FunctionDefault.jsx
function FunctionDefault (line 1) | function FunctionDefault() {
FILE: examples/webpack-hot-middleware/src/FunctionNamed.jsx
function FunctionNamed (line 1) | function FunctionNamed() {
FILE: examples/webpack-hot-middleware/src/LazyComponent.jsx
function LazyComponent (line 1) | function LazyComponent() {
FILE: examples/webpack-plugin-serve/src/App.jsx
function App (line 10) | function App() {
FILE: examples/webpack-plugin-serve/src/ClassDefault.jsx
class ClassDefault (line 3) | class ClassDefault extends Component {
method render (line 4) | render() {
FILE: examples/webpack-plugin-serve/src/ClassNamed.jsx
class ClassNamed (line 3) | class ClassNamed extends Component {
method render (line 4) | render() {
FILE: examples/webpack-plugin-serve/src/FunctionDefault.jsx
function FunctionDefault (line 1) | function FunctionDefault() {
FILE: examples/webpack-plugin-serve/src/FunctionNamed.jsx
function FunctionNamed (line 1) | function FunctionNamed() {
FILE: examples/webpack-plugin-serve/src/LazyComponent.jsx
function LazyComponent (line 1) | function LazyComponent() {
FILE: lib/index.js
class ReactRefreshPlugin (line 13) | class ReactRefreshPlugin {
method constructor (line 17) | constructor(options = {}) {
method apply (line 35) | apply(compiler) {
FILE: lib/runtime/RefreshUtils.js
function getModuleExports (line 9) | function getModuleExports(moduleId) {
function getReactRefreshBoundarySignature (line 44) | function getReactRefreshBoundarySignature(moduleExports) {
function getWebpackHotData (line 73) | function getWebpackHotData(moduleExports) {
function createDebounceUpdate (line 84) | function createDebounceUpdate() {
function isReactRefreshBoundary (line 116) | function isReactRefreshBoundary(moduleExports) {
function registerExportsForReactRefresh (line 156) | function registerExportsForReactRefresh(moduleExports, moduleId) {
function shouldInvalidateReactRefreshBoundary (line 189) | function shouldInvalidateReactRefreshBoundary(prevSignature, nextSignatu...
function executeRuntime (line 204) | function executeRuntime(moduleExports, moduleId, webpackHot, refreshOver...
FILE: lib/utils/getAdditionalEntries.js
function getAdditionalEntries (line 12) | function getAdditionalEntries(options) {
FILE: lib/utils/getIntegrationEntry.js
function getIntegrationEntry (line 6) | function getIntegrationEntry(integrationType) {
FILE: lib/utils/getSocketIntegration.js
function getSocketIntegration (line 6) | function getSocketIntegration(integrationType) {
FILE: lib/utils/injectRefreshLoader.js
function injectRefreshLoader (line 25) | function injectRefreshLoader(moduleData, injectOptions) {
FILE: lib/utils/makeRefreshRuntimeModule.js
function makeRefreshRuntimeModule (line 8) | function makeRefreshRuntimeModule(webpack) {
FILE: loader/index.js
function ReactRefreshLoader (line 34) | function ReactRefreshLoader(source, inputSourceMap, meta) {
FILE: loader/utils/getIdentitySourceMap.js
function getIdentitySourceMap (line 9) | function getIdentitySourceMap(source, resourcePath) {
FILE: loader/utils/getModuleSystem.js
function getModuleSystem (line 14) | async function getModuleSystem(ModuleFilenameHelpers, options) {
FILE: loader/utils/getRefreshModuleRuntime.js
function getRefreshModuleRuntime (line 21) | function getRefreshModuleRuntime(Template, options) {
FILE: overlay/components/CompileErrorTrace.js
function CompileErrorTrace (line 17) | function CompileErrorTrace(document, root, props) {
FILE: overlay/components/PageHeader.js
function PageHeader (line 18) | function PageHeader(document, root, props) {
FILE: overlay/components/RuntimeErrorFooter.js
function RuntimeErrorFooter (line 20) | function RuntimeErrorFooter(document, root, props) {
FILE: overlay/components/RuntimeErrorHeader.js
function RuntimeErrorHeader (line 17) | function RuntimeErrorHeader(document, root, props) {
FILE: overlay/components/RuntimeErrorStack.js
function RuntimeErrorStack (line 17) | function RuntimeErrorStack(document, root, props) {
FILE: overlay/components/Spacer.js
function Spacer (line 13) | function Spacer(document, root, props) {
FILE: overlay/containers/CompileErrorContainer.js
function CompileErrorContainer (line 17) | function CompileErrorContainer(document, root, props) {
FILE: overlay/containers/RuntimeErrorContainer.js
function RuntimeErrorContainer (line 17) | function RuntimeErrorContainer(document, root, props) {
FILE: overlay/index.js
function IframeRoot (line 70) | function IframeRoot(document, root, props) {
function OverlayRoot (line 101) | function OverlayRoot(document, root) {
function ensureRootExists (line 152) | function ensureRootExists(renderFn) {
function render (line 187) | function render() {
function cleanup (line 242) | function cleanup() {
function clearCompileError (line 254) | function clearCompileError() {
function clearRuntimeErrors (line 269) | function clearRuntimeErrors(dismissOverlay) {
function showCompileError (line 288) | function showCompileError(message) {
function showRuntimeErrors (line 303) | function showRuntimeErrors(errors) {
function isWebpackCompileError (line 326) | function isWebpackCompileError(error) {
function handleRuntimeError (line 336) | function handleRuntimeError(error) {
FILE: overlay/utils.js
function debounce (line 7) | function debounce(fn, wait) {
function formatFilename (line 35) | function formatFilename(filename) {
function removeAllChildren (line 58) | function removeAllChildren(element, skip) {
FILE: sockets/WDSSocket.js
function initWDSSocket (line 6) | function initWDSSocket(messageHandler) {
FILE: sockets/WHMEventSource.js
function initWHMEventSource (line 13) | function initWHMEventSource(messageHandler) {
FILE: sockets/WPSSocket.js
function initWPSSocket (line 9) | function initWPSSocket(messageHandler) {
FILE: test/conformance/environment.js
class SandboxEnvironment (line 4) | class SandboxEnvironment extends TestEnvironment {
method setup (line 5) | async setup() {
method teardown (line 18) | async teardown() {
FILE: test/helpers/compilation/index.js
constant BUNDLE_FILENAME (line 6) | const BUNDLE_FILENAME = 'main';
constant CONTEXT_PATH (line 7) | const CONTEXT_PATH = path.join(__dirname, '../..', 'loader/fixtures');
constant OUTPUT_PATH (line 8) | const OUTPUT_PATH = path.join(__dirname, 'dist');
function getCompilation (line 33) | async function getCompilation(subContext, options = {}) {
FILE: test/helpers/compilation/normalizeErrors.js
function removeCwd (line 5) | function removeCwd(str) {
function normalizeErrors (line 22) | function normalizeErrors(errors) {
FILE: test/helpers/sandbox/configs.js
constant BUNDLE_FILENAME (line 3) | const BUNDLE_FILENAME = 'main';
function getIndexHTML (line 9) | function getIndexHTML(port) {
function getPackageJson (line 29) | function getPackageJson(esModule = false) {
function getWDSConfig (line 41) | function getWDSConfig(srcDir) {
FILE: test/helpers/sandbox/index.js
function getSandbox (line 65) | async function getSandbox({ esModule = false, id = nanoid(), initialFile...
FILE: test/helpers/sandbox/spawn.js
function getPackageExecutable (line 8) | function getPackageExecutable(packageName, binName) {
function killTestProcess (line 25) | function killTestProcess(instance) {
function spawnTestProcess (line 60) | function spawnTestProcess(processPath, argv, options = {}) {
function spawnWebpackServe (line 131) | function spawnWebpackServe(port, dirs, options = {}) {
FILE: test/jest-environment.js
class TestEnvironment (line 4) | class TestEnvironment extends NodeEnvironment {
method setup (line 5) | async setup() {
FILE: test/jest-global-setup.js
function setup (line 4) | async function setup() {
FILE: test/jest-global-teardown.js
function teardown (line 1) | async function teardown() {
FILE: test/jest-resolver.js
function resolver (line 6) | function resolver(request, options) {
FILE: test/loader/unit/normalizeOptions.test.js
constant DEFAULT_OPTIONS (line 4) | const DEFAULT_OPTIONS = {
FILE: test/mocks/fetch.js
function mockRestore (line 13) | function mockRestore() {
FILE: test/unit/normalizeOptions.test.js
constant DEFAULT_OPTIONS (line 4) | const DEFAULT_OPTIONS = {
FILE: types/lib/index.d.ts
class ReactRefreshPlugin (line 2) | class ReactRefreshPlugin {
FILE: types/lib/types.d.ts
type ErrorOverlayOptions (line 1) | type ErrorOverlayOptions = {
type NormalizedErrorOverlayOptions (line 17) | type NormalizedErrorOverlayOptions = import('type-fest').SetRequired
type ReactRefreshPluginOptions (line 21) | type ReactRefreshPluginOptions = {
type OverlayOverrides (line 47) | type OverlayOverrides = {
type NormalizedPluginOptions (line 53) | type NormalizedPluginOptions = import('type-fest').SetRequired
FILE: types/loader/types.d.ts
type ESModuleOptions (line 1) | type ESModuleOptions = {
type ReactRefreshLoaderOptions (line 11) | type ReactRefreshLoaderOptions = {
type NormalizedLoaderOptions (line 21) | type NormalizedLoaderOptions = import('type-fest').SetRequired
Condensed preview — 194 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (325K chars).
[
{
"path": ".babelrc.json",
"chars": 101,
"preview": "{\n \"env\": {\n \"test\": {\n \"plugins\": [\"@babel/plugin-transform-modules-commonjs\"]\n }\n }\n}\n"
},
{
"path": ".eslintignore",
"chars": 120,
"preview": "*dist/\n*node_modules/\n*umd/\n*__tmp__\n\n# Ignore examples because they might have custom ESLint configurations\nexamples/*\n"
},
{
"path": ".eslintrc.json",
"chars": 1627,
"preview": "{\n \"extends\": [\"eslint:recommended\", \"plugin:prettier/recommended\"],\n \"parserOptions\": {\n \"ecmaVersion\": 2022\n },\n"
},
{
"path": ".gitattributes",
"chars": 19,
"preview": "* text=auto eol=lf\n"
},
{
"path": ".github/workflows/ci.yml",
"chars": 2297,
"preview": "name: CI\n\non:\n pull_request:\n push:\n branches:\n - main\n\nconcurrency:\n group: ${{ github.workflow }}-${{ githu"
},
{
"path": ".gitignore",
"chars": 274,
"preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n*node_modules\n\n# d"
},
{
"path": ".prettierignore",
"chars": 37,
"preview": "*dist/\n*node_modules/\n*umd/\n*__tmp__\n"
},
{
"path": ".prettierrc.json",
"chars": 73,
"preview": "{\n \"printWidth\": 100,\n \"singleQuote\": true,\n \"trailingComma\": \"es5\"\n}\n"
},
{
"path": "CHANGELOG.md",
"chars": 24108,
"preview": "## 0.6.2 (26 Nov 2025)\n\n### Fixes\n\n- Relaxed peer dependency requirement on `type-fest` to allow v5.x\n ([#934](https://"
},
{
"path": "LICENSE",
"chars": 1068,
"preview": "MIT License\n\nCopyright (c) 2019 Michael Mok\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "README.md",
"chars": 10326,
"preview": "# React Refresh Webpack Plugin\n\n[actions]: https://github.com/pmmmwh/react-refresh-webpack-plugin/actions/workflows/ci.y"
},
{
"path": "client/ErrorOverlayEntry.js",
"chars": 3031,
"preview": "/* global __react_refresh_error_overlay__, __react_refresh_socket__ */\n\nif (process.env.NODE_ENV !== 'production') {\n c"
},
{
"path": "client/ReactRefreshEntry.js",
"chars": 860,
"preview": "/* global __react_refresh_library__ */\n\nif (process.env.NODE_ENV !== 'production') {\n const safeThis = require('core-js"
},
{
"path": "client/package.json",
"chars": 25,
"preview": "{\n \"type\": \"commonjs\"\n}\n"
},
{
"path": "client/utils/errorEventHandlers.js",
"chars": 3090,
"preview": "/**\n * @callback EventCallback\n * @param {string | Error | null} context\n * @returns {void}\n */\n/**\n * @callback EventHa"
},
{
"path": "client/utils/formatWebpackErrors.js",
"chars": 3425,
"preview": "/**\n * @typedef {Object} WebpackErrorObj\n * @property {string} moduleIdentifier\n * @property {string} moduleName\n * @pro"
},
{
"path": "client/utils/retry.js",
"chars": 504,
"preview": "function runWithRetry(callback, maxRetries, message) {\n function executeWithRetryAndTimeout(currentCount) {\n try {\n "
},
{
"path": "docs/API.md",
"chars": 6807,
"preview": "# API\n\n## Directives\n\nThe `react-refresh/babel` plugin provide support to directive comments out of the box.\n\n### `reset"
},
{
"path": "docs/TROUBLESHOOTING.md",
"chars": 11848,
"preview": "# Troubleshooting\n\n## Coming from `react-hot-loader`\n\nIf you are coming from `react-hot-loader`, before using the plugin"
},
{
"path": "examples/flow-with-babel/.flowconfig",
"chars": 58,
"preview": "[ignore]\n\n[include]\n\n[libs]\n\n[lints]\n\n[options]\n\n[strict]\n"
},
{
"path": "examples/flow-with-babel/babel.config.js",
"chars": 521,
"preview": "module.exports = (api) => {\n // This caches the Babel config\n api.cache.using(() => process.env.NODE_ENV);\n return {\n"
},
{
"path": "examples/flow-with-babel/package.json",
"chars": 733,
"preview": "{\n \"name\": \"using-flow-with-babel\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"dependencies\": {\n \"react\": \"^19.0.0\""
},
{
"path": "examples/flow-with-babel/public/index.html",
"chars": 244,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/flow-with-babel/src/App.jsx",
"chars": 630,
"preview": "// @flow\n\nimport { lazy, Suspense } from 'react';\nimport { ArrowFunction } from './ArrowFunction';\nimport ClassDefault f"
},
{
"path": "examples/flow-with-babel/src/ArrowFunction.jsx",
"chars": 70,
"preview": "// @flow\n\nexport const ArrowFunction = () => <h1>Arrow Function</h1>;\n"
},
{
"path": "examples/flow-with-babel/src/ClassDefault.jsx",
"chars": 180,
"preview": "// @flow\n\nimport { Component } from 'react';\n\nclass ClassDefault extends Component<{}> {\n render() {\n return <h1>Def"
},
{
"path": "examples/flow-with-babel/src/ClassNamed.jsx",
"chars": 153,
"preview": "// @flow\n\nimport { Component } from 'react';\n\nexport class ClassNamed extends Component<{}> {\n render() {\n return <h"
},
{
"path": "examples/flow-with-babel/src/FunctionDefault.jsx",
"chars": 117,
"preview": "// @flow\n\nfunction FunctionDefault() {\n return <h1>Default Export Function</h1>;\n}\n\nexport default FunctionDefault;\n"
},
{
"path": "examples/flow-with-babel/src/FunctionNamed.jsx",
"chars": 87,
"preview": "// @flow\n\nexport function FunctionNamed() {\n return <h1>Named Export Function</h1>;\n}\n"
},
{
"path": "examples/flow-with-babel/src/LazyComponent.jsx",
"chars": 104,
"preview": "// @flow\n\nfunction LazyComponent() {\n return <h1>Lazy Component</h1>;\n}\n\nexport default LazyComponent;\n"
},
{
"path": "examples/flow-with-babel/src/index.js",
"chars": 191,
"preview": "// @flow\n\nimport { createRoot } from 'react-dom/client';\nimport App from './App';\n\nconst container = document.getElement"
},
{
"path": "examples/flow-with-babel/webpack.config.js",
"chars": 792,
"preview": "const path = require('path');\nconst ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\nconst HtmlWebp"
},
{
"path": "examples/typescript-with-babel/babel.config.js",
"chars": 527,
"preview": "module.exports = (api) => {\n // This caches the Babel config\n api.cache.using(() => process.env.NODE_ENV);\n return {\n"
},
{
"path": "examples/typescript-with-babel/package.json",
"chars": 859,
"preview": "{\n \"name\": \"using-typescript-with-babel\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"dependencies\": {\n \"react\": \"^1"
},
{
"path": "examples/typescript-with-babel/public/index.html",
"chars": 242,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/typescript-with-babel/src/App.tsx",
"chars": 620,
"preview": "import { lazy, Suspense } from 'react';\nimport { ArrowFunction } from './ArrowFunction';\nimport ClassDefault from './Cla"
},
{
"path": "examples/typescript-with-babel/src/ArrowFunction.tsx",
"chars": 60,
"preview": "export const ArrowFunction = () => <h1>Arrow Function</h1>;\n"
},
{
"path": "examples/typescript-with-babel/src/ClassDefault.tsx",
"chars": 166,
"preview": "import { Component } from 'react';\n\nclass ClassDefault extends Component {\n render() {\n return <h1>Default Export Cl"
},
{
"path": "examples/typescript-with-babel/src/ClassNamed.tsx",
"chars": 139,
"preview": "import { Component } from 'react';\n\nexport class ClassNamed extends Component {\n render() {\n return <h1>Named Export"
},
{
"path": "examples/typescript-with-babel/src/FunctionDefault.tsx",
"chars": 107,
"preview": "function FunctionDefault() {\n return <h1>Default Export Function</h1>;\n}\n\nexport default FunctionDefault;\n"
},
{
"path": "examples/typescript-with-babel/src/FunctionNamed.tsx",
"chars": 77,
"preview": "export function FunctionNamed() {\n return <h1>Named Export Function</h1>;\n}\n"
},
{
"path": "examples/typescript-with-babel/src/LazyComponent.tsx",
"chars": 94,
"preview": "function LazyComponent() {\n return <h1>Lazy Component</h1>;\n}\n\nexport default LazyComponent;\n"
},
{
"path": "examples/typescript-with-babel/src/index.tsx",
"chars": 182,
"preview": "import { createRoot } from 'react-dom/client';\nimport App from './App';\n\nconst container = document.getElementById('app'"
},
{
"path": "examples/typescript-with-babel/tsconfig.json",
"chars": 247,
"preview": "{\n \"compilerOptions\": {\n \"jsx\": \"react-jsx\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"module\": \"ESNext\",\n "
},
{
"path": "examples/typescript-with-babel/webpack.config.js",
"chars": 916,
"preview": "const path = require('path');\nconst ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\nconst ForkTsCh"
},
{
"path": "examples/typescript-with-swc/package.json",
"chars": 761,
"preview": "{\n \"name\": \"using-typescript-with-swc\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"dependencies\": {\n \"react\": \"^19."
},
{
"path": "examples/typescript-with-swc/public/index.html",
"chars": 243,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/typescript-with-swc/src/App.tsx",
"chars": 620,
"preview": "import { lazy, Suspense } from 'react';\nimport { ArrowFunction } from './ArrowFunction';\nimport ClassDefault from './Cla"
},
{
"path": "examples/typescript-with-swc/src/ArrowFunction.tsx",
"chars": 60,
"preview": "export const ArrowFunction = () => <h1>Arrow Function</h1>;\n"
},
{
"path": "examples/typescript-with-swc/src/ClassDefault.tsx",
"chars": 166,
"preview": "import { Component } from 'react';\n\nclass ClassDefault extends Component {\n render() {\n return <h1>Default Export Cl"
},
{
"path": "examples/typescript-with-swc/src/ClassNamed.tsx",
"chars": 139,
"preview": "import { Component } from 'react';\n\nexport class ClassNamed extends Component {\n render() {\n return <h1>Named Export"
},
{
"path": "examples/typescript-with-swc/src/FunctionDefault.tsx",
"chars": 107,
"preview": "function FunctionDefault() {\n return <h1>Default Export Function</h1>;\n}\n\nexport default FunctionDefault;\n"
},
{
"path": "examples/typescript-with-swc/src/FunctionNamed.tsx",
"chars": 77,
"preview": "export function FunctionNamed() {\n return <h1>Named Export Function</h1>;\n}\n"
},
{
"path": "examples/typescript-with-swc/src/LazyComponent.tsx",
"chars": 94,
"preview": "function LazyComponent() {\n return <h1>Lazy Component</h1>;\n}\n\nexport default LazyComponent;\n"
},
{
"path": "examples/typescript-with-swc/src/index.tsx",
"chars": 182,
"preview": "import { createRoot } from 'react-dom/client';\nimport App from './App';\n\nconst container = document.getElementById('app'"
},
{
"path": "examples/typescript-with-swc/tsconfig.json",
"chars": 247,
"preview": "{\n \"compilerOptions\": {\n \"jsx\": \"react-jsx\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"module\": \"ESNext\",\n "
},
{
"path": "examples/typescript-with-swc/webpack.config.js",
"chars": 1687,
"preview": "const path = require('path');\nconst ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\nconst ForkTsCh"
},
{
"path": "examples/typescript-with-tsc/package.json",
"chars": 748,
"preview": "{\n \"name\": \"using-typescript-with-tsc\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"dependencies\": {\n \"react\": \"^19."
},
{
"path": "examples/typescript-with-tsc/public/index.html",
"chars": 243,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/typescript-with-tsc/src/App.tsx",
"chars": 620,
"preview": "import { lazy, Suspense } from 'react';\nimport { ArrowFunction } from './ArrowFunction';\nimport ClassDefault from './Cla"
},
{
"path": "examples/typescript-with-tsc/src/ArrowFunction.tsx",
"chars": 60,
"preview": "export const ArrowFunction = () => <h1>Arrow Function</h1>;\n"
},
{
"path": "examples/typescript-with-tsc/src/ClassDefault.tsx",
"chars": 166,
"preview": "import { Component } from 'react';\n\nclass ClassDefault extends Component {\n render() {\n return <h1>Default Export Cl"
},
{
"path": "examples/typescript-with-tsc/src/ClassNamed.tsx",
"chars": 139,
"preview": "import { Component } from 'react';\n\nexport class ClassNamed extends Component {\n render() {\n return <h1>Named Export"
},
{
"path": "examples/typescript-with-tsc/src/FunctionDefault.tsx",
"chars": 107,
"preview": "function FunctionDefault() {\n return <h1>Default Export Function</h1>;\n}\n\nexport default FunctionDefault;\n"
},
{
"path": "examples/typescript-with-tsc/src/FunctionNamed.tsx",
"chars": 77,
"preview": "export function FunctionNamed() {\n return <h1>Named Export Function</h1>;\n}\n"
},
{
"path": "examples/typescript-with-tsc/src/LazyComponent.tsx",
"chars": 94,
"preview": "function LazyComponent() {\n return <h1>Lazy Component</h1>;\n}\n\nexport default LazyComponent;\n"
},
{
"path": "examples/typescript-with-tsc/src/index.tsx",
"chars": 182,
"preview": "import { createRoot } from 'react-dom/client';\nimport App from './App';\n\nconst container = document.getElementById('app'"
},
{
"path": "examples/typescript-with-tsc/tsconfig.dev.json",
"chars": 111,
"preview": "{\n \"extends\": \"./tsconfig.json\",\n \"compilerOptions\": {\n \"jsx\": \"react-jsxdev\"\n },\n \"include\": [\"src\"]\n}\n"
},
{
"path": "examples/typescript-with-tsc/tsconfig.json",
"chars": 247,
"preview": "{\n \"compilerOptions\": {\n \"jsx\": \"react-jsx\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"module\": \"ESNext\",\n "
},
{
"path": "examples/typescript-with-tsc/webpack.config.js",
"chars": 1379,
"preview": "const path = require('path');\nconst ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\nconst ForkTsCh"
},
{
"path": "examples/webpack-dev-server/babel.config.js",
"chars": 493,
"preview": "module.exports = (api) => {\n // This caches the Babel config\n api.cache.using(() => process.env.NODE_ENV);\n return {\n"
},
{
"path": "examples/webpack-dev-server/package.json",
"chars": 671,
"preview": "{\n \"name\": \"using-webpack-dev-server\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"dependencies\": {\n \"react\": \"^19.0"
},
{
"path": "examples/webpack-dev-server/public/index.html",
"chars": 243,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/webpack-dev-server/src/App.jsx",
"chars": 620,
"preview": "import { lazy, Suspense } from 'react';\nimport { ArrowFunction } from './ArrowFunction';\nimport ClassDefault from './Cla"
},
{
"path": "examples/webpack-dev-server/src/ArrowFunction.jsx",
"chars": 60,
"preview": "export const ArrowFunction = () => <h1>Arrow Function</h1>;\n"
},
{
"path": "examples/webpack-dev-server/src/ClassDefault.jsx",
"chars": 166,
"preview": "import { Component } from 'react';\n\nclass ClassDefault extends Component {\n render() {\n return <h1>Default Export Cl"
},
{
"path": "examples/webpack-dev-server/src/ClassNamed.jsx",
"chars": 139,
"preview": "import { Component } from 'react';\n\nexport class ClassNamed extends Component {\n render() {\n return <h1>Named Export"
},
{
"path": "examples/webpack-dev-server/src/FunctionDefault.jsx",
"chars": 107,
"preview": "function FunctionDefault() {\n return <h1>Default Export Function</h1>;\n}\n\nexport default FunctionDefault;\n"
},
{
"path": "examples/webpack-dev-server/src/FunctionNamed.jsx",
"chars": 77,
"preview": "export function FunctionNamed() {\n return <h1>Named Export Function</h1>;\n}\n"
},
{
"path": "examples/webpack-dev-server/src/LazyComponent.jsx",
"chars": 94,
"preview": "function LazyComponent() {\n return <h1>Lazy Component</h1>;\n}\n\nexport default LazyComponent;\n"
},
{
"path": "examples/webpack-dev-server/src/index.js",
"chars": 181,
"preview": "import { createRoot } from 'react-dom/client';\nimport App from './App';\n\nconst container = document.getElementById('app'"
},
{
"path": "examples/webpack-dev-server/webpack.config.js",
"chars": 792,
"preview": "const path = require('path');\nconst ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\nconst HtmlWebp"
},
{
"path": "examples/webpack-hot-middleware/babel.config.js",
"chars": 493,
"preview": "module.exports = (api) => {\n // This caches the Babel config\n api.cache.using(() => process.env.NODE_ENV);\n return {\n"
},
{
"path": "examples/webpack-hot-middleware/package.json",
"chars": 713,
"preview": "{\n \"name\": \"using-webpack-hot-middleware\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"dependencies\": {\n \"react\": \"^"
},
{
"path": "examples/webpack-hot-middleware/public/index.html",
"chars": 243,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/webpack-hot-middleware/server.js",
"chars": 824,
"preview": "const path = require('path');\nconst express = require('express');\nconst webpack = require('webpack');\nconst config = req"
},
{
"path": "examples/webpack-hot-middleware/src/App.jsx",
"chars": 620,
"preview": "import { lazy, Suspense } from 'react';\nimport { ArrowFunction } from './ArrowFunction';\nimport ClassDefault from './Cla"
},
{
"path": "examples/webpack-hot-middleware/src/ArrowFunction.jsx",
"chars": 60,
"preview": "export const ArrowFunction = () => <h1>Arrow Function</h1>;\n"
},
{
"path": "examples/webpack-hot-middleware/src/ClassDefault.jsx",
"chars": 166,
"preview": "import { Component } from 'react';\n\nclass ClassDefault extends Component {\n render() {\n return <h1>Default Export Cl"
},
{
"path": "examples/webpack-hot-middleware/src/ClassNamed.jsx",
"chars": 139,
"preview": "import { Component } from 'react';\n\nexport class ClassNamed extends Component {\n render() {\n return <h1>Named Export"
},
{
"path": "examples/webpack-hot-middleware/src/FunctionDefault.jsx",
"chars": 107,
"preview": "function FunctionDefault() {\n return <h1>Default Export Function</h1>;\n}\n\nexport default FunctionDefault;\n"
},
{
"path": "examples/webpack-hot-middleware/src/FunctionNamed.jsx",
"chars": 77,
"preview": "export function FunctionNamed() {\n return <h1>Named Export Function</h1>;\n}\n"
},
{
"path": "examples/webpack-hot-middleware/src/LazyComponent.jsx",
"chars": 94,
"preview": "function LazyComponent() {\n return <h1>Lazy Component</h1>;\n}\n\nexport default LazyComponent;\n"
},
{
"path": "examples/webpack-hot-middleware/src/index.js",
"chars": 181,
"preview": "import { createRoot } from 'react-dom/client';\nimport App from './App';\n\nconst container = document.getElementById('app'"
},
{
"path": "examples/webpack-hot-middleware/webpack.config.js",
"chars": 1061,
"preview": "const path = require('path');\nconst ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\nconst HtmlWebp"
},
{
"path": "examples/webpack-plugin-serve/babel.config.js",
"chars": 493,
"preview": "module.exports = (api) => {\n // This caches the Babel config\n api.cache.using(() => process.env.NODE_ENV);\n return {\n"
},
{
"path": "examples/webpack-plugin-serve/package.json",
"chars": 672,
"preview": "{\n \"name\": \"using-webpack-plugin-serve\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"dependencies\": {\n \"react\": \"^19"
},
{
"path": "examples/webpack-plugin-serve/public/index.html",
"chars": 243,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "examples/webpack-plugin-serve/src/App.jsx",
"chars": 620,
"preview": "import { lazy, Suspense } from 'react';\nimport { ArrowFunction } from './ArrowFunction';\nimport ClassDefault from './Cla"
},
{
"path": "examples/webpack-plugin-serve/src/ArrowFunction.jsx",
"chars": 60,
"preview": "export const ArrowFunction = () => <h1>Arrow Function</h1>;\n"
},
{
"path": "examples/webpack-plugin-serve/src/ClassDefault.jsx",
"chars": 166,
"preview": "import { Component } from 'react';\n\nclass ClassDefault extends Component {\n render() {\n return <h1>Default Export Cl"
},
{
"path": "examples/webpack-plugin-serve/src/ClassNamed.jsx",
"chars": 139,
"preview": "import { Component } from 'react';\n\nexport class ClassNamed extends Component {\n render() {\n return <h1>Named Export"
},
{
"path": "examples/webpack-plugin-serve/src/FunctionDefault.jsx",
"chars": 107,
"preview": "function FunctionDefault() {\n return <h1>Default Export Function</h1>;\n}\n\nexport default FunctionDefault;\n"
},
{
"path": "examples/webpack-plugin-serve/src/FunctionNamed.jsx",
"chars": 77,
"preview": "export function FunctionNamed() {\n return <h1>Named Export Function</h1>;\n}\n"
},
{
"path": "examples/webpack-plugin-serve/src/LazyComponent.jsx",
"chars": 94,
"preview": "function LazyComponent() {\n return <h1>Lazy Component</h1>;\n}\n\nexport default LazyComponent;\n"
},
{
"path": "examples/webpack-plugin-serve/src/index.js",
"chars": 181,
"preview": "import { createRoot } from 'react-dom/client';\nimport App from './App';\n\nconst container = document.getElementById('app'"
},
{
"path": "examples/webpack-plugin-serve/webpack.config.js",
"chars": 1194,
"preview": "const path = require('path');\nconst ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\nconst HtmlWebp"
},
{
"path": "jest.config.js",
"chars": 358,
"preview": "module.exports = {\n globalSetup: '<rootDir>/jest-global-setup.js',\n globalTeardown: '<rootDir>/jest-global-teardown.js"
},
{
"path": "lib/globals.js",
"chars": 371,
"preview": "/**\n * Gets current bundle's global scope identifier for React Refresh.\n * @param {Record<string, string>} runtimeGlobal"
},
{
"path": "lib/index.js",
"chars": 9036,
"preview": "const { validate: validateOptions } = require('schema-utils');\nconst { getRefreshGlobalScope } = require('./globals');\nc"
},
{
"path": "lib/options.json",
"chars": 1982,
"preview": "{\n \"additionalProperties\": false,\n \"type\": \"object\",\n \"definitions\": {\n \"Path\": { \"type\": \"string\" },\n \"MatchCo"
},
{
"path": "lib/runtime/RefreshUtils.js",
"chars": 9537,
"preview": "/* global __webpack_require__ */\nvar Refresh = require('react-refresh/runtime');\n\n/**\n * Extracts exports from a webpack"
},
{
"path": "lib/types.js",
"chars": 1564,
"preview": "/**\n * @typedef {Object} ErrorOverlayOptions\n * @property {string | false} [entry] Path to a JS file that sets up the er"
},
{
"path": "lib/utils/getAdditionalEntries.js",
"chars": 853,
"preview": "/**\n * @typedef {Object} AdditionalEntries\n * @property {string[]} prependEntries\n * @property {string[]} overlayEntries"
},
{
"path": "lib/utils/getIntegrationEntry.js",
"chars": 606,
"preview": "/**\n * Gets entry point of a supported socket integration.\n * @param {'wds' | 'whm' | 'wps' | string} integrationType A "
},
{
"path": "lib/utils/getSocketIntegration.js",
"chars": 897,
"preview": "/**\n * Gets the socket integration to use for Webpack messages.\n * @param {'wds' | 'whm' | 'wps' | string} integrationTy"
},
{
"path": "lib/utils/index.js",
"chars": 545,
"preview": "const getAdditionalEntries = require('./getAdditionalEntries');\nconst getIntegrationEntry = require('./getIntegrationEnt"
},
{
"path": "lib/utils/injectRefreshLoader.js",
"chars": 2210,
"preview": "const path = require('node:path');\n\n/**\n * @callback MatchObject\n * @param {string} [str]\n * @returns {boolean}\n */\n\n/**"
},
{
"path": "lib/utils/makeRefreshRuntimeModule.js",
"chars": 4253,
"preview": "/**\n * Makes a runtime module to intercept module execution for React Refresh.\n * This module creates an isolated `__web"
},
{
"path": "lib/utils/normalizeOptions.js",
"chars": 1122,
"preview": "const { d, n } = require('../../options');\n\n/**\n * Normalizes the options for the plugin.\n * @param {import('../types')."
},
{
"path": "loader/index.js",
"chars": 3608,
"preview": "// This is a patch for mozilla/source-map#349 -\n// internally, it uses the existence of the `fetch` global to toggle bro"
},
{
"path": "loader/options.json",
"chars": 1009,
"preview": "{\n \"additionalProperties\": false,\n \"type\": \"object\",\n \"definitions\": {\n \"MatchCondition\": {\n \"anyOf\": [{ \"ins"
},
{
"path": "loader/types.js",
"chars": 676,
"preview": "/**\n * @typedef {Object} ESModuleOptions\n * @property {string | RegExp | Array<string | RegExp>} [exclude] Files to expl"
},
{
"path": "loader/utils/getIdentitySourceMap.js",
"chars": 793,
"preview": "const { SourceMapGenerator } = require('source-map');\n\n/**\n * Generates an identity source map from a source file.\n * @p"
},
{
"path": "loader/utils/getModuleSystem.js",
"chars": 5287,
"preview": "const fs = require('node:fs/promises');\nconst path = require('node:path');\n\n/** @type {Map<string, string | undefined>} "
},
{
"path": "loader/utils/getRefreshModuleRuntime.js",
"chars": 2637,
"preview": "const webpackGlobal = require('./webpackGlobal');\n\n/**\n * @typedef ModuleRuntimeOptions {Object}\n * @property {boolean} "
},
{
"path": "loader/utils/index.js",
"chars": 424,
"preview": "const getIdentitySourceMap = require('./getIdentitySourceMap');\nconst getModuleSystem = require('./getModuleSystem');\nco"
},
{
"path": "loader/utils/normalizeOptions.js",
"chars": 634,
"preview": "const { d, n } = require('../../options');\n\n/**\n * Normalizes the options for the loader.\n * @param {import('../types')."
},
{
"path": "loader/utils/webpackGlobal.js",
"chars": 329,
"preview": "// When available, use `__webpack_global__` which is a stable runtime function to use `__webpack_require__` in this comp"
},
{
"path": "options/index.js",
"chars": 1071,
"preview": "/**\n * Sets a constant default value for the property when it is undefined.\n * @template T\n * @template {keyof T} Proper"
},
{
"path": "overlay/components/CompileErrorTrace.js",
"chars": 1950,
"preview": "const Anser = require('anser');\nconst entities = require('html-entities');\nconst utils = require('../utils.js');\n\n/**\n *"
},
{
"path": "overlay/components/PageHeader.js",
"chars": 1881,
"preview": "const Spacer = require('./Spacer.js');\nconst theme = require('../theme.js');\n\n/**\n * @typedef {Object} PageHeaderProps\n "
},
{
"path": "overlay/components/RuntimeErrorFooter.js",
"chars": 2688,
"preview": "const Spacer = require('./Spacer.js');\nconst theme = require('../theme.js');\n\n/**\n * @typedef {Object} RuntimeErrorFoote"
},
{
"path": "overlay/components/RuntimeErrorHeader.js",
"chars": 1070,
"preview": "const Spacer = require('./Spacer.js');\nconst theme = require('../theme.js');\n\n/**\n * @typedef {Object} RuntimeErrorHeade"
},
{
"path": "overlay/components/RuntimeErrorStack.js",
"chars": 2211,
"preview": "const ErrorStackParser = require('error-stack-parser');\nconst theme = require('../theme.js');\nconst utils = require('../"
},
{
"path": "overlay/components/Spacer.js",
"chars": 420,
"preview": "/**\n * @typedef {Object} SpacerProps\n * @property {string} space\n */\n\n/**\n * An empty element to add spacing manually.\n "
},
{
"path": "overlay/containers/CompileErrorContainer.js",
"chars": 775,
"preview": "const CompileErrorTrace = require('../components/CompileErrorTrace.js');\nconst PageHeader = require('../components/PageH"
},
{
"path": "overlay/containers/RuntimeErrorContainer.js",
"chars": 830,
"preview": "const PageHeader = require('../components/PageHeader.js');\nconst RuntimeErrorStack = require('../components/RuntimeError"
},
{
"path": "overlay/index.js",
"chars": 10466,
"preview": "const RuntimeErrorFooter = require('./components/RuntimeErrorFooter.js');\nconst RuntimeErrorHeader = require('./componen"
},
{
"path": "overlay/package.json",
"chars": 25,
"preview": "{\n \"type\": \"commonjs\"\n}\n"
},
{
"path": "overlay/theme.js",
"chars": 1323,
"preview": "/**\n * @typedef {Object} Theme\n * @property {string} black\n * @property {string} bright-black\n * @property {string} red\n"
},
{
"path": "overlay/utils.js",
"chars": 1948,
"preview": "/**\n * Debounce a function to delay invoking until wait (ms) have elapsed since the last invocation.\n * @param {function"
},
{
"path": "package.json",
"chars": 4478,
"preview": "{\n \"name\": \"@pmmmwh/react-refresh-webpack-plugin\",\n \"version\": \"0.6.2\",\n \"description\": \"An **EXPERIMENTAL** Webpack "
},
{
"path": "scripts/test.js",
"chars": 781,
"preview": "// Setup environment before any code -\n// this makes sure everything coming after will run in the correct env.\nprocess.e"
},
{
"path": "sockets/WDSSocket.js",
"chars": 937,
"preview": "/**\n * Initializes a socket server for HMR for webpack-dev-server.\n * @param {function(*): void} messageHandler A handle"
},
{
"path": "sockets/WHMEventSource.js",
"chars": 876,
"preview": "/**\n * The hard-coded singleton key for webpack-hot-middleware's client instance.\n *\n * [Ref](https://github.com/webpack"
},
{
"path": "sockets/WPSSocket.js",
"chars": 1527,
"preview": "/* global ʎɐɹɔosǝʌɹǝs */\nconst { ClientSocket } = require('webpack-plugin-serve/lib/client/ClientSocket');\n\n/**\n * Initi"
},
{
"path": "sockets/package.json",
"chars": 25,
"preview": "{\n \"type\": \"commonjs\"\n}\n"
},
{
"path": "test/conformance/ReactRefresh.test.js",
"chars": 35802,
"preview": "/**\n * @jest-environment <rootDir>/conformance/environment\n */\n\nconst getSandbox = require('../helpers/sandbox');\n\n// ht"
},
{
"path": "test/conformance/environment.js",
"chars": 617,
"preview": "const puppeteer = require('puppeteer');\nconst TestEnvironment = require('../jest-environment');\n\nclass SandboxEnvironmen"
},
{
"path": "test/helpers/compilation/fixtures/source-map-loader.js",
"chars": 136,
"preview": "module.exports = function sourceMapLoader(source) {\n const callback = this.async();\n callback(null, source, this.query"
},
{
"path": "test/helpers/compilation/index.js",
"chars": 4647,
"preview": "const path = require('path');\nconst { createFsFromVolume, Volume } = require('memfs');\nconst webpack = require('webpack'"
},
{
"path": "test/helpers/compilation/normalizeErrors.js",
"chars": 760,
"preview": "/**\n * @param {string} str\n * @return {string}\n */\nfunction removeCwd(str) {\n let cwd = process.cwd();\n let result = s"
},
{
"path": "test/helpers/sandbox/aliasWDSv4.js",
"chars": 121,
"preview": "const moduleAlias = require('module-alias');\n\nmoduleAlias.addAliases({ 'webpack-dev-server': 'webpack-dev-server-v4' });"
},
{
"path": "test/helpers/sandbox/configs.js",
"chars": 1963,
"preview": "const path = require('path');\n\nconst BUNDLE_FILENAME = 'main';\n\n/**\n * @param {number} port\n * @returns {string}\n */\nfun"
},
{
"path": "test/helpers/sandbox/fixtures/hmr-notifier.js",
"chars": 183,
"preview": "if (module.hot) {\n module.hot.addStatusHandler(function (status) {\n if (status === 'idle') {\n if (window.onHotS"
},
{
"path": "test/helpers/sandbox/index.js",
"chars": 8477,
"preview": "const path = require('path');\nconst fse = require('fs-extra');\nconst { nanoid } = require('nanoid');\nconst { getIndexHTM"
},
{
"path": "test/helpers/sandbox/spawn.js",
"chars": 3956,
"preview": "const path = require('path');\nconst spawn = require('cross-spawn');\n\n/**\n * @param {string} packageName\n * @returns {str"
},
{
"path": "test/jest-environment.js",
"chars": 360,
"preview": "const { TestEnvironment: NodeEnvironment } = require('jest-environment-node');\nconst yn = require('yn');\n\nclass TestEnvi"
},
{
"path": "test/jest-global-setup.js",
"chars": 554,
"preview": "const puppeteer = require('puppeteer');\nconst yn = require('yn');\n\nasync function setup() {\n if (yn(process.env.BROWSER"
},
{
"path": "test/jest-global-teardown.js",
"chars": 146,
"preview": "async function teardown() {\n if (global.__BROWSER_INSTANCE__) {\n await global.__BROWSER_INSTANCE__.close();\n }\n}\n\nm"
},
{
"path": "test/jest-resolver.js",
"chars": 463,
"preview": "/**\n * @param {string} request\n * @param {*} options\n * @return {string}\n */\nfunction resolver(request, options) {\n // "
},
{
"path": "test/jest-test-setup.js",
"chars": 953,
"preview": "require('jest-location-mock');\n\n/**\n * Skips a test block conditionally.\n * @param {boolean} condition The condition to "
},
{
"path": "test/loader/fixtures/auto/package.json",
"chars": 21,
"preview": "{\n \"name\": \"auto\"\n}\n"
},
{
"path": "test/loader/fixtures/cjs/esm/index.js",
"chars": 22,
"preview": "export default 'esm';\n"
},
{
"path": "test/loader/fixtures/cjs/esm/package.json",
"chars": 23,
"preview": "{\n \"type\": \"module\"\n}\n"
},
{
"path": "test/loader/fixtures/cjs/index.js",
"chars": 25,
"preview": "module.exports = 'Test';\n"
},
{
"path": "test/loader/fixtures/cjs/package.json",
"chars": 42,
"preview": "{\n \"name\": \"cjs\",\n \"type\": \"commonjs\"\n}\n"
},
{
"path": "test/loader/fixtures/esm/cjs/index.js",
"chars": 24,
"preview": "module.exports = 'cjs';\n"
},
{
"path": "test/loader/fixtures/esm/cjs/package.json",
"chars": 25,
"preview": "{\n \"type\": \"commonjs\"\n}\n"
},
{
"path": "test/loader/fixtures/esm/index.js",
"chars": 23,
"preview": "export default 'Test';\n"
},
{
"path": "test/loader/fixtures/esm/package.json",
"chars": 40,
"preview": "{\n \"name\": \"esm\",\n \"type\": \"module\"\n}\n"
},
{
"path": "test/loader/loader.test.js",
"chars": 11203,
"preview": "const validate = require('sourcemap-validator');\nconst mockFetch = require('../mocks/fetch');\n\ndescribe('loader', () => "
},
{
"path": "test/loader/unit/getIdentitySourceMap.test.js",
"chars": 684,
"preview": "const { SourceMapConsumer } = require('source-map');\nconst validate = require('sourcemap-validator');\nconst getIdentityS"
},
{
"path": "test/loader/unit/getModuleSystem.test.js",
"chars": 4182,
"preview": "const path = require('path');\nconst { ModuleFilenameHelpers } = require('webpack');\n\ndescribe('getModuleSystem', () => {"
},
{
"path": "test/loader/unit/getRefreshModuleRuntime.test.js",
"chars": 7083,
"preview": "const { Template } = require('webpack');\nconst getRefreshModuleRuntime = require('../../../loader/utils/getRefreshModule"
},
{
"path": "test/loader/unit/normalizeOptions.test.js",
"chars": 1578,
"preview": "const normalizeOptions = require('../../../loader/utils/normalizeOptions');\n\n/** @type {Partial<import('../../../types/l"
},
{
"path": "test/loader/validateOptions.test.js",
"chars": 7475,
"preview": "describe('validateOptions', () => {\n let getCompilation;\n\n beforeEach(() => {\n jest.isolateModules(() => {\n ge"
},
{
"path": "test/mocks/fetch.js",
"chars": 449,
"preview": "/** @type {Set<function(): void>} */\nconst cleanupHandlers = new Set();\nafterEach(() => {\n [...cleanupHandlers].map((ca"
},
{
"path": "test/unit/fixtures/socketIntegration.js",
"chars": 21,
"preview": "module.exports = {};\n"
},
{
"path": "test/unit/getAdditionalEntries.test.js",
"chars": 751,
"preview": "const getAdditionalEntries = require('../../lib/utils/getAdditionalEntries');\n\nconst ErrorOverlayEntry = require.resolve"
},
{
"path": "test/unit/getIntegrationEntry.test.js",
"chars": 692,
"preview": "const getIntegrationEntry = require('../../lib/utils/getIntegrationEntry');\n\ndescribe('getIntegrationEntry', () => {\n i"
},
{
"path": "test/unit/getSocketIntegration.test.js",
"chars": 1182,
"preview": "const getSocketIntegration = require('../../lib/utils/getSocketIntegration');\n\ndescribe('getSocketIntegration', () => {\n"
},
{
"path": "test/unit/globals.test.js",
"chars": 308,
"preview": "const { getRefreshGlobalScope } = require('../../lib/globals');\n\ndescribe('getRefreshGlobalScope', () => {\n it('should "
},
{
"path": "test/unit/makeRefreshRuntimeModule.test.js",
"chars": 4297,
"preview": "const makeRefreshRuntimeModule = require('../../lib/utils/makeRefreshRuntimeModule');\n\ndescribe('makeRefreshRuntimeModul"
},
{
"path": "test/unit/normalizeOptions.test.js",
"chars": 2174,
"preview": "const normalizeOptions = require('../../lib/utils/normalizeOptions');\n\n/** @type {Partial<import('../../types/types').Re"
},
{
"path": "test/unit/validateOptions.test.js",
"chars": 10478,
"preview": "const ReactRefreshPlugin = require('../../lib');\n\ndescribe('validateOptions', () => {\n it('should accept \"exclude\" when"
},
{
"path": "tsconfig.json",
"chars": 402,
"preview": "{\n \"compilerOptions\": {\n \"allowJs\": true,\n \"declaration\": true,\n \"emitDeclarationOnly\": true,\n \"esModuleInt"
},
{
"path": "types/lib/index.d.ts",
"chars": 669,
"preview": "export = ReactRefreshPlugin;\ndeclare class ReactRefreshPlugin {\n /**\n * @param {import('./types').ReactRefreshPluginO"
},
{
"path": "types/lib/types.d.ts",
"chars": 1671,
"preview": "export type ErrorOverlayOptions = {\n /**\n * Path to a JS file that sets up the error overlay integration.\n */\n ent"
},
{
"path": "types/loader/index.d.ts",
"chars": 721,
"preview": "export = ReactRefreshLoader;\n/**\n * A simple Webpack loader to inject react-refresh HMR code into modules.\n *\n * [Refere"
},
{
"path": "types/loader/types.d.ts",
"chars": 693,
"preview": "export type ESModuleOptions = {\n /**\n * Files to explicitly exclude from flagged as ES Modules.\n */\n exclude?: str"
},
{
"path": "types/options/index.d.ts",
"chars": 1004,
"preview": "/**\n * Sets a constant default value for the property when it is undefined.\n * @template T\n * @template {keyof T} Proper"
},
{
"path": "webpack.config.js",
"chars": 523,
"preview": "const path = require('node:path');\nconst TerserPlugin = require('terser-webpack-plugin');\n\nmodule.exports = {\n mode: 'p"
}
]
About this extraction
This page contains the full source code of the pmmmwh/react-refresh-webpack-plugin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 194 files (293.4 KB), approximately 79.3k tokens, and a symbol index with 141 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.