fix: React Refresh has trouble inferring router exports
This commit is contained in:
parent
b9dfea12d5
commit
7113d4db53
|
@ -4,6 +4,8 @@ import {
|
||||||
RouterProvider,
|
RouterProvider,
|
||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
|
|
||||||
|
import {performReactRefresh} from 'react-refresh/runtime';
|
||||||
|
|
||||||
export const hooks = {
|
export const hooks = {
|
||||||
'@flecks/core.hmr.hook': (hook, fleck, flecks) => {
|
'@flecks/core.hmr.hook': (hook, fleck, flecks) => {
|
||||||
if ('@flecks/react/router.routes' === hook) {
|
if ('@flecks/react/router.routes' === hook) {
|
||||||
|
@ -48,17 +50,23 @@ export const mixin = (Flecks) => class FlecksWithReactRouterClient extends Fleck
|
||||||
constructor(runtime) {
|
constructor(runtime) {
|
||||||
super(runtime);
|
super(runtime);
|
||||||
const flecks = this;
|
const flecks = this;
|
||||||
|
let debounceRefresh;
|
||||||
this.reactRouter = {
|
this.reactRouter = {
|
||||||
invalidate() {
|
invalidate() {
|
||||||
const {root} = flecks.get('@flecks/react/router');
|
if (debounceRefresh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Sorry.
|
// Sorry.
|
||||||
setTimeout(() => {
|
debounceRefresh = setTimeout(() => {
|
||||||
|
const {root} = flecks.get('@flecks/react/router');
|
||||||
Promise.resolve(flecks.invokeFleck('@flecks/react/router.routes', root))
|
Promise.resolve(flecks.invokeFleck('@flecks/react/router.routes', root))
|
||||||
.then((routes) => {
|
.then((routes) => {
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
this.router._internalSetRoutes(routes);
|
this.router._internalSetRoutes(routes);
|
||||||
|
performReactRefresh();
|
||||||
|
debounceRefresh = undefined;
|
||||||
});
|
});
|
||||||
}, 20);
|
}, 10);
|
||||||
},
|
},
|
||||||
router: undefined,
|
router: undefined,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import {resolve} from 'path';
|
import {resolve} from 'path';
|
||||||
|
|
||||||
|
import {register} from 'react-refresh/runtime';
|
||||||
|
|
||||||
function filePathToSegmentPath(path) {
|
function filePathToSegmentPath(path) {
|
||||||
let localPath = path;
|
let localPath = path;
|
||||||
let suffix = '';
|
let suffix = '';
|
||||||
|
@ -34,16 +36,24 @@ export async function createRoutesFromFiletree({importer, paths, resolver}) {
|
||||||
// Build initial router object.
|
// Build initial router object.
|
||||||
Object.entries(moduleMap)
|
Object.entries(moduleMap)
|
||||||
.map(([, paths]) => (
|
.map(([, paths]) => (
|
||||||
// Second-longest: path without extension.
|
|
||||||
paths
|
paths
|
||||||
.sort((l, r) => (l.length < r.length ? -1 : 1))
|
.sort((l, r) => (l.length < r.length ? -1 : 1))
|
||||||
.slice(0, -1)
|
|
||||||
.pop()
|
.pop()
|
||||||
))
|
))
|
||||||
.sort((l, r) => (l < r ? -1 : 1))
|
.sort((l, r) => (l < r ? -1 : 1))
|
||||||
.forEach((path) => {
|
.map((path) => {
|
||||||
|
let trimmed = path;
|
||||||
|
// @todo dynamic
|
||||||
|
const extensions = ['.jsx', '.js', '.tsx', '.ts', '.mdx'];
|
||||||
|
const extension = extensions.find((ext) => path.endsWith(ext));
|
||||||
|
if (extension) {
|
||||||
|
trimmed = path.slice(0, -extension.length);
|
||||||
|
}
|
||||||
|
return [path, trimmed];
|
||||||
|
})
|
||||||
|
.forEach(([path, trimmed]) => {
|
||||||
let walk = children;
|
let walk = children;
|
||||||
const parts = ['/', ...resolve('/', path).split('/').slice(1)];
|
const parts = ['/', ...resolve('/', trimmed).split('/').slice(1)];
|
||||||
const segments = parts.map(filePathToSegmentPath);
|
const segments = parts.map(filePathToSegmentPath);
|
||||||
for (let i = 0; i < segments.length; ++i) {
|
for (let i = 0; i < segments.length; ++i) {
|
||||||
const segment = segments[i];
|
const segment = segments[i];
|
||||||
|
@ -90,6 +100,10 @@ export async function createRoutesFromFiletree({importer, paths, resolver}) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
elements.map(async ([children, node, path]) => {
|
elements.map(async ([children, node, path]) => {
|
||||||
const route = await importer(path);
|
const route = await importer(path);
|
||||||
|
// React Refresh has trouble inferring component types when modules are structured as React
|
||||||
|
// Router prefers (e.g. `const export index = true` not being a component export). We'll give
|
||||||
|
// it a helping hand.
|
||||||
|
register(route, `${path} %exports%`);
|
||||||
let {hoist} = route;
|
let {hoist} = route;
|
||||||
if (hoist > 0) {
|
if (hoist > 0) {
|
||||||
const parts = node.path.split('/');
|
const parts = node.path.split('/');
|
||||||
|
@ -108,6 +122,11 @@ export async function createRoutesFromFiletree({importer, paths, resolver}) {
|
||||||
case 'children':
|
case 'children':
|
||||||
// ???
|
// ???
|
||||||
return;
|
return;
|
||||||
|
case 'default':
|
||||||
|
if (!route.Component) {
|
||||||
|
node.Component = value;
|
||||||
|
}
|
||||||
|
return;
|
||||||
case 'hoist':
|
case 'hoist':
|
||||||
return;
|
return;
|
||||||
case 'index':
|
case 'index':
|
||||||
|
|
Loading…
Reference in New Issue
Block a user