From a8ab994071eb2fa71d42fd21015885c62ce5b3d7 Mon Sep 17 00:00:00 2001 From: Ty Hopp Date: Mon, 16 May 2022 09:43:28 +0800 Subject: [PATCH] feat(gatsby): Support for off-main-thread in develop (#35648) * feat(gatsby): initial support for off-main-thread in develop Co-authored-by: tyhopp * feat(gatsby): Refactor partytown local proxy logic * Use origin instead of host in serve/develop proxy Co-authored-by: Michal Piechowiak --- packages/gatsby-script/src/gatsby-script.tsx | 10 ++- packages/gatsby/src/commands/serve.ts | 16 ++--- .../partytown/gatsby-browser.tsx | 63 +++++++++++++++++++ .../internal-plugins/partytown/gatsby-node.ts | 14 ++++- .../src/internal-plugins/partytown/proxy.ts | 16 +++++ 5 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 packages/gatsby/src/internal-plugins/partytown/gatsby-browser.tsx create mode 100644 packages/gatsby/src/internal-plugins/partytown/proxy.ts diff --git a/packages/gatsby-script/src/gatsby-script.tsx b/packages/gatsby-script/src/gatsby-script.tsx index 55828b5d4af03..24751a14248a2 100644 --- a/packages/gatsby-script/src/gatsby-script.tsx +++ b/packages/gatsby-script/src/gatsby-script.tsx @@ -40,6 +40,7 @@ export function Script(props: ScriptProps): ReactElement | null { onLoad, onError, } = props || {} + const { collectScript } = useContext(PartytownContext) useEffect(() => { let script: HTMLScriptElement | null @@ -53,6 +54,12 @@ export function Script(props: ScriptProps): ReactElement | null { script = injectScript(props) }) break + case ScriptStrategy.offMainThread: + if (typeof window !== `undefined` && collectScript) { + const attributes = resolveAttributes(props) + collectScript(attributes) + } + break } return (): void => { @@ -70,8 +77,7 @@ export function Script(props: ScriptProps): ReactElement | null { const inlineScript = resolveInlineScript(props) const attributes = resolveAttributes(props) - const { collectScript } = useContext(PartytownContext) - if (collectScript) { + if (typeof window === `undefined` && collectScript) { collectScript(attributes) } diff --git a/packages/gatsby/src/commands/serve.ts b/packages/gatsby/src/commands/serve.ts index 2f65a4ca804ee..1913c07e6f01b 100644 --- a/packages/gatsby/src/commands/serve.ts +++ b/packages/gatsby/src/commands/serve.ts @@ -25,7 +25,10 @@ import { initTracer } from "../utils/tracer" import { configureTrailingSlash } from "../utils/express-middlewares" import { getDataStore, detectLmdbStore } from "../datastore" import { functionMiddlewares } from "../internal-plugins/functions/middleware" -import proxy from "express-http-proxy" +import { + partytownProxyPath, + partytownProxy, +} from "../internal-plugins/partytown/proxy" process.env.GATSBY_EXPERIMENTAL_LMDB_STORE = `1` detectLmdbStore() @@ -124,16 +127,7 @@ module.exports = async (program: IServeProgram): Promise => { // Proxy gatsby-script using off-main-thread strategy const { partytownProxiedURLs = [] } = config || {} - app.use( - `/__partytown-proxy`, - proxy(req => new URL(req.query.url as string).host as string, { - filter: req => partytownProxiedURLs.some(url => req.query?.url === url), - proxyReqPathResolver: req => { - const { pathname = ``, search = `` } = new URL(req.query?.url as string) - return pathname + search - }, - }) - ) + app.use(partytownProxyPath, partytownProxy(partytownProxiedURLs)) // eslint-disable-next-line new-cap const router = express.Router() diff --git a/packages/gatsby/src/internal-plugins/partytown/gatsby-browser.tsx b/packages/gatsby/src/internal-plugins/partytown/gatsby-browser.tsx new file mode 100644 index 0000000000000..6529ee5d76dab --- /dev/null +++ b/packages/gatsby/src/internal-plugins/partytown/gatsby-browser.tsx @@ -0,0 +1,63 @@ +import React, { ReactElement, useState } from "react" +import type { GatsbySSR } from "gatsby" +import { Partytown } from "@builder.io/partytown/react" +import { PartytownContext } from "gatsby-script" +import type { PartytownProps } from "@builder.io/partytown/react" + +interface ICollectedForwardsState { + collectedForwards: Set + collectedAnyScript: boolean +} + +function PartytownProvider({ children }): ReactElement { + const [{ collectedForwards, collectedAnyScript }, setState] = + useState({ + collectedForwards: new Set(), + collectedAnyScript: false, + }) + + return ( + { + let stateShouldChange = false + const potentialNewState = { + collectedAnyScript, + collectedForwards, + } + + if (!collectedAnyScript) { + potentialNewState.collectedAnyScript = true + stateShouldChange = true + } + + if (newScript?.forward) { + if (Array.isArray(newScript.forward)) { + for (const singleForward of newScript.forward) { + if (!potentialNewState.collectedForwards.has(singleForward)) { + potentialNewState.collectedForwards.add(singleForward) + stateShouldChange = true + } + } + } else { + console.log(`unexpected shape of forward`, newScript) + } + } + + if (stateShouldChange) { + setState(potentialNewState) + } + }, + }} + > + {children} + {collectedAnyScript && ( + + )} + + ) +} + +export const wrapRootElement: GatsbySSR[`wrapRootElement`] = ({ element }) => ( + {element} +) diff --git a/packages/gatsby/src/internal-plugins/partytown/gatsby-node.ts b/packages/gatsby/src/internal-plugins/partytown/gatsby-node.ts index f4d4ed7427173..f8d81cbf3c6b7 100644 --- a/packages/gatsby/src/internal-plugins/partytown/gatsby-node.ts +++ b/packages/gatsby/src/internal-plugins/partytown/gatsby-node.ts @@ -1,5 +1,7 @@ import path from "path" import { copyLibFiles } from "@builder.io/partytown/utils" +import { CreateDevServerArgs } from "gatsby" +import { partytownProxyPath, partytownProxy } from "./proxy" /** * Copy Partytown library files to public. @@ -24,9 +26,19 @@ exports.createPages = ({ actions, store }): void => { const encodedURL: string = encodeURI(host) createRedirect({ - fromPath: `/__partytown-proxy?url=${encodedURL}`, + fromPath: `${partytownProxyPath}?url=${encodedURL}`, toPath: encodedURL, statusCode: 200, }) } } + +export async function onCreateDevServer({ + app, + store, +}: CreateDevServerArgs): Promise { + const { config } = store.getState() + const { partytownProxiedURLs = [] } = config || {} + + app.use(partytownProxyPath, partytownProxy(partytownProxiedURLs)) +} diff --git a/packages/gatsby/src/internal-plugins/partytown/proxy.ts b/packages/gatsby/src/internal-plugins/partytown/proxy.ts new file mode 100644 index 0000000000000..8bf597be2ca86 --- /dev/null +++ b/packages/gatsby/src/internal-plugins/partytown/proxy.ts @@ -0,0 +1,16 @@ +import proxy from "express-http-proxy" +import type { RequestHandler } from "express" + +export const partytownProxyPath = `/__partytown-proxy` + +export function partytownProxy( + partytownProxiedURLs: Array +): RequestHandler { + return proxy(req => new URL(req.query.url as string).origin as string, { + filter: req => partytownProxiedURLs.some(url => req.query?.url === url), + proxyReqPathResolver: req => { + const { pathname = ``, search = `` } = new URL(req.query?.url as string) + return pathname + search + }, + }) +}