From 846338c1ce90591756cf512c3a547874a908c6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Oliveira?= Date: Mon, 25 Sep 2023 15:43:21 -0300 Subject: [PATCH] feat: fetch hook --- packages/core/src/data/api/fetch-utils.ts | 30 ++++++++++--- packages/core/src/types.ts | 11 +++++ packages/core/src/utils/getHeadlessConfig.ts | 2 + .../config/__tests__/withHeadlessConfig.ts | 42 +++++++++++++++++++ .../next/src/config/withHeadlessConfig.ts | 30 ++++++++++++- projects/wp-nextjs/headless.config.js | 8 ++++ 6 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 packages/next/src/config/__tests__/withHeadlessConfig.ts diff --git a/packages/core/src/data/api/fetch-utils.ts b/packages/core/src/data/api/fetch-utils.ts index b249b49d8..ea92fc735 100644 --- a/packages/core/src/data/api/fetch-utils.ts +++ b/packages/core/src/data/api/fetch-utils.ts @@ -1,4 +1,4 @@ -import { LOGTYPE, addQueryArgs, getHeadlessConfig, log } from '../../utils'; +import { LOGTYPE, addQueryArgs, getHeadstartWPConfig, log } from '../../utils'; export const getAuthHeader = () => { return null; @@ -15,15 +15,26 @@ export const getAuthHeader = () => { * @returns {object} */ export const apiPost = async (url: string, args: { [index: string]: any } = {}) => { - const response = await fetch(url, { + const config = getHeadstartWPConfig(); + + const fetchArgs = { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(args), - }); + }; + + const { url: filteredUrl, args: filteredArgs } = config.filters?.fetch?.( + 'POST', + url, + fetchArgs, + ) ?? { + url, + fetchArgs, + }; - const config = getHeadlessConfig(); + const response = await fetch(filteredUrl, filteredArgs); if (config.debug?.requests) { log(LOGTYPE.DEBUG, 'POST', url, args); @@ -60,7 +71,7 @@ export const apiGet = async ( } : {}; - const config = getHeadlessConfig(); + const config = getHeadstartWPConfig(); const fetchUrl = addQueryArgs(url, queryArgs); @@ -68,7 +79,14 @@ export const apiGet = async ( log(LOGTYPE.DEBUG, 'GET', fetchUrl, args); } - const data = await fetch(fetchUrl, args); + const { url: filteredUrl, args: filteredArgs } = config.filters?.fetch?.( + 'GET', + fetchUrl, + args, + burstCache, + ) ?? { url: fetchUrl, args }; + + const data = await fetch(filteredUrl, filteredArgs); const receivedHeaders: { [index: string]: any } = [ ...Array.from(data.headers.entries()), diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index c5be9d8cb..3524addfa 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -47,4 +47,15 @@ export type HeadlessConfig = { redirects?: boolean; devMode?: boolean; }; + filters?: { + fetch?: ( + method: 'POST' | 'GET', + url: string, + args: Record, + burstCache?: boolean, + ) => { + url: string; + args: Record; + }; + }; }; diff --git a/packages/core/src/utils/getHeadlessConfig.ts b/packages/core/src/utils/getHeadlessConfig.ts index d53c4368f..d69200f7d 100644 --- a/packages/core/src/utils/getHeadlessConfig.ts +++ b/packages/core/src/utils/getHeadlessConfig.ts @@ -30,6 +30,7 @@ export function getHeadstartWPConfig() { hostUrl, integrations, debug, + filters, } = __10up__HEADLESS_CONFIG; const headlessConfig: HeadlessConfig = { @@ -41,6 +42,7 @@ export function getHeadstartWPConfig() { useWordPressPlugin: useWordPressPlugin || false, integrations, debug, + filters, sites: (sites || []).map((site) => { // if host is not defined but hostUrl is, infer host from hostUrl if (typeof site.host === 'undefined' && typeof site.hostUrl !== 'undefined') { diff --git a/packages/next/src/config/__tests__/withHeadlessConfig.ts b/packages/next/src/config/__tests__/withHeadlessConfig.ts new file mode 100644 index 000000000..baae8e358 --- /dev/null +++ b/packages/next/src/config/__tests__/withHeadlessConfig.ts @@ -0,0 +1,42 @@ +import { toStringWithFunctions } from '../withHeadlessConfig'; + +describe('toStringWithFunctions', () => { + it('converts regular objects to strings', () => { + const obj = { + a: 'a', + b: 'b', + c: 'c', + }; + expect(toStringWithFunctions(obj)).toMatchInlineSnapshot(` + "{ + "a": "a", + "b": "b", + "c": "c" + }" + `); + }); + it('converts functions to strings', () => { + const obj = { + a: 'test', + fn: () => { + // eslint-disable-next-line no-console + console.log('test'); + }, + nested: { + fn: () => {}, + }, + }; + expect(toStringWithFunctions(obj)).toMatchInlineSnapshot(` + "{ + "a": "test", + "fn": () => { + // eslint-disable-next-line no-console + console.log('test'); + }, + "nested": { + "fn": () => { } + } + }" + `); + }); +}); diff --git a/packages/next/src/config/withHeadlessConfig.ts b/packages/next/src/config/withHeadlessConfig.ts index 0b08d7a5a..377ed304b 100644 --- a/packages/next/src/config/withHeadlessConfig.ts +++ b/packages/next/src/config/withHeadlessConfig.ts @@ -17,6 +17,34 @@ const isPackageInstalled = (packageName: string): boolean => { return false; }; + +/** + * Stringify an object, including functions + * + * @param obj A JavaScript object + * + * @returns + */ +export function toStringWithFunctions(obj: Record) { + const placeholder = '____HEADSTARTWP_FUNCTION_PLACEHOLDER____'; + const fns: Array = []; + let json = JSON.stringify( + obj, + function (key, value) { + if (typeof value === 'function') { + fns.push(value); + return placeholder; + } + return value; + }, + 2, + ); + json = json.replace(new RegExp(`"${placeholder}"`, 'g'), function () { + return fns.shift(); + }); + return json; +} + function traverse(rules) { for (const rule of rules) { if (typeof rule.loader === 'string' && rule.loader.includes('css-loader')) { @@ -155,7 +183,7 @@ export function withHeadlessConfig( webpack: (config, options) => { const importSetHeadlessConfig = ` import { setHeadstartWPConfig } from '@headstartwp/core/utils'; - setHeadstartWPConfig(${JSON.stringify(headlessConfig)}); + setHeadstartWPConfig(${toStringWithFunctions(headlessConfig)}); `; // clear webpack cache whenever headless.config.js changes or one of the env files diff --git a/projects/wp-nextjs/headless.config.js b/projects/wp-nextjs/headless.config.js index 24aaec4db..e9c8a0c91 100644 --- a/projects/wp-nextjs/headless.config.js +++ b/projects/wp-nextjs/headless.config.js @@ -49,4 +49,12 @@ module.exports = { */ devMode: process.env?.ENABLE_DEV_MODE === 'true', }, + filters: { + fetch: (method, url, args) => { + return { + url, + args, + }; + }, + }, };