@rspack/plugin-react-refresh 1.0.0-beta.5 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -6
- package/dist/index.js +5 -16
- package/dist/options.d.ts +30 -3
- package/dist/options.js +1 -2
- package/dist/paths.d.ts +5 -0
- package/dist/paths.js +19 -0
- package/dist/sockets/WDSSocket.js +1 -2
- package/dist/sockets/utils/getCurrentScriptSource.js +1 -1
- package/dist/sockets/utils/getSocketUrlParts.js +1 -1
- package/dist/sockets/utils/getUrlFromParts.js +1 -1
- package/dist/sockets/utils/getWDSMetadata.js +1 -1
- package/dist/utils/getAdditionalEntries.js +3 -3
- package/dist/utils/getSocketIntegration.js +1 -2
- package/package.json +12 -13
package/README.md
CHANGED
@@ -5,6 +5,12 @@
|
|
5
5
|
|
6
6
|
# @rspack/plugin-react-refresh
|
7
7
|
|
8
|
+
<p>
|
9
|
+
<a href="https://www.npmjs.com/package/@rspack/plugin-react-refresh?activeTab=readme"><img src="https://img.shields.io/npm/v/@rspack/plugin-react-refresh?style=flat-square&colorA=564341&colorB=EDED91" alt="npm version" /></a>
|
10
|
+
<a href="https://npmcharts.com/compare/@rspack/plugin-react-refresh?minimal=true"><img src="https://img.shields.io/npm/dm/@rspack/plugin-react-refresh.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="downloads" /></a>
|
11
|
+
<a href="https://github.com/web-infra-dev/rspack/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="license" /></a>
|
12
|
+
</p>
|
13
|
+
|
8
14
|
React refresh plugin for [Rspack](https://github.com/web-infra-dev/rspack).
|
9
15
|
|
10
16
|
## Installation
|
@@ -29,8 +35,8 @@ Enabling [React Fast Refresh](https://reactnative.dev/docs/fast-refresh) functio
|
|
29
35
|
- Code transformation can be added through loaders, such as [jsc.transform.react.refresh](https://swc.rs/docs/configuration/compilation#jsctransformreactrefresh) for [swc-loader](https://swc.rs/docs/usage/swc-loader) or the [react-refresh/babel](https://github.com/facebook/react/tree/main/packages/react-refresh) for [babel-loader](https://github.com/babel/babel-loader).
|
30
36
|
|
31
37
|
```js
|
32
|
-
const ReactRefreshPlugin = require(
|
33
|
-
const isDev = process.env.NODE_ENV ===
|
38
|
+
const ReactRefreshPlugin = require("@rspack/plugin-react-refresh");
|
39
|
+
const isDev = process.env.NODE_ENV === "development";
|
34
40
|
|
35
41
|
module.exports = {
|
36
42
|
experiments: {
|
@@ -39,17 +45,17 @@ module.exports = {
|
|
39
45
|
},
|
40
46
|
},
|
41
47
|
// ...
|
42
|
-
mode: isDev ?
|
48
|
+
mode: isDev ? "development" : "production",
|
43
49
|
module: {
|
44
50
|
rules: [
|
45
51
|
{
|
46
52
|
test: /\.jsx$/,
|
47
53
|
use: {
|
48
|
-
loader:
|
54
|
+
loader: "builtin:swc-loader",
|
49
55
|
options: {
|
50
56
|
jsc: {
|
51
57
|
parser: {
|
52
|
-
syntax:
|
58
|
+
syntax: "ecmascript",
|
53
59
|
jsx: true,
|
54
60
|
},
|
55
61
|
transform: {
|
@@ -75,6 +81,93 @@ Compared to the previous approach, this method decouples the React Fast Refresh
|
|
75
81
|
- For usage with `builtin:swc-loader`, you can refer to the example at [examples/react-refresh](https://github.com/rspack-contrib/rspack-examples/tree/main/rspack/react-refresh/rspack.config.js), When using with `swc-loader`, simply replace `builtin:swc-loader` with `swc-loader`.
|
76
82
|
- For usage with `babel-loader`, you can refer to the example at [examples/react-refresh-babel-loader](https://github.com/rspack-contrib/rspack-examples/tree/main/rspack/react-refresh-babel-loader/rspack.config.js)
|
77
83
|
|
84
|
+
## Options
|
85
|
+
|
86
|
+
### include
|
87
|
+
|
88
|
+
- Type: [Rspack.RuleSetCondition](https://rspack.dev/config/module#condition)
|
89
|
+
- Default: `/\.([cm]js|[jt]sx?|flow)$/i`
|
90
|
+
|
91
|
+
Include files to be processed by the plugin. The value is the same as the `rule.test` option in Rspack.
|
92
|
+
|
93
|
+
```js
|
94
|
+
new ReactRefreshPlugin({
|
95
|
+
include: [/\.jsx$/, /\.tsx$/],
|
96
|
+
});
|
97
|
+
```
|
98
|
+
|
99
|
+
### exclude
|
100
|
+
|
101
|
+
- Type: [Rspack.RuleSetCondition](https://rspack.dev/config/module#condition)
|
102
|
+
- Default: `/node_modules/`
|
103
|
+
|
104
|
+
Exclude files from being processed by the plugin. The value is the same as the `rule.exclude` option in Rspack.
|
105
|
+
|
106
|
+
```js
|
107
|
+
new ReactRefreshPlugin({
|
108
|
+
exclude: [/node_modules/, /some-other-module/],
|
109
|
+
});
|
110
|
+
```
|
111
|
+
|
112
|
+
### forceEnable
|
113
|
+
|
114
|
+
- Type: `boolean`
|
115
|
+
- Default: `false`
|
116
|
+
|
117
|
+
Whether to force enable the plugin.
|
118
|
+
|
119
|
+
By default, the plugin will not be enabled in non-development environments. If you want to force enable the plugin, you can set this option to `true`.
|
120
|
+
|
121
|
+
```js
|
122
|
+
new ReactRefreshPlugin({
|
123
|
+
forceEnable: true,
|
124
|
+
});
|
125
|
+
```
|
126
|
+
|
127
|
+
It is useful if you want to:
|
128
|
+
|
129
|
+
- Use the plugin in production.
|
130
|
+
- Use the plugin with the `none` mode without setting `NODE_ENV`.
|
131
|
+
- Use the plugin in environments we do not support, such as `electron-prerender` (**WARNING: Proceed at your own risk**).
|
132
|
+
|
133
|
+
### library
|
134
|
+
|
135
|
+
- Type: `string`
|
136
|
+
- Default: `output.uniqueName || output.library`
|
137
|
+
|
138
|
+
Sets a namespace for the React Refresh runtime.
|
139
|
+
|
140
|
+
It is most useful when multiple instances of React Refresh is running together simultaneously.
|
141
|
+
|
142
|
+
### overlay
|
143
|
+
|
144
|
+
- Type: `boolean | OverlayOptions`
|
145
|
+
- Default: `false`
|
146
|
+
|
147
|
+
Modify the behavior of the error overlay.
|
148
|
+
|
149
|
+
- Enable the error overlay:
|
150
|
+
|
151
|
+
```js
|
152
|
+
new ReactRefreshPlugin({
|
153
|
+
overlay: true,
|
154
|
+
});
|
155
|
+
```
|
156
|
+
|
157
|
+
- Configure the error overlay:
|
158
|
+
|
159
|
+
```js
|
160
|
+
new ReactRefreshPlugin({
|
161
|
+
overlay: {
|
162
|
+
// ...
|
163
|
+
},
|
164
|
+
});
|
165
|
+
```
|
166
|
+
|
167
|
+
## Credits
|
168
|
+
|
169
|
+
Thanks to the [react-refresh-webpack-plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin) created by [@pmmmwh](https://github.com/pmmmwh), which inspires implement this plugin.
|
170
|
+
|
78
171
|
## License
|
79
172
|
|
80
|
-
|
173
|
+
`@rspack/plugin-react-refresh` is [MIT licensed](https://github.com/web-infra-dev/rspack/blob/main/LICENSE).
|
package/dist/index.js
CHANGED
@@ -4,20 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
4
|
};
|
5
5
|
const node_path_1 = __importDefault(require("node:path"));
|
6
6
|
const options_1 = require("./options");
|
7
|
+
const paths_1 = require("./paths");
|
7
8
|
const getAdditionalEntries_1 = require("./utils/getAdditionalEntries");
|
8
9
|
const getSocketIntegration_1 = require("./utils/getSocketIntegration");
|
9
|
-
const reactRefreshPath = require.resolve('../client/reactRefresh.js');
|
10
|
-
const reactRefreshEntryPath = require.resolve('../client/reactRefreshEntry.js');
|
11
|
-
const refreshUtilsPath = require.resolve('../client/refreshUtils.js');
|
12
|
-
const refreshRuntimeDirPath = node_path_1.default.dirname(require.resolve('react-refresh', {
|
13
|
-
paths: [reactRefreshPath],
|
14
|
-
}));
|
15
|
-
const runtimePaths = [
|
16
|
-
reactRefreshEntryPath,
|
17
|
-
reactRefreshPath,
|
18
|
-
refreshUtilsPath,
|
19
|
-
refreshRuntimeDirPath,
|
20
|
-
];
|
21
10
|
class ReactRefreshRspackPlugin {
|
22
11
|
constructor(options = {}) {
|
23
12
|
this.options = (0, options_1.normalizeOptions)(options);
|
@@ -48,14 +37,14 @@ class ReactRefreshRspackPlugin {
|
|
48
37
|
}).apply(compiler);
|
49
38
|
}
|
50
39
|
new compiler.webpack.ProvidePlugin({
|
51
|
-
$ReactRefreshRuntime$: reactRefreshPath,
|
40
|
+
$ReactRefreshRuntime$: paths_1.reactRefreshPath,
|
52
41
|
}).apply(compiler);
|
53
42
|
compiler.options.module.rules.unshift({
|
54
43
|
// biome-ignore lint: exists
|
55
44
|
include: this.options.include,
|
56
45
|
exclude: {
|
57
46
|
// biome-ignore lint: exists
|
58
|
-
or: [this.options.exclude, [...runtimePaths]].filter(Boolean),
|
47
|
+
or: [this.options.exclude, [...paths_1.runtimePaths]].filter(Boolean),
|
59
48
|
},
|
60
49
|
use: 'builtin:react-refresh-loader',
|
61
50
|
});
|
@@ -66,7 +55,7 @@ class ReactRefreshRspackPlugin {
|
|
66
55
|
compiler.options.output.library)),
|
67
56
|
};
|
68
57
|
const providedModules = {
|
69
|
-
__react_refresh_utils__: refreshUtilsPath,
|
58
|
+
__react_refresh_utils__: paths_1.refreshUtilsPath,
|
70
59
|
};
|
71
60
|
if (this.options.overlay === false) {
|
72
61
|
// Stub errorOverlay module so their calls can be erased
|
@@ -90,5 +79,5 @@ class ReactRefreshRspackPlugin {
|
|
90
79
|
};
|
91
80
|
}
|
92
81
|
}
|
93
|
-
ReactRefreshRspackPlugin.deprecated_runtimePaths = runtimePaths;
|
82
|
+
ReactRefreshRspackPlugin.deprecated_runtimePaths = paths_1.runtimePaths;
|
94
83
|
module.exports = ReactRefreshRspackPlugin;
|
package/dist/options.d.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import type { RuleSetCondition } from '@rspack/core';
|
1
2
|
import type { IntegrationType } from './utils/getSocketIntegration';
|
2
3
|
interface OverlayOptions {
|
3
4
|
entry: string;
|
@@ -9,11 +10,37 @@ interface OverlayOptions {
|
|
9
10
|
sockProtocol?: string;
|
10
11
|
}
|
11
12
|
export type PluginOptions = {
|
12
|
-
|
13
|
-
|
13
|
+
/**
|
14
|
+
* Include files to be processed by the plugin.
|
15
|
+
* The value is the same as the `rule.test` option in Rspack.
|
16
|
+
* @default /\.([cm]js|[jt]sx?|flow)$/i
|
17
|
+
*/
|
18
|
+
include?: RuleSetCondition | null;
|
19
|
+
/**
|
20
|
+
* Exclude files from being processed by the plugin.
|
21
|
+
* The value is the same as the `rule.exclude` option in Rspack.
|
22
|
+
* @default /node_modules/
|
23
|
+
*/
|
24
|
+
exclude?: RuleSetCondition | null;
|
25
|
+
/**
|
26
|
+
* Sets a namespace for the React Refresh runtime.
|
27
|
+
* It is most useful when multiple instances of React Refresh is running
|
28
|
+
* together simultaneously.
|
29
|
+
* @default `output.uniqueName || output.library`
|
30
|
+
*/
|
14
31
|
library?: string;
|
32
|
+
/**
|
33
|
+
* Whether to force enable the plugin.
|
34
|
+
* By default, the plugin will not be enabled in non-development environments.
|
35
|
+
* If you want to force enable the plugin, you can set this option to `true`.
|
36
|
+
* @default false
|
37
|
+
*/
|
15
38
|
forceEnable?: boolean;
|
16
|
-
|
39
|
+
/**
|
40
|
+
* Modify the behavior of the error overlay.
|
41
|
+
* @default false
|
42
|
+
*/
|
43
|
+
overlay?: boolean | Partial<OverlayOptions>;
|
17
44
|
};
|
18
45
|
export interface NormalizedPluginOptions extends Required<PluginOptions> {
|
19
46
|
overlay: false | OverlayOptions;
|
package/dist/options.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.normalizeOptions =
|
3
|
+
exports.normalizeOptions = normalizeOptions;
|
4
4
|
const d = (object, property, defaultValue) => {
|
5
5
|
// TODO: should we also add default for null?
|
6
6
|
if (typeof object[property] === 'undefined' &&
|
@@ -35,4 +35,3 @@ function normalizeOptions(options) {
|
|
35
35
|
options.overlay = normalizeOverlay(options.overlay);
|
36
36
|
return options;
|
37
37
|
}
|
38
|
-
exports.normalizeOptions = normalizeOptions;
|
package/dist/paths.d.ts
ADDED
package/dist/paths.js
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.runtimePaths = exports.refreshRuntimeDirPath = exports.refreshUtilsPath = exports.reactRefreshEntryPath = exports.reactRefreshPath = void 0;
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
8
|
+
exports.reactRefreshPath = require.resolve('../client/reactRefresh.js');
|
9
|
+
exports.reactRefreshEntryPath = require.resolve('../client/reactRefreshEntry.js');
|
10
|
+
exports.refreshUtilsPath = require.resolve('../client/refreshUtils.js');
|
11
|
+
exports.refreshRuntimeDirPath = node_path_1.default.dirname(require.resolve('react-refresh', {
|
12
|
+
paths: [exports.reactRefreshPath],
|
13
|
+
}));
|
14
|
+
exports.runtimePaths = [
|
15
|
+
exports.reactRefreshEntryPath,
|
16
|
+
exports.reactRefreshPath,
|
17
|
+
exports.refreshUtilsPath,
|
18
|
+
exports.refreshRuntimeDirPath,
|
19
|
+
];
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.init =
|
6
|
+
exports.init = init;
|
7
7
|
/**
|
8
8
|
* The following code is modified based on
|
9
9
|
* https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/f1c8b9a44198449093ca95f85af5df97925e1cfc/sockets/WDSSocket.js
|
@@ -40,4 +40,3 @@ function init(messageHandler, resourceQuery) {
|
|
40
40
|
});
|
41
41
|
}
|
42
42
|
}
|
43
|
-
exports.init = init;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.default = getCurrentScriptSource;
|
3
4
|
function getCurrentScriptSource() {
|
4
5
|
// `document.currentScript` is the most accurate way to get the current running script,
|
5
6
|
// but is not supported in all browsers (most notably, IE).
|
@@ -19,4 +20,3 @@ function getCurrentScriptSource() {
|
|
19
20
|
const currentScript = scriptElementsWithSrc[scriptElementsWithSrc.length - 1];
|
20
21
|
return currentScript.getAttribute('src');
|
21
22
|
}
|
22
|
-
exports.default = getCurrentScriptSource;
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.default = getSocketUrlParts;
|
6
7
|
const getCurrentScriptSource_1 = __importDefault(require("./getCurrentScriptSource"));
|
7
8
|
function getSocketUrlParts(resourceQuery, metadata = {}) {
|
8
9
|
const urlParts = {};
|
@@ -105,4 +106,3 @@ function getSocketUrlParts(resourceQuery, metadata = {}) {
|
|
105
106
|
port: urlParts.port || undefined,
|
106
107
|
};
|
107
108
|
}
|
108
|
-
exports.default = getSocketUrlParts;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.default = urlFromParts;
|
3
4
|
/**
|
4
5
|
* Create a valid URL from parsed URL parts.
|
5
6
|
* @param urlParts The parsed URL parts.
|
@@ -26,4 +27,3 @@ function urlFromParts(urlParts, metadata = {}) {
|
|
26
27
|
const url = new URL(urlParts.pathname, fullProtocol + fullHost);
|
27
28
|
return url.href;
|
28
29
|
}
|
29
|
-
exports.default = urlFromParts;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.default = getWDSMetadata;
|
3
4
|
function getWDSMetadata(SocketClient) {
|
4
5
|
let enforceWs = false;
|
5
6
|
if (typeof SocketClient.name !== 'undefined' &&
|
@@ -27,4 +28,3 @@ function getWDSMetadata(SocketClient) {
|
|
27
28
|
version: version,
|
28
29
|
};
|
29
30
|
}
|
30
|
-
exports.default = getWDSMetadata;
|
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.getAdditionalEntries =
|
6
|
+
exports.getAdditionalEntries = getAdditionalEntries;
|
7
7
|
const node_querystring_1 = __importDefault(require("node:querystring"));
|
8
|
+
const paths_1 = require("../paths");
|
8
9
|
function getAdditionalEntries({ devServer, options, }) {
|
9
10
|
const resourceQuery = {};
|
10
11
|
if (devServer) {
|
@@ -75,7 +76,7 @@ function getAdditionalEntries({ devServer, options, }) {
|
|
75
76
|
});
|
76
77
|
const prependEntries = [
|
77
78
|
// React-refresh runtime
|
78
|
-
|
79
|
+
paths_1.reactRefreshEntryPath,
|
79
80
|
];
|
80
81
|
const overlayEntries = [
|
81
82
|
// Error overlay runtime
|
@@ -85,4 +86,3 @@ function getAdditionalEntries({ devServer, options, }) {
|
|
85
86
|
].filter(Boolean);
|
86
87
|
return { prependEntries, overlayEntries };
|
87
88
|
}
|
88
|
-
exports.getAdditionalEntries = getAdditionalEntries;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.getSocketIntegration =
|
3
|
+
exports.getSocketIntegration = getSocketIntegration;
|
4
4
|
function getSocketIntegration(integrationType) {
|
5
5
|
let resolvedSocketIntegration;
|
6
6
|
switch (integrationType) {
|
@@ -15,4 +15,3 @@ function getSocketIntegration(integrationType) {
|
|
15
15
|
}
|
16
16
|
return resolvedSocketIntegration;
|
17
17
|
}
|
18
|
-
exports.getSocketIntegration = getSocketIntegration;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@rspack/plugin-react-refresh",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.1",
|
4
4
|
"repository": "https://github.com/rspack-contrib/rspack-plugin-react-refresh",
|
5
5
|
"license": "MIT",
|
6
6
|
"description": "React refresh plugin for rspack",
|
@@ -12,6 +12,7 @@
|
|
12
12
|
},
|
13
13
|
"./react-refresh": "./client/reactRefresh.js",
|
14
14
|
"./react-refresh-entry": "./client/reactRefreshEntry.js",
|
15
|
+
"./overlay": "./client/overlay/index.js",
|
15
16
|
"./package.json": "./package.json"
|
16
17
|
},
|
17
18
|
"files": [
|
@@ -27,15 +28,13 @@
|
|
27
28
|
]
|
28
29
|
},
|
29
30
|
"devDependencies": {
|
30
|
-
"@biomejs/biome": "^1.
|
31
|
-
"@rspack/core": "1.
|
32
|
-
"@
|
33
|
-
"@
|
34
|
-
"
|
35
|
-
"@types/jest": "29.5.12",
|
36
|
-
"react-refresh": "^0.14.0",
|
31
|
+
"@biomejs/biome": "^1.9.4",
|
32
|
+
"@rspack/core": "1.1.4",
|
33
|
+
"@types/node": "^22.10.1",
|
34
|
+
"@types/jest": "29.5.14",
|
35
|
+
"react-refresh": "^0.14.2",
|
37
36
|
"cross-env": "^7.0.3",
|
38
|
-
"execa": "9.
|
37
|
+
"execa": "9.5.1",
|
39
38
|
"fs-extra": "11.2.0",
|
40
39
|
"jest": "29.7.0",
|
41
40
|
"jest-cli": "29.7.0",
|
@@ -43,12 +42,12 @@
|
|
43
42
|
"nano-staged": "^0.8.0",
|
44
43
|
"semver": "7.6.3",
|
45
44
|
"simple-git-hooks": "^2.11.1",
|
46
|
-
"ts-jest": "29.
|
47
|
-
"typescript": "5.
|
45
|
+
"ts-jest": "29.2.5",
|
46
|
+
"typescript": "5.7.2"
|
48
47
|
},
|
49
48
|
"dependencies": {
|
50
|
-
"error-stack-parser": "^2.
|
51
|
-
"html-entities": "^2.
|
49
|
+
"error-stack-parser": "^2.1.4",
|
50
|
+
"html-entities": "^2.5.2"
|
52
51
|
},
|
53
52
|
"peerDependencies": {
|
54
53
|
"react-refresh": ">=0.10.0 <1.0.0"
|