Skip to content

Commit 91ffb8b

Browse files
committed
feat: runtime entry option
1 parent bdf4ba9 commit 91ffb8b

8 files changed

Lines changed: 77 additions & 7 deletions

File tree

lib/options.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@
6767
]
6868
},
6969
"library": { "type": "string" },
70+
"runtimeEntry": {
71+
"anyOf": [{ "const": false }, { "$ref": "#/definitions/Path" }]
72+
},
7073
"overlay": {
7174
"anyOf": [{ "type": "boolean" }, { "$ref": "#/definitions/OverlayOptions" }]
7275
}

lib/types.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* @property {string | RegExp | Array<string | RegExp>} [include] Files to explicitly include for processing.
1818
* @property {string} [library] Name of the library bundle.
1919
* @property {boolean | ErrorOverlayOptions} [overlay] Modifies how the error overlay integration works in the plugin.
20+
* @property {string | false} [runtimeEntry] Runtime entry to prepend to Webpack entries, or false to disable automatic injection.
2021
*/
2122

2223
/**
@@ -25,7 +26,7 @@
2526
*/
2627

2728
/**
28-
* @typedef {import('type-fest').SetRequired<import('type-fest').Except<ReactRefreshPluginOptions, 'overlay'>, 'exclude' | 'include'> & OverlayOverrides} NormalizedPluginOptions
29+
* @typedef {import('type-fest').SetRequired<import('type-fest').Except<ReactRefreshPluginOptions, 'overlay'>, 'exclude' | 'include' | 'runtimeEntry'> & OverlayOverrides} NormalizedPluginOptions
2930
*/
3031

3132
module.exports = {};

lib/utils/getAdditionalEntries.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
function getAdditionalEntries(options) {
1313
const prependEntries = [
1414
// React-refresh runtime
15-
require.resolve('../../client/ReactRefreshEntry'),
16-
];
15+
options.runtimeEntry && require.resolve(options.runtimeEntry),
16+
].filter(Boolean);
1717

1818
const overlayEntries = [
1919
// Error overlay runtime

lib/utils/normalizeOptions.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const normalizeOptions = (options) => {
1010
d(options, 'include', /\.([cm]js|[jt]sx?|flow)$/i);
1111
d(options, 'forceEnable');
1212
d(options, 'library');
13+
d(options, 'runtimeEntry', require.resolve('../../client/ReactRefreshEntry'));
1314

1415
n(options, 'overlay', (overlay) => {
1516
/** @type {import('../types').NormalizedErrorOverlayOptions} */

test/unit/getAdditionalEntries.test.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,33 @@ const ReactRefreshEntry = require.resolve('../../client/ReactRefreshEntry');
55

66
describe('getAdditionalEntries', () => {
77
it('should work with default settings', () => {
8-
expect(getAdditionalEntries({ overlay: { entry: ErrorOverlayEntry } })).toStrictEqual({
8+
expect(
9+
getAdditionalEntries({
10+
overlay: { entry: ErrorOverlayEntry },
11+
runtimeEntry: ReactRefreshEntry,
12+
})
13+
).toStrictEqual({
914
overlayEntries: [ErrorOverlayEntry],
1015
prependEntries: [ReactRefreshEntry],
1116
});
1217
});
1318

1419
it('should skip overlay entries when overlay is false in options', () => {
15-
expect(getAdditionalEntries({ overlay: false })).toStrictEqual({
20+
expect(
21+
getAdditionalEntries({
22+
overlay: false,
23+
runtimeEntry: ReactRefreshEntry,
24+
})
25+
).toStrictEqual({
1626
overlayEntries: [],
1727
prependEntries: [ReactRefreshEntry],
1828
});
1929
});
30+
31+
it('should skip prepend entries when runtimeEntry is false in options', () => {
32+
expect(getAdditionalEntries({ overlay: false, runtimeEntry: false })).toStrictEqual({
33+
overlayEntries: [],
34+
prependEntries: [],
35+
});
36+
});
2037
});

test/unit/normalizeOptions.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
const normalizeOptions = require('../../lib/utils/normalizeOptions');
22

3+
const ReactRefreshEntry = require.resolve('../../client/ReactRefreshEntry');
4+
35
/** @type {Partial<import('../../types/types').ReactRefreshPluginOptions>} */
46
const DEFAULT_OPTIONS = {
57
exclude: /node_modules/i,
68
include: /\.([cm]js|[jt]sx?|flow)$/i,
9+
runtimeEntry: ReactRefreshEntry,
710
overlay: {
811
entry: require.resolve('../../client/ErrorOverlayEntry'),
912
module: require.resolve('../../overlay'),
@@ -23,6 +26,7 @@ describe('normalizeOptions', () => {
2326
forceEnable: true,
2427
include: 'include',
2528
library: 'library',
29+
runtimeEntry: 'runtimeEntry',
2630
overlay: {
2731
entry: 'entry',
2832
module: 'overlay',
@@ -34,6 +38,7 @@ describe('normalizeOptions', () => {
3438
forceEnable: true,
3539
include: 'include',
3640
library: 'library',
41+
runtimeEntry: 'runtimeEntry',
3742
overlay: {
3843
entry: 'entry',
3944
module: 'overlay',
@@ -53,6 +58,13 @@ describe('normalizeOptions', () => {
5358
});
5459
});
5560

61+
it('should keep "runtimeEntry" when it is false', () => {
62+
expect(normalizeOptions({ runtimeEntry: false })).toStrictEqual({
63+
...DEFAULT_OPTIONS,
64+
runtimeEntry: false,
65+
});
66+
});
67+
5668
it('should keep "overlay.entry" when it is false', () => {
5769
const options = { ...DEFAULT_OPTIONS };
5870
options.overlay.entry = false;

test/unit/validateOptions.test.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,37 @@ describe('validateOptions', () => {
121121
`);
122122
});
123123

124+
it('should accept "runtimeEntry" when it is an absolute path string', () => {
125+
expect(() => {
126+
new ReactRefreshPlugin({ runtimeEntry: '/test' });
127+
}).not.toThrow();
128+
});
129+
130+
it('should accept "runtimeEntry" when it is a string', () => {
131+
expect(() => {
132+
new ReactRefreshPlugin({ runtimeEntry: 'test' });
133+
}).not.toThrow();
134+
});
135+
136+
it('should accept "runtimeEntry" when it is false', () => {
137+
expect(() => {
138+
new ReactRefreshPlugin({ runtimeEntry: false });
139+
}).not.toThrow();
140+
});
141+
142+
it('should reject "runtimeEntry" when it is not a string nor false', () => {
143+
expect(() => {
144+
new ReactRefreshPlugin({ runtimeEntry: true });
145+
}).toThrowErrorMatchingInlineSnapshot(`
146+
"Invalid options object. React Refresh Plugin has been initialized using an options object that does not match the API schema.
147+
- options.runtimeEntry should be one of these:
148+
false | string
149+
Details:
150+
* options.runtimeEntry should be equal to constant false.
151+
* options.runtimeEntry should be a string."
152+
`);
153+
});
154+
124155
it('should accept "overlay" when it is true', () => {
125156
expect(() => {
126157
new ReactRefreshPlugin({ overlay: true });
@@ -311,7 +342,7 @@ describe('validateOptions', () => {
311342
}).toThrowErrorMatchingInlineSnapshot(`
312343
"Invalid options object. React Refresh Plugin has been initialized using an options object that does not match the API schema.
313344
- options has an unknown property 'unknown'. These properties are valid:
314-
object { esModule?, exclude?, forceEnable?, include?, library?, overlay? }"
345+
object { esModule?, exclude?, forceEnable?, include?, library?, runtimeEntry?, overlay? }"
315346
`);
316347
});
317348
});

types/lib/types.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ export type ReactRefreshPluginOptions = {
4343
* Modifies how the error overlay integration works in the plugin.
4444
*/
4545
overlay?: boolean | ErrorOverlayOptions | undefined;
46+
/**
47+
* Runtime entry to prepend to Webpack entries, or false to disable automatic
48+
* injection.
49+
*/
50+
runtimeEntry?: string | false | undefined;
4651
};
4752
export type OverlayOverrides = {
4853
/**
@@ -52,6 +57,6 @@ export type OverlayOverrides = {
5257
};
5358
export type NormalizedPluginOptions = import('type-fest').SetRequired<
5459
import('type-fest').Except<ReactRefreshPluginOptions, 'overlay'>,
55-
'exclude' | 'include'
60+
'exclude' | 'include' | 'runtimeEntry'
5661
> &
5762
OverlayOverrides;

0 commit comments

Comments
 (0)