From 983a81d677ed5f6f6b3d19813b9e3302d1a7165a Mon Sep 17 00:00:00 2001 From: Ryan Tremblay Date: Tue, 8 Jul 2025 14:07:46 -0700 Subject: [PATCH 1/3] Add fast refresh to sandbox and playground --- package-lock.json | 6 ++++++ packages/dev/inspector-v2/webpack.config.js | 4 ++-- packages/tools/playground/package.json | 3 +++ packages/tools/playground/webpack.config.js | 9 ++++++++- packages/tools/sandbox/package.json | 3 +++ packages/tools/sandbox/webpack.config.js | 16 ++++++++++++++-- 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index fe9e9787559..c50c37a888d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29354,6 +29354,7 @@ "devDependencies": { "@dev/build-tools": "1.0.0", "@dev/core": "1.0.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.6.0", "@svgr/webpack": "^7.0.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", @@ -29366,6 +29367,8 @@ "monaco-editor-webpack-plugin": "^4.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-refresh": "^0.17.0", + "react-refresh-typescript": "^2.0.10", "sass-loader": "^16.0.0", "style-loader": "^3.3.0", "ts-debounce": "4.0.0", @@ -29405,6 +29408,7 @@ "@dev/core": "1.0.0", "@dev/inspector-v2": "1.0.0", "@dev/loaders": "1.0.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.6.0", "@svgr/webpack": "^7.0.0", "@types/dagre": "^0.7.47", "@types/react": "^18.0.0", @@ -29414,6 +29418,8 @@ "file-loader": "^6.2.0", "html-webpack-plugin": "^5.4.0", "mini-css-extract-plugin": "^2.4.3", + "react-refresh": "^0.17.0", + "react-refresh-typescript": "^2.0.10", "sass-loader": "^16.0.0", "style-loader": "^3.3.0", "url-loader": "^4.1.1", diff --git a/packages/dev/inspector-v2/webpack.config.js b/packages/dev/inspector-v2/webpack.config.js index 0c0f5848f71..93774ced901 100644 --- a/packages/dev/inspector-v2/webpack.config.js +++ b/packages/dev/inspector-v2/webpack.config.js @@ -38,13 +38,13 @@ module.exports = (env) => { tsOptions: { configFile: "tsconfig.build.json", getCustomTransformers: () => ({ - before: [ReactRefreshTypeScript()].filter(Boolean), + before: [ReactRefreshTypeScript()], }), transpileOnly: true, }, }), }, - plugins: [new ReactRefreshWebpackPlugin()].filter(Boolean), + plugins: [new ReactRefreshWebpackPlugin()], }; }; diff --git a/packages/tools/playground/package.json b/packages/tools/playground/package.json index 845806f2121..f97268bcfd3 100644 --- a/packages/tools/playground/package.json +++ b/packages/tools/playground/package.json @@ -15,6 +15,7 @@ "devDependencies": { "@dev/build-tools": "1.0.0", "@dev/core": "1.0.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.6.0", "@svgr/webpack": "^7.0.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", @@ -27,6 +28,8 @@ "monaco-editor-webpack-plugin": "^4.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-refresh": "^0.17.0", + "react-refresh-typescript": "^2.0.10", "sass-loader": "^16.0.0", "style-loader": "^3.3.0", "ts-debounce": "4.0.0", diff --git a/packages/tools/playground/webpack.config.js b/packages/tools/playground/webpack.config.js index ea42e68d144..5244bb264e2 100644 --- a/packages/tools/playground/webpack.config.js +++ b/packages/tools/playground/webpack.config.js @@ -1,6 +1,8 @@ const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin"); const webpackTools = require("@dev/build-tools").webpackTools; const path = require("path"); +const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); +const ReactRefreshTypeScript = require("react-refresh-typescript").default; module.exports = (env) => { const commonConfig = { @@ -10,6 +12,7 @@ module.exports = (env) => { ...env, outputFilename: "babylon.playground.js", dirName: __dirname, + enableHotReload: true, }, { static: ["public"], @@ -67,6 +70,9 @@ module.exports = (env) => { compilerOptions: { rootDir: "../../", }, + getCustomTransformers: () => ({ + before: [!env.production && ReactRefreshTypeScript()].filter(Boolean), + }), }, }), }, @@ -75,7 +81,8 @@ module.exports = (env) => { // publicPath: "public/", languages: ["typescript", "javascript"], }), - ], + !env.production && new ReactRefreshWebpackPlugin(), + ].filter(Boolean), }; return commonConfig; }; diff --git a/packages/tools/sandbox/package.json b/packages/tools/sandbox/package.json index ae00599feac..84129045ca2 100644 --- a/packages/tools/sandbox/package.json +++ b/packages/tools/sandbox/package.json @@ -29,6 +29,7 @@ "@dev/core": "1.0.0", "@dev/loaders": "1.0.0", "@dev/inspector-v2": "1.0.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.6.0", "@svgr/webpack": "^7.0.0", "@types/dagre": "^0.7.47", "@types/react": "^18.0.0", @@ -38,6 +39,8 @@ "file-loader": "^6.2.0", "html-webpack-plugin": "^5.4.0", "mini-css-extract-plugin": "^2.4.3", + "react-refresh": "^0.17.0", + "react-refresh-typescript": "^2.0.10", "sass-loader": "^16.0.0", "style-loader": "^3.3.0", "url-loader": "^4.1.1", diff --git a/packages/tools/sandbox/webpack.config.js b/packages/tools/sandbox/webpack.config.js index c61d08088c9..0b293210172 100644 --- a/packages/tools/sandbox/webpack.config.js +++ b/packages/tools/sandbox/webpack.config.js @@ -1,5 +1,7 @@ const path = require("path"); const webpackTools = require("@dev/build-tools").webpackTools; +const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); +const ReactRefreshTypeScript = require("react-refresh-typescript").default; module.exports = (env) => { const commonConfig = { @@ -9,6 +11,7 @@ module.exports = (env) => { ...env, outputFilename: "babylon.sandbox.js", dirName: __dirname, + enableHotReload: true, }, { static: ["public"], @@ -50,9 +53,18 @@ module.exports = (env) => { // React, react dom etc' ], module: { - rules: webpackTools.getRules(), + rules: webpackTools.getRules({ + includeAssets: true, + includeCSS: true, + sideEffects: true, + tsOptions: { + getCustomTransformers: () => ({ + before: [!env.production && ReactRefreshTypeScript()].filter(Boolean), + }), + }, + }), }, - plugins: [], + plugins: [!env.production && new ReactRefreshWebpackPlugin()].filter(Boolean), }; return commonConfig; }; From ade35960074c26ee3c3cce9b310f48128a057213 Mon Sep 17 00:00:00 2001 From: Ryan Tremblay Date: Mon, 14 Jul 2025 13:42:07 -0700 Subject: [PATCH 2/3] Move fast refresh configuration into shared webpack tools --- packages/dev/buildTools/src/webpackTools.ts | 30 ++++++++++++++++++--- packages/dev/inspector-v2/webpack.config.js | 8 +----- packages/tools/playground/webpack.config.js | 21 ++++++--------- packages/tools/sandbox/webpack.config.js | 9 +------ 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/packages/dev/buildTools/src/webpackTools.ts b/packages/dev/buildTools/src/webpackTools.ts index 02a3cd321c8..227acf50652 100644 --- a/packages/dev/buildTools/src/webpackTools.ts +++ b/packages/dev/buildTools/src/webpackTools.ts @@ -5,7 +5,9 @@ import type { BuildType, DevPackageName, UMDPackageName } from "./packageMapping import { getPackageMappingByDevName, getPublicPackageName, isValidDevPackageName, umdPackageMapping } from "./packageMapping.js"; import * as path from "path"; import { camelize, copyFile } from "./utils.js"; -import type { RuleSetRule, Configuration, Compiler } from "webpack"; +import type { RuleSetRule, Configuration, Compiler, WebpackPluginInstance } from "webpack"; +import * as ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin"; +import ReactRefreshTypeScript from "react-refresh-typescript"; // eslint-disable-next-line @typescript-eslint/naming-convention export const externalsFunction = (excludePackages: string[] = [], type: BuildType = "umd") => { @@ -65,12 +67,22 @@ export const getRules = ( resourceType?: "asset/inline" | "asset/resource"; extraRules?: RuleSetRule[]; mode?: "development" | "production"; + enableFastRefresh?: boolean; // for react fast refresh } = { includeAssets: true, includeCSS: true, sideEffects: true, } ) => { + const getCustomTransformers = options.enableFastRefresh + ? (program: ts.Program) => { + const transformers: ts.CustomTransformers = options?.tsOptions?.getCustomTransformers?.(program) ?? {}; + transformers.before = transformers.before ?? []; + transformers.before.push(ReactRefreshTypeScript()); + return transformers; + } + : options?.tsOptions?.getCustomTransformers; + const rules: RuleSetRule[] = [ { test: /\.tsx?$/, @@ -79,7 +91,7 @@ export const getRules = ( sideEffects: options.sideEffects, options: { configFile: "tsconfig.build.json", - ...options.tsOptions, + ...{ ...options.tsOptions, getCustomTransformers }, }, }, { @@ -177,9 +189,18 @@ export const commonDevWebpackConfiguration = ( port: number; static?: string[]; showBuildProgress?: boolean; - } + }, + additionalPlugins?: WebpackPluginInstance[] ) => { const production = env.mode === "production" || process.env.NODE_ENV === "production"; + const enableHotReload = (env.enableHotReload !== undefined || process.env.ENABLE_HOT_RELOAD === "true") && !production ? true : false; + + let plugins: WebpackPluginInstance[] | undefined = additionalPlugins; + if (devServerConfig && enableHotReload) { + plugins = plugins ?? []; + plugins.push(new ReactRefreshWebpackPlugin()); + } + return { mode: production ? "production" : "development", devtool: production ? "source-map" : "inline-cheap-module-source-map", @@ -190,7 +211,7 @@ export const commonDevWebpackConfiguration = ( webSocketServer: production ? false : "ws", compress: production, server: env.enableHttps !== undefined || process.env.ENABLE_HTTPS === "true" ? "https" : "http", - hot: (env.enableHotReload !== undefined || process.env.ENABLE_HOT_RELOAD === "true") && !production ? true : false, + hot: enableHotReload, liveReload: (env.enableLiveReload !== undefined || process.env.ENABLE_LIVE_RELOAD === "true") && !production ? true : false, headers: { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -217,6 +238,7 @@ export const commonDevWebpackConfiguration = ( devtoolModuleFilenameTemplate: production ? "webpack://[namespace]/[resource-path]?[loaders]" : "file:///[absolute-resource-path]", } : undefined, + plugins, }; }; diff --git a/packages/dev/inspector-v2/webpack.config.js b/packages/dev/inspector-v2/webpack.config.js index a0a3ed98323..e7b39da849b 100644 --- a/packages/dev/inspector-v2/webpack.config.js +++ b/packages/dev/inspector-v2/webpack.config.js @@ -1,7 +1,5 @@ const path = require("path"); const webpackTools = require("@dev/build-tools").webpackTools; -const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); -const ReactRefreshTypeScript = require("react-refresh-typescript").default; module.exports = (env) => { return { @@ -36,16 +34,12 @@ module.exports = (env) => { rules: webpackTools.getRules({ sideEffects: true, includeCSS: false, + enableFastRefresh: !env.production, tsOptions: { configFile: "tsconfig.build.json", - getCustomTransformers: () => ({ - before: [ReactRefreshTypeScript()], - }), transpileOnly: true, }, }), }, - - plugins: [new ReactRefreshWebpackPlugin()], }; }; diff --git a/packages/tools/playground/webpack.config.js b/packages/tools/playground/webpack.config.js index 5f72d273727..55913c45203 100644 --- a/packages/tools/playground/webpack.config.js +++ b/packages/tools/playground/webpack.config.js @@ -1,8 +1,6 @@ const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin"); const webpackTools = require("@dev/build-tools").webpackTools; const path = require("path"); -const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); -const ReactRefreshTypeScript = require("react-refresh-typescript").default; module.exports = (env) => { const commonConfig = { @@ -17,7 +15,13 @@ module.exports = (env) => { { static: ["public"], port: process.env.PLAYGROUND_PORT || 1338, - } + }, + [ + new MonacoWebpackPlugin({ + // publicPath: "public/", + languages: ["typescript", "javascript"], + }), + ] ), resolve: { extensions: [".js", ".ts", ".tsx", ".scss", "*.svg"], @@ -73,19 +77,10 @@ module.exports = (env) => { compilerOptions: { rootDir: "../../", }, - getCustomTransformers: () => ({ - before: [!env.production && ReactRefreshTypeScript()].filter(Boolean), - }), }, + enableFastRefresh: !env.production, }), }, - plugins: [ - new MonacoWebpackPlugin({ - // publicPath: "public/", - languages: ["typescript", "javascript"], - }), - !env.production && new ReactRefreshWebpackPlugin(), - ].filter(Boolean), }; return commonConfig; }; diff --git a/packages/tools/sandbox/webpack.config.js b/packages/tools/sandbox/webpack.config.js index 0b293210172..9c6c2e52ead 100644 --- a/packages/tools/sandbox/webpack.config.js +++ b/packages/tools/sandbox/webpack.config.js @@ -1,7 +1,5 @@ const path = require("path"); const webpackTools = require("@dev/build-tools").webpackTools; -const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); -const ReactRefreshTypeScript = require("react-refresh-typescript").default; module.exports = (env) => { const commonConfig = { @@ -57,14 +55,9 @@ module.exports = (env) => { includeAssets: true, includeCSS: true, sideEffects: true, - tsOptions: { - getCustomTransformers: () => ({ - before: [!env.production && ReactRefreshTypeScript()].filter(Boolean), - }), - }, + enableFastRefresh: !env.production, }), }, - plugins: [!env.production && new ReactRefreshWebpackPlugin()].filter(Boolean), }; return commonConfig; }; From 8b062a29d8c6707196d4d8ea0f447ec657f3334c Mon Sep 17 00:00:00 2001 From: Ryan Tremblay Date: Mon, 14 Jul 2025 14:16:24 -0700 Subject: [PATCH 3/3] Fix production check --- packages/dev/inspector-v2/webpack.config.js | 3 ++- packages/tools/playground/webpack.config.js | 3 ++- packages/tools/sandbox/webpack.config.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/dev/inspector-v2/webpack.config.js b/packages/dev/inspector-v2/webpack.config.js index e7b39da849b..f85d2f01bfd 100644 --- a/packages/dev/inspector-v2/webpack.config.js +++ b/packages/dev/inspector-v2/webpack.config.js @@ -2,6 +2,7 @@ const path = require("path"); const webpackTools = require("@dev/build-tools").webpackTools; module.exports = (env) => { + const production = env.mode === "production" || process.env.NODE_ENV === "production"; return { entry: "./test/app/index.ts", @@ -34,7 +35,7 @@ module.exports = (env) => { rules: webpackTools.getRules({ sideEffects: true, includeCSS: false, - enableFastRefresh: !env.production, + enableFastRefresh: !production, tsOptions: { configFile: "tsconfig.build.json", transpileOnly: true, diff --git a/packages/tools/playground/webpack.config.js b/packages/tools/playground/webpack.config.js index 55913c45203..37a96abbb3e 100644 --- a/packages/tools/playground/webpack.config.js +++ b/packages/tools/playground/webpack.config.js @@ -3,6 +3,7 @@ const webpackTools = require("@dev/build-tools").webpackTools; const path = require("path"); module.exports = (env) => { + const production = env.mode === "production" || process.env.NODE_ENV === "production"; const commonConfig = { entry: "./src/legacy/legacy.ts", ...webpackTools.commonDevWebpackConfiguration( @@ -78,7 +79,7 @@ module.exports = (env) => { rootDir: "../../", }, }, - enableFastRefresh: !env.production, + enableFastRefresh: !production, }), }, }; diff --git a/packages/tools/sandbox/webpack.config.js b/packages/tools/sandbox/webpack.config.js index 9c6c2e52ead..3ef955a8c8e 100644 --- a/packages/tools/sandbox/webpack.config.js +++ b/packages/tools/sandbox/webpack.config.js @@ -2,6 +2,7 @@ const path = require("path"); const webpackTools = require("@dev/build-tools").webpackTools; module.exports = (env) => { + const production = env.mode === "production" || process.env.NODE_ENV === "production"; const commonConfig = { entry: "./src/legacy/legacy.ts", ...webpackTools.commonDevWebpackConfiguration( @@ -55,7 +56,7 @@ module.exports = (env) => { includeAssets: true, includeCSS: true, sideEffects: true, - enableFastRefresh: !env.production, + enableFastRefresh: !production, }), }, };