hrtyy.dev

rscq, CLI Parser for React Server Component Payloads

I wanted to parse React Server Component Payloads. So I created rscq.

Introduction

If you are using React Server Components, inspecting RSC payloads might be important for you.

Google Chrome is a powerful tool. You can inspect the GET request for these payloads, as well as the responses, in the Network tab. Sometimes, a message "Failed to load response data" is displayed, and I'm not sure why. In such cases, I usually use "Copy as cURL" and paste the command into the terminal.

1curl 'http://localhost:3000/page3?_rsc=8nwf1' \
2 -H 'Accept: */*' \
3 -H 'Accept-Language: en-US,en;q=0.9,ja;q=0.8,pl;q=0.7' \
4 -H 'Connection: keep-alive' \
5 -H 'Next-Router-State-Tree: %5B%22%22%2C%7B%22children%22%3A%5B%5B%22id%22%2C%22page3%22%2C%22d%22%5D%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%5D%7D%2Cnull%2C%22refetch%22%5D%7D%5D' \
6 -H 'Next-Url: /page3' \
7 -H 'RSC: 1' \
8 -H 'Referer: http://localhost:3000/' \
9 -H 'Sec-Fetch-Dest: empty' \
10 -H 'Sec-Fetch-Mode: cors' \
11 -H 'Sec-Fetch-Site: same-origin' \
12 -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36' \
13 -H 'sec-ch-ua: "Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"' \
14 -H 'sec-ch-ua-mobile: ?0' \
15 -H 'sec-ch-ua-platform: "macOS"' \
16 --compressed

I run this command and get the following response. This is a RSC payload.

10:["N157NNKhIC8b0k4urA243",[["children",["id","page3","d"],[["id","page3","d"],{"children":["__PAGE__",{}]}],"$L1",[[],"$L2"]]]]
23:I{"id":1443,"chunks":["272:static/chunks/webpack-bf6fccfdfe35d157.js","971:static/chunks/fd9d1056-2581dce591ac5cde.js","864:static/chunks/864-b23738e09c185fe9.js"],"name":"","async":false}
34:I{"id":8639,"chunks":["272:static/chunks/webpack-bf6fccfdfe35d157.js","971:static/chunks/fd9d1056-2581dce591ac5cde.js","864:static/chunks/864-b23738e09c185fe9.js"],"name":"","async":false}
41:["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children",["id","page3","d"],"children"],"loading":"$undefined","loadingStyles":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined","childProp":{"current":["$L5","$L6",null],"segment":"__PAGE__"},"styles":[]}]
52:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","link","2",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}]]
68:"$Sreact.suspense"
79:I{"id":7772,"chunks":["233:static/chunks/233-f9c6a8ef9ae4b8c3.js","531:static/chunks/app/[id]/page-d4e2ada29cefa5fc.js"],"name":"Client4","async":false}
86:["$","div",null,{"children":["$L7",["$","$8",null,{"fallback":["$","div",null,{"children":"Preparing"}],"children":["$","$L9",null,{"children":"$La"}]}]]}]
95:null
10b:I{"id":2233,"chunks":["233:static/chunks/233-f9c6a8ef9ae4b8c3.js","531:static/chunks/app/[id]/page-d4e2ada29cefa5fc.js"],"name":"Client1","async":false}
117:["$","div",null,{"children":["This is Light Server Component",["$","div",null,{"children":["$","$Lb",null,{"title":"Light Component"}]}]]}]
12a:["$","div",null,{"children":"Heavy Server Component"}]

Can you read this payload? I can but I don't want. I created rscq CLI tool to make this payload easier.

10--------------------
2 N157NNKhIC8b0k4urA243
3 children
4 id
5 page3
6 d
7 id
8 page3
9 d
10 map[children:[__PAGE__ map[]]]
11 $L1
12 $L2
13--------------------0
143--------------------
15 272:static/chunks/webpack-bf6fccfdfe35d157.js
16 971:static/chunks/fd9d1056-2581dce591ac5cde.js
17 864:static/chunks/864-b23738e09c185fe9.js
18--------------------3
194--------------------
20 272:static/chunks/webpack-bf6fccfdfe35d157.js
21 971:static/chunks/fd9d1056-2581dce591ac5cde.js
22 864:static/chunks/864-b23738e09c185fe9.js
23--------------------4
241--------------------
25 <$L3
26 childProp={map[current:[$L5 $L6 <nil>] segment:__PAGE__]}
27 segmentPath={[children [id page3 d] children]}
28 template={
29 <$L4>
30 </$L4>
31 }
32
33 parallelRouterKey={children}
34 >
35 </$L3>
36--------------------1
372--------------------
38 <meta key=0
39 charSet={utf-8}
40 >
41 </meta>
42 <meta key=1
43 name={viewport}
44 content={width=device-width, initial-scale=1}
45 >
46 </meta>
47 <link key=2
48 rel={icon}
49 href={/favicon.ico}
50 type={image/x-icon}
51 sizes={16x16}
52 >
53 </link>
54--------------------2
558--------------------
56 "$Sreact.suspense"
57--------------------8
589--------------------
59 233:static/chunks/233-f9c6a8ef9ae4b8c3.js
60 531:static/chunks/app/[id]/page-d4e2ada29cefa5fc.js
61--------------------9
626--------------------
63 <div>
64 $L7
65
66 <$8
67 fallback={
68 <div>
69 Preparing
70 </div>
71 }
72
73 >
74 <$L9>
75 $La
76 </$L9>
77 </$8>
78 </div>
79--------------------6
805--------------------
81 <nil>
82--------------------5
83b--------------------
84 233:static/chunks/233-f9c6a8ef9ae4b8c3.js
85 531:static/chunks/app/[id]/page-d4e2ada29cefa5fc.js
86--------------------b
877--------------------
88 <div>
89 This is Light Server Component
90
91 <div>
92 <$Lb
93 title={Light Component}
94 >
95 </$Lb>
96 </div>
97 </div>
98--------------------7
99a--------------------
100 <div>
101 Heavy Server Component
102 </div>
103--------------------a

It's gotten better, hasn't it?

I developed it partly for fun. This tool is beta. As of now, it doesn't even display its version, help information or anything else. It simply parses the payload and displays the result.

Usage

1curl .... | rscq

https://github.com/horita-yuya/rscq

References & Code reading bookmark