@react-perfscope/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ray
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # @react-perfscope/core
2
+
3
+ Core recording engine for `react-perfscope`. Provides a `Recorder` and pluggable `Collector`s that emit normalized performance signals.
4
+
5
+ ## Status
6
+
7
+ Phase 2 complete — `@react-perfscope/core` ships all 6 core collectors (forced-reflow, long-tasks, layout-shift, network, web-vitals, paint) with deferred stack parsing and synchronous dirty tracking on forced-reflow.
8
+
9
+ **Forced-reflow note:** Synchronous dirty tracking via `MutationObserver.takeRecords()` ensures the collector only emits when DOM mutated since the last layout read. Stack parsing is deferred until `signal.stack` is accessed.
10
+
11
+ **Paint collector note:** Phase 2 emits paint entries with a zero-sized `rect` placeholder. Real mutated-region geometry arrives with the UI package in Phase 3.
12
+
13
+ The `render` signal is owned by the upcoming `@react-perfscope/react` package (Phase 3) and not yet emitted.
14
+
15
+ ## Source-map resolution
16
+
17
+ `createSourceMapResolver()` returns an async resolver that follows `//# sourceMappingURL=` references (including inline `data:` URIs), caches the parsed source map per source URL, and resolves a `StackFrame` to its original source position. The UI uses this to make bundled stack traces readable.
18
+
19
+ ```ts
20
+ import { createSourceMapResolver } from '@react-perfscope/core'
21
+
22
+ const resolver = createSourceMapResolver()
23
+ const original = await resolver.resolve(parsedFrame)
24
+ ```
25
+
26
+ Falls back to the input frame on any failure (missing source map, network error, etc.).
27
+
28
+ ## Example
29
+
30
+ ```ts
31
+ import {
32
+ createRecorder,
33
+ createForcedReflowCollector,
34
+ createLongTasksCollector,
35
+ createLayoutShiftCollector,
36
+ createNetworkCollector,
37
+ createWebVitalsCollector,
38
+ createPaintCollector,
39
+ } from '@react-perfscope/core'
40
+
41
+ const recorder = createRecorder()
42
+ recorder.use(createForcedReflowCollector())
43
+ recorder.use(createLongTasksCollector())
44
+ recorder.use(createLayoutShiftCollector())
45
+ recorder.use(createNetworkCollector())
46
+ recorder.use(createWebVitalsCollector())
47
+ recorder.use(createPaintCollector())
48
+
49
+ recorder.start()
50
+ // ... user interaction ...
51
+ const result = recorder.stop()
52
+
53
+ console.log(result.signals)
54
+ ```
55
+
56
+ ---
57
+
58
+ <a id="한국어"></a>
59
+
60
+ # 한국어
61
+
62
+ `react-perfscope`의 핵심 레코딩 엔진. `Recorder`와 플러그인 방식의 `Collector`를 제공해서 정규화된 성능 신호를 내보낸다.
63
+
64
+ ## 상태
65
+
66
+ Phase 2 완료 — `@react-perfscope/core`에 6개 collector가 전부 포함됐다 (forced-reflow, long-tasks, layout-shift, network, web-vitals, paint). 스택 파싱은 지연 처리되고, forced-reflow는 동기적으로 dirty 추적을 한다.
67
+
68
+ **forced-reflow 참고:** `MutationObserver.takeRecords()`를 이용한 동기 dirty 추적으로, 마지막 레이아웃 읽기 이후 DOM이 실제로 변경됐을 때만 신호를 내보낸다. 스택 파싱은 `signal.stack`에 접근할 때까지 미뤄진다.
69
+
70
+ **paint collector 참고:** Phase 2에서는 paint 항목을 크기가 0인 `rect` 플레이스홀더와 함께 내보낸다. 실제 변경 영역 geometry는 Phase 3에서 UI 패키지와 함께 들어온다.
71
+
72
+ `render` 신호는 곧 나올 `@react-perfscope/react` 패키지(Phase 3)가 담당하고, 아직 내보내지 않는다.
73
+
74
+ ## Source-map 해석
75
+
76
+ `createSourceMapResolver()`는 `//# sourceMappingURL=` 참조 (inline `data:` URI 포함)를 따라가서 source map을 가져오고, 파싱된 결과를 소스 URL 단위로 캐시한 다음, `StackFrame`을 원본 소스 위치로 해석해주는 async resolver를 반환한다. UI에서 번들된 스택 트레이스를 읽을 수 있게 해주는 데 쓰인다.
77
+
78
+ ```ts
79
+ import { createSourceMapResolver } from '@react-perfscope/core'
80
+
81
+ const resolver = createSourceMapResolver()
82
+ const original = await resolver.resolve(parsedFrame)
83
+ ```
84
+
85
+ source map이 없거나 네트워크 에러 등 어떤 이유로든 실패하면 원본 frame을 그대로 반환한다.
86
+
87
+ ## 예제
88
+
89
+ ```ts
90
+ import {
91
+ createRecorder,
92
+ createForcedReflowCollector,
93
+ createLongTasksCollector,
94
+ createLayoutShiftCollector,
95
+ createNetworkCollector,
96
+ createWebVitalsCollector,
97
+ createPaintCollector,
98
+ } from '@react-perfscope/core'
99
+
100
+ const recorder = createRecorder()
101
+ recorder.use(createForcedReflowCollector())
102
+ recorder.use(createLongTasksCollector())
103
+ recorder.use(createLayoutShiftCollector())
104
+ recorder.use(createNetworkCollector())
105
+ recorder.use(createWebVitalsCollector())
106
+ recorder.use(createPaintCollector())
107
+
108
+ recorder.start()
109
+ // ... 유저 인터랙션 ...
110
+ const result = recorder.stop()
111
+
112
+ console.log(result.signals)
113
+ ```