diff --git a/packages/cli/package.json b/packages/cli/package.json index c74b6b502b..52b4d23aa2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -29,6 +29,7 @@ "backstage-cli": "bin/backstage-cli" }, "dependencies": { + "@hot-loader/react-dom": "^16.13.0", "@lerna/package-graph": "^3.18.5", "@lerna/project": "^3.18.0", "@rollup/plugin-commonjs": "^11.0.2", @@ -54,6 +55,7 @@ "ora": "^4.0.3", "react": "^16.0.0", "react-dev-utils": "^10.2.0", + "react-hot-loader": "^4.12.21", "react-scripts": "^3.4.1", "recursive-readdir": "^2.2.2", "replace-in-file": "^6.0.0", diff --git a/packages/cli/src/lib/bundle/config.ts b/packages/cli/src/lib/bundle/config.ts index f172746ce3..fc2dbc3173 100644 --- a/packages/cli/src/lib/bundle/config.ts +++ b/packages/cli/src/lib/bundle/config.ts @@ -38,11 +38,7 @@ export function createConfig(options: BundlingOptions): webpack.Configuration { bail: false, devtool: 'cheap-module-eval-source-map', context: paths.targetPath, - entry: [ - `${require.resolve('webpack-dev-server/client')}?/`, - require.resolve('webpack/hot/dev-server'), - paths.targetDevEntry, - ], + entry: [require.resolve('react-hot-loader/patch'), paths.targetDevEntry], resolve: { extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'], mainFields: ['main:src', 'browser', 'module', 'main'], @@ -52,6 +48,9 @@ export function createConfig(options: BundlingOptions): webpack.Configuration { [paths.targetPackageJson], ), ], + alias: { + 'react-dom': '@hot-loader/react-dom', + }, }, module: { rules: [ @@ -71,7 +70,7 @@ export function createConfig(options: BundlingOptions): webpack.Configuration { exclude: /node_modules/, loader: '@sucrase/webpack-loader', options: { - transforms: ['typescript', 'jsx'], + transforms: ['typescript', 'jsx', 'react-hot-loader'], }, }, { @@ -79,7 +78,7 @@ export function createConfig(options: BundlingOptions): webpack.Configuration { exclude: /node_modules/, loader: '@sucrase/webpack-loader', options: { - transforms: ['jsx'], + transforms: ['jsx', 'react-hot-loader'], }, }, { diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index bd532bdd50..1733392696 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -41,6 +41,7 @@ "@types/node": "^12.0.0", "react": "^16.12.0", "react-dom": "^16.12.0", + "react-hot-loader": "^4.12.21", "react-router": "^5.2.0", "react-router-dom": "^5.2.0" }, diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx index 90a0847b4d..b251ebfb6d 100644 --- a/packages/dev-utils/src/devApp/render.tsx +++ b/packages/dev-utils/src/devApp/render.tsx @@ -14,6 +14,7 @@ * limitations under the License. */ +import { hot } from 'react-hot-loader/root'; import React, { FC, ComponentType } from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; @@ -90,10 +91,10 @@ class DevAppBuilder { } /** - * Build and render directory to #root element + * Build and render directory to #root element, with react hot loading. */ render(): void { - const DevApp = this.build(); + const DevApp = hot(this.build()); const paths = this.findPluginPaths(this.plugins); diff --git a/yarn.lock b/yarn.lock index 123ea40293..0bfef7c122 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1427,6 +1427,16 @@ dependencies: "@hapi/hoek" "^8.3.0" +"@hot-loader/react-dom@^16.13.0": + version "16.13.0" + resolved "https://registry.npmjs.org/@hot-loader/react-dom/-/react-dom-16.13.0.tgz#de245b42358110baf80aaf47a0592153d4047997" + integrity sha512-lJZrmkucz2MrQJTQtJobx5MICXcfQvKihszqv655p557HPi0hMOWxrNpiHv3DWD8ugNWjtWcVWqRnFvwsHq1mQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.0" + "@iarna/cli@^1.2.0": version "1.2.0" resolved "https://registry.npmjs.org/@iarna/cli/-/cli-1.2.0.tgz#0f7af5e851afe895104583c4ca07377a8094d641" @@ -9689,7 +9699,7 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -10624,7 +10634,7 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -global@^4.3.2, global@^4.4.0: +global@^4.3.0, global@^4.3.2, global@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== @@ -17983,6 +17993,20 @@ react-hook-form@^5.7.2: resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-5.7.2.tgz#a84e259e5d37dd30949af4f79c4dac31101b79ac" integrity sha512-bJvY348vayIvEUmSK7Fvea/NgqbT2racA2IbnJz/aPlQ3GBtaTeDITH6rtCa6y++obZzG6E3Q8VuoXPir7QYUg== +react-hot-loader@^4.12.21: + version "4.12.21" + resolved "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.12.21.tgz#332e830801fb33024b5a147d6b13417f491eb975" + integrity sha512-Ynxa6ROfWUeKWsTHxsrL2KMzujxJVPjs385lmB2t5cHUxdoRPGind9F00tOkdc1l5WBleOF4XEAMILY1KPIIDA== + dependencies: + fast-levenshtein "^2.0.6" + global "^4.3.0" + hoist-non-react-statics "^3.3.0" + loader-utils "^1.1.0" + prop-types "^15.6.1" + react-lifecycles-compat "^3.0.4" + shallowequal "^1.1.0" + source-map "^0.7.3" + react-hotkeys@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz#a7719c7340cbba888b0e9184f806a9ec0ac2c53f" @@ -19184,7 +19208,7 @@ saxes@^3.1.9: dependencies: xmlchars "^2.1.1" -scheduler@^0.19.1: +scheduler@^0.19.0, scheduler@^0.19.1: version "0.19.1" resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==