react-reinspect 0.1.2 → 0.1.4
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 +179 -4
- package/dist/plugin/reinspectAutoDiscoverPlugin.d.ts.map +1 -1
- package/dist/plugin/reinspectAutoDiscoverPlugin.js +85 -8
- package/dist/plugin/reinspectNextAutoDiscoverLoader.d.ts +11 -0
- package/dist/plugin/reinspectNextAutoDiscoverLoader.d.ts.map +1 -0
- package/dist/plugin/reinspectNextAutoDiscoverLoader.js +58 -0
- package/dist/plugin/reinspectNextPlugin.d.ts +32 -0
- package/dist/plugin/reinspectNextPlugin.d.ts.map +1 -0
- package/dist/plugin/reinspectNextPlugin.js +70 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -72,6 +72,19 @@ export default defineConfig({
|
|
|
72
72
|
|
|
73
73
|
Without this plugin, only manually wrapped components (`withReinspect`) are inspectable.
|
|
74
74
|
|
|
75
|
+
Next.js (webpack mode) can use:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
// next.config.ts
|
|
79
|
+
import { withReinspectAutoDiscover } from 'react-reinspect/next-plugin'
|
|
80
|
+
|
|
81
|
+
const nextConfig = {}
|
|
82
|
+
|
|
83
|
+
export default withReinspectAutoDiscover(nextConfig)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If your Next dev server runs with Turbopack, switch to webpack mode for this transform plugin.
|
|
87
|
+
|
|
75
88
|
|
|
76
89
|
## Example
|
|
77
90
|
|
|
@@ -88,9 +101,16 @@ You are a senior React code agent, your task is to integrate react-reinspect to
|
|
|
88
101
|
Do all of the following in one pass:
|
|
89
102
|
1) Install `react-reinspect` using this repo's package manager.
|
|
90
103
|
2) Turn it on in dev mode ONLY by wiring `ReinspectProvider` at app root.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
- Vite: use `enabled: import.meta.env.DEV`
|
|
105
|
+
- Next.js: use `enabled: process.env.NODE_ENV !== 'production'`
|
|
106
|
+
- Next App Router: mount a client `Providers` component from `app/layout.tsx`
|
|
107
|
+
- Next Pages Router: mount `ReinspectProvider` in `pages/_app.tsx`
|
|
108
|
+
3) If this app uses Vite, add `reinspectAutoDiscoverPlugin` from `react-reinspect/vite-plugin` in `vite.config.*`.
|
|
109
|
+
4) If this app uses Next.js (webpack mode), wrap the Next config with `withReinspectAutoDiscover` from `react-reinspect/next-plugin`.
|
|
110
|
+
5) If Next.js is running with Turbopack, either switch dev to webpack for auto-discovery transforms (`next dev --webpack`) or fall back to manual wrapping (`withReinspect`).
|
|
111
|
+
6) Keep production safe (e.g.: `enabled: import.meta.env.DEV` or however we manage dev/prod in this repo.).
|
|
112
|
+
7) Run validation (build/tests if available) and fix any issues.
|
|
113
|
+
8) Output a concise summary with changed files and how to use it.
|
|
94
114
|
|
|
95
115
|
Use this example as the baseline:
|
|
96
116
|
|
|
@@ -108,6 +128,60 @@ export function AppProviders({ children }: { children: React.ReactNode }) {
|
|
|
108
128
|
return <ReinspectProvider config={reinspectConfig}>{children}</ReinspectProvider>
|
|
109
129
|
}
|
|
110
130
|
|
|
131
|
+
// Next.js App Router (app/providers.tsx)
|
|
132
|
+
'use client'
|
|
133
|
+
import { ReinspectProvider, type ReinspectConfig } from 'react-reinspect'
|
|
134
|
+
import 'react-reinspect/style.css'
|
|
135
|
+
|
|
136
|
+
const nextReinspectConfig: ReinspectConfig = {
|
|
137
|
+
enabled: process.env.NODE_ENV !== 'production',
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
141
|
+
return (
|
|
142
|
+
<ReinspectProvider config={nextReinspectConfig}>
|
|
143
|
+
{children}
|
|
144
|
+
</ReinspectProvider>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Next.js App Router mount (app/layout.tsx)
|
|
149
|
+
import { Providers } from './providers'
|
|
150
|
+
|
|
151
|
+
export default function RootLayout({
|
|
152
|
+
children,
|
|
153
|
+
}: {
|
|
154
|
+
children: React.ReactNode
|
|
155
|
+
}) {
|
|
156
|
+
return (
|
|
157
|
+
<html lang="en">
|
|
158
|
+
<body>
|
|
159
|
+
<Providers>{children}</Providers>
|
|
160
|
+
</body>
|
|
161
|
+
</html>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
For auto-discovery setup, apply one of these depending on framework:
|
|
166
|
+
|
|
167
|
+
// Vite
|
|
168
|
+
import { defineConfig } from 'vite'
|
|
169
|
+
import react from '@vitejs/plugin-react'
|
|
170
|
+
import { reinspectAutoDiscoverPlugin } from 'react-reinspect/vite-plugin'
|
|
171
|
+
|
|
172
|
+
export default defineConfig({
|
|
173
|
+
plugins: [reinspectAutoDiscoverPlugin(), react()],
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
// Next.js (webpack mode)
|
|
177
|
+
import { withReinspectAutoDiscover } from 'react-reinspect/next-plugin'
|
|
178
|
+
|
|
179
|
+
const nextConfig = {}
|
|
180
|
+
export default withReinspectAutoDiscover(nextConfig)
|
|
181
|
+
|
|
182
|
+
// Next.js dev script for auto-discovery:
|
|
183
|
+
// package.json -> "dev": "next dev --webpack"
|
|
184
|
+
|
|
111
185
|
Output format I want from you:
|
|
112
186
|
- What changed (bullet list)
|
|
113
187
|
- Why this is safe in production
|
|
@@ -118,6 +192,8 @@ Output format I want from you:
|
|
|
118
192
|
## Manual Quick Start
|
|
119
193
|
### 1) Wrap your app with `ReinspectProvider`
|
|
120
194
|
|
|
195
|
+
Vite:
|
|
196
|
+
|
|
121
197
|
```tsx
|
|
122
198
|
import {
|
|
123
199
|
ReinspectProvider,
|
|
@@ -137,7 +213,106 @@ export function AppProviders({ children }: { children: React.ReactNode }) {
|
|
|
137
213
|
}
|
|
138
214
|
```
|
|
139
215
|
|
|
140
|
-
|
|
216
|
+
Next.js App Router:
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
// app/providers.tsx
|
|
220
|
+
'use client'
|
|
221
|
+
|
|
222
|
+
import { ReinspectProvider, type ReinspectConfig } from 'react-reinspect'
|
|
223
|
+
import 'react-reinspect/style.css'
|
|
224
|
+
|
|
225
|
+
const reinspectConfig: ReinspectConfig = {
|
|
226
|
+
enabled: process.env.NODE_ENV !== 'production',
|
|
227
|
+
// startActive: true,
|
|
228
|
+
// showFloatingToggle: true,
|
|
229
|
+
// inspectMode: 'first-party',
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
233
|
+
return <ReinspectProvider config={reinspectConfig}>{children}</ReinspectProvider>
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
// app/layout.tsx
|
|
239
|
+
import { Providers } from './providers'
|
|
240
|
+
|
|
241
|
+
export default function RootLayout({
|
|
242
|
+
children,
|
|
243
|
+
}: {
|
|
244
|
+
children: React.ReactNode
|
|
245
|
+
}) {
|
|
246
|
+
return (
|
|
247
|
+
<html lang="en">
|
|
248
|
+
<body>
|
|
249
|
+
<Providers>{children}</Providers>
|
|
250
|
+
</body>
|
|
251
|
+
</html>
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Next.js Pages Router:
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
// pages/_app.tsx
|
|
260
|
+
import type { AppProps } from 'next/app'
|
|
261
|
+
import { ReinspectProvider, type ReinspectConfig } from 'react-reinspect'
|
|
262
|
+
import 'react-reinspect/style.css'
|
|
263
|
+
|
|
264
|
+
const reinspectConfig: ReinspectConfig = {
|
|
265
|
+
enabled: process.env.NODE_ENV !== 'production',
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
269
|
+
return (
|
|
270
|
+
<ReinspectProvider config={reinspectConfig}>
|
|
271
|
+
<Component {...pageProps} />
|
|
272
|
+
</ReinspectProvider>
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 2) Enable auto-discovery transforms (pick your framework)
|
|
278
|
+
|
|
279
|
+
Vite:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
// vite.config.ts
|
|
283
|
+
import { defineConfig } from 'vite'
|
|
284
|
+
import react from '@vitejs/plugin-react'
|
|
285
|
+
import { reinspectAutoDiscoverPlugin } from 'react-reinspect/vite-plugin'
|
|
286
|
+
|
|
287
|
+
export default defineConfig({
|
|
288
|
+
plugins: [reinspectAutoDiscoverPlugin(), react()],
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Next.js (webpack mode):
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
// next.config.ts
|
|
296
|
+
import { withReinspectAutoDiscover } from 'react-reinspect/next-plugin'
|
|
297
|
+
|
|
298
|
+
const nextConfig = {}
|
|
299
|
+
export default withReinspectAutoDiscover(nextConfig)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
If your Next dev server runs with Turbopack, switch to webpack mode for auto-discovery transforms.
|
|
303
|
+
If you keep Turbopack enabled, skip the Next transform plugin and use manual wrapping (`withReinspect`) instead.
|
|
304
|
+
|
|
305
|
+
Next.js webpack dev script example:
|
|
306
|
+
|
|
307
|
+
```json
|
|
308
|
+
{
|
|
309
|
+
"scripts": {
|
|
310
|
+
"dev": "next dev --webpack"
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### 3) Use it in the browser
|
|
141
316
|
|
|
142
317
|
- Click `Reinspect settings` button.
|
|
143
318
|
- Right-click a wrapped component.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reinspectAutoDiscoverPlugin.d.ts","sourceRoot":"","sources":["../../reinspectAutoDiscoverPlugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,KAAK,iBAAiB,GAAG,aAAa,GAAG,aAAa,CAAA;AAgBtD,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;
|
|
1
|
+
{"version":3,"file":"reinspectAutoDiscoverPlugin.d.ts","sourceRoot":"","sources":["../../src/plugin/reinspectAutoDiscoverPlugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,KAAK,iBAAiB,GAAG,aAAa,GAAG,aAAa,CAAA;AAgBtD,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AAmQD,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,iBAAiB,GACvB,2BAA2B,CAwP7B;AAED,wBAAgB,2BAA2B,IAAI,MAAM,CA2CpD"}
|
|
@@ -47,19 +47,92 @@ function unwrapExpression(node) {
|
|
|
47
47
|
}
|
|
48
48
|
return currentNode;
|
|
49
49
|
}
|
|
50
|
-
function
|
|
50
|
+
function isReactCreateElementCall(node) {
|
|
51
51
|
const callee = unwrapExpression(node.callee);
|
|
52
52
|
if (t.isIdentifier(callee)) {
|
|
53
|
-
return callee.name === '
|
|
53
|
+
return callee.name === 'createElement';
|
|
54
54
|
}
|
|
55
55
|
if (t.isMemberExpression(callee) &&
|
|
56
56
|
t.isIdentifier(callee.object) &&
|
|
57
57
|
callee.object.name === 'React' &&
|
|
58
58
|
t.isIdentifier(callee.property)) {
|
|
59
|
-
return callee.property.name === '
|
|
59
|
+
return callee.property.name === 'createElement';
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
function isAstNode(value) {
|
|
64
|
+
return (typeof value === 'object' &&
|
|
65
|
+
value !== null &&
|
|
66
|
+
'type' in value &&
|
|
67
|
+
typeof value.type === 'string');
|
|
68
|
+
}
|
|
69
|
+
function containsRenderableReactNode(node) {
|
|
70
|
+
if (!node) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (t.isJSXElement(node) || t.isJSXFragment(node)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (t.isCallExpression(node) && isReactCreateElementCall(node)) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
for (const fieldValue of Object.values(node)) {
|
|
80
|
+
if (Array.isArray(fieldValue)) {
|
|
81
|
+
for (const value of fieldValue) {
|
|
82
|
+
if (isAstNode(value) && containsRenderableReactNode(value)) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (isAstNode(fieldValue) && containsRenderableReactNode(fieldValue)) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
function isComponentFunction(node) {
|
|
95
|
+
if (t.isBlockStatement(node.body)) {
|
|
96
|
+
return containsRenderableReactNode(node.body);
|
|
97
|
+
}
|
|
98
|
+
return containsRenderableReactNode(node.body);
|
|
99
|
+
}
|
|
100
|
+
function isMemoForwardRefCallee(callee) {
|
|
101
|
+
const expression = unwrapExpression(callee);
|
|
102
|
+
if (t.isIdentifier(expression)) {
|
|
103
|
+
return expression.name === 'memo' || expression.name === 'forwardRef';
|
|
104
|
+
}
|
|
105
|
+
if (t.isMemberExpression(expression) &&
|
|
106
|
+
t.isIdentifier(expression.object) &&
|
|
107
|
+
expression.object.name === 'React' &&
|
|
108
|
+
t.isIdentifier(expression.property)) {
|
|
109
|
+
return (expression.property.name === 'memo' ||
|
|
110
|
+
expression.property.name === 'forwardRef');
|
|
60
111
|
}
|
|
61
112
|
return false;
|
|
62
113
|
}
|
|
114
|
+
function isMemoForwardRefCall(node) {
|
|
115
|
+
const callee = unwrapExpression(node.callee);
|
|
116
|
+
if (!isMemoForwardRefCallee(callee)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
if (node.arguments.length === 0) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
const firstArgument = node.arguments[0];
|
|
123
|
+
if (!t.isExpression(firstArgument)) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
const componentCandidate = unwrapExpression(firstArgument);
|
|
127
|
+
if (t.isArrowFunctionExpression(componentCandidate) ||
|
|
128
|
+
t.isFunctionExpression(componentCandidate)) {
|
|
129
|
+
return isComponentFunction(componentCandidate);
|
|
130
|
+
}
|
|
131
|
+
if (t.isIdentifier(componentCandidate)) {
|
|
132
|
+
return isPascalCaseIdentifier(componentCandidate.name);
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
63
136
|
function isWrappedInitializer(node) {
|
|
64
137
|
const expression = unwrapExpression(node);
|
|
65
138
|
if (!t.isCallExpression(expression)) {
|
|
@@ -72,7 +145,7 @@ function isWrappedInitializer(node) {
|
|
|
72
145
|
function isComponentInitializer(node) {
|
|
73
146
|
const expression = unwrapExpression(node);
|
|
74
147
|
if (t.isArrowFunctionExpression(expression) || t.isFunctionExpression(expression)) {
|
|
75
|
-
return
|
|
148
|
+
return isComponentFunction(expression);
|
|
76
149
|
}
|
|
77
150
|
if (t.isCallExpression(expression)) {
|
|
78
151
|
return isMemoForwardRefCall(expression);
|
|
@@ -144,7 +217,8 @@ export function transformModuleForAutoDiscover(code, fileId, scope) {
|
|
|
144
217
|
for (let index = 0; index < program.body.length; index += 1) {
|
|
145
218
|
const statement = program.body[index];
|
|
146
219
|
if (t.isFunctionDeclaration(statement) && statement.id) {
|
|
147
|
-
if (isPascalCaseIdentifier(statement.id.name)
|
|
220
|
+
if (isPascalCaseIdentifier(statement.id.name) &&
|
|
221
|
+
isComponentFunction(statement)) {
|
|
148
222
|
program.body.splice(index + 1, 0, createFunctionWrapAssignment(statement.id.name, scope, fallbackName));
|
|
149
223
|
index += 1;
|
|
150
224
|
modified = true;
|
|
@@ -155,7 +229,8 @@ export function transformModuleForAutoDiscover(code, fileId, scope) {
|
|
|
155
229
|
statement.declaration &&
|
|
156
230
|
t.isFunctionDeclaration(statement.declaration) &&
|
|
157
231
|
statement.declaration.id &&
|
|
158
|
-
isPascalCaseIdentifier(statement.declaration.id.name)
|
|
232
|
+
isPascalCaseIdentifier(statement.declaration.id.name) &&
|
|
233
|
+
isComponentFunction(statement.declaration)) {
|
|
159
234
|
program.body.splice(index + 1, 0, createFunctionWrapAssignment(statement.declaration.id.name, scope, fallbackName));
|
|
160
235
|
index += 1;
|
|
161
236
|
modified = true;
|
|
@@ -200,7 +275,9 @@ export function transformModuleForAutoDiscover(code, fileId, scope) {
|
|
|
200
275
|
}
|
|
201
276
|
const declaration = statement.declaration;
|
|
202
277
|
if (t.isFunctionDeclaration(declaration)) {
|
|
203
|
-
if (declaration.id &&
|
|
278
|
+
if (declaration.id &&
|
|
279
|
+
isPascalCaseIdentifier(declaration.id.name) &&
|
|
280
|
+
isComponentFunction(declaration)) {
|
|
204
281
|
const localName = declaration.id.name;
|
|
205
282
|
const replacementStatements = [
|
|
206
283
|
declaration,
|
|
@@ -212,7 +289,7 @@ export function transformModuleForAutoDiscover(code, fileId, scope) {
|
|
|
212
289
|
modified = true;
|
|
213
290
|
continue;
|
|
214
291
|
}
|
|
215
|
-
if (!declaration.id) {
|
|
292
|
+
if (!declaration.id && isComponentFunction(declaration)) {
|
|
216
293
|
const localIdentifier = t.identifier(DEFAULT_EXPORT_LOCAL_IDENTIFIER);
|
|
217
294
|
const wrappedValue = createAutoWrapCall(functionDeclarationToExpression(declaration), undefined, scope, fallbackName);
|
|
218
295
|
const replacementStatements = [
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface ReinspectNextLoaderOptions {
|
|
2
|
+
includeThirdParty?: boolean;
|
|
3
|
+
}
|
|
4
|
+
interface LoaderContextLike {
|
|
5
|
+
resourcePath: string;
|
|
6
|
+
getOptions?: () => ReinspectNextLoaderOptions;
|
|
7
|
+
async?: () => ((error: Error | null, code?: string) => void) | undefined;
|
|
8
|
+
}
|
|
9
|
+
export default function reinspectNextAutoDiscoverLoader(this: LoaderContextLike, sourceCode: string): string | void;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=reinspectNextAutoDiscoverLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reinspectNextAutoDiscoverLoader.d.ts","sourceRoot":"","sources":["../../src/plugin/reinspectNextAutoDiscoverLoader.ts"],"names":[],"mappings":"AAQA,UAAU,0BAA0B;IAClC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,UAAU,iBAAiB;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,0BAA0B,CAAA;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;CACzE;AA4DD,MAAM,CAAC,OAAO,UAAU,+BAA+B,CACrD,IAAI,EAAE,iBAAiB,EACvB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAyBf"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { shouldSkipThirdPartyModule, transformModuleForAutoDiscover, } from './reinspectAutoDiscoverPlugin';
|
|
3
|
+
const SUPPORTED_FILE_PATTERN = /\.[cm]?[jt]sx?$/;
|
|
4
|
+
function normalizeModuleId(id) {
|
|
5
|
+
return id.split(path.sep).join('/');
|
|
6
|
+
}
|
|
7
|
+
function isSupportedSourceFile(id) {
|
|
8
|
+
if (!SUPPORTED_FILE_PATTERN.test(id)) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (id.includes('/node_modules/react-reinspect/')) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
function resolveAutoDiscoverScope(normalizedId, includeThirdParty) {
|
|
17
|
+
const isThirdParty = normalizedId.includes('/node_modules/');
|
|
18
|
+
if (!isThirdParty) {
|
|
19
|
+
return 'first-party';
|
|
20
|
+
}
|
|
21
|
+
if (!includeThirdParty || shouldSkipThirdPartyModule(normalizedId)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return 'third-party';
|
|
25
|
+
}
|
|
26
|
+
function runTransform(sourceCode, normalizedId, options) {
|
|
27
|
+
if (!isSupportedSourceFile(normalizedId)) {
|
|
28
|
+
return sourceCode;
|
|
29
|
+
}
|
|
30
|
+
const includeThirdParty = Boolean(options.includeThirdParty);
|
|
31
|
+
const scope = resolveAutoDiscoverScope(normalizedId, includeThirdParty);
|
|
32
|
+
if (!scope) {
|
|
33
|
+
return sourceCode;
|
|
34
|
+
}
|
|
35
|
+
const transformedResult = transformModuleForAutoDiscover(sourceCode, normalizedId, scope);
|
|
36
|
+
return transformedResult.modified ? transformedResult.code : sourceCode;
|
|
37
|
+
}
|
|
38
|
+
export default function reinspectNextAutoDiscoverLoader(sourceCode) {
|
|
39
|
+
const options = this.getOptions?.() ?? {};
|
|
40
|
+
const normalizedId = normalizeModuleId(this.resourcePath ?? '');
|
|
41
|
+
const callback = this.async?.();
|
|
42
|
+
try {
|
|
43
|
+
const transformedCode = runTransform(sourceCode, normalizedId, options);
|
|
44
|
+
if (callback) {
|
|
45
|
+
callback(null, transformedCode);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
return transformedCode;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const nextError = error instanceof Error ? error : new Error('Failed to transform module');
|
|
52
|
+
if (callback) {
|
|
53
|
+
callback(nextError);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
throw nextError;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface ReinspectNextPluginOptions {
|
|
2
|
+
includeThirdParty?: boolean;
|
|
3
|
+
enableInProduction?: boolean;
|
|
4
|
+
}
|
|
5
|
+
interface NextWebpackOptions {
|
|
6
|
+
dev: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface NextWebpackUseEntry {
|
|
9
|
+
loader?: string;
|
|
10
|
+
options?: {
|
|
11
|
+
includeThirdParty?: boolean;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
interface NextWebpackRule {
|
|
15
|
+
test?: RegExp;
|
|
16
|
+
enforce?: 'pre' | 'post';
|
|
17
|
+
exclude?: RegExp;
|
|
18
|
+
use?: NextWebpackUseEntry | NextWebpackUseEntry[];
|
|
19
|
+
}
|
|
20
|
+
interface NextWebpackModuleConfig {
|
|
21
|
+
rules?: NextWebpackRule[];
|
|
22
|
+
}
|
|
23
|
+
interface NextWebpackConfig {
|
|
24
|
+
module?: NextWebpackModuleConfig;
|
|
25
|
+
}
|
|
26
|
+
type NextWebpackFunction = (config: NextWebpackConfig, options: NextWebpackOptions) => NextWebpackConfig;
|
|
27
|
+
interface NextConfigLike {
|
|
28
|
+
webpack?: NextWebpackFunction;
|
|
29
|
+
}
|
|
30
|
+
export declare function withReinspectAutoDiscover(nextConfig?: NextConfigLike, pluginOptions?: ReinspectNextPluginOptions): NextConfigLike;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=reinspectNextPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reinspectNextPlugin.d.ts","sourceRoot":"","sources":["../../src/plugin/reinspectNextPlugin.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,0BAA0B;IACzC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED,UAAU,kBAAkB;IAC1B,GAAG,EAAE,OAAO,CAAA;CACb;AAED,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE;QACR,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAC5B,CAAA;CACF;AAED,UAAU,eAAe;IACvB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,EAAE,CAAA;CAClD;AAED,UAAU,uBAAuB;IAC/B,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,UAAU,iBAAiB;IACzB,MAAM,CAAC,EAAE,uBAAuB,CAAA;CACjC;AAED,KAAK,mBAAmB,GAAG,CACzB,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,kBAAkB,KACxB,iBAAiB,CAAA;AAEtB,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,mBAAmB,CAAA;CAC9B;AAqED,wBAAgB,yBAAyB,CACvC,UAAU,GAAE,cAAmB,EAC/B,aAAa,GAAE,0BAA+B,GAC7C,cAAc,CAqBhB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
function resolveNextLoaderPath() {
|
|
3
|
+
const loaderUrl = new URL('./reinspectNextAutoDiscoverLoader.js', import.meta.url);
|
|
4
|
+
if (loaderUrl.protocol === 'file:') {
|
|
5
|
+
return fileURLToPath(loaderUrl);
|
|
6
|
+
}
|
|
7
|
+
return loaderUrl.pathname;
|
|
8
|
+
}
|
|
9
|
+
function hasReinspectLoaderRule(rules) {
|
|
10
|
+
for (const rule of rules) {
|
|
11
|
+
const ruleUse = Array.isArray(rule.use)
|
|
12
|
+
? rule.use
|
|
13
|
+
: rule.use
|
|
14
|
+
? [rule.use]
|
|
15
|
+
: [];
|
|
16
|
+
if (ruleUse.some((entry) => entry.loader === resolveNextLoaderPath())) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
function addReinspectLoaderRule(config, options) {
|
|
23
|
+
const moduleConfig = config.module ?? {};
|
|
24
|
+
const rules = moduleConfig.rules ?? [];
|
|
25
|
+
if (hasReinspectLoaderRule(rules)) {
|
|
26
|
+
config.module = {
|
|
27
|
+
...moduleConfig,
|
|
28
|
+
rules,
|
|
29
|
+
};
|
|
30
|
+
return config;
|
|
31
|
+
}
|
|
32
|
+
const nextLoaderPath = resolveNextLoaderPath();
|
|
33
|
+
const nextRules = [
|
|
34
|
+
{
|
|
35
|
+
test: /\.[cm]?[jt]sx?$/,
|
|
36
|
+
enforce: 'pre',
|
|
37
|
+
exclude: /node_modules/,
|
|
38
|
+
use: [
|
|
39
|
+
{
|
|
40
|
+
loader: nextLoaderPath,
|
|
41
|
+
options: {
|
|
42
|
+
includeThirdParty: Boolean(options.includeThirdParty),
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
...rules,
|
|
48
|
+
];
|
|
49
|
+
config.module = {
|
|
50
|
+
...moduleConfig,
|
|
51
|
+
rules: nextRules,
|
|
52
|
+
};
|
|
53
|
+
return config;
|
|
54
|
+
}
|
|
55
|
+
export function withReinspectAutoDiscover(nextConfig = {}, pluginOptions = {}) {
|
|
56
|
+
const originalWebpack = nextConfig.webpack;
|
|
57
|
+
return {
|
|
58
|
+
...nextConfig,
|
|
59
|
+
webpack(config, options) {
|
|
60
|
+
const resolvedConfig = typeof originalWebpack === 'function'
|
|
61
|
+
? originalWebpack(config, options) ?? config
|
|
62
|
+
: config;
|
|
63
|
+
const shouldEnable = options.dev || Boolean(pluginOptions.enableInProduction);
|
|
64
|
+
if (!shouldEnable) {
|
|
65
|
+
return resolvedConfig;
|
|
66
|
+
}
|
|
67
|
+
return addReinspectLoaderRule(resolvedConfig, pluginOptions);
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-reinspect",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Visual runtime inspector for React components with render counters and style overrides.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"types": "./dist/plugin/reinspectAutoDiscoverPlugin.d.ts",
|
|
24
24
|
"import": "./dist/plugin/reinspectAutoDiscoverPlugin.js"
|
|
25
25
|
},
|
|
26
|
+
"./next-plugin": {
|
|
27
|
+
"types": "./dist/plugin/reinspectNextPlugin.d.ts",
|
|
28
|
+
"import": "./dist/plugin/reinspectNextPlugin.js"
|
|
29
|
+
},
|
|
26
30
|
"./style.css": "./dist/lib/style.css"
|
|
27
31
|
},
|
|
28
32
|
"files": [
|