diff --git a/package-lock.json b/package-lock.json index 644e4812f66..21621d9fee0 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/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 0ee074c185b..f85d2f01bfd 100644 --- a/packages/dev/inspector-v2/webpack.config.js +++ b/packages/dev/inspector-v2/webpack.config.js @@ -1,9 +1,8 @@ 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 production = env.mode === "production" || process.env.NODE_ENV === "production"; return { entry: "./test/app/index.ts", @@ -36,16 +35,12 @@ module.exports = (env) => { rules: webpackTools.getRules({ sideEffects: true, includeCSS: false, + enableFastRefresh: !production, tsOptions: { configFile: "tsconfig.build.json", - getCustomTransformers: () => ({ - before: [ReactRefreshTypeScript()].filter(Boolean), - }), transpileOnly: true, }, }), }, - - plugins: [new ReactRefreshWebpackPlugin()].filter(Boolean), }; }; 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 51339b0d881..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( @@ -10,11 +11,18 @@ module.exports = (env) => { ...env, outputFilename: "babylon.playground.js", dirName: __dirname, + enableHotReload: true, }, { static: ["public"], port: process.env.PLAYGROUND_PORT || 1338, - } + }, + [ + new MonacoWebpackPlugin({ + // publicPath: "public/", + languages: ["typescript", "javascript"], + }), + ] ), resolve: { extensions: [".js", ".ts", ".tsx", ".scss", "*.svg"], @@ -71,14 +79,9 @@ module.exports = (env) => { rootDir: "../../", }, }, + enableFastRefresh: !production, }), }, - plugins: [ - new MonacoWebpackPlugin({ - // publicPath: "public/", - languages: ["typescript", "javascript"], - }), - ], }; 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..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( @@ -9,6 +10,7 @@ module.exports = (env) => { ...env, outputFilename: "babylon.sandbox.js", dirName: __dirname, + enableHotReload: true, }, { static: ["public"], @@ -50,9 +52,13 @@ module.exports = (env) => { // React, react dom etc' ], module: { - rules: webpackTools.getRules(), + rules: webpackTools.getRules({ + includeAssets: true, + includeCSS: true, + sideEffects: true, + enableFastRefresh: !production, + }), }, - plugins: [], }; return commonConfig; };