UNPKG

nuxt

Version:

Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.

109 lines (108 loc) 3.53 kB
import { computed, reactive, toValue } from "vue"; import { hash } from "ohash"; import { useRequestFetch } from "./ssr.js"; import { useAsyncData } from "./asyncData.js"; import { fetchDefaults } from "#build/nuxt.config.mjs"; export function useFetch(request, arg1, arg2) { const [opts = {}, autoKey] = typeof arg1 === "string" ? [{}, arg1] : [arg1, arg2]; const _request = computed(() => toValue(request)); const _key = opts.key || hash([autoKey, typeof _request.value === "string" ? _request.value : "", ...generateOptionSegments(opts)]); if (!_key || typeof _key !== "string") { throw new TypeError("[nuxt] [useFetch] key must be a string: " + _key); } if (!request) { throw new Error("[nuxt] [useFetch] request is missing."); } const key = _key === autoKey ? "$f" + _key : _key; if (!opts.baseURL && typeof _request.value === "string" && (_request.value[0] === "/" && _request.value[1] === "/")) { throw new Error('[nuxt] [useFetch] the request URL must not start with "//".'); } const { server, lazy, default: defaultFn, transform, pick, watch, immediate, getCachedData, deep, dedupe, ...fetchOptions } = opts; const _fetchOptions = reactive({ ...fetchDefaults, ...fetchOptions, cache: typeof opts.cache === "boolean" ? void 0 : opts.cache }); const _asyncDataOptions = { server, lazy, default: defaultFn, transform, pick, immediate, getCachedData, deep, dedupe, watch: watch === false ? [] : [_fetchOptions, _request, ...watch || []] }; if (import.meta.dev && import.meta.client) { _asyncDataOptions._functionName = opts._functionName || "useFetch"; } let controller; const asyncData = useAsyncData(key, () => { controller?.abort?.(); controller = typeof AbortController !== "undefined" ? new AbortController() : {}; const timeoutLength = toValue(opts.timeout); let timeoutId; if (timeoutLength) { timeoutId = setTimeout(() => controller.abort(), timeoutLength); controller.signal.onabort = () => clearTimeout(timeoutId); } let _$fetch = opts.$fetch || globalThis.$fetch; if (import.meta.server && !opts.$fetch) { const isLocalFetch = typeof _request.value === "string" && _request.value[0] === "/" && (!toValue(opts.baseURL) || toValue(opts.baseURL)[0] === "/"); if (isLocalFetch) { _$fetch = useRequestFetch(); } } return _$fetch(_request.value, { signal: controller.signal, ..._fetchOptions }).finally(() => { clearTimeout(timeoutId); }); }, _asyncDataOptions); return asyncData; } export function useLazyFetch(request, arg1, arg2) { const [opts = {}, autoKey] = typeof arg1 === "string" ? [{}, arg1] : [arg1, arg2]; if (import.meta.dev && import.meta.client) { opts._functionName ||= "useLazyFetch"; } return useFetch( request, { ...opts, lazy: true }, // @ts-expect-error we pass an extra argument with the resolved auto-key to prevent another from being injected autoKey ); } function generateOptionSegments(opts) { const segments = [ toValue(opts.method)?.toUpperCase() || "GET", toValue(opts.baseURL) ]; for (const _obj of [opts.params || opts.query]) { const obj = toValue(_obj); if (!obj) { continue; } const unwrapped = {}; for (const [key, value] of Object.entries(obj)) { unwrapped[toValue(key)] = toValue(value); } segments.push(unwrapped); } return segments; }