phantom-build 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/README.md +378 -0
- package/dist/analyzer.d.ts +11 -0
- package/dist/analyzer.d.ts.map +1 -0
- package/dist/analyzer.js +330 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/ast-compat.d.ts +11 -0
- package/dist/ast-compat.d.ts.map +1 -0
- package/dist/ast-compat.js +84 -0
- package/dist/ast-compat.js.map +1 -0
- package/dist/classify/boundary.d.ts +30 -0
- package/dist/classify/boundary.d.ts.map +1 -0
- package/dist/classify/boundary.js +145 -0
- package/dist/classify/boundary.js.map +1 -0
- package/dist/classify/browser-globals.d.ts +29 -0
- package/dist/classify/browser-globals.d.ts.map +1 -0
- package/dist/classify/browser-globals.js +197 -0
- package/dist/classify/browser-globals.js.map +1 -0
- package/dist/classify/index.d.ts +14 -0
- package/dist/classify/index.d.ts.map +1 -0
- package/dist/classify/index.js +294 -0
- package/dist/classify/index.js.map +1 -0
- package/dist/classify/lazy-llm.d.ts +122 -0
- package/dist/classify/lazy-llm.d.ts.map +1 -0
- package/dist/classify/lazy-llm.js +142 -0
- package/dist/classify/lazy-llm.js.map +1 -0
- package/dist/classify/lazy.d.ts +23 -0
- package/dist/classify/lazy.d.ts.map +1 -0
- package/dist/classify/lazy.js +686 -0
- package/dist/classify/lazy.js.map +1 -0
- package/dist/classify/llm-client.d.ts +59 -0
- package/dist/classify/llm-client.d.ts.map +1 -0
- package/dist/classify/llm-client.js +193 -0
- package/dist/classify/llm-client.js.map +1 -0
- package/dist/classify/purity.d.ts +21 -0
- package/dist/classify/purity.d.ts.map +1 -0
- package/dist/classify/purity.js +47 -0
- package/dist/classify/purity.js.map +1 -0
- package/dist/classify/react-patterns.d.ts +15 -0
- package/dist/classify/react-patterns.d.ts.map +1 -0
- package/dist/classify/react-patterns.js +82 -0
- package/dist/classify/react-patterns.js.map +1 -0
- package/dist/classify/taint.d.ts +32 -0
- package/dist/classify/taint.d.ts.map +1 -0
- package/dist/classify/taint.js +68 -0
- package/dist/classify/taint.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +109 -0
- package/dist/cli.js.map +1 -0
- package/dist/extract/chunk-module.d.ts +20 -0
- package/dist/extract/chunk-module.d.ts.map +1 -0
- package/dist/extract/chunk-module.js +163 -0
- package/dist/extract/chunk-module.js.map +1 -0
- package/dist/extract/client-stub.d.ts +25 -0
- package/dist/extract/client-stub.d.ts.map +1 -0
- package/dist/extract/client-stub.js +233 -0
- package/dist/extract/client-stub.js.map +1 -0
- package/dist/extract/import-resolver.d.ts +20 -0
- package/dist/extract/import-resolver.d.ts.map +1 -0
- package/dist/extract/import-resolver.js +51 -0
- package/dist/extract/import-resolver.js.map +1 -0
- package/dist/extract/index.d.ts +20 -0
- package/dist/extract/index.d.ts.map +1 -0
- package/dist/extract/index.js +105 -0
- package/dist/extract/index.js.map +1 -0
- package/dist/extract/lazy-transform.d.ts +14 -0
- package/dist/extract/lazy-transform.d.ts.map +1 -0
- package/dist/extract/lazy-transform.js +473 -0
- package/dist/extract/lazy-transform.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +7 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +535 -0
- package/dist/plugin.js.map +1 -0
- package/dist/runtime/index.d.ts +28 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +73 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/types.d.ts +219 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/vite.d.ts +3 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +3 -0
- package/dist/vite.js.map +1 -0
- package/dist/webpack.d.ts +3 -0
- package/dist/webpack.d.ts.map +1 -0
- package/dist/webpack.js +3 -0
- package/dist/webpack.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Lazy Optimization — IR schema, response schema, system prompt, and merge logic.
|
|
3
|
+
*
|
|
4
|
+
* Defines the compact IR sent to the LLM for the ~20% of decisions that static
|
|
5
|
+
* analysis can't make well: Suspense grouping, cross-component state awareness,
|
|
6
|
+
* and prefetch strategy refinement.
|
|
7
|
+
*
|
|
8
|
+
* Supports batched multi-module analysis — a single LLM call can process
|
|
9
|
+
* candidates from every module in the build for cross-module awareness.
|
|
10
|
+
*/
|
|
11
|
+
import type { LazyCandidate } from '../types.js';
|
|
12
|
+
export interface LazyIR {
|
|
13
|
+
/** The parent component being analyzed */
|
|
14
|
+
parent: string;
|
|
15
|
+
file: string;
|
|
16
|
+
/** Child components that passed deterministic filtering */
|
|
17
|
+
candidates: Array<{
|
|
18
|
+
name: string;
|
|
19
|
+
source: string;
|
|
20
|
+
jsxPosition: number;
|
|
21
|
+
conditional: boolean;
|
|
22
|
+
/** From ComponentProfile (if available) */
|
|
23
|
+
hasHandlers: boolean;
|
|
24
|
+
hasState: boolean;
|
|
25
|
+
hasEffects: boolean;
|
|
26
|
+
handlerCount: number;
|
|
27
|
+
estimatedSize: number;
|
|
28
|
+
/** Heuristic assignment (LLM can override) */
|
|
29
|
+
heuristicPrefetch: string;
|
|
30
|
+
heuristicReason: string;
|
|
31
|
+
}>;
|
|
32
|
+
/** Components that were kept static (for LLM awareness) */
|
|
33
|
+
keptStatic: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
reason: string;
|
|
36
|
+
}>;
|
|
37
|
+
/** Cross-component state relationships detected statically */
|
|
38
|
+
sharedState: Array<{
|
|
39
|
+
components: string[];
|
|
40
|
+
stateDescription: string;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
export interface BatchedLazyIR {
|
|
44
|
+
/** All modules with lazy candidates in this build */
|
|
45
|
+
modules: LazyIR[];
|
|
46
|
+
/** Total candidate count across all modules */
|
|
47
|
+
totalCandidates: number;
|
|
48
|
+
}
|
|
49
|
+
/** Per-candidate decision from the LLM */
|
|
50
|
+
export interface LazyLLMDecision {
|
|
51
|
+
name: string;
|
|
52
|
+
/** Override the heuristic strategy (or confirm it) */
|
|
53
|
+
prefetch: 'immediate' | 'viewport' | 'interaction' | 'idle';
|
|
54
|
+
/** Group ID — components with same group share a Suspense boundary */
|
|
55
|
+
suspenseGroup: string | null;
|
|
56
|
+
/** Confidence 0-1 that this decision is correct */
|
|
57
|
+
confidence: number;
|
|
58
|
+
/** Brief reason */
|
|
59
|
+
reason: string;
|
|
60
|
+
}
|
|
61
|
+
/** Single-module LLM response */
|
|
62
|
+
export interface LazyLLMResponse {
|
|
63
|
+
/** Optimized decisions for each candidate */
|
|
64
|
+
decisions: LazyLLMDecision[];
|
|
65
|
+
/** Any candidates the LLM thinks should be moved to keepStatic */
|
|
66
|
+
overrideToStatic: Array<{
|
|
67
|
+
name: string;
|
|
68
|
+
reason: string;
|
|
69
|
+
}>;
|
|
70
|
+
/** Cross-component insights */
|
|
71
|
+
insights: string[];
|
|
72
|
+
}
|
|
73
|
+
/** Batched response — one LazyLLMResponse per module, keyed by file path */
|
|
74
|
+
export interface BatchedLazyLLMResponse {
|
|
75
|
+
modules: Record<string, LazyLLMResponse>;
|
|
76
|
+
/** Global insights that span multiple modules */
|
|
77
|
+
globalInsights: string[];
|
|
78
|
+
}
|
|
79
|
+
export declare const LAZY_SYSTEM_PROMPT = "You are a React performance optimization assistant. You receive a JSON object describing a React component's child imports that have been identified as candidates for React.lazy() wrapping.\n\nYour job:\n1. Confirm or override the heuristic prefetch strategy for each candidate\n2. Assign suspense groups \u2014 components that share state or must hydrate together should share a group ID\n3. Flag any candidates that should actually be kept static (the heuristic may have been too aggressive)\n\nGrouping rules:\n- Components sharing mutable state MUST be in the same Suspense group\n- Adjacent siblings with no shared state CAN be grouped (reduces boundaries)\n- Conditionally rendered components should NEVER be grouped with unconditionally rendered ones\n- Context consumers that depend on the same provider can be grouped\n\nStrategy definitions:\n- \"immediate\": Component is critical path, must hydrate ASAP\n- \"viewport\": Component is below fold but visible on scroll\n- \"interaction\": Component only renders on user action (conditional)\n- \"idle\": Component can load when browser is idle (low priority, background)\n\nRespond with ONLY a valid JSON object matching this schema:\n{\n \"decisions\": [{ \"name\": string, \"prefetch\": string, \"suspenseGroup\": string|null, \"confidence\": number, \"reason\": string }],\n \"overrideToStatic\": [{ \"name\": string, \"reason\": string }],\n \"insights\": [string]\n}";
|
|
80
|
+
export declare const LAZY_BATCHED_SYSTEM_PROMPT = "You are a React performance optimization assistant. You receive a JSON object containing MULTIPLE modules from a single build, each with child component imports identified as candidates for React.lazy() wrapping.\n\nBecause you see ALL modules at once, you can make cross-module decisions:\n- Detect shared state between components in different modules\n- Identify common import patterns across the application\n- Make globally consistent Suspense grouping decisions\n\nYour job for EACH module:\n1. Confirm or override the heuristic prefetch strategy for each candidate\n2. Assign suspense groups \u2014 components that share state or must hydrate together should share a group ID\n3. Flag any candidates that should actually be kept static (the heuristic may have been too aggressive)\n\nGrouping rules:\n- Components sharing mutable state MUST be in the same Suspense group\n- Adjacent siblings with no shared state CAN be grouped (reduces boundaries)\n- Conditionally rendered components should NEVER be grouped with unconditionally rendered ones\n- Context consumers that depend on the same provider can be grouped\n- Components imported in MULTIPLE modules should have consistent strategies\n\nStrategy definitions:\n- \"immediate\": Component is critical path, must hydrate ASAP\n- \"viewport\": Component is below fold but visible on scroll\n- \"interaction\": Component only renders on user action (conditional)\n- \"idle\": Component can load when browser is idle (low priority, background)\n\nRespond with ONLY a valid JSON object matching this schema:\n{\n \"modules\": {\n \"<file_path>\": {\n \"decisions\": [{ \"name\": string, \"prefetch\": string, \"suspenseGroup\": string|null, \"confidence\": number, \"reason\": string }],\n \"overrideToStatic\": [{ \"name\": string, \"reason\": string }],\n \"insights\": [string]\n }\n },\n \"globalInsights\": [string]\n}";
|
|
81
|
+
/**
|
|
82
|
+
* Build a BatchedLazyIR from multiple modules' stashed data.
|
|
83
|
+
* Used by the plugin to construct the single LLM call payload.
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildBatchedIR(moduleData: Array<{
|
|
86
|
+
ir: LazyIR;
|
|
87
|
+
}>): BatchedLazyIR;
|
|
88
|
+
/**
|
|
89
|
+
* Apply a batched LLM response to each module's candidates.
|
|
90
|
+
* Returns a map of file path → merged results.
|
|
91
|
+
*/
|
|
92
|
+
export declare function mergeBatchedLLMDecisions(moduleStash: Map<string, {
|
|
93
|
+
candidates: LazyCandidate[];
|
|
94
|
+
keepStatic: Array<{
|
|
95
|
+
localName: string;
|
|
96
|
+
source: string;
|
|
97
|
+
reason: string;
|
|
98
|
+
}>;
|
|
99
|
+
}>, batchedResponse: BatchedLazyLLMResponse, confidenceThreshold?: number): Map<string, {
|
|
100
|
+
updated: LazyCandidate[];
|
|
101
|
+
movedToStatic: Array<{
|
|
102
|
+
localName: string;
|
|
103
|
+
source: string;
|
|
104
|
+
reason: string;
|
|
105
|
+
}>;
|
|
106
|
+
insights: string[];
|
|
107
|
+
}>;
|
|
108
|
+
/**
|
|
109
|
+
* Merge LLM optimization response into the heuristic lazy candidates.
|
|
110
|
+
*
|
|
111
|
+
* Called after inference returns. Updates prefetch strategies, suspense
|
|
112
|
+
* groups, and filters out any candidates the LLM thinks should be static.
|
|
113
|
+
*/
|
|
114
|
+
export declare function mergeLLMDecisions(candidates: LazyCandidate[], llmResponse: LazyLLMResponse, confidenceThreshold?: number): {
|
|
115
|
+
updated: LazyCandidate[];
|
|
116
|
+
movedToStatic: Array<{
|
|
117
|
+
localName: string;
|
|
118
|
+
source: string;
|
|
119
|
+
reason: string;
|
|
120
|
+
}>;
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=lazy-llm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy-llm.d.ts","sourceRoot":"","sources":["../../src/classify/lazy-llm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Lazy Optimization — IR schema, response schema, system prompt, and merge logic.
|
|
3
|
+
*
|
|
4
|
+
* Defines the compact IR sent to the LLM for the ~20% of decisions that static
|
|
5
|
+
* analysis can't make well: Suspense grouping, cross-component state awareness,
|
|
6
|
+
* and prefetch strategy refinement.
|
|
7
|
+
*
|
|
8
|
+
* Supports batched multi-module analysis — a single LLM call can process
|
|
9
|
+
* candidates from every module in the build for cross-module awareness.
|
|
10
|
+
*/
|
|
11
|
+
// ── System prompt ────────────────────────────────────────────────────────
|
|
12
|
+
export const LAZY_SYSTEM_PROMPT = `You are a React performance optimization assistant. You receive a JSON object describing a React component's child imports that have been identified as candidates for React.lazy() wrapping.
|
|
13
|
+
|
|
14
|
+
Your job:
|
|
15
|
+
1. Confirm or override the heuristic prefetch strategy for each candidate
|
|
16
|
+
2. Assign suspense groups — components that share state or must hydrate together should share a group ID
|
|
17
|
+
3. Flag any candidates that should actually be kept static (the heuristic may have been too aggressive)
|
|
18
|
+
|
|
19
|
+
Grouping rules:
|
|
20
|
+
- Components sharing mutable state MUST be in the same Suspense group
|
|
21
|
+
- Adjacent siblings with no shared state CAN be grouped (reduces boundaries)
|
|
22
|
+
- Conditionally rendered components should NEVER be grouped with unconditionally rendered ones
|
|
23
|
+
- Context consumers that depend on the same provider can be grouped
|
|
24
|
+
|
|
25
|
+
Strategy definitions:
|
|
26
|
+
- "immediate": Component is critical path, must hydrate ASAP
|
|
27
|
+
- "viewport": Component is below fold but visible on scroll
|
|
28
|
+
- "interaction": Component only renders on user action (conditional)
|
|
29
|
+
- "idle": Component can load when browser is idle (low priority, background)
|
|
30
|
+
|
|
31
|
+
Respond with ONLY a valid JSON object matching this schema:
|
|
32
|
+
{
|
|
33
|
+
"decisions": [{ "name": string, "prefetch": string, "suspenseGroup": string|null, "confidence": number, "reason": string }],
|
|
34
|
+
"overrideToStatic": [{ "name": string, "reason": string }],
|
|
35
|
+
"insights": [string]
|
|
36
|
+
}`;
|
|
37
|
+
export const LAZY_BATCHED_SYSTEM_PROMPT = `You are a React performance optimization assistant. You receive a JSON object containing MULTIPLE modules from a single build, each with child component imports identified as candidates for React.lazy() wrapping.
|
|
38
|
+
|
|
39
|
+
Because you see ALL modules at once, you can make cross-module decisions:
|
|
40
|
+
- Detect shared state between components in different modules
|
|
41
|
+
- Identify common import patterns across the application
|
|
42
|
+
- Make globally consistent Suspense grouping decisions
|
|
43
|
+
|
|
44
|
+
Your job for EACH module:
|
|
45
|
+
1. Confirm or override the heuristic prefetch strategy for each candidate
|
|
46
|
+
2. Assign suspense groups — components that share state or must hydrate together should share a group ID
|
|
47
|
+
3. Flag any candidates that should actually be kept static (the heuristic may have been too aggressive)
|
|
48
|
+
|
|
49
|
+
Grouping rules:
|
|
50
|
+
- Components sharing mutable state MUST be in the same Suspense group
|
|
51
|
+
- Adjacent siblings with no shared state CAN be grouped (reduces boundaries)
|
|
52
|
+
- Conditionally rendered components should NEVER be grouped with unconditionally rendered ones
|
|
53
|
+
- Context consumers that depend on the same provider can be grouped
|
|
54
|
+
- Components imported in MULTIPLE modules should have consistent strategies
|
|
55
|
+
|
|
56
|
+
Strategy definitions:
|
|
57
|
+
- "immediate": Component is critical path, must hydrate ASAP
|
|
58
|
+
- "viewport": Component is below fold but visible on scroll
|
|
59
|
+
- "interaction": Component only renders on user action (conditional)
|
|
60
|
+
- "idle": Component can load when browser is idle (low priority, background)
|
|
61
|
+
|
|
62
|
+
Respond with ONLY a valid JSON object matching this schema:
|
|
63
|
+
{
|
|
64
|
+
"modules": {
|
|
65
|
+
"<file_path>": {
|
|
66
|
+
"decisions": [{ "name": string, "prefetch": string, "suspenseGroup": string|null, "confidence": number, "reason": string }],
|
|
67
|
+
"overrideToStatic": [{ "name": string, "reason": string }],
|
|
68
|
+
"insights": [string]
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"globalInsights": [string]
|
|
72
|
+
}`;
|
|
73
|
+
/**
|
|
74
|
+
* Build a BatchedLazyIR from multiple modules' stashed data.
|
|
75
|
+
* Used by the plugin to construct the single LLM call payload.
|
|
76
|
+
*/
|
|
77
|
+
export function buildBatchedIR(moduleData) {
|
|
78
|
+
const modules = moduleData.map((d) => d.ir);
|
|
79
|
+
const totalCandidates = modules.reduce((sum, m) => sum + m.candidates.length, 0);
|
|
80
|
+
return { modules, totalCandidates };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Apply a batched LLM response to each module's candidates.
|
|
84
|
+
* Returns a map of file path → merged results.
|
|
85
|
+
*/
|
|
86
|
+
export function mergeBatchedLLMDecisions(moduleStash, batchedResponse, confidenceThreshold = 0.8) {
|
|
87
|
+
const results = new Map();
|
|
88
|
+
for (const [filePath, stashed] of moduleStash) {
|
|
89
|
+
const moduleResponse = batchedResponse.modules[filePath];
|
|
90
|
+
if (!moduleResponse) {
|
|
91
|
+
// LLM didn't return data for this module — keep heuristic decisions
|
|
92
|
+
results.set(filePath, {
|
|
93
|
+
updated: stashed.candidates,
|
|
94
|
+
movedToStatic: [],
|
|
95
|
+
insights: [],
|
|
96
|
+
});
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const { updated, movedToStatic } = mergeLLMDecisions(stashed.candidates, moduleResponse, confidenceThreshold);
|
|
100
|
+
results.set(filePath, {
|
|
101
|
+
updated,
|
|
102
|
+
movedToStatic,
|
|
103
|
+
insights: moduleResponse.insights ?? [],
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return results;
|
|
107
|
+
}
|
|
108
|
+
// ── Merge function ───────────────────────────────────────────────────────
|
|
109
|
+
/**
|
|
110
|
+
* Merge LLM optimization response into the heuristic lazy candidates.
|
|
111
|
+
*
|
|
112
|
+
* Called after inference returns. Updates prefetch strategies, suspense
|
|
113
|
+
* groups, and filters out any candidates the LLM thinks should be static.
|
|
114
|
+
*/
|
|
115
|
+
export function mergeLLMDecisions(candidates, llmResponse, confidenceThreshold = 0.8) {
|
|
116
|
+
const movedToStatic = [];
|
|
117
|
+
// Build lookup from LLM decisions
|
|
118
|
+
const decisionMap = new Map(llmResponse.decisions.map((d) => [d.name, d]));
|
|
119
|
+
const remaining = [];
|
|
120
|
+
for (const candidate of candidates) {
|
|
121
|
+
// Check if LLM wants to move this to static
|
|
122
|
+
const override = llmResponse.overrideToStatic.find((o) => o.name === candidate.localName);
|
|
123
|
+
if (override) {
|
|
124
|
+
movedToStatic.push({
|
|
125
|
+
localName: candidate.localName,
|
|
126
|
+
source: candidate.source,
|
|
127
|
+
reason: `LLM override: ${override.reason}`,
|
|
128
|
+
});
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// Apply LLM decision if confidence is above threshold
|
|
132
|
+
const decision = decisionMap.get(candidate.localName);
|
|
133
|
+
if (decision && decision.confidence >= confidenceThreshold) {
|
|
134
|
+
candidate.prefetch = decision.prefetch;
|
|
135
|
+
candidate.suspenseGroup = decision.suspenseGroup;
|
|
136
|
+
candidate.reason = `LLM: ${decision.reason}`;
|
|
137
|
+
}
|
|
138
|
+
remaining.push(candidate);
|
|
139
|
+
}
|
|
140
|
+
return { updated: remaining, movedToStatic };
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=lazy-llm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy-llm.js","sourceRoot":"","sources":["../../src/classify/lazy-llm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AnalyzedModule, ClassifiedSegment, LazyCandidateResult, ComponentProfile } from '../types.js';
|
|
2
|
+
/** Re-export map type: barrel file path → (exportedName → { source, importedName }) */
|
|
3
|
+
type ReExportMap = Map<string, Map<string, {
|
|
4
|
+
source: string;
|
|
5
|
+
importedName: string;
|
|
6
|
+
}>>;
|
|
7
|
+
/**
|
|
8
|
+
* Detect which imported child components are candidates for React.lazy wrapping.
|
|
9
|
+
*
|
|
10
|
+
* Runs after segment classification so it can use handler/effect counts
|
|
11
|
+
* from sibling modules (via componentProfiles). Works standalone with
|
|
12
|
+
* heuristics when profiles aren't available.
|
|
13
|
+
*
|
|
14
|
+
* @param analyzed - The parsed + scope-analyzed module
|
|
15
|
+
* @param sourceCode - Raw source text
|
|
16
|
+
* @param segments - Already-classified segments for THIS module
|
|
17
|
+
* @param componentProfiles - Optional: analysis results from imported modules
|
|
18
|
+
* (keyed by resolved file path or import source)
|
|
19
|
+
* @param reExportMap - Optional: barrel file re-export mappings accumulated during build
|
|
20
|
+
*/
|
|
21
|
+
export declare function detectLazyCandidates(analyzed: AnalyzedModule, sourceCode: string, segments: ClassifiedSegment[], componentProfiles?: Map<string, ComponentProfile>, reExportMap?: ReExportMap): LazyCandidateResult;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=lazy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/classify/lazy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAEjB,mBAAmB,EACnB,gBAAgB,EAEjB,MAAM,aAAa,CAAC;AAErB,uFAAuF;AACvF,KAAK,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAAC;AAiCtF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,cAAc,EACxB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,iBAAiB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACjD,WAAW,CAAC,EAAE,WAAW,GACxB,mBAAmB,CAqGrB"}
|