one
Version:
One is a new React Framework that makes Vite serve both native and web.
443 lines (442 loc) • 17.1 kB
JavaScript
import { useCallback, useSyncExternalStore } from "react";
import { registerDevtoolsFunction } from "./devtools/registry.native.js";
import { useParams, usePathname } from "./hooks.native.js";
import { findNearestNotFoundRoute, setNotFoundState } from "./notFoundState.native.js";
import { router } from "./router/imperative-api.native.js";
import { preloadedLoaderData, preloadingLoader, routeNode } from "./router/router.native.js";
import { subscribeToClientMatches, getClientMatchesSnapshot, updateMatchLoaderData } from "./useMatches.native.js";
import { getLoaderPath } from "./utils/cleanUrl.native.js";
import { dynamicImport } from "./utils/dynamicImport.native.js";
import { weakKey } from "./utils/weakKey.native.js";
import { useServerContext } from "./vite/one-server-only.native.js";
function _instanceof(left, right) {
return right != null && typeof Symbol < "u" && right[Symbol.hasInstance] ? !!right[Symbol.hasInstance](left) : left instanceof right;
}
var loaderTimingHistory = [],
MAX_TIMING_HISTORY = 50,
recordLoaderTiming = process.env.NODE_ENV === "development" ? function (entry) {
loaderTimingHistory.unshift(entry), loaderTimingHistory.length > MAX_TIMING_HISTORY && loaderTimingHistory.pop(), typeof window < "u" && typeof CustomEvent < "u" && (window.dispatchEvent(new CustomEvent("one-loader-timing", {
detail: entry
})), entry.error && window.dispatchEvent(new CustomEvent("one-error", {
detail: {
error: {
message: entry.error,
name: "LoaderError"
},
route: {
pathname: entry.path
},
timestamp: Date.now(),
type: "loader"
}
})));
} : void 0;
function getLoaderTimingHistory() {
return loaderTimingHistory;
}
registerDevtoolsFunction("getLoaderTimingHistory", getLoaderTimingHistory);
registerDevtoolsFunction("recordLoaderTiming", recordLoaderTiming);
var loaderState = {},
subscribers = /* @__PURE__ */new Set();
function updateState(path, updates) {
loaderState[path] = {
...loaderState[path],
...updates
}, subscribers.forEach(function (callback) {
callback();
});
}
function subscribe(callback) {
return subscribers.add(callback), function () {
return subscribers.delete(callback);
};
}
function getLoaderState(path, preloadedData2) {
return loaderState[path] || (loaderState[path] = {
data: preloadedData2,
error: void 0,
promise: void 0,
state: "idle",
hasLoadedOnce: !!preloadedData2
}), loaderState[path];
}
async function refetchLoader(pathname2) {
var startTime2 = performance.now();
updateState(pathname2, {
state: "loading",
error: null
});
try {
var _dynamicImport2,
cacheBust = `${Date.now()}`,
loaderJSUrl2 = getLoaderPath(pathname2, !0, cacheBust),
moduleLoadStart2 = performance.now(),
module2 = await ((_dynamicImport2 = dynamicImport(loaderJSUrl2)) === null || _dynamicImport2 === void 0 ? void 0 : _dynamicImport2.catch(function () {
return null;
})),
moduleLoadTime2 = performance.now() - moduleLoadStart2;
if (!module2?.loader) {
updateState(pathname2, {
data: void 0,
state: "idle",
hasLoadedOnce: !0
});
return;
}
var executionStart2 = performance.now(),
result2 = await module2.loader(),
executionTime2 = performance.now() - executionStart2,
totalTime2 = performance.now() - startTime2;
if (result2?.__oneRedirect) {
recordLoaderTiming?.({
path: pathname2,
startTime: startTime2,
moduleLoadTime: moduleLoadTime2,
executionTime: executionTime2,
totalTime: totalTime2,
source: "refetch"
}), updateState(pathname2, {
data: void 0,
state: "idle",
hasLoadedOnce: !0
}), router.replace(result2.__oneRedirect);
return;
}
if (result2?.__oneError === 404) {
recordLoaderTiming?.({
path: pathname2,
startTime: startTime2,
moduleLoadTime: moduleLoadTime2,
executionTime: executionTime2,
totalTime: totalTime2,
source: "refetch"
});
var notFoundRoute2 = findNearestNotFoundRoute(pathname2, routeNode);
setNotFoundState({
notFoundPath: result2.__oneNotFoundPath || "/+not-found",
notFoundRouteNode: notFoundRoute2 || void 0,
originalPath: pathname2
});
return;
}
updateState(pathname2, {
data: result2,
state: "idle",
timestamp: Date.now(),
hasLoadedOnce: !0
});
var currentMatches = getClientMatchesSnapshot(),
pageMatch = currentMatches[currentMatches.length - 1],
normalizedPathname = pathname2.replace(/\/$/, "") || "/",
normalizedMatchPathname = (pageMatch?.pathname || "").replace(/\/$/, "") || "/";
pageMatch && normalizedMatchPathname === normalizedPathname && updateMatchLoaderData(pageMatch.routeId, result2), recordLoaderTiming?.({
path: pathname2,
startTime: startTime2,
moduleLoadTime: moduleLoadTime2,
executionTime: executionTime2,
totalTime: totalTime2,
source: "refetch"
});
} catch (err) {
var totalTime1 = performance.now() - startTime2;
throw updateState(pathname2, {
error: err,
state: "idle"
}), recordLoaderTiming?.({
path: pathname2,
startTime: startTime2,
totalTime: totalTime1,
error: _instanceof(err, Error) ? err.message : String(err),
source: "refetch"
}), err;
}
}
process.env.NODE_ENV === "development" && typeof window < "u" && (window.__oneRefetchLoader = refetchLoader);
async function refetchMatchLoader(routeId, currentPath2) {
var _dynamicImport2,
cacheBust = `${Date.now()}`,
loaderJSUrl2 = getLoaderPath(currentPath2, !0, cacheBust),
module2 = await ((_dynamicImport2 = dynamicImport(loaderJSUrl2)) === null || _dynamicImport2 === void 0 ? void 0 : _dynamicImport2.catch(function () {
return null;
}));
if (module2?.loader) {
var result2 = await module2.loader();
result2?.__oneRedirect || result2?.__oneError || updateMatchLoaderData(routeId, result2);
}
}
function useLoaderState(loader) {
var {
loaderProps: loaderPropsFromServerContext,
loaderData: loaderDataFromServerContext
} = useServerContext() || {},
params = useParams(),
pathname = usePathname(),
currentPath = pathname.replace(/\/index$/, "").replace(/\/$/, "") || "/";
if (typeof window > "u" && loader) {
var serverData = useAsyncFn(loader, loaderPropsFromServerContext || {
path: pathname,
params
});
return {
data: serverData,
refetch: async function () {},
state: "idle"
};
}
var matchRouteId = loader ? function () {
var result2 = loader();
return typeof result2 == "string" && result2.startsWith("./") ? result2 : null;
}() : null,
clientMatches = useSyncExternalStore(subscribeToClientMatches, getClientMatchesSnapshot, getClientMatchesSnapshot),
serverContextPath = loaderPropsFromServerContext?.path,
preloadedData = serverContextPath === currentPath ? loaderDataFromServerContext : void 0,
loaderStateEntry = useSyncExternalStore(subscribe, function () {
return getLoaderState(currentPath, preloadedData);
}, function () {
return getLoaderState(currentPath, preloadedData);
}),
refetch = useCallback(function () {
return refetchLoader(currentPath);
}, [currentPath]);
if (matchRouteId) {
var _clientMatches_,
match = clientMatches.find(function (m) {
return m.routeId === matchRouteId;
}),
isPageMatch = clientMatches.length > 0 && ((_clientMatches_ = clientMatches[clientMatches.length - 1]) === null || _clientMatches_ === void 0 ? void 0 : _clientMatches_.routeId) === matchRouteId,
matchPathNormalized = (match?.pathname || "").replace(/\/$/, "") || "/",
matchPathFresh = !isPageMatch || matchPathNormalized === currentPath;
if (match && match.loaderData != null && matchPathFresh) return {
data: match.loaderData,
// refetch updates both loaderState (for useLoaderState() consumers without a loader)
// and the match entry (for this component and useMatches consumers)
refetch: async function () {
await refetchLoader(currentPath);
var fresh = loaderState[currentPath];
fresh?.data != null && updateMatchLoaderData(matchRouteId, fresh.data);
},
state: loaderStateEntry.state
};
}
if (!loader) return {
refetch,
state: loaderStateEntry.state
};
if (!loaderStateEntry.data && !loaderStateEntry.promise && !loaderStateEntry.hasLoadedOnce && loader) {
var resolvedPreloadData = preloadedLoaderData[currentPath];
if (resolvedPreloadData != null) delete preloadedLoaderData[currentPath], delete preloadingLoader[currentPath], loaderStateEntry.data = resolvedPreloadData, loaderStateEntry.hasLoadedOnce = !0;else if (preloadingLoader[currentPath]) {
var preloadPromise = preloadingLoader[currentPath],
promise = preloadPromise.then(function (val) {
delete preloadingLoader[currentPath], delete preloadedLoaderData[currentPath], val != null ? updateState(currentPath, {
data: val,
hasLoadedOnce: !0,
promise: void 0
}) : updateState(currentPath, {
promise: void 0
});
}).catch(function (err) {
console.error("Error running loader()", err), delete preloadingLoader[currentPath], updateState(currentPath, {
error: err,
promise: void 0
});
});
loaderStateEntry.promise = promise;
} else {
var loadData = async function () {
var startTime = performance.now();
try {
var _dynamicImport,
loaderJSUrl = getLoaderPath(currentPath, !0),
nativeLoaderJSUrl = `${loaderJSUrl}?platform=ios`;
try {
var moduleLoadStart = performance.now(),
loaderJsCodeResp = await fetch(nativeLoaderJSUrl);
if (!loaderJsCodeResp.ok) throw new Error(`Response not ok: ${loaderJsCodeResp.status}`);
var loaderJsCode = await loaderJsCodeResp.text(),
result = eval(`() => { var exports = {}; ${loaderJsCode}; return exports; }`)(),
moduleLoadTime = performance.now() - moduleLoadStart;
if (typeof result.loader != "function") throw new Error("Loader code isn't exporting a `loader` function");
var executionStart = performance.now(),
data = await result.loader(),
executionTime = performance.now() - executionStart,
totalTime = performance.now() - startTime;
if (data?.__oneRedirect) {
recordLoaderTiming?.({
path: currentPath,
startTime,
moduleLoadTime,
executionTime,
totalTime,
source: "initial"
}), updateState(currentPath, {
data: void 0,
hasLoadedOnce: !0,
promise: void 0
}), router.replace(data.__oneRedirect);
return;
}
if (data?.__oneError === 404) {
recordLoaderTiming?.({
path: currentPath,
startTime,
moduleLoadTime,
executionTime,
totalTime,
source: "initial"
});
var notFoundRoute = findNearestNotFoundRoute(currentPath, routeNode);
setNotFoundState({
notFoundPath: data.__oneNotFoundPath || "/+not-found",
notFoundRouteNode: notFoundRoute || void 0,
originalPath: currentPath
});
return;
}
updateState(currentPath, {
data,
hasLoadedOnce: !0,
promise: void 0
}), recordLoaderTiming?.({
path: currentPath,
startTime,
moduleLoadTime,
executionTime,
totalTime,
source: "initial"
});
return;
} catch (e) {
var totalTime = performance.now() - startTime;
updateState(currentPath, {
data: {},
promise: void 0
}), recordLoaderTiming?.({
path: currentPath,
startTime,
totalTime,
error: _instanceof(e, Error) ? e.message : String(e),
source: "initial"
});
return;
}
var loaderJSUrl = getLoaderPath(currentPath, !0),
moduleLoadStart = performance.now(),
module = await ((_dynamicImport = dynamicImport(loaderJSUrl)) === null || _dynamicImport === void 0 ? void 0 : _dynamicImport.catch(function () {
return null;
})),
moduleLoadTime = performance.now() - moduleLoadStart;
if (!module?.loader) {
updateState(currentPath, {
data: void 0,
hasLoadedOnce: !0,
promise: void 0
});
return;
}
var executionStart = performance.now(),
result = await module.loader(),
executionTime = performance.now() - executionStart,
totalTime = performance.now() - startTime;
if (result?.__oneRedirect) {
recordLoaderTiming?.({
path: currentPath,
startTime,
moduleLoadTime,
executionTime,
totalTime,
source: "initial"
}), updateState(currentPath, {
data: void 0,
hasLoadedOnce: !0,
promise: void 0
}), router.replace(result.__oneRedirect);
return;
}
if (result?.__oneError === 404) {
recordLoaderTiming?.({
path: currentPath,
startTime,
moduleLoadTime,
executionTime,
totalTime,
source: "initial"
});
var notFoundRoute = findNearestNotFoundRoute(currentPath, routeNode);
setNotFoundState({
notFoundPath: result.__oneNotFoundPath || "/+not-found",
notFoundRouteNode: notFoundRoute || void 0,
originalPath: currentPath
});
return;
}
updateState(currentPath, {
data: result,
hasLoadedOnce: !0,
promise: void 0
}), recordLoaderTiming?.({
path: currentPath,
startTime,
moduleLoadTime,
executionTime,
totalTime,
source: "initial"
});
} catch (err) {
var totalTime = performance.now() - startTime;
updateState(currentPath, {
error: err,
promise: void 0
}), recordLoaderTiming?.({
path: currentPath,
startTime,
totalTime,
error: _instanceof(err, Error) ? err.message : String(err),
source: "initial"
});
}
},
promise = loadData();
loaderStateEntry.promise = promise;
}
}
if (loader) {
if (loaderStateEntry.error && !loaderStateEntry.hasLoadedOnce) throw loaderStateEntry.error;
if (loaderStateEntry.data === void 0 && loaderStateEntry.promise && !loaderStateEntry.hasLoadedOnce) throw loaderStateEntry.promise;
return {
data: loaderStateEntry.data,
refetch,
state: loaderStateEntry.state
};
} else return {
refetch,
state: loaderStateEntry.state
};
}
function useLoader(loader2) {
var {
data: data2
} = useLoaderState(loader2);
return data2;
}
var results = /* @__PURE__ */new Map(),
started = /* @__PURE__ */new Map();
function resetLoaderState() {
results.clear(), started.clear();
}
function useAsyncFn(val, props) {
var key = (val ? weakKey(val) : "") + JSON.stringify(props);
if (val && !started.get(key)) {
started.set(key, !0);
var next = val(props);
_instanceof(next, Promise) && (next = next.then(function (final) {
results.set(key, final);
}).catch(function (err) {
console.error("Error running loader()", err), results.set(key, void 0);
})), results.set(key, next);
}
var current = results.get(key);
if (_instanceof(current, Promise)) throw current;
return current;
}
export { getLoaderTimingHistory, refetchLoader, refetchMatchLoader, resetLoaderState, useLoader, useLoaderState };
//# sourceMappingURL=useLoader.native.js.map