fix: router HMR

This commit is contained in:
cha0s 2024-02-18 10:11:17 -06:00
parent 1563f055f3
commit 5ba0aa21c0
6 changed files with 492 additions and 309 deletions

609
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -217,14 +217,15 @@ module.exports = class Build extends Flecks {
},
);
// Our very own lil' chunk.
Flecks.set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', {
chunks: 'all',
enforce: true,
priority: 100,
test: new RegExp(`(?:${
include.map((path) => path.replace(/[\\/]/g, '[\\/]')).join('|')
})`),
});
// @todo this breaks context, investigate
// Flecks.set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', {
// chunks: 'all',
// enforce: true,
// priority: 100,
// test: new RegExp(`(?:${
// include.map((path) => path.replace(/[\\/]/g, '[\\/]')).join('|')
// })`),
// });
}
// Resolution.
const {resolve, resolveLoader} = config;

View File

@ -0,0 +1,62 @@
diff --git a/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js b/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js
index 3e66f1e..d1b1b14 100644
--- a/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js
+++ b/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js
@@ -224,26 +224,26 @@ function executeRuntime(moduleExports, moduleId, webpackHot, refreshOverlay, isT
data.prevData = getWebpackHotData(moduleExports);
}
);
- webpackHot.accept(
- /**
- * An error handler to allow self-recovering behaviours.
- * @param {Error} error An error occurred during evaluation of a module.
- * @returns {void}
- */
- function hotErrorHandler(error) {
- if (typeof refreshOverlay !== 'undefined' && refreshOverlay) {
- refreshOverlay.handleRuntimeError(error);
- }
+ // webpackHot.accept(
+ // /**
+ // * An error handler to allow self-recovering behaviours.
+ // * @param {Error} error An error occurred during evaluation of a module.
+ // * @returns {void}
+ // */
+ // function hotErrorHandler(error) {
+ // if (typeof refreshOverlay !== 'undefined' && refreshOverlay) {
+ // refreshOverlay.handleRuntimeError(error);
+ // }
- if (typeof isTest !== 'undefined' && isTest) {
- if (window.onHotAcceptError) {
- window.onHotAcceptError(error.message);
- }
- }
+ // if (typeof isTest !== 'undefined' && isTest) {
+ // if (window.onHotAcceptError) {
+ // window.onHotAcceptError(error.message);
+ // }
+ // }
- __webpack_require__.c[moduleId].hot.accept(hotErrorHandler);
- }
- );
+ // __webpack_require__.c[moduleId].hot.accept(hotErrorHandler);
+ // }
+ // );
if (isHotUpdate) {
if (
diff --git a/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/utils/makeRefreshRuntimeModule.js b/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/utils/makeRefreshRuntimeModule.js
index 4e25c4b..1cdac82 100644
--- a/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/utils/makeRefreshRuntimeModule.js
+++ b/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/utils/makeRefreshRuntimeModule.js
@@ -32,7 +32,7 @@ function makeRefreshRuntimeModule(webpack) {
`${refreshGlobal}.setup(options.id);`,
'try {',
webpack.Template.indent(
- 'originalFactory.call(this, moduleObject, moduleExports, webpackRequire);'
+ 'originalFactory && originalFactory.call(this, moduleObject, moduleExports, webpackRequire);'
),
'} finally {',
webpack.Template.indent([

View File

@ -5,8 +5,24 @@ import {
} from 'react-router-dom';
export const hooks = {
'@flecks/core.hmr.hook': (hook, fleck, flecks) => {
if ('@flecks/react/router.routes' === hook) {
// Routes got HMR'd.
flecks.reactRouter.invalidate();
}
},
'@flecks/core.reload': (fleck, config, flecks) => {
// Root changed in config.
if (
'@flecks/react/router' === fleck
&& flecks.get('@flecks/react/router').root !== config.root
) {
throw new Error('root changed');
}
},
'@flecks/react.roots': async (req, res, flecks) => {
const {routes} = flecks.reactRouter;
const {root} = flecks.get('@flecks/react/router');
const routes = await flecks.invokeFleck('@flecks/react/router.routes', root);
// Determine if any of the initial routes are lazy
const lazyMatches = matchRoutes(routes, window.location)?.filter(({route}) => route.lazy);
// Load the lazy matches and update the routes before creating the router
@ -22,7 +38,30 @@ export const hooks = {
}),
);
}
const router = createBrowserRouter(routes);
return [RouterProvider, {router}];
flecks.reactRouter.router = createBrowserRouter(routes);
return [RouterProvider, {router: flecks.reactRouter.router}];
},
};
export const mixin = (Flecks) => class FlecksWithReactRouterClient extends Flecks {
constructor(runtime) {
super(runtime);
const flecks = this;
this.reactRouter = {
invalidate() {
const {root} = flecks.get('@flecks/react/router');
// Sorry.
setTimeout(() => {
Promise.resolve(flecks.invokeFleck('@flecks/react/router.routes', root))
.then((routes) => {
// eslint-disable-next-line no-underscore-dangle
this.router._internalSetRoutes(routes);
});
}, 20);
},
router: undefined,
};
}
};

View File

@ -13,20 +13,7 @@ export const hooks = {
*/
root: '@flecks/react/router',
}),
'@flecks/core.starting': async (flecks) => {
const {root} = flecks.get('@flecks/react/router');
flecks.reactRouter.routes = await flecks.invokeFleck('@flecks/react/router.routes', root);
},
'@flecks/web.config': (req, flecks) => ({
root: flecks.get('@flecks/react/router').root,
}),
};
export const mixin = (Flecks) => class FlecksWithReactRouterServer extends Flecks {
constructor(runtime) {
super(runtime);
this.reactRouter = {handler: undefined, routes: undefined};
}
};

View File

@ -1,4 +1,3 @@
import {Flecks} from '@flecks/core';
import {
createStaticHandler,
createStaticRouter,
@ -8,30 +7,58 @@ import {
import {createFetchRequest} from './request';
export const hooks = {
'@flecks/core.hmr.hook': (hook, fleck, flecks) => {
if ('@flecks/react/router.routes' === hook) {
flecks.reactRouter.invalidate();
}
},
'@flecks/core.reload': (fleck, config, flecks) => {
if ('@flecks/react/router' === fleck) {
flecks.reactRouter.invalidate();
}
},
'@flecks/web/server.request.socket': (flecks) => async (req, res, next) => {
const {handler} = flecks.reactRouter;
const handler = await flecks.reactRouter.ensureLatestHandler();
const context = await handler.query(createFetchRequest(req, res));
if (context instanceof Response && [301, 302, 303, 307, 308].includes(context.status)) {
res.redirect(context.status, context.headers.get('Location'));
return;
}
if ([404].includes(context.statusCode)) {
res.status(context.statusCode);
next();
return;
}
next();
},
'@flecks/react.roots': async (req, res, flecks) => {
const {handler} = flecks.reactRouter;
const handler = await flecks.reactRouter.ensureLatestHandler();
const context = await handler.query(createFetchRequest(req, res));
if ([404].includes(context.statusCode)) {
res.status(context.statusCode);
req.abort();
return undefined;
}
const router = createStaticRouter(handler.dataRoutes, context);
return [StaticRouterProvider, {context, router}];
},
'@flecks/server.up': Flecks.priority(
async (flecks) => {
flecks.reactRouter.handler = createStaticHandler(flecks.reactRouter.routes);
},
{before: '@flecks/web/server'},
),
};
export const mixin = (Flecks) => class FlecksWithReactRouterServer extends Flecks {
constructor(runtime) {
super(runtime);
const flecks = this;
let routes;
let handler;
this.reactRouter = {
async ensureLatestHandler() {
if (!routes) {
const {root} = flecks.get('@flecks/react/router');
routes = await flecks.invokeFleck('@flecks/react/router.routes', root);
handler = createStaticHandler(routes);
}
return handler;
},
invalidate() {
routes = undefined;
},
};
}
};