From 55421c4cc6be101c5c77763499a5050a00592257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvar=20Lagerl=C3=B6f?= <14835120+alvarlagerlof@users.noreply.github.com> Date: Fri, 10 May 2024 13:48:49 +0200 Subject: [PATCH] Add a button to parse from `__next_f` from script tags in @rsc-parse/embedded Next.js stores the RSC payload in script tags. I've added a button to the panel in `@rsc-parse/embedded` to make #923 easier to debug. --- .changeset/nine-cobras-fly.md | 10 ++++ .../ReadNextScriptTagsButton.stories.tsx | 14 +++++ .../components/ReadNextScriptTagsButton.tsx | 16 +++++ packages/core/src/main.ts | 2 + packages/embedded/RscDevtoolsPanel.tsx | 58 ++++++++++++++++++- 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 .changeset/nine-cobras-fly.md create mode 100644 packages/core/src/components/ReadNextScriptTagsButton.stories.tsx create mode 100644 packages/core/src/components/ReadNextScriptTagsButton.tsx diff --git a/.changeset/nine-cobras-fly.md b/.changeset/nine-cobras-fly.md new file mode 100644 index 00000000..909ba736 --- /dev/null +++ b/.changeset/nine-cobras-fly.md @@ -0,0 +1,10 @@ +--- +"@rsc-parser/embedded": patch +"@rsc-parser/core": patch +"@rsc-parser/embedded-example": patch +"@rsc-parser/chrome-extension": patch +"@rsc-parser/storybook": patch +"@rsc-parser/website": patch +--- + +Add a button to read Next.js payload script tags diff --git a/packages/core/src/components/ReadNextScriptTagsButton.stories.tsx b/packages/core/src/components/ReadNextScriptTagsButton.stories.tsx new file mode 100644 index 00000000..22984d55 --- /dev/null +++ b/packages/core/src/components/ReadNextScriptTagsButton.stories.tsx @@ -0,0 +1,14 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { ReadNextScriptTagsButton } from "./ReadNextScriptTagsButton"; + +const meta: Meta = { + component: ReadNextScriptTagsButton, +}; + +export default meta; +type Story = StoryObj; + +export const example: Story = { + name: "example", +}; diff --git a/packages/core/src/components/ReadNextScriptTagsButton.tsx b/packages/core/src/components/ReadNextScriptTagsButton.tsx new file mode 100644 index 00000000..394af056 --- /dev/null +++ b/packages/core/src/components/ReadNextScriptTagsButton.tsx @@ -0,0 +1,16 @@ +import React from "react"; + +export function ReadNextScriptTagsButton({ + onClickRead, +}: { + onClickRead: () => void; +}) { + return ( + + ); +} diff --git a/packages/core/src/main.ts b/packages/core/src/main.ts index 83f5829a..b6197a6e 100644 --- a/packages/core/src/main.ts +++ b/packages/core/src/main.ts @@ -6,6 +6,7 @@ import { Logo } from "./components/Logo"; import { RecordButton } from "./components/RecordButton"; import { DebugCopyMessagesButton } from "./components/DebugCopyMessagesButton"; import { ClearMessagesButton } from "./components/ClearMessagesButton"; +import { ReadNextScriptTagsButton } from "./components/ReadNextScriptTagsButton"; import { PanelLayout } from "./components/PanelLayout"; import { BottomPanel, @@ -24,6 +25,7 @@ export { RecordButton, DebugCopyMessagesButton, ClearMessagesButton, + ReadNextScriptTagsButton, PanelLayout, BottomPanel, BottomPanelOpenButton, diff --git a/packages/embedded/RscDevtoolsPanel.tsx b/packages/embedded/RscDevtoolsPanel.tsx index f6fffede..f1fde279 100644 --- a/packages/embedded/RscDevtoolsPanel.tsx +++ b/packages/embedded/RscDevtoolsPanel.tsx @@ -15,6 +15,7 @@ import { ClearMessagesButton, PanelLayout, fetchPatcher, + ReadNextScriptTagsButton, } from "@rsc-parser/core"; import React, { ReactNode, @@ -28,8 +29,13 @@ import React, { export function RscDevtoolsPanel() { const [isOpen, setIsOpen] = useState(false); - const { isRecording, startRecording, messages, clearMessages } = - useRscMessages(); + const { + isRecording, + startRecording, + messages, + clearMessages, + readNextScriptTags, + } = useRscMessages(); return ( @@ -53,6 +59,11 @@ export function RscDevtoolsPanel() { {messages.length > 0 ? ( ) : null} + { + readNextScriptTags(); + }} + /> } closeButton={ @@ -146,7 +157,48 @@ function useRscMessages() { setMessages([]); }, []); - return { isRecording, startRecording, messages, clearMessages }; + const readNextScriptTags = useCallback(() => { + try { + // @ts-expect-error This is a hack + const payload = self.__next_f.map((f) => f?.[1]).join(""); + + console.log("TEST", payload); + + const messages = [ + { + type: "RSC_CHUNK", + tabId: 0, + data: { + fetchUrl: window.location.href, + fetchMethod: "GET", + fetchStartTime: 0, + chunkStartTime: 0, + chunkEndTime: 0, + chunkValue: Array.from(new TextEncoder().encode(payload)), + }, + } satisfies RscChunkMessage, + ]; + + setIsRecording(true); + startTransition(() => { + setMessages(() => messages); + }); + } catch (error) { + console.error( + new Error("Error parsing Next.js payload", { + cause: error, + }), + ); + } + }, []); + + return { + isRecording, + startRecording, + messages, + clearMessages, + readNextScriptTags, + }; } function arraysEqual(a: unknown[], b: unknown[]) {