版博士V2.0程序
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 

323 righe
9.7 KiB

  1. import {
  2. __spreadProps,
  3. __spreadValues
  4. } from "./chunk-E3WVRKG7.mjs";
  5. // src/data-fetching/defineLoader.ts
  6. import {
  7. useRouter,
  8. useRoute
  9. } from "vue-router";
  10. // src/data-fetching/dataCache.ts
  11. import { ref, effectScope } from "vue";
  12. function isCacheExpired(entry, options) {
  13. const { cacheTime } = options;
  14. return (
  15. // cacheTime == 0 means no cache
  16. !cacheTime || // did we hit the expiration time
  17. Date.now() - entry.when >= cacheTime || Array.from(entry.children).some(
  18. (childEntry) => isCacheExpired(childEntry, options)
  19. )
  20. );
  21. }
  22. function createDataLoaderEntry(options, initialData) {
  23. return withinScope(() => ({
  24. pending: ref(false),
  25. error: ref(),
  26. // set to 0 to when there is an initialData so the next request will always trigger the data loaders
  27. when: initialData === void 0 ? Date.now() : 0,
  28. children: /* @__PURE__ */ new Set(),
  29. // @ts-expect-error: data always start as empty
  30. data: ref(initialData),
  31. params: {},
  32. query: {},
  33. // hash: null,
  34. isReady: false
  35. // this was just too annoying to type
  36. }));
  37. }
  38. function updateDataLoaderEntry(entry, data, params, query, hash) {
  39. entry.when = Date.now();
  40. entry.params = params;
  41. entry.query = query;
  42. entry.hash = hash.v;
  43. entry.isReady = true;
  44. entry.data.value = data;
  45. }
  46. var scope;
  47. function withinScope(fn) {
  48. return (scope = scope || effectScope(true)).run(fn);
  49. }
  50. function stopScope() {
  51. if (scope) {
  52. scope.stop();
  53. scope = void 0;
  54. }
  55. }
  56. var currentContext;
  57. function getCurrentContext() {
  58. return currentContext || [];
  59. }
  60. function setCurrentContext(context) {
  61. currentContext = context;
  62. }
  63. // src/data-fetching/locationUtils.ts
  64. function includesParams(outer, inner) {
  65. for (const key in inner) {
  66. const innerValue = inner[key];
  67. const outerValue = outer[key];
  68. if (typeof innerValue === "string") {
  69. if (innerValue !== outerValue)
  70. return false;
  71. } else if (!innerValue || !outerValue) {
  72. if (innerValue !== outerValue)
  73. return false;
  74. } else {
  75. if (!Array.isArray(outerValue) || outerValue.length !== innerValue.length || innerValue.some((value, i) => value !== outerValue[i]))
  76. return false;
  77. }
  78. }
  79. return true;
  80. }
  81. // src/data-fetching/defineLoader.ts
  82. var DEFAULT_DEFINE_LOADER_OPTIONS = {
  83. cacheTime: 1e3 * 5,
  84. // 5s
  85. lazy: false,
  86. // same as no key
  87. key: ""
  88. };
  89. function defineLoader(nameOrLoader, _loaderOrOptions, opts) {
  90. const loader = typeof nameOrLoader === "function" ? nameOrLoader : _loaderOrOptions;
  91. opts = typeof _loaderOrOptions === "object" ? _loaderOrOptions : opts;
  92. const options = __spreadValues(__spreadValues({}, DEFAULT_DEFINE_LOADER_OPTIONS), opts);
  93. const entries = /* @__PURE__ */ new WeakMap();
  94. let pendingPromise;
  95. let currentNavigation;
  96. const pendingLoad = () => pendingPromise;
  97. const dataLoader = () => {
  98. let [parentEntry, _router, _route] = getCurrentContext();
  99. const router = _router || useRouter();
  100. const route = _route || useRoute();
  101. if (
  102. // no cache: we need to load
  103. !entries.has(router) || // invoked by the parent, we should try to load again
  104. parentEntry
  105. ) {
  106. load(route, router, parentEntry);
  107. }
  108. const entry = entries.get(router);
  109. const promise = Promise.resolve(pendingPromise).then(() => dataLoaderResult).finally(() => {
  110. if (parentEntry) {
  111. parentEntry.children.add(entry);
  112. }
  113. setCurrentContext(parentEntry && [parentEntry, router, route]);
  114. });
  115. const { data, pending, error } = entry;
  116. function refresh() {
  117. invalidate();
  118. load(route, router, parentEntry);
  119. return pendingPromise.catch(() => {
  120. });
  121. }
  122. function invalidate() {
  123. entry.when = 0;
  124. }
  125. const dataLoaderResult = {
  126. data,
  127. pending,
  128. error,
  129. refresh,
  130. invalidate,
  131. pendingLoad
  132. };
  133. return Object.assign(promise, dataLoaderResult);
  134. };
  135. function load(route, router, parent, initialRootData) {
  136. const hasCacheEntry = entries.has(router);
  137. const initialData = initialRootData && initialRootData[options.key];
  138. if (!hasCacheEntry) {
  139. entries.set(router, createDataLoaderEntry(options, initialData));
  140. }
  141. const entry = entries.get(router);
  142. if (initialData) {
  143. entry.when = 0;
  144. return Promise.resolve();
  145. }
  146. const needsNewLoad = !hasCacheEntry || shouldFetchAgain(entry, route);
  147. const { isReady, pending, error } = entry;
  148. const { lazy } = options;
  149. const isExpired = isCacheExpired(entry, options);
  150. if (pendingPromise && // if we need to fetch again due to param/query changes
  151. !needsNewLoad && // if it's a new navigation and there is no entry, we cannot rely on the pendingPromise as we don't know what
  152. // params and query were used and could have changed. If we had an entry, then we can rely on the result of
  153. // `needsNewLoad`
  154. currentNavigation === route && // if we are not ready but we have a pendingPromise, we are already fetching so we can reuse it
  155. (!isReady || !isExpired)) {
  156. return lazy ? Promise.resolve() : pendingPromise;
  157. }
  158. if (needsNewLoad || // if we never finished loading we cannot rely on needsNewLoad
  159. !isReady && currentNavigation !== route || // we did a load but the cache expired
  160. isReady && isExpired) {
  161. pending.value = true;
  162. error.value = null;
  163. currentNavigation = route;
  164. const [trackedRoute, params, query, hash] = trackRoute(route);
  165. if (!pendingPromise) {
  166. setCurrentContext([entry, router, route]);
  167. }
  168. const thisPromise = pendingPromise = loader(trackedRoute).then((data) => {
  169. if (pendingPromise === thisPromise) {
  170. updateDataLoaderEntry(entry, data, params, query, hash);
  171. }
  172. }).catch((err) => {
  173. error.value = err;
  174. return Promise.reject(err);
  175. }).finally(() => {
  176. if (pendingPromise === thisPromise) {
  177. pendingPromise = null;
  178. pending.value = false;
  179. }
  180. setCurrentContext(parent && [parent, router, route]);
  181. });
  182. }
  183. return lazy || // lazy resolves immediately to not block navigation guards
  184. !pendingPromise ? Promise.resolve() : (
  185. // pendingPromise is thisPromise
  186. pendingPromise
  187. );
  188. }
  189. dataLoader._ = {
  190. // loader,
  191. entries,
  192. load,
  193. options
  194. };
  195. dataLoader[IsLoader] = true;
  196. return dataLoader;
  197. }
  198. function shouldFetchAgain(entry, route) {
  199. return (
  200. // manually invalidated
  201. !entry.when || !includesParams(route.params, entry.params) || !includesParams(route.query, entry.query) || entry.hash != null && entry.hash !== route.hash || Array.from(entry.children).some(
  202. (childEntry) => shouldFetchAgain(childEntry, route)
  203. )
  204. );
  205. }
  206. var IsLoader = Symbol();
  207. function isDataLoader(loader) {
  208. return loader && loader[IsLoader];
  209. }
  210. function trackRoute(route) {
  211. const [params, paramReads] = trackObjectReads(route.params);
  212. const [query, queryReads] = trackObjectReads(route.query);
  213. let hash = { v: null };
  214. return [
  215. __spreadProps(__spreadValues({}, route), {
  216. // track the hash
  217. get hash() {
  218. return hash.v = route.hash;
  219. },
  220. params,
  221. query
  222. }),
  223. paramReads,
  224. queryReads,
  225. hash
  226. ];
  227. }
  228. function trackObjectReads(obj) {
  229. const reads = {};
  230. return [
  231. new Proxy(obj, {
  232. get(target, p, receiver) {
  233. const value = Reflect.get(target, p, receiver);
  234. reads[p] = value;
  235. return value;
  236. }
  237. }),
  238. reads
  239. ];
  240. }
  241. // src/data-fetching/dataFetchingGuard.ts
  242. var HasDataLoaderMeta = Symbol();
  243. var ADDED_SYMBOL = Symbol();
  244. function setupDataFetchingGuard(router, { initialData } = {}) {
  245. if (process.env.NODE_ENV !== "production") {
  246. if (ADDED_SYMBOL in router) {
  247. console.warn(
  248. "[vue-router]: Data fetching guard added twice. Make sure to remove the extra call."
  249. );
  250. return;
  251. }
  252. router[ADDED_SYMBOL] = true;
  253. }
  254. const fetchedState = {};
  255. let isFetched;
  256. router.beforeEach((to) => {
  257. return Promise.all(
  258. // retrieve all loaders as a flat array
  259. to.matched.flatMap((route) => route.meta[HasDataLoaderMeta]).filter(Boolean).map(
  260. (moduleImport) => moduleImport().then((mod) => {
  261. const loaders = Object.keys(mod).filter((exportName) => isDataLoader(mod[exportName])).map((loaderName) => mod[loaderName]);
  262. return Promise.all(
  263. // load will ensure only one request is happening at a time
  264. loaders.map((loader) => {
  265. const {
  266. options: { key },
  267. entries
  268. } = loader._;
  269. return loader._.load(
  270. to,
  271. router,
  272. void 0,
  273. initialData
  274. // FIXME: could the data.value be passed as an argument here?
  275. ).then(() => {
  276. if (!initialData) {
  277. if (key) {
  278. fetchedState[key] = entries.get(router).data.value;
  279. }
  280. } else if (process.env.NODE_ENV !== "production" && !key && !isFetched) {
  281. }
  282. });
  283. })
  284. );
  285. })
  286. )
  287. ).then(() => {
  288. initialData = void 0;
  289. isFetched = true;
  290. });
  291. });
  292. return initialData ? null : fetchedState;
  293. }
  294. // src/runtime.ts
  295. var _definePage = (route) => route;
  296. function _mergeRouteRecord(main, ...routeRecords) {
  297. return routeRecords.reduce((acc, routeRecord) => {
  298. const meta = Object.assign({}, acc.meta, routeRecord.meta);
  299. const alias = [].concat(
  300. acc.alias || [],
  301. routeRecord.alias || []
  302. );
  303. Object.assign(acc, routeRecord);
  304. acc.meta = meta;
  305. acc.alias = alias;
  306. return acc;
  307. }, main);
  308. }
  309. export {
  310. HasDataLoaderMeta as _HasDataLoaderMeta,
  311. defineLoader as _defineLoader,
  312. _definePage,
  313. _mergeRouteRecord,
  314. setupDataFetchingGuard as _setupDataFetchingGuard,
  315. stopScope as _stopDataFetchingScope
  316. };