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. // Our very own lil' chunk.
Flecks.set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', { // @todo this breaks context, investigate
chunks: 'all', // Flecks.set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', {
enforce: true, // chunks: 'all',
priority: 100, // enforce: true,
test: new RegExp(`(?:${ // priority: 100,
include.map((path) => path.replace(/[\\/]/g, '[\\/]')).join('|') // test: new RegExp(`(?:${
})`), // include.map((path) => path.replace(/[\\/]/g, '[\\/]')).join('|')
}); // })`),
// });
} }
// Resolution. // Resolution.
const {resolve, resolveLoader} = config; 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'; } from 'react-router-dom';
export const hooks = { 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) => { '@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 // Determine if any of the initial routes are lazy
const lazyMatches = matchRoutes(routes, window.location)?.filter(({route}) => route.lazy); const lazyMatches = matchRoutes(routes, window.location)?.filter(({route}) => route.lazy);
// Load the lazy matches and update the routes before creating the router // Load the lazy matches and update the routes before creating the router
@ -22,7 +38,30 @@ export const hooks = {
}), }),
); );
} }
const router = createBrowserRouter(routes); flecks.reactRouter.router = createBrowserRouter(routes);
return [RouterProvider, {router}]; 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', 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) => ({ '@flecks/web.config': (req, flecks) => ({
root: flecks.get('@flecks/react/router').root, 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 { import {
createStaticHandler, createStaticHandler,
createStaticRouter, createStaticRouter,
@ -8,30 +7,58 @@ import {
import {createFetchRequest} from './request'; import {createFetchRequest} from './request';
export const hooks = { 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) => { '@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)); const context = await handler.query(createFetchRequest(req, res));
if (context instanceof Response && [301, 302, 303, 307, 308].includes(context.status)) { if (context instanceof Response && [301, 302, 303, 307, 308].includes(context.status)) {
res.redirect(context.status, context.headers.get('Location')); res.redirect(context.status, context.headers.get('Location'));
return; return;
} }
if ([404].includes(context.statusCode)) {
res.status(context.statusCode);
next();
return;
}
next(); next();
}, },
'@flecks/react.roots': async (req, res, flecks) => { '@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)); 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); const router = createStaticRouter(handler.dataRoutes, context);
return [StaticRouterProvider, {context, router}]; return [StaticRouterProvider, {context, router}];
}, },
'@flecks/server.up': Flecks.priority( };
async (flecks) => {
flecks.reactRouter.handler = createStaticHandler(flecks.reactRouter.routes); export const mixin = (Flecks) => class FlecksWithReactRouterServer extends Flecks {
},
{before: '@flecks/web/server'}, 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;
},
};
}
}; };