diff --git a/packages/pwa-kit-build/package-lock.json b/packages/pwa-kit-build/package-lock.json index b8d07ba0ce..7d948eb3c6 100644 --- a/packages/pwa-kit-build/package-lock.json +++ b/packages/pwa-kit-build/package-lock.json @@ -2194,6 +2194,70 @@ "webcrypto-core": "^1.4.0" } }, + "@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz", + "integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==", + "dev": true, + "requires": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.8.1", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, "@polka/url": { "version": "1.0.0-next.21", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", @@ -3880,6 +3944,12 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -4671,6 +4741,15 @@ "is-arrayish": "^0.2.1" } }, + "error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "dev": true, + "requires": { + "stackframe": "^1.1.1" + } + }, "es-abstract": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", @@ -8671,6 +8750,15 @@ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", @@ -9400,6 +9488,12 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "dev": true + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -10590,6 +10684,12 @@ } } }, + "stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", + "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", + "dev": true + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -12402,6 +12502,12 @@ "decamelize": "^1.2.0" } }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, "zip-stream": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", diff --git a/packages/pwa-kit-build/package.json b/packages/pwa-kit-build/package.json index 6cc6d543e6..5472d7a5ff 100644 --- a/packages/pwa-kit-build/package.json +++ b/packages/pwa-kit-build/package.json @@ -112,9 +112,11 @@ }, "devDependencies": { "@loadable/component": "^5.15.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.4", "internal-lib-build": "^2.0.0-dev", "nock": "^13.1.1", "pwa-kit-runtime": "^2.0.0-dev", + "react-refresh": "^0.11.0", "superagent": "^6.1.0", "supertest": "^4.0.2" }, diff --git a/packages/pwa-kit-build/src/configs/babel/babel-config.js b/packages/pwa-kit-build/src/configs/babel/babel-config.js index 76bc148ec7..0bc413e86b 100644 --- a/packages/pwa-kit-build/src/configs/babel/babel-config.js +++ b/packages/pwa-kit-build/src/configs/babel/babel-config.js @@ -37,7 +37,8 @@ const config = { idInterpolationPattern: '[sha512:contenthash:base64:6]', ast: true } - ] + ], + require('react-refresh/babel') ], env: { test: { diff --git a/packages/pwa-kit-build/src/configs/webpack/config.js b/packages/pwa-kit-build/src/configs/webpack/config.js index 509ae6366f..a4584c5a41 100644 --- a/packages/pwa-kit-build/src/configs/webpack/config.js +++ b/packages/pwa-kit-build/src/configs/webpack/config.js @@ -18,6 +18,7 @@ import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer' import LoadablePlugin from '@loadable/webpack-plugin' import SpeedMeasurePlugin from 'speed-measure-webpack-plugin' import {createModuleReplacementPlugin, PwaKitConfigPlugin} from './plugins' +import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin' const projectDir = process.cwd() const sdkDir = path.resolve(path.join(__dirname, '..', '..', '..')) @@ -86,7 +87,7 @@ const baseConfig = (target) => { // Perf/quality trade-off - see https://webpack.js.org/configuration/devtool/#devtool devtool: mode === production ? 'source-map' : 'eval', output: { - publicPath: '', + publicPath: '/mobify/bundle/development/', path: buildDir }, resolve: { @@ -103,7 +104,8 @@ const baseConfig = (target) => { 'react-router-dom': findInProjectThenSDK('react-router-dom'), 'react-dom': findInProjectThenSDK('react-dom'), 'react-helmet': findInProjectThenSDK('react-helmet'), - bluebird: findInProjectThenSDK('bluebird') + bluebird: findInProjectThenSDK('bluebird'), + 'webpack-hot-middleware': findInProjectThenSDK('webpack-hot-middleware'), }, ...(target === 'web' ? {fallback: {crypto: false}} : {}) }, @@ -123,6 +125,8 @@ const baseConfig = (target) => { generateStatsFile: true }), mode === development && new webpack.NoEmitOnErrorsPlugin(), + mode === development && new webpack.HotModuleReplacementPlugin(), + mode === development && new ReactRefreshWebpackPlugin(), createModuleReplacementPlugin(projectDir), @@ -215,9 +219,7 @@ const client = ...config, // Must be named "client". See - https://www.npmjs.com/package/webpack-hot-server-middleware#usage name: 'client', - entry: { - main: './app/main' - }, + entry: ['./app/main', 'webpack-hot-middleware/client?path=/__mrt/hmr'], plugins: [ ...config.plugins, new LoadablePlugin({writeToDisk: true}), diff --git a/packages/pwa-kit-build/src/ssr/server/build-dev-server.js b/packages/pwa-kit-build/src/ssr/server/build-dev-server.js index 337ca4880c..9193f07f51 100644 --- a/packages/pwa-kit-build/src/ssr/server/build-dev-server.js +++ b/packages/pwa-kit-build/src/ssr/server/build-dev-server.js @@ -15,6 +15,7 @@ import mimeTypes from 'mime-types' import webpack from 'webpack' import webpackDevMiddleware from 'webpack-dev-middleware' import webpackHotServerMiddleware from 'webpack-hot-server-middleware' +import webpackHotClientMiddleware from 'webpack-hot-middleware' import open from 'open' import requireFromString from 'require-from-string' import config from '../../configs/webpack/config' @@ -82,7 +83,15 @@ export const DevServerMixin = { // routes must not have our SSR middleware applied to them. // But the SSR render function must! app.__compiler = webpack(config) - app.__devMiddleware = webpackDevMiddleware(app.__compiler, {serverSideRender: true}) + app.__devMiddleware = webpackDevMiddleware(app.__compiler, { + serverSideRender: true + }) + app.__clientHotReloadMiddleware = webpackHotClientMiddleware( + app.__compiler.compilers.find((compiler) => compiler.name === 'client'), + { + path: '/' + } + ) app.__webpackReady = () => Boolean(app.__devMiddleware.context.state) app.__waitForWebpackReady = () => { return new Promise((resolve) => { @@ -98,6 +107,7 @@ export const DevServerMixin = { } app.use('/mobify/bundle/development', app.__devMiddleware) + app.use('/__mrt/hmr', app.__clientHotReloadMiddleware) app.use('/__mrt/status', (req, res) => { return res.json({ready: app.__webpackReady()})