@bleedingdev/modern-js-renderer-solid 0.0.0-bootstrap → 3.9.3-ultramodern.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/actions.js +283 -0
- package/dist/esm/application-router.js +25 -0
- package/dist/esm/client.js +49 -0
- package/dist/esm/entry-application.js +60 -0
- package/dist/esm/entry-client.js +23 -0
- package/dist/esm/federation-context.js +25 -0
- package/dist/esm/federation-ssr.js +84 -0
- package/dist/esm/federation.js +83 -0
- package/dist/esm/i18n/I18nProvider.js +33 -0
- package/dist/esm/i18n/LocalizedLink.js +74 -0
- package/dist/esm/i18n/context.js +3 -0
- package/dist/esm/i18n/index.js +8 -0
- package/dist/esm/i18n/languageSync.js +50 -0
- package/dist/esm/i18n/types.js +0 -0
- package/dist/esm/i18n/useI18n.js +74 -0
- package/dist/esm/index.js +58 -0
- package/dist/esm/manifest.js +150 -0
- package/dist/esm/route-completion.js +150 -0
- package/dist/esm/route-data-error.js +108 -0
- package/dist/esm/router-binding/Asset.js +201 -0
- package/dist/esm/router-binding/CatchBoundary.js +94 -0
- package/dist/esm/router-binding/ClientOnly.js +26 -0
- package/dist/esm/router-binding/HeadContent.js +8 -0
- package/dist/esm/router-binding/LICENSE +21 -0
- package/dist/esm/router-binding/Match.js +319 -0
- package/dist/esm/router-binding/Matches.js +117 -0
- package/dist/esm/router-binding/PROVENANCE.json +94 -0
- package/dist/esm/router-binding/RouterProvider.js +51 -0
- package/dist/esm/router-binding/SafeFragment.js +5 -0
- package/dist/esm/router-binding/ScriptOnce.js +15 -0
- package/dist/esm/router-binding/Scripts.js +30 -0
- package/dist/esm/router-binding/ScrollRestoration.js +16 -0
- package/dist/esm/router-binding/Transitioner.js +103 -0
- package/dist/esm/router-binding/awaited.js +48 -0
- package/dist/esm/router-binding/fileRoute.js +83 -0
- package/dist/esm/router-binding/flightData.js +23 -0
- package/dist/esm/router-binding/headContentUtils.js +162 -0
- package/dist/esm/router-binding/history.js +0 -0
- package/dist/esm/router-binding/index.js +35 -0
- package/dist/esm/router-binding/lazyRouteComponent.js +30 -0
- package/dist/esm/router-binding/link.js +389 -0
- package/dist/esm/router-binding/matchContext.js +7 -0
- package/dist/esm/router-binding/nonRouteComponentContext.js +13 -0
- package/dist/esm/router-binding/not-found.js +35 -0
- package/dist/esm/router-binding/publicMatchData.js +447 -0
- package/dist/esm/router-binding/registryTransfer.js +210 -0
- package/dist/esm/router-binding/renderRouteNotFound.js +23 -0
- package/dist/esm/router-binding/route.js +143 -0
- package/dist/esm/router-binding/router.js +13 -0
- package/dist/esm/router-binding/routerContext.js +3 -0
- package/dist/esm/router-binding/routerStores.js +50 -0
- package/dist/esm/router-binding/scroll-restoration.js +13 -0
- package/dist/esm/router-binding/typePrimitives.js +0 -0
- package/dist/esm/router-binding/useBlocker.js +152 -0
- package/dist/esm/router-binding/useCanGoBack.js +7 -0
- package/dist/esm/router-binding/useLoaderData.js +9 -0
- package/dist/esm/router-binding/useLoaderDeps.js +8 -0
- package/dist/esm/router-binding/useLocation.js +14 -0
- package/dist/esm/router-binding/useMatch.js +28 -0
- package/dist/esm/router-binding/useNavigate.js +19 -0
- package/dist/esm/router-binding/useParams.js +13 -0
- package/dist/esm/router-binding/useRouteContext.js +8 -0
- package/dist/esm/router-binding/useRouter.js +10 -0
- package/dist/esm/router-binding/useRouterState.js +19 -0
- package/dist/esm/router-binding/useSearch.js +13 -0
- package/dist/esm/router-binding/utils.js +23 -0
- package/dist/esm/router.js +187 -0
- package/dist/esm-node/actions.js +263 -0
- package/dist/esm-node/application-router.js +25 -0
- package/dist/esm-node/client.js +49 -0
- package/dist/esm-node/entry-application.js +110 -0
- package/dist/esm-node/entry-client.js +23 -0
- package/dist/esm-node/entry-server.js +47 -0
- package/dist/esm-node/federation-context.js +25 -0
- package/dist/esm-node/federation-ssr.js +84 -0
- package/dist/esm-node/federation.js +83 -0
- package/dist/esm-node/i18n/I18nProvider.js +42 -0
- package/dist/esm-node/i18n/LocalizedLink.js +142 -0
- package/dist/esm-node/i18n/context.js +3 -0
- package/dist/esm-node/i18n/index.js +8 -0
- package/dist/esm-node/i18n/languageSync.js +50 -0
- package/dist/esm-node/i18n/types.js +1 -0
- package/dist/esm-node/i18n/useI18n.js +74 -0
- package/dist/esm-node/index.js +58 -0
- package/dist/esm-node/manifest.js +150 -0
- package/dist/esm-node/native-promise-serialization.js +113 -0
- package/dist/esm-node/plugin/compiler.js +209 -0
- package/dist/esm-node/plugin/create.js +235 -0
- package/dist/esm-node/plugin/index.js +73 -0
- package/dist/esm-node/plugin/profile.js +52 -0
- package/dist/esm-node/route-completion.js +160 -0
- package/dist/esm-node/route-data-error.js +108 -0
- package/dist/esm-node/router-binding/Asset.js +171 -0
- package/dist/esm-node/router-binding/CatchBoundary.js +136 -0
- package/dist/esm-node/router-binding/ClientOnly.js +46 -0
- package/dist/esm-node/router-binding/HeadContent.js +8 -0
- package/dist/esm-node/router-binding/LICENSE +21 -0
- package/dist/esm-node/router-binding/Match.js +660 -0
- package/dist/esm-node/router-binding/Matches.js +161 -0
- package/dist/esm-node/router-binding/PROVENANCE.json +94 -0
- package/dist/esm-node/router-binding/RouterProvider.js +87 -0
- package/dist/esm-node/router-binding/SafeFragment.js +5 -0
- package/dist/esm-node/router-binding/ScriptOnce.js +16 -0
- package/dist/esm-node/router-binding/Scripts.js +49 -0
- package/dist/esm-node/router-binding/ScrollRestoration.js +16 -0
- package/dist/esm-node/router-binding/Transitioner.js +103 -0
- package/dist/esm-node/router-binding/awaited.js +75 -0
- package/dist/esm-node/router-binding/fileRoute.js +83 -0
- package/dist/esm-node/router-binding/flightData.js +23 -0
- package/dist/esm-node/router-binding/headContentUtils.js +162 -0
- package/dist/esm-node/router-binding/history.js +1 -0
- package/dist/esm-node/router-binding/index.js +35 -0
- package/dist/esm-node/router-binding/lazyRouteComponent.js +30 -0
- package/dist/esm-node/router-binding/link.js +399 -0
- package/dist/esm-node/router-binding/matchContext.js +7 -0
- package/dist/esm-node/router-binding/nonRouteComponentContext.js +22 -0
- package/dist/esm-node/router-binding/not-found.js +49 -0
- package/dist/esm-node/router-binding/publicMatchData.js +447 -0
- package/dist/esm-node/router-binding/registryTransfer.js +210 -0
- package/dist/esm-node/router-binding/renderRouteNotFound.js +22 -0
- package/dist/esm-node/router-binding/route.js +162 -0
- package/dist/esm-node/router-binding/router.js +13 -0
- package/dist/esm-node/router-binding/routerContext.js +3 -0
- package/dist/esm-node/router-binding/routerStores.js +50 -0
- package/dist/esm-node/router-binding/scroll-restoration.js +12 -0
- package/dist/esm-node/router-binding/typePrimitives.js +1 -0
- package/dist/esm-node/router-binding/useBlocker.js +152 -0
- package/dist/esm-node/router-binding/useCanGoBack.js +7 -0
- package/dist/esm-node/router-binding/useLoaderData.js +9 -0
- package/dist/esm-node/router-binding/useLoaderDeps.js +8 -0
- package/dist/esm-node/router-binding/useLocation.js +14 -0
- package/dist/esm-node/router-binding/useMatch.js +28 -0
- package/dist/esm-node/router-binding/useNavigate.js +19 -0
- package/dist/esm-node/router-binding/useParams.js +13 -0
- package/dist/esm-node/router-binding/useRouteContext.js +8 -0
- package/dist/esm-node/router-binding/useRouter.js +10 -0
- package/dist/esm-node/router-binding/useRouterState.js +19 -0
- package/dist/esm-node/router-binding/useSearch.js +13 -0
- package/dist/esm-node/router-binding/utils.js +23 -0
- package/dist/esm-node/router.js +187 -0
- package/dist/esm-node/server.js +396 -0
- package/dist/types/actions.d.ts +45 -0
- package/dist/types/application-router.d.ts +5 -0
- package/dist/types/client.d.ts +23 -0
- package/dist/types/entry-application.d.ts +10 -0
- package/dist/types/entry-client.d.ts +5 -0
- package/dist/types/entry-server.d.ts +5 -0
- package/dist/types/federation-context.d.ts +16 -0
- package/dist/types/federation-ssr.d.ts +21 -0
- package/dist/types/federation.d.ts +30 -0
- package/dist/types/i18n/I18nProvider.d.ts +21 -0
- package/dist/types/i18n/LocalizedLink.d.ts +43 -0
- package/dist/types/i18n/context.d.ts +11 -0
- package/dist/types/i18n/index.d.ts +9 -0
- package/dist/types/i18n/languageSync.d.ts +31 -0
- package/dist/types/i18n/types.d.ts +33 -0
- package/dist/types/i18n/useI18n.d.ts +24 -0
- package/dist/types/index.d.ts +41 -0
- package/dist/types/manifest.d.ts +55 -0
- package/dist/types/native-promise-serialization.d.ts +9 -0
- package/dist/types/plugin/compiler.d.ts +6 -0
- package/dist/types/plugin/create.d.ts +21 -0
- package/dist/types/plugin/index.d.ts +3 -0
- package/dist/types/plugin/lazy-modules.d.cts +15 -0
- package/dist/types/plugin/preserve-import-loader.d.cts +3 -0
- package/dist/types/plugin/profile.d.ts +2 -0
- package/dist/types/plugin/solid-loader.d.cts +2 -0
- package/dist/types/plugin/svg-component-template.d.cts +6 -0
- package/dist/types/route-completion.d.ts +21 -0
- package/dist/types/route-data-error.d.ts +17 -0
- package/dist/types/router-binding/Asset.d.ts +3 -0
- package/dist/types/router-binding/CatchBoundary.d.ts +13 -0
- package/dist/types/router-binding/ClientOnly.d.ts +31 -0
- package/dist/types/router-binding/HeadContent.d.ts +13 -0
- package/dist/types/router-binding/Match.d.ts +6 -0
- package/dist/types/router-binding/Matches.d.ts +26 -0
- package/dist/types/router-binding/RouterProvider.d.ts +10 -0
- package/dist/types/router-binding/SafeFragment.d.ts +2 -0
- package/dist/types/router-binding/ScriptOnce.d.ts +6 -0
- package/dist/types/router-binding/Scripts.d.ts +2 -0
- package/dist/types/router-binding/ScrollRestoration.d.ts +14 -0
- package/dist/types/router-binding/Transitioner.d.ts +2 -0
- package/dist/types/router-binding/awaited.d.ts +11 -0
- package/dist/types/router-binding/fileRoute.d.ts +54 -0
- package/dist/types/router-binding/flightData.d.ts +38 -0
- package/dist/types/router-binding/headContentUtils.d.ts +15 -0
- package/dist/types/router-binding/history.d.ts +8 -0
- package/dist/types/router-binding/index.d.ts +45 -0
- package/dist/types/router-binding/lazyRouteComponent.d.ts +2 -0
- package/dist/types/router-binding/link.d.ts +43 -0
- package/dist/types/router-binding/matchContext.d.ts +7 -0
- package/dist/types/router-binding/nonRouteComponentContext.d.ts +5 -0
- package/dist/types/router-binding/not-found.d.ts +11 -0
- package/dist/types/router-binding/publicMatchData.d.ts +19 -0
- package/dist/types/router-binding/registryTransfer.d.ts +47 -0
- package/dist/types/router-binding/renderRouteNotFound.d.ts +11 -0
- package/dist/types/router-binding/route.d.ts +105 -0
- package/dist/types/router-binding/router.d.ts +70 -0
- package/dist/types/router-binding/routerContext.d.ts +3 -0
- package/dist/types/router-binding/routerStores.d.ts +2 -0
- package/dist/types/router-binding/scroll-restoration.d.ts +2 -0
- package/dist/types/router-binding/typePrimitives.d.ts +10 -0
- package/dist/types/router-binding/useBlocker.d.ts +70 -0
- package/dist/types/router-binding/useCanGoBack.d.ts +2 -0
- package/dist/types/router-binding/useLoaderData.d.ts +8 -0
- package/dist/types/router-binding/useLoaderDeps.d.ts +8 -0
- package/dist/types/router-binding/useLocation.d.ts +7 -0
- package/dist/types/router-binding/useMatch.d.ts +10 -0
- package/dist/types/router-binding/useNavigate.d.ts +5 -0
- package/dist/types/router-binding/useParams.d.ts +9 -0
- package/dist/types/router-binding/useRouteContext.d.ts +4 -0
- package/dist/types/router-binding/useRouter.d.ts +4 -0
- package/dist/types/router-binding/useRouterState.d.ts +8 -0
- package/dist/types/router-binding/useSearch.d.ts +9 -0
- package/dist/types/router-binding/utils.d.ts +25 -0
- package/dist/types/router.d.ts +31 -0
- package/dist/types/server.d.ts +47 -0
- package/package.json +118 -4
- package/src/actions.tsx +437 -0
- package/src/application-router.tsx +41 -0
- package/src/client.ts +106 -0
- package/src/entry-application.tsx +73 -0
- package/src/entry-client.tsx +48 -0
- package/src/entry-server.tsx +85 -0
- package/src/federation-context.ts +47 -0
- package/src/federation-ssr.ts +117 -0
- package/src/federation.tsx +193 -0
- package/src/i18n/I18nProvider.tsx +54 -0
- package/src/i18n/LocalizedLink.tsx +122 -0
- package/src/i18n/context.ts +13 -0
- package/src/i18n/index.ts +35 -0
- package/src/i18n/languageSync.ts +113 -0
- package/src/i18n/types.ts +35 -0
- package/src/i18n/useI18n.ts +121 -0
- package/src/index.ts +41 -0
- package/src/manifest.ts +337 -0
- package/src/native-promise-serialization.ts +167 -0
- package/src/plugin/compiler.ts +320 -0
- package/src/plugin/create.ts +270 -0
- package/src/plugin/index.ts +72 -0
- package/src/plugin/lazy-modules.cjs +146 -0
- package/src/plugin/preserve-import-loader.cjs +46 -0
- package/src/plugin/profile.ts +42 -0
- package/src/plugin/solid-loader.cjs +83 -0
- package/src/plugin/svg-component-template.cjs +19 -0
- package/src/route-completion.tsx +222 -0
- package/src/route-data-error.ts +175 -0
- package/src/router-binding/Asset.tsx +283 -0
- package/src/router-binding/CatchBoundary.tsx +130 -0
- package/src/router-binding/ClientOnly.tsx +76 -0
- package/src/router-binding/HeadContent.tsx +23 -0
- package/src/router-binding/LICENSE +21 -0
- package/src/router-binding/Match.tsx +397 -0
- package/src/router-binding/Matches.tsx +242 -0
- package/src/router-binding/PROVENANCE.json +94 -0
- package/src/router-binding/RouterProvider.tsx +129 -0
- package/src/router-binding/SafeFragment.tsx +5 -0
- package/src/router-binding/ScriptOnce.tsx +23 -0
- package/src/router-binding/Scripts.tsx +44 -0
- package/src/router-binding/ScrollRestoration.tsx +49 -0
- package/src/router-binding/Transitioner.tsx +172 -0
- package/src/router-binding/awaited.tsx +71 -0
- package/src/router-binding/fileRoute.ts +268 -0
- package/src/router-binding/flightData.ts +90 -0
- package/src/router-binding/headContentUtils.tsx +290 -0
- package/src/router-binding/history.ts +9 -0
- package/src/router-binding/index.tsx +318 -0
- package/src/router-binding/lazyRouteComponent.tsx +70 -0
- package/src/router-binding/link.tsx +865 -0
- package/src/router-binding/matchContext.tsx +15 -0
- package/src/router-binding/nonRouteComponentContext.tsx +23 -0
- package/src/router-binding/not-found.tsx +65 -0
- package/src/router-binding/publicMatchData.ts +674 -0
- package/src/router-binding/registryTransfer.ts +383 -0
- package/src/router-binding/renderRouteNotFound.tsx +53 -0
- package/src/router-binding/route.tsx +665 -0
- package/src/router-binding/router.ts +121 -0
- package/src/router-binding/routerContext.tsx +6 -0
- package/src/router-binding/routerStores.ts +85 -0
- package/src/router-binding/scroll-restoration.tsx +15 -0
- package/src/router-binding/typePrimitives.ts +74 -0
- package/src/router-binding/useBlocker.tsx +359 -0
- package/src/router-binding/useCanGoBack.ts +9 -0
- package/src/router-binding/useLoaderData.tsx +50 -0
- package/src/router-binding/useLoaderDeps.tsx +46 -0
- package/src/router-binding/useLocation.tsx +43 -0
- package/src/router-binding/useMatch.tsx +111 -0
- package/src/router-binding/useNavigate.tsx +43 -0
- package/src/router-binding/useParams.tsx +72 -0
- package/src/router-binding/useRouteContext.ts +30 -0
- package/src/router-binding/useRouter.tsx +17 -0
- package/src/router-binding/useRouterState.tsx +50 -0
- package/src/router-binding/useSearch.tsx +72 -0
- package/src/router-binding/utils.ts +59 -0
- package/src/router.ts +376 -0
- package/src/server.ts +645 -0
package/src/actions.tsx
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import type { DecodedDataOutcome } from '@modern-js/renderer-core/data';
|
|
2
|
+
import { createDataClient } from '@modern-js/renderer-core/data';
|
|
3
|
+
import type { RendererIdentity } from '@modern-js/renderer-core/identity';
|
|
4
|
+
import {
|
|
5
|
+
assertRendererIdentity,
|
|
6
|
+
identityCacheKey,
|
|
7
|
+
} from '@modern-js/renderer-core/identity';
|
|
8
|
+
import type { JSX } from '@solidjs/web';
|
|
9
|
+
import { getRequestEvent } from '@solidjs/web';
|
|
10
|
+
import type { Accessor } from 'solid-js';
|
|
11
|
+
import { createSignal, getOwner, omit, onCleanup, untrack } from 'solid-js';
|
|
12
|
+
import type { AnyRouter } from './router-binding/index';
|
|
13
|
+
import { redirect, useMatch, useRouter } from './router-binding/index';
|
|
14
|
+
import type {
|
|
15
|
+
PublicMatchError,
|
|
16
|
+
PublicSnapshotOwner,
|
|
17
|
+
} from './router-binding/publicMatchData';
|
|
18
|
+
import {
|
|
19
|
+
preparePublicLoaderData,
|
|
20
|
+
preparePublicMatchError,
|
|
21
|
+
} from './router-binding/publicMatchData';
|
|
22
|
+
|
|
23
|
+
export interface RouteActionOptions {
|
|
24
|
+
router: AnyRouter;
|
|
25
|
+
routeId: string;
|
|
26
|
+
rendererIdentity: RendererIdentity;
|
|
27
|
+
url?: string | URL;
|
|
28
|
+
fetch?: typeof globalThis.fetch;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface RouteAction {
|
|
32
|
+
readonly routeId: string;
|
|
33
|
+
readonly pending: Accessor<boolean>;
|
|
34
|
+
readonly outcome: Accessor<DecodedDataOutcome | undefined>;
|
|
35
|
+
readonly error: Accessor<Error | undefined>;
|
|
36
|
+
readonly url: Accessor<string>;
|
|
37
|
+
/** Cancellation and superseded submissions resolve without publishing stale data. */
|
|
38
|
+
submit(request: Request): Promise<DecodedDataOutcome | undefined>;
|
|
39
|
+
submitForm(
|
|
40
|
+
form: HTMLFormElement,
|
|
41
|
+
submitter?: HTMLElement | null,
|
|
42
|
+
): Promise<DecodedDataOutcome | undefined>;
|
|
43
|
+
cancel(): void;
|
|
44
|
+
dispose(): void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** An asynchronous action exposes its public failure to the form's owner. */
|
|
48
|
+
export class RouteActionError extends Error {
|
|
49
|
+
readonly routeId: string;
|
|
50
|
+
readonly status: number;
|
|
51
|
+
readonly data: unknown;
|
|
52
|
+
readonly outcome: Extract<
|
|
53
|
+
DecodedDataOutcome,
|
|
54
|
+
{ kind: 'error' | 'not-found' }
|
|
55
|
+
>;
|
|
56
|
+
|
|
57
|
+
constructor(
|
|
58
|
+
routeId: string,
|
|
59
|
+
outcome: Extract<DecodedDataOutcome, { kind: 'error' | 'not-found' }>,
|
|
60
|
+
) {
|
|
61
|
+
super(
|
|
62
|
+
outcome.kind === 'error'
|
|
63
|
+
? outcome.error.message
|
|
64
|
+
: 'Action route not found',
|
|
65
|
+
);
|
|
66
|
+
this.name = outcome.kind === 'error' ? outcome.error.name : 'RouteNotFound';
|
|
67
|
+
this.routeId = routeId;
|
|
68
|
+
this.status = outcome.status;
|
|
69
|
+
this.data = outcome.kind === 'error' ? outcome.data : outcome.value;
|
|
70
|
+
this.outcome = outcome;
|
|
71
|
+
Reflect.deleteProperty(this, 'stack');
|
|
72
|
+
const stack =
|
|
73
|
+
outcome.kind === 'error'
|
|
74
|
+
? Object.getOwnPropertyDescriptor(outcome.error, 'stack')?.value
|
|
75
|
+
: undefined;
|
|
76
|
+
if (typeof stack === 'string') this.stack = stack;
|
|
77
|
+
Object.freeze(this);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function actionFailure(
|
|
82
|
+
cause: unknown,
|
|
83
|
+
owner?: PublicSnapshotOwner,
|
|
84
|
+
privateContexts: readonly unknown[] = [],
|
|
85
|
+
): Error {
|
|
86
|
+
let projection: ReturnType<typeof preparePublicMatchError>;
|
|
87
|
+
try {
|
|
88
|
+
projection = preparePublicMatchError(
|
|
89
|
+
cause instanceof Error
|
|
90
|
+
? cause
|
|
91
|
+
: new Error('The Solid route action failed', { cause }),
|
|
92
|
+
owner,
|
|
93
|
+
privateContexts,
|
|
94
|
+
);
|
|
95
|
+
} catch {
|
|
96
|
+
projection = Object.freeze({
|
|
97
|
+
name: 'DataProtocolError',
|
|
98
|
+
message: 'Invalid public Solid action error',
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const nested = 'error' in projection ? projection.error : undefined;
|
|
102
|
+
const diagnostic = (
|
|
103
|
+
nested && typeof nested === 'object' ? nested : projection
|
|
104
|
+
) as PublicMatchError;
|
|
105
|
+
const failure = new Error(
|
|
106
|
+
typeof diagnostic.message === 'string' &&
|
|
107
|
+
diagnostic.message !== 'Unexpected Server Error'
|
|
108
|
+
? diagnostic.message
|
|
109
|
+
: 'The Solid route action failed',
|
|
110
|
+
Object.hasOwn(diagnostic, 'cause')
|
|
111
|
+
? { cause: diagnostic.cause }
|
|
112
|
+
: undefined,
|
|
113
|
+
);
|
|
114
|
+
failure.name =
|
|
115
|
+
typeof diagnostic.name === 'string' ? diagnostic.name : 'Error';
|
|
116
|
+
// Only the helper's checked diagnostic stack enters the public error.
|
|
117
|
+
Reflect.deleteProperty(failure, 'stack');
|
|
118
|
+
if (typeof diagnostic.stack === 'string') failure.stack = diagnostic.stack;
|
|
119
|
+
return Object.freeze(failure);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function actionOutcome(
|
|
123
|
+
result: DecodedDataOutcome,
|
|
124
|
+
owner: PublicSnapshotOwner,
|
|
125
|
+
privateContexts: readonly unknown[],
|
|
126
|
+
): DecodedDataOutcome {
|
|
127
|
+
if (result.kind !== 'success')
|
|
128
|
+
return preparePublicLoaderData(
|
|
129
|
+
result,
|
|
130
|
+
owner,
|
|
131
|
+
privateContexts,
|
|
132
|
+
) as DecodedDataOutcome;
|
|
133
|
+
// Deferred slots belong to the public value. Framing completion stays private
|
|
134
|
+
// and submit()/pending represent its lifecycle to the action owner.
|
|
135
|
+
return Object.freeze({
|
|
136
|
+
kind: 'success',
|
|
137
|
+
value: preparePublicLoaderData(result.value, owner, privateContexts),
|
|
138
|
+
status: result.status,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function routerIdentity(router: AnyRouter): RendererIdentity | undefined {
|
|
143
|
+
const context = router.options.context as
|
|
144
|
+
| { ultramodern?: { rendererIdentity?: RendererIdentity } }
|
|
145
|
+
| undefined;
|
|
146
|
+
if (context?.ultramodern === undefined) return undefined;
|
|
147
|
+
const identity = context.ultramodern?.rendererIdentity;
|
|
148
|
+
if (!identity) {
|
|
149
|
+
throw new Error('Solid router context requires its renderer identity');
|
|
150
|
+
}
|
|
151
|
+
identityCacheKey(identity);
|
|
152
|
+
return identity;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function createRouteAction(options: RouteActionOptions): RouteAction {
|
|
156
|
+
const { router, routeId } = options;
|
|
157
|
+
if (!routeId)
|
|
158
|
+
throw new Error('A Solid action requires its filesystem route ID');
|
|
159
|
+
identityCacheKey(options.rendererIdentity);
|
|
160
|
+
if (options.rendererIdentity.renderer !== 'solid') {
|
|
161
|
+
throw new Error('A Solid action requires the Solid renderer identity');
|
|
162
|
+
}
|
|
163
|
+
const configuredIdentity = routerIdentity(router);
|
|
164
|
+
if (configuredIdentity) {
|
|
165
|
+
assertRendererIdentity(options.rendererIdentity, configuredIdentity);
|
|
166
|
+
}
|
|
167
|
+
const identity = Object.freeze({ ...options.rendererIdentity });
|
|
168
|
+
const client = createDataClient(routeId, identity, { fetch: options.fetch });
|
|
169
|
+
// Capture the request while the native SSR request scope is active.
|
|
170
|
+
const requestURL = getRequestEvent()?.request.url;
|
|
171
|
+
const url = () => {
|
|
172
|
+
const base =
|
|
173
|
+
typeof window === 'undefined' ? requestURL : window.location.href;
|
|
174
|
+
const location = options.url ?? router.state.location.publicHref;
|
|
175
|
+
if (!base && !URL.canParse(String(location))) {
|
|
176
|
+
throw new Error('A server Solid action requires its native request URL');
|
|
177
|
+
}
|
|
178
|
+
return new URL(location, base).href;
|
|
179
|
+
};
|
|
180
|
+
const [pending, setPending] = createSignal(false);
|
|
181
|
+
const [outcome, setOutcome] = createSignal<DecodedDataOutcome>();
|
|
182
|
+
const [error, setError] = createSignal<Error>();
|
|
183
|
+
let active: AbortController | undefined;
|
|
184
|
+
let disposed = false;
|
|
185
|
+
|
|
186
|
+
function cancel() {
|
|
187
|
+
const current = active;
|
|
188
|
+
if (!current) return;
|
|
189
|
+
active = undefined;
|
|
190
|
+
current.abort(new DOMException('The action was cancelled', 'AbortError'));
|
|
191
|
+
setPending(false);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function dispose() {
|
|
195
|
+
if (disposed) return;
|
|
196
|
+
disposed = true;
|
|
197
|
+
cancel();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function submit(request: Request): Promise<DecodedDataOutcome | undefined> {
|
|
201
|
+
if (disposed) throw new Error('The Solid action owner has been disposed');
|
|
202
|
+
if (request.method === 'GET' || request.method === 'HEAD') {
|
|
203
|
+
throw new Error('A Solid action requires a mutation Request');
|
|
204
|
+
}
|
|
205
|
+
cancel();
|
|
206
|
+
const controller = new AbortController();
|
|
207
|
+
active = controller;
|
|
208
|
+
const signal = controller.signal;
|
|
209
|
+
const abortRequest = () => controller.abort(request.signal.reason);
|
|
210
|
+
if (request.signal.aborted) abortRequest();
|
|
211
|
+
else request.signal.addEventListener('abort', abortRequest, { once: true });
|
|
212
|
+
const current = () => active === controller && !signal.aborted && !disposed;
|
|
213
|
+
const privateContexts = [router.options.context, request];
|
|
214
|
+
const owner: PublicSnapshotOwner = {
|
|
215
|
+
signal,
|
|
216
|
+
fail(failure) {
|
|
217
|
+
if (!current()) return;
|
|
218
|
+
setError(actionFailure(failure, owner, privateContexts));
|
|
219
|
+
controller.abort(failure);
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
setOutcome(undefined);
|
|
223
|
+
setError(undefined);
|
|
224
|
+
setPending(true);
|
|
225
|
+
const cancelled = Symbol('cancelled action');
|
|
226
|
+
let resolveCancellation!: (value: typeof cancelled) => void;
|
|
227
|
+
const cancellation = new Promise<typeof cancelled>(resolve => {
|
|
228
|
+
resolveCancellation = resolve;
|
|
229
|
+
});
|
|
230
|
+
const abort = () => {
|
|
231
|
+
if (active === controller) {
|
|
232
|
+
active = undefined;
|
|
233
|
+
setPending(false);
|
|
234
|
+
}
|
|
235
|
+
resolveCancellation(cancelled);
|
|
236
|
+
};
|
|
237
|
+
if (signal.aborted) abort();
|
|
238
|
+
else signal.addEventListener('abort', abort, { once: true });
|
|
239
|
+
|
|
240
|
+
return (async () => {
|
|
241
|
+
try {
|
|
242
|
+
if (!current()) return undefined;
|
|
243
|
+
const result = await Promise.race([
|
|
244
|
+
client.action({ request: new Request(request, { signal }) }),
|
|
245
|
+
cancellation,
|
|
246
|
+
]);
|
|
247
|
+
if (result === cancelled || !current()) return undefined;
|
|
248
|
+
const publicResult = actionOutcome(result, owner, privateContexts);
|
|
249
|
+
setOutcome(publicResult);
|
|
250
|
+
// The core promises remain intact; terminal framing owns action completion.
|
|
251
|
+
if (
|
|
252
|
+
(await Promise.race([
|
|
253
|
+
Promise.resolve(result.completion),
|
|
254
|
+
cancellation,
|
|
255
|
+
])) === cancelled ||
|
|
256
|
+
!current()
|
|
257
|
+
)
|
|
258
|
+
return undefined;
|
|
259
|
+
if (
|
|
260
|
+
publicResult.kind === 'error' ||
|
|
261
|
+
publicResult.kind === 'not-found'
|
|
262
|
+
) {
|
|
263
|
+
setError(new RouteActionError(routeId, publicResult));
|
|
264
|
+
} else if (result.kind === 'redirect') {
|
|
265
|
+
// A navigation is a GET. HTTP allows that for 303, and for 301/302
|
|
266
|
+
// only after POST; other redirects keep the method and body.
|
|
267
|
+
if (
|
|
268
|
+
result.status === 307 ||
|
|
269
|
+
result.status === 308 ||
|
|
270
|
+
((result.status === 301 || result.status === 302) &&
|
|
271
|
+
request.method !== 'POST')
|
|
272
|
+
)
|
|
273
|
+
throw new Error(
|
|
274
|
+
`A native action redirect must not preserve the method (HTTP ${result.status} after ${request.method}); redirect with 303 to navigate after the mutation`,
|
|
275
|
+
);
|
|
276
|
+
// HTTP Location is relative to the mutation URL. Native resolution
|
|
277
|
+
// retains protocol policy and chooses document versus route navigation.
|
|
278
|
+
const resolved = router.resolveRedirect(
|
|
279
|
+
redirect({
|
|
280
|
+
href: new URL(result.location, request.url).href,
|
|
281
|
+
statusCode: result.status,
|
|
282
|
+
}),
|
|
283
|
+
);
|
|
284
|
+
// Native navigation commits the destination synchronously. Invalidate
|
|
285
|
+
// immediately so cached matches refresh there, before the old owner
|
|
286
|
+
// can be disposed; the abandoned page does not load again.
|
|
287
|
+
const navigation = router.navigate({
|
|
288
|
+
...resolved.options,
|
|
289
|
+
replace: true,
|
|
290
|
+
});
|
|
291
|
+
const refresh = resolved.options.reloadDocument
|
|
292
|
+
? Promise.resolve()
|
|
293
|
+
: router.invalidate({ sync: true });
|
|
294
|
+
await Promise.race([
|
|
295
|
+
Promise.all([navigation, refresh]),
|
|
296
|
+
cancellation,
|
|
297
|
+
]);
|
|
298
|
+
} else if (result.status < 400) {
|
|
299
|
+
await Promise.race([router.invalidate({ sync: true }), cancellation]);
|
|
300
|
+
}
|
|
301
|
+
return current() ? publicResult : undefined;
|
|
302
|
+
} catch (failure) {
|
|
303
|
+
owner.fail(failure);
|
|
304
|
+
return undefined;
|
|
305
|
+
} finally {
|
|
306
|
+
request.signal.removeEventListener('abort', abortRequest);
|
|
307
|
+
signal.removeEventListener('abort', abort);
|
|
308
|
+
if (active === controller) {
|
|
309
|
+
active = undefined;
|
|
310
|
+
setPending(false);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
})();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function submitForm(
|
|
317
|
+
form: HTMLFormElement,
|
|
318
|
+
submitter?: HTMLElement | null,
|
|
319
|
+
) {
|
|
320
|
+
try {
|
|
321
|
+
const button =
|
|
322
|
+
submitter instanceof HTMLButtonElement ||
|
|
323
|
+
submitter instanceof HTMLInputElement
|
|
324
|
+
? submitter
|
|
325
|
+
: undefined;
|
|
326
|
+
const method = button?.hasAttribute('formmethod')
|
|
327
|
+
? button.formMethod
|
|
328
|
+
: form.method;
|
|
329
|
+
if (method.toLowerCase() !== 'post') {
|
|
330
|
+
throw new Error('A Solid action form requires method="post"');
|
|
331
|
+
}
|
|
332
|
+
const target = button?.hasAttribute('formtarget')
|
|
333
|
+
? button.formTarget
|
|
334
|
+
: form.target;
|
|
335
|
+
if (target && target.toLowerCase() !== '_self') {
|
|
336
|
+
throw new Error(
|
|
337
|
+
'A Solid action form requires the current browsing context',
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
const destination = button?.hasAttribute('formaction')
|
|
341
|
+
? button.formAction
|
|
342
|
+
: form.action;
|
|
343
|
+
const formData = new FormData(form, button);
|
|
344
|
+
const encoding = button?.hasAttribute('formenctype')
|
|
345
|
+
? button.formEnctype
|
|
346
|
+
: form.enctype;
|
|
347
|
+
let body: BodyInit;
|
|
348
|
+
if (encoding === 'multipart/form-data') {
|
|
349
|
+
body = formData;
|
|
350
|
+
} else if (encoding === 'application/x-www-form-urlencoded') {
|
|
351
|
+
const encoded = new URLSearchParams();
|
|
352
|
+
for (const [name, value] of formData) {
|
|
353
|
+
encoded.append(name, typeof value === 'string' ? value : value.name);
|
|
354
|
+
}
|
|
355
|
+
body = encoded;
|
|
356
|
+
} else {
|
|
357
|
+
throw new Error(`Unsupported Solid action form encoding: ${encoding}`);
|
|
358
|
+
}
|
|
359
|
+
return await submit(
|
|
360
|
+
new Request(new URL(destination || url(), url()), {
|
|
361
|
+
method: 'POST',
|
|
362
|
+
body,
|
|
363
|
+
credentials: 'same-origin',
|
|
364
|
+
}),
|
|
365
|
+
);
|
|
366
|
+
} catch (failure) {
|
|
367
|
+
if (!disposed)
|
|
368
|
+
setError(actionFailure(failure, undefined, [router.options.context]));
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (getOwner()) onCleanup(dispose);
|
|
374
|
+
return Object.freeze({
|
|
375
|
+
routeId,
|
|
376
|
+
pending,
|
|
377
|
+
outcome,
|
|
378
|
+
error,
|
|
379
|
+
url,
|
|
380
|
+
submit,
|
|
381
|
+
submitForm,
|
|
382
|
+
cancel,
|
|
383
|
+
dispose,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Bind a form to the closest native route without a second route-ID authority. */
|
|
388
|
+
export function useRouteAction(): RouteAction {
|
|
389
|
+
const router = useRouter();
|
|
390
|
+
if (!router) throw new Error('useRouteAction requires a native Solid router');
|
|
391
|
+
const identity = routerIdentity(router);
|
|
392
|
+
if (!identity) {
|
|
393
|
+
throw new Error(
|
|
394
|
+
'useRouteAction requires the application renderer identity',
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
const match = useMatch({ strict: false });
|
|
398
|
+
// One-time snapshot: this hook identifies the filesystem route it was
|
|
399
|
+
// called from, which is fixed for the component instance's lifetime (a
|
|
400
|
+
// route component is not reused across matches). Reading the accessor
|
|
401
|
+
// here is intentionally non-reactive, so `untrack` is the correct escape
|
|
402
|
+
// hatch rather than a tracking scope.
|
|
403
|
+
const routeMatch = untrack(match);
|
|
404
|
+
const route = router.routesById[routeMatch.routeId];
|
|
405
|
+
const routeId = (
|
|
406
|
+
route?.options.staticData as { ultramodernRouteId?: string } | undefined
|
|
407
|
+
)?.ultramodernRouteId;
|
|
408
|
+
if (!routeId) {
|
|
409
|
+
throw new Error('useRouteAction requires a native filesystem route');
|
|
410
|
+
}
|
|
411
|
+
return createRouteAction({ router, routeId, rendererIdentity: identity });
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export type ActionFormProps = Omit<
|
|
415
|
+
JSX.FormHTMLAttributes<HTMLFormElement>,
|
|
416
|
+
'action' | 'method' | 'onSubmit' | 'onSubmitCapture'
|
|
417
|
+
> & {
|
|
418
|
+
action: RouteAction;
|
|
419
|
+
children?: JSX.Element;
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
/** Native controls produce the request body; the renderer owns data transport. */
|
|
423
|
+
export function ActionForm(props: ActionFormProps): JSX.Element {
|
|
424
|
+
const submit: JSX.EventHandler<HTMLFormElement, SubmitEvent> = event => {
|
|
425
|
+
event.preventDefault();
|
|
426
|
+
void props.action.submitForm(event.currentTarget, event.submitter);
|
|
427
|
+
};
|
|
428
|
+
return (
|
|
429
|
+
<form
|
|
430
|
+
{...omit(props, 'action')}
|
|
431
|
+
action={props.action.url()}
|
|
432
|
+
method="post"
|
|
433
|
+
enctype={props.enctype ?? 'application/x-www-form-urlencoded'}
|
|
434
|
+
onSubmit={submit}
|
|
435
|
+
/>
|
|
436
|
+
);
|
|
437
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DataProtocolError } from '@modern-js/renderer-core/data';
|
|
2
|
+
import { type JSX, useHead } from '@solidjs/web';
|
|
3
|
+
import type { AnyRouter, RegisteredRouter } from '@tanstack/router-core';
|
|
4
|
+
import { ownApplicationRouteData } from './route-completion';
|
|
5
|
+
import { toHeadTags, useTags } from './router-binding/headContentUtils';
|
|
6
|
+
import { Matches } from './router-binding/Matches';
|
|
7
|
+
import {
|
|
8
|
+
RouterContextProvider,
|
|
9
|
+
type RouterProps,
|
|
10
|
+
} from './router-binding/RouterProvider';
|
|
11
|
+
|
|
12
|
+
function ApplicationHead(): null {
|
|
13
|
+
const tags = useTags();
|
|
14
|
+
// The application document owns Solid's hydration bootstrap. Register route
|
|
15
|
+
// metadata through the native head registry without emitting a second script.
|
|
16
|
+
useHead(() => toHeadTags(tags()));
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Native routing and head hooks share the same request/application provider. */
|
|
21
|
+
export function ApplicationRouter<
|
|
22
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
23
|
+
TDehydrated extends Record<string, unknown> = Record<string, unknown>,
|
|
24
|
+
>(props: Omit<RouterProps<TRouter, TDehydrated>, 'context'>): JSX.Element {
|
|
25
|
+
if (Object.hasOwn(props, 'context'))
|
|
26
|
+
throw new DataProtocolError(
|
|
27
|
+
'Set public Solid router context in createApplicationRouter; ApplicationRouter context overrides are unsupported',
|
|
28
|
+
);
|
|
29
|
+
const { router, ...rest } = props;
|
|
30
|
+
ownApplicationRouteData(router);
|
|
31
|
+
return (
|
|
32
|
+
<RouterContextProvider router={router} {...rest}>
|
|
33
|
+
{() => (
|
|
34
|
+
<>
|
|
35
|
+
<ApplicationHead />
|
|
36
|
+
<Matches />
|
|
37
|
+
</>
|
|
38
|
+
)}
|
|
39
|
+
</RouterContextProvider>
|
|
40
|
+
);
|
|
41
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type DocumentBootstrap,
|
|
3
|
+
readDocumentBootstrap,
|
|
4
|
+
} from '@modern-js/renderer-core/document';
|
|
5
|
+
import type { NativeFederationBinding } from '@modern-js/renderer-core/federation';
|
|
6
|
+
import type { RendererIdentity } from '@modern-js/renderer-core/identity';
|
|
7
|
+
import type { JSX } from '@solidjs/web';
|
|
8
|
+
import { hydrate, render } from '@solidjs/web';
|
|
9
|
+
import { runWithOwner } from 'solid-js';
|
|
10
|
+
import { createFederationScope, provideFederation } from './federation-context';
|
|
11
|
+
|
|
12
|
+
type NativeMountOptions = NonNullable<Parameters<typeof hydrate>[2]>;
|
|
13
|
+
export type ApplicationMountElement = Parameters<typeof hydrate>[1];
|
|
14
|
+
|
|
15
|
+
export type SolidDocumentBootstrap = DocumentBootstrap;
|
|
16
|
+
|
|
17
|
+
/** Read the server's exact identity before creating a native router or owner. */
|
|
18
|
+
export function readSolidDocumentBootstrap(
|
|
19
|
+
document: Document,
|
|
20
|
+
expectedIdentity: RendererIdentity,
|
|
21
|
+
): SolidDocumentBootstrap {
|
|
22
|
+
if (expectedIdentity.renderer !== 'solid') {
|
|
23
|
+
throw new Error('The Solid document requires a Solid renderer identity');
|
|
24
|
+
}
|
|
25
|
+
const { identity, documentId, hydrating } = readDocumentBootstrap(
|
|
26
|
+
document,
|
|
27
|
+
expectedIdentity,
|
|
28
|
+
);
|
|
29
|
+
return { identity, documentId, hydrating };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The generated entry passes its bundler's native HMR disposal callback. */
|
|
33
|
+
export interface ApplicationMountOptions {
|
|
34
|
+
renderId?: NativeMountOptions['renderId'];
|
|
35
|
+
onError?: NativeMountOptions['onError'];
|
|
36
|
+
hot?: { dispose(callback: () => void): void };
|
|
37
|
+
/** This browser compilation's native Module Federation runtime. */
|
|
38
|
+
federation?: NativeFederationBinding;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const applications = new WeakSet<ApplicationMountElement>();
|
|
42
|
+
|
|
43
|
+
function createApplication(
|
|
44
|
+
view: () => JSX.Element,
|
|
45
|
+
element: ApplicationMountElement,
|
|
46
|
+
options: ApplicationMountOptions,
|
|
47
|
+
hydrating: boolean,
|
|
48
|
+
): () => void {
|
|
49
|
+
if (applications.has(element)) {
|
|
50
|
+
throw new Error('A Solid application already owns this mount element');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let nativeDispose: (() => void) | undefined;
|
|
54
|
+
let disposed = false;
|
|
55
|
+
applications.add(element);
|
|
56
|
+
|
|
57
|
+
const dispose = () => {
|
|
58
|
+
if (disposed) return;
|
|
59
|
+
disposed = true;
|
|
60
|
+
try {
|
|
61
|
+
nativeDispose?.();
|
|
62
|
+
} finally {
|
|
63
|
+
applications.delete(element);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const nativeOptions = {
|
|
69
|
+
renderId: options.renderId,
|
|
70
|
+
onError: options.onError,
|
|
71
|
+
};
|
|
72
|
+
// Its federated components load through this application's own host.
|
|
73
|
+
const root = provideFederation(
|
|
74
|
+
createFederationScope(options.federation),
|
|
75
|
+
view,
|
|
76
|
+
);
|
|
77
|
+
// Each application gets an independent native owner. Do not inherit a
|
|
78
|
+
// caller's component owner, including when mounting during a transition.
|
|
79
|
+
nativeDispose = runWithOwner(null, () =>
|
|
80
|
+
hydrating
|
|
81
|
+
? hydrate(root, element, nativeOptions)
|
|
82
|
+
: render(root, element, undefined, nativeOptions),
|
|
83
|
+
);
|
|
84
|
+
options.hot?.dispose(dispose);
|
|
85
|
+
return dispose;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
dispose();
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function mountApplication(
|
|
93
|
+
view: () => JSX.Element,
|
|
94
|
+
element: ApplicationMountElement,
|
|
95
|
+
options: ApplicationMountOptions = {},
|
|
96
|
+
): () => void {
|
|
97
|
+
return createApplication(view, element, options, false);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function hydrateApplication(
|
|
101
|
+
view: () => JSX.Element,
|
|
102
|
+
element: ApplicationMountElement,
|
|
103
|
+
options: ApplicationMountOptions = {},
|
|
104
|
+
): () => void {
|
|
105
|
+
return createApplication(view, element, options, true);
|
|
106
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { LocalisedUrlsOption } from '@modern-js/i18n-runtime-extensions/paths';
|
|
2
|
+
import type { NativeI18nView } from '@modern-js/renderer-core/entry-client';
|
|
3
|
+
import type { NativeRouterFactory } from '@modern-js/renderer-core/router';
|
|
4
|
+
import type { JSX } from '@solidjs/web';
|
|
5
|
+
import type { Component } from 'solid-js';
|
|
6
|
+
import { ApplicationRouter } from './application-router';
|
|
7
|
+
import { I18nProvider } from './i18n/I18nProvider';
|
|
8
|
+
import type { I18nInstanceLike } from './i18n/types';
|
|
9
|
+
import { createApplicationRouter } from './route-completion';
|
|
10
|
+
import {
|
|
11
|
+
createFileSystemRouteTree,
|
|
12
|
+
type FileSystemRouteModule,
|
|
13
|
+
} from './router';
|
|
14
|
+
import {
|
|
15
|
+
type AnyRoute,
|
|
16
|
+
type AnyRouter,
|
|
17
|
+
createMemoryHistory,
|
|
18
|
+
} from './router-binding/index';
|
|
19
|
+
|
|
20
|
+
export type SolidI18nView = NativeI18nView<unknown, LocalisedUrlsOption>;
|
|
21
|
+
|
|
22
|
+
/** The Solid route tree and router of a generated entry. */
|
|
23
|
+
export const solidRouterFactory: NativeRouterFactory<AnyRoute, AnyRouter> = {
|
|
24
|
+
routeTree: (routes, modules, options) =>
|
|
25
|
+
createFileSystemRouteTree(
|
|
26
|
+
routes,
|
|
27
|
+
modules as Readonly<Record<string, FileSystemRouteModule>>,
|
|
28
|
+
options,
|
|
29
|
+
),
|
|
30
|
+
router: ({ location, ...options }) =>
|
|
31
|
+
createApplicationRouter({
|
|
32
|
+
...options,
|
|
33
|
+
...(location
|
|
34
|
+
? {
|
|
35
|
+
origin: location.origin,
|
|
36
|
+
history: createMemoryHistory({ initialEntries: [location.href] }),
|
|
37
|
+
}
|
|
38
|
+
: {}),
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function componentView(
|
|
43
|
+
component: unknown,
|
|
44
|
+
i18n?: SolidI18nView,
|
|
45
|
+
): () => JSX.Element {
|
|
46
|
+
const App = component as Component;
|
|
47
|
+
if (!i18n) return () => <App />;
|
|
48
|
+
return () => (
|
|
49
|
+
<I18nProvider
|
|
50
|
+
instance={i18n.instance as I18nInstanceLike}
|
|
51
|
+
languages={i18n.languages}
|
|
52
|
+
localisedUrls={i18n.localisedUrls}
|
|
53
|
+
>
|
|
54
|
+
<App />
|
|
55
|
+
</I18nProvider>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function routerView(
|
|
60
|
+
router: AnyRouter,
|
|
61
|
+
i18n?: SolidI18nView,
|
|
62
|
+
): () => JSX.Element {
|
|
63
|
+
if (!i18n) return () => <ApplicationRouter router={router} />;
|
|
64
|
+
return () => (
|
|
65
|
+
<I18nProvider
|
|
66
|
+
instance={i18n.instance as I18nInstanceLike}
|
|
67
|
+
languages={i18n.languages}
|
|
68
|
+
localisedUrls={i18n.localisedUrls}
|
|
69
|
+
>
|
|
70
|
+
<ApplicationRouter router={router} />
|
|
71
|
+
</I18nProvider>
|
|
72
|
+
);
|
|
73
|
+
}
|