@rozenite/vite-plugin 1.0.0-alpha.1 → 1.0.0-alpha.10
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 +82 -0
- package/dist/client-plugin.d.ts.map +1 -1
- package/dist/index.cjs +193 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +193 -40
- package/dist/package-json.d.ts.map +1 -1
- package/dist/react-native-plugin.d.ts.map +1 -1
- package/dist/require-plugin.d.ts +3 -0
- package/dist/require-plugin.d.ts.map +1 -0
- package/dist/server-plugin.d.ts.map +1 -1
- package/package.json +2 -6
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
### A Vite plugin for developing React Native DevTools plugins with hot reload and development tools.
|
|
4
|
+
|
|
5
|
+
[![mit licence][license-badge]][license] [![npm downloads][npm-downloads-badge]][npm-downloads] [![Chat][chat-badge]][chat] [![PRs Welcome][prs-welcome-badge]][prs-welcome]
|
|
6
|
+
|
|
7
|
+
The Rozenite Vite Plugin provides a complete development environment for React Native DevTools plugins. It handles multiple build targets (client panels and React Native entry points), provides hot reload during development, and generates optimized production builds with proper manifest files.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Multi-Target Building**: Build for client panels and React Native
|
|
12
|
+
- **Hot Reload Development**: Instant updates during plugin development
|
|
13
|
+
- **React Native Web Support**: Seamless React Native component development
|
|
14
|
+
- **Automatic Manifest Generation**: Creates `rozenite.json` manifest files
|
|
15
|
+
- **Panel HTML Generation**: Automatically generates HTML for plugin panels
|
|
16
|
+
- **TypeScript Support**: Full TypeScript support with type generation
|
|
17
|
+
- **Development Server**: Built-in development server with CORS support
|
|
18
|
+
- **Production Optimization**: Optimized builds for production deployment
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Install the Vite plugin as a development dependency:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install --save-dev @rozenite/vite-plugin
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Basic Configuration
|
|
31
|
+
|
|
32
|
+
Add the Rozenite plugin to your Vite configuration:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// vite.config.ts
|
|
36
|
+
import { defineConfig } from 'vite';
|
|
37
|
+
import { rozenitePlugin } from '@rozenite/vite-plugin';
|
|
38
|
+
|
|
39
|
+
export default defineConfig({
|
|
40
|
+
plugins: rozenitePlugin(),
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Build Targets
|
|
45
|
+
|
|
46
|
+
The Vite plugin automatically handles different build targets based on environment variables:
|
|
47
|
+
|
|
48
|
+
### Client Panels (Default)
|
|
49
|
+
|
|
50
|
+
For plugin panels that run in the browser:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Build panels
|
|
54
|
+
npm run build
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### React Native Entry Points
|
|
58
|
+
|
|
59
|
+
For React Native integration:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Build React Native target
|
|
63
|
+
VITE_ROZENITE_TARGET=react-native npm run build
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Made with ❤️ at Callstack
|
|
67
|
+
|
|
68
|
+
`rozenite` is an open source project and will always remain free to use. If you think it's cool, please star it 🌟.
|
|
69
|
+
|
|
70
|
+
[Callstack][callstack-readme-with-love] is a group of React and React Native geeks, contact us at [hello@callstack.com](mailto:hello@callstack.com) if you need any help with these or just want to say hi!
|
|
71
|
+
|
|
72
|
+
Like the project? ⚛️ [Join the team](https://callstack.com/careers/?utm_campaign=Senior_RN&utm_source=github&utm_medium=readme) who does amazing stuff for clients and drives React Native Open Source! 🔥
|
|
73
|
+
|
|
74
|
+
[callstack-readme-with-love]: https://callstack.com/?utm_source=github.com&utm_medium=referral&utm_campaign=rozenite&utm_term=readme-with-love
|
|
75
|
+
[license-badge]: https://img.shields.io/npm/l/rozenite?style=for-the-badge
|
|
76
|
+
[license]: https://github.com/callstackincubator/rozenite/blob/main/LICENSE
|
|
77
|
+
[npm-downloads-badge]: https://img.shields.io/npm/dm/rozenite?style=for-the-badge
|
|
78
|
+
[npm-downloads]: https://www.npmjs.com/package/@rozenite/vite-plugin
|
|
79
|
+
[prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
|
|
80
|
+
[prs-welcome]: https://github.com/callstackincubator/rozenite/blob/main/CONTRIBUTING.md
|
|
81
|
+
[chat-badge]: https://img.shields.io/discord/426714625279524876.svg?style=for-the-badge
|
|
82
|
+
[chat]: https://discord.gg/xgGt7KAjxv
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-plugin.d.ts","sourceRoot":"","sources":["../src/client-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAyBlD,eAAO,MAAM,oBAAoB,QAAO,
|
|
1
|
+
{"version":3,"file":"client-plugin.d.ts","sourceRoot":"","sources":["../src/client-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAyBlD,eAAO,MAAM,oBAAoB,QAAO,MAwLvC,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,46 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const react = require("@vitejs/plugin-react");
|
|
4
|
-
const viteRequire = require("vite-require");
|
|
5
4
|
const reactNativeWeb = require("vite-plugin-react-native-web");
|
|
6
5
|
const process$1 = require("node:process");
|
|
7
|
-
const fs = require("node:fs");
|
|
8
6
|
const path = require("node:path");
|
|
7
|
+
const fs = require("node:fs");
|
|
9
8
|
const ejs = require("ejs");
|
|
10
9
|
const node_url = require("node:url");
|
|
11
10
|
const vite = require("vite");
|
|
12
11
|
const fs$1 = require("node:fs/promises");
|
|
13
|
-
const
|
|
12
|
+
const maybeDtsPlugin = require("vite-plugin-dts");
|
|
13
|
+
const assert = require("node:assert");
|
|
14
14
|
var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
|
|
15
|
-
const resolveFileWithExtensions = (directory, baseName) => {
|
|
16
|
-
const extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
17
|
-
for (const ext of extensions) {
|
|
18
|
-
const filePath = path.join(directory, baseName + ext);
|
|
19
|
-
if (fs.existsSync(filePath)) {
|
|
20
|
-
return filePath;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return null;
|
|
24
|
-
};
|
|
25
15
|
const rozeniteServerPlugin = () => {
|
|
26
16
|
return {
|
|
27
17
|
name: "rozenite-server-plugin",
|
|
28
18
|
config(config) {
|
|
29
|
-
var _a;
|
|
30
19
|
const projectRoot = config.root ?? process$1.cwd();
|
|
31
|
-
const backgroundFilePath = resolveFileWithExtensions(
|
|
32
|
-
projectRoot,
|
|
33
|
-
"background"
|
|
34
|
-
);
|
|
35
|
-
if (!backgroundFilePath) {
|
|
36
|
-
throw new Error("Background file not found");
|
|
37
|
-
}
|
|
38
20
|
config.build ?? (config.build = {});
|
|
39
|
-
|
|
40
|
-
|
|
21
|
+
config.build.lib = {
|
|
22
|
+
entry: path.resolve(projectRoot, "metro.ts"),
|
|
23
|
+
formats: ["es", "cjs"],
|
|
24
|
+
fileName: (format) => `metro.${format === "es" ? "js" : "cjs"}`
|
|
25
|
+
};
|
|
41
26
|
config.build.ssr = true;
|
|
42
|
-
config.build.rollupOptions
|
|
43
|
-
|
|
27
|
+
config.build.rollupOptions = {
|
|
28
|
+
output: {
|
|
29
|
+
exports: "named",
|
|
30
|
+
interop: "auto"
|
|
31
|
+
}
|
|
44
32
|
};
|
|
45
33
|
}
|
|
46
34
|
};
|
|
@@ -168,8 +156,14 @@ const rozeniteClientPlugin = () => {
|
|
|
168
156
|
const packageJSON = await getPackageJSON(projectRoot);
|
|
169
157
|
server.middlewares.use((req, res, next) => {
|
|
170
158
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
171
|
-
res.setHeader(
|
|
172
|
-
|
|
159
|
+
res.setHeader(
|
|
160
|
+
"Access-Control-Allow-Methods",
|
|
161
|
+
"GET, POST, PUT, DELETE, OPTIONS"
|
|
162
|
+
);
|
|
163
|
+
res.setHeader(
|
|
164
|
+
"Access-Control-Allow-Headers",
|
|
165
|
+
"Content-Type, Authorization"
|
|
166
|
+
);
|
|
173
167
|
if (req.method === "OPTIONS") {
|
|
174
168
|
res.statusCode = 200;
|
|
175
169
|
res.end();
|
|
@@ -179,15 +173,21 @@ const rozeniteClientPlugin = () => {
|
|
|
179
173
|
const url = req.url || "/";
|
|
180
174
|
if (url === "/rozenite.json") {
|
|
181
175
|
res.setHeader("Content-Type", "application/json");
|
|
182
|
-
res.end(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
176
|
+
res.end(
|
|
177
|
+
JSON.stringify(
|
|
178
|
+
{
|
|
179
|
+
name: packageJSON.name,
|
|
180
|
+
version: packageJSON.version,
|
|
181
|
+
description: packageJSON.description,
|
|
182
|
+
panels: panels.map((panel2) => ({
|
|
183
|
+
name: panel2.label,
|
|
184
|
+
source: "/" + panel2.htmlFile
|
|
185
|
+
}))
|
|
186
|
+
},
|
|
187
|
+
null,
|
|
188
|
+
2
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
191
|
return;
|
|
192
192
|
}
|
|
193
193
|
const panel = panels.find((panel2) => "/" + panel2.htmlFile === url);
|
|
@@ -246,7 +246,6 @@ const rozeniteReactNativePlugin = () => {
|
|
|
246
246
|
(_a = config.build).rollupOptions ?? (_a.rollupOptions = {});
|
|
247
247
|
config.build.lib = {
|
|
248
248
|
entry: path.resolve(projectRoot, "react-native.ts"),
|
|
249
|
-
formats: ["es", "cjs"],
|
|
250
249
|
fileName: (format) => `react-native.${format === "es" ? "js" : "cjs"}`
|
|
251
250
|
};
|
|
252
251
|
config.build.rollupOptions.external = (id) => {
|
|
@@ -255,21 +254,175 @@ const rozeniteReactNativePlugin = () => {
|
|
|
255
254
|
}
|
|
256
255
|
return !id.startsWith(".") && !path.isAbsolute(id);
|
|
257
256
|
};
|
|
257
|
+
config.build.rollupOptions.output = [
|
|
258
|
+
{
|
|
259
|
+
format: "es",
|
|
260
|
+
exports: "named",
|
|
261
|
+
interop: "auto",
|
|
262
|
+
chunkFileNames: "[name].js",
|
|
263
|
+
...config.build.rollupOptions.output ?? {}
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
format: "cjs",
|
|
267
|
+
exports: "named",
|
|
268
|
+
interop: "auto",
|
|
269
|
+
chunkFileNames: "[name].cjs",
|
|
270
|
+
...config.build.rollupOptions.output ?? {}
|
|
271
|
+
}
|
|
272
|
+
];
|
|
258
273
|
delete config.build.rollupOptions.input;
|
|
259
274
|
}
|
|
260
275
|
};
|
|
261
276
|
};
|
|
277
|
+
const REQUIRE_REGEX = /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
278
|
+
const IMPORT_PREFIX = "__import_";
|
|
279
|
+
function requirePlugin() {
|
|
280
|
+
let input = "";
|
|
281
|
+
let inputName = "";
|
|
282
|
+
let isDevMode = false;
|
|
283
|
+
const moduleToChunkMap = /* @__PURE__ */ new Map();
|
|
284
|
+
const moduleInfoMap = /* @__PURE__ */ new Map();
|
|
285
|
+
const extractModuleName = (filePath) => {
|
|
286
|
+
return path.basename(filePath).replace(/\.[^/.]+$/, "");
|
|
287
|
+
};
|
|
288
|
+
const getFileExtension = (format) => {
|
|
289
|
+
return format === "es" ? ".js" : ".cjs";
|
|
290
|
+
};
|
|
291
|
+
const findRequireStatements = (code) => {
|
|
292
|
+
const requires = /* @__PURE__ */ new Set();
|
|
293
|
+
let match;
|
|
294
|
+
REQUIRE_REGEX.lastIndex = 0;
|
|
295
|
+
while ((match = REQUIRE_REGEX.exec(code)) !== null) {
|
|
296
|
+
const moduleName = match[1];
|
|
297
|
+
if (moduleName && moduleName.trim()) {
|
|
298
|
+
requires.add(moduleName.trim());
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return requires;
|
|
302
|
+
};
|
|
303
|
+
const transformRequireToImports = (code) => {
|
|
304
|
+
const imports = [];
|
|
305
|
+
const importMap = /* @__PURE__ */ new Map();
|
|
306
|
+
const requires = findRequireStatements(code);
|
|
307
|
+
requires.forEach((moduleName, index) => {
|
|
308
|
+
const importName = `${IMPORT_PREFIX}${index}`;
|
|
309
|
+
importMap.set(moduleName, importName);
|
|
310
|
+
imports.push(`import * as ${importName} from '${moduleName}';`);
|
|
311
|
+
});
|
|
312
|
+
let transformedCode = code.replace(REQUIRE_REGEX, (match, moduleName) => {
|
|
313
|
+
const importName = importMap.get(moduleName.trim());
|
|
314
|
+
return importName || match;
|
|
315
|
+
});
|
|
316
|
+
if (imports.length > 0) {
|
|
317
|
+
transformedCode = imports.join("\n") + "\n" + transformedCode;
|
|
318
|
+
}
|
|
319
|
+
return { code: transformedCode, imports, importMap };
|
|
320
|
+
};
|
|
321
|
+
const transformRequireToChunkReferences = (code, format) => {
|
|
322
|
+
return code.replace(REQUIRE_REGEX, (match, moduleName) => {
|
|
323
|
+
const chunkName = moduleToChunkMap.get(moduleName.trim());
|
|
324
|
+
if (chunkName) {
|
|
325
|
+
const extension = getFileExtension(format);
|
|
326
|
+
return `require('./${chunkName}${extension}')`;
|
|
327
|
+
}
|
|
328
|
+
return match;
|
|
329
|
+
});
|
|
330
|
+
};
|
|
331
|
+
return {
|
|
332
|
+
name: "vite-require-plugin",
|
|
333
|
+
configResolved(config) {
|
|
334
|
+
isDevMode = config.command === "serve";
|
|
335
|
+
},
|
|
336
|
+
transform(code, id) {
|
|
337
|
+
if (!isDevMode || id !== input) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
const result = transformRequireToImports(code);
|
|
342
|
+
return {
|
|
343
|
+
code: result.code,
|
|
344
|
+
map: null
|
|
345
|
+
};
|
|
346
|
+
} catch (error) {
|
|
347
|
+
console.error("Error transforming require statements:", error);
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
async buildStart(options) {
|
|
352
|
+
try {
|
|
353
|
+
assert(Array.isArray(options.input), "input must be an array");
|
|
354
|
+
assert(
|
|
355
|
+
options.input.length === 1,
|
|
356
|
+
"input must be an array with one entry"
|
|
357
|
+
);
|
|
358
|
+
input = options.input[0];
|
|
359
|
+
inputName = extractModuleName(input);
|
|
360
|
+
const code = fs.readFileSync(input, "utf-8");
|
|
361
|
+
const requires = findRequireStatements(code);
|
|
362
|
+
for (const req of requires) {
|
|
363
|
+
try {
|
|
364
|
+
const resolved = await this.resolve(req, input);
|
|
365
|
+
if (resolved) {
|
|
366
|
+
const fileName = extractModuleName(resolved.id);
|
|
367
|
+
this.addWatchFile(resolved.id);
|
|
368
|
+
this.emitFile({
|
|
369
|
+
type: "chunk",
|
|
370
|
+
id: resolved.id,
|
|
371
|
+
fileName
|
|
372
|
+
});
|
|
373
|
+
moduleToChunkMap.set(req, fileName);
|
|
374
|
+
moduleInfoMap.set(req, {
|
|
375
|
+
fileName,
|
|
376
|
+
resolvedId: resolved.id
|
|
377
|
+
});
|
|
378
|
+
} else {
|
|
379
|
+
console.warn(`Could not resolve module: ${req}`);
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.error(`Error resolving module ${req}:`, error);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.error("Error in buildStart:", error);
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
renderChunk(code, chunk, options) {
|
|
391
|
+
try {
|
|
392
|
+
const additionalChunkNames = Array.from(moduleToChunkMap.values());
|
|
393
|
+
if (additionalChunkNames.includes(chunk.fileName)) {
|
|
394
|
+
chunk.fileName = chunk.fileName + getFileExtension(options.format);
|
|
395
|
+
}
|
|
396
|
+
if (chunk.name !== inputName) {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
const transformedCode = transformRequireToChunkReferences(
|
|
400
|
+
code,
|
|
401
|
+
options.format
|
|
402
|
+
);
|
|
403
|
+
return {
|
|
404
|
+
code: transformedCode,
|
|
405
|
+
map: null
|
|
406
|
+
};
|
|
407
|
+
} catch (error) {
|
|
408
|
+
console.error("Error in renderChunk:", error);
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const dtsPlugin = "default" in maybeDtsPlugin ? maybeDtsPlugin.default : maybeDtsPlugin;
|
|
262
415
|
const rozenitePlugin = () => {
|
|
263
416
|
const isServer = process.env.VITE_ROZENITE_TARGET === "server";
|
|
264
417
|
const isReactNative = process.env.VITE_ROZENITE_TARGET === "react-native";
|
|
265
418
|
if (isServer) {
|
|
266
|
-
return [rozeniteServerPlugin()];
|
|
419
|
+
return [rozeniteServerPlugin(), dtsPlugin()];
|
|
267
420
|
} else if (isReactNative) {
|
|
268
421
|
return [
|
|
269
422
|
react(),
|
|
270
|
-
|
|
423
|
+
requirePlugin(),
|
|
271
424
|
rozeniteReactNativePlugin(),
|
|
272
|
-
dtsPlugin(
|
|
425
|
+
dtsPlugin()
|
|
273
426
|
];
|
|
274
427
|
}
|
|
275
428
|
return [
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAezC,eAAO,MAAM,cAAc,QAAO,YAAY,EAqB7C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,43 +1,31 @@
|
|
|
1
1
|
import react from "@vitejs/plugin-react";
|
|
2
|
-
import { viteRequire } from "vite-require";
|
|
3
2
|
import reactNativeWeb from "vite-plugin-react-native-web";
|
|
4
3
|
import process$1 from "node:process";
|
|
5
|
-
import fs from "node:fs";
|
|
6
4
|
import path from "node:path";
|
|
5
|
+
import fs, { readFileSync } from "node:fs";
|
|
7
6
|
import ejs from "ejs";
|
|
8
7
|
import { fileURLToPath } from "node:url";
|
|
9
8
|
import { transformWithEsbuild } from "vite";
|
|
10
9
|
import fs$1 from "node:fs/promises";
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
const extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
14
|
-
for (const ext of extensions) {
|
|
15
|
-
const filePath = path.join(directory, baseName + ext);
|
|
16
|
-
if (fs.existsSync(filePath)) {
|
|
17
|
-
return filePath;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return null;
|
|
21
|
-
};
|
|
10
|
+
import maybeDtsPlugin from "vite-plugin-dts";
|
|
11
|
+
import assert from "node:assert";
|
|
22
12
|
const rozeniteServerPlugin = () => {
|
|
23
13
|
return {
|
|
24
14
|
name: "rozenite-server-plugin",
|
|
25
15
|
config(config) {
|
|
26
|
-
var _a;
|
|
27
16
|
const projectRoot = config.root ?? process$1.cwd();
|
|
28
|
-
const backgroundFilePath = resolveFileWithExtensions(
|
|
29
|
-
projectRoot,
|
|
30
|
-
"background"
|
|
31
|
-
);
|
|
32
|
-
if (!backgroundFilePath) {
|
|
33
|
-
throw new Error("Background file not found");
|
|
34
|
-
}
|
|
35
17
|
config.build ?? (config.build = {});
|
|
36
|
-
|
|
37
|
-
|
|
18
|
+
config.build.lib = {
|
|
19
|
+
entry: path.resolve(projectRoot, "metro.ts"),
|
|
20
|
+
formats: ["es", "cjs"],
|
|
21
|
+
fileName: (format) => `metro.${format === "es" ? "js" : "cjs"}`
|
|
22
|
+
};
|
|
38
23
|
config.build.ssr = true;
|
|
39
|
-
config.build.rollupOptions
|
|
40
|
-
|
|
24
|
+
config.build.rollupOptions = {
|
|
25
|
+
output: {
|
|
26
|
+
exports: "named",
|
|
27
|
+
interop: "auto"
|
|
28
|
+
}
|
|
41
29
|
};
|
|
42
30
|
}
|
|
43
31
|
};
|
|
@@ -165,8 +153,14 @@ const rozeniteClientPlugin = () => {
|
|
|
165
153
|
const packageJSON = await getPackageJSON(projectRoot);
|
|
166
154
|
server.middlewares.use((req, res, next) => {
|
|
167
155
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
168
|
-
res.setHeader(
|
|
169
|
-
|
|
156
|
+
res.setHeader(
|
|
157
|
+
"Access-Control-Allow-Methods",
|
|
158
|
+
"GET, POST, PUT, DELETE, OPTIONS"
|
|
159
|
+
);
|
|
160
|
+
res.setHeader(
|
|
161
|
+
"Access-Control-Allow-Headers",
|
|
162
|
+
"Content-Type, Authorization"
|
|
163
|
+
);
|
|
170
164
|
if (req.method === "OPTIONS") {
|
|
171
165
|
res.statusCode = 200;
|
|
172
166
|
res.end();
|
|
@@ -176,15 +170,21 @@ const rozeniteClientPlugin = () => {
|
|
|
176
170
|
const url = req.url || "/";
|
|
177
171
|
if (url === "/rozenite.json") {
|
|
178
172
|
res.setHeader("Content-Type", "application/json");
|
|
179
|
-
res.end(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
173
|
+
res.end(
|
|
174
|
+
JSON.stringify(
|
|
175
|
+
{
|
|
176
|
+
name: packageJSON.name,
|
|
177
|
+
version: packageJSON.version,
|
|
178
|
+
description: packageJSON.description,
|
|
179
|
+
panels: panels.map((panel2) => ({
|
|
180
|
+
name: panel2.label,
|
|
181
|
+
source: "/" + panel2.htmlFile
|
|
182
|
+
}))
|
|
183
|
+
},
|
|
184
|
+
null,
|
|
185
|
+
2
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
188
|
return;
|
|
189
189
|
}
|
|
190
190
|
const panel = panels.find((panel2) => "/" + panel2.htmlFile === url);
|
|
@@ -243,7 +243,6 @@ const rozeniteReactNativePlugin = () => {
|
|
|
243
243
|
(_a = config.build).rollupOptions ?? (_a.rollupOptions = {});
|
|
244
244
|
config.build.lib = {
|
|
245
245
|
entry: path.resolve(projectRoot, "react-native.ts"),
|
|
246
|
-
formats: ["es", "cjs"],
|
|
247
246
|
fileName: (format) => `react-native.${format === "es" ? "js" : "cjs"}`
|
|
248
247
|
};
|
|
249
248
|
config.build.rollupOptions.external = (id) => {
|
|
@@ -252,21 +251,175 @@ const rozeniteReactNativePlugin = () => {
|
|
|
252
251
|
}
|
|
253
252
|
return !id.startsWith(".") && !path.isAbsolute(id);
|
|
254
253
|
};
|
|
254
|
+
config.build.rollupOptions.output = [
|
|
255
|
+
{
|
|
256
|
+
format: "es",
|
|
257
|
+
exports: "named",
|
|
258
|
+
interop: "auto",
|
|
259
|
+
chunkFileNames: "[name].js",
|
|
260
|
+
...config.build.rollupOptions.output ?? {}
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
format: "cjs",
|
|
264
|
+
exports: "named",
|
|
265
|
+
interop: "auto",
|
|
266
|
+
chunkFileNames: "[name].cjs",
|
|
267
|
+
...config.build.rollupOptions.output ?? {}
|
|
268
|
+
}
|
|
269
|
+
];
|
|
255
270
|
delete config.build.rollupOptions.input;
|
|
256
271
|
}
|
|
257
272
|
};
|
|
258
273
|
};
|
|
274
|
+
const REQUIRE_REGEX = /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
275
|
+
const IMPORT_PREFIX = "__import_";
|
|
276
|
+
function requirePlugin() {
|
|
277
|
+
let input = "";
|
|
278
|
+
let inputName = "";
|
|
279
|
+
let isDevMode = false;
|
|
280
|
+
const moduleToChunkMap = /* @__PURE__ */ new Map();
|
|
281
|
+
const moduleInfoMap = /* @__PURE__ */ new Map();
|
|
282
|
+
const extractModuleName = (filePath) => {
|
|
283
|
+
return path.basename(filePath).replace(/\.[^/.]+$/, "");
|
|
284
|
+
};
|
|
285
|
+
const getFileExtension = (format) => {
|
|
286
|
+
return format === "es" ? ".js" : ".cjs";
|
|
287
|
+
};
|
|
288
|
+
const findRequireStatements = (code) => {
|
|
289
|
+
const requires = /* @__PURE__ */ new Set();
|
|
290
|
+
let match;
|
|
291
|
+
REQUIRE_REGEX.lastIndex = 0;
|
|
292
|
+
while ((match = REQUIRE_REGEX.exec(code)) !== null) {
|
|
293
|
+
const moduleName = match[1];
|
|
294
|
+
if (moduleName && moduleName.trim()) {
|
|
295
|
+
requires.add(moduleName.trim());
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return requires;
|
|
299
|
+
};
|
|
300
|
+
const transformRequireToImports = (code) => {
|
|
301
|
+
const imports = [];
|
|
302
|
+
const importMap = /* @__PURE__ */ new Map();
|
|
303
|
+
const requires = findRequireStatements(code);
|
|
304
|
+
requires.forEach((moduleName, index) => {
|
|
305
|
+
const importName = `${IMPORT_PREFIX}${index}`;
|
|
306
|
+
importMap.set(moduleName, importName);
|
|
307
|
+
imports.push(`import * as ${importName} from '${moduleName}';`);
|
|
308
|
+
});
|
|
309
|
+
let transformedCode = code.replace(REQUIRE_REGEX, (match, moduleName) => {
|
|
310
|
+
const importName = importMap.get(moduleName.trim());
|
|
311
|
+
return importName || match;
|
|
312
|
+
});
|
|
313
|
+
if (imports.length > 0) {
|
|
314
|
+
transformedCode = imports.join("\n") + "\n" + transformedCode;
|
|
315
|
+
}
|
|
316
|
+
return { code: transformedCode, imports, importMap };
|
|
317
|
+
};
|
|
318
|
+
const transformRequireToChunkReferences = (code, format) => {
|
|
319
|
+
return code.replace(REQUIRE_REGEX, (match, moduleName) => {
|
|
320
|
+
const chunkName = moduleToChunkMap.get(moduleName.trim());
|
|
321
|
+
if (chunkName) {
|
|
322
|
+
const extension = getFileExtension(format);
|
|
323
|
+
return `require('./${chunkName}${extension}')`;
|
|
324
|
+
}
|
|
325
|
+
return match;
|
|
326
|
+
});
|
|
327
|
+
};
|
|
328
|
+
return {
|
|
329
|
+
name: "vite-require-plugin",
|
|
330
|
+
configResolved(config) {
|
|
331
|
+
isDevMode = config.command === "serve";
|
|
332
|
+
},
|
|
333
|
+
transform(code, id) {
|
|
334
|
+
if (!isDevMode || id !== input) {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
const result = transformRequireToImports(code);
|
|
339
|
+
return {
|
|
340
|
+
code: result.code,
|
|
341
|
+
map: null
|
|
342
|
+
};
|
|
343
|
+
} catch (error) {
|
|
344
|
+
console.error("Error transforming require statements:", error);
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
async buildStart(options) {
|
|
349
|
+
try {
|
|
350
|
+
assert(Array.isArray(options.input), "input must be an array");
|
|
351
|
+
assert(
|
|
352
|
+
options.input.length === 1,
|
|
353
|
+
"input must be an array with one entry"
|
|
354
|
+
);
|
|
355
|
+
input = options.input[0];
|
|
356
|
+
inputName = extractModuleName(input);
|
|
357
|
+
const code = readFileSync(input, "utf-8");
|
|
358
|
+
const requires = findRequireStatements(code);
|
|
359
|
+
for (const req of requires) {
|
|
360
|
+
try {
|
|
361
|
+
const resolved = await this.resolve(req, input);
|
|
362
|
+
if (resolved) {
|
|
363
|
+
const fileName = extractModuleName(resolved.id);
|
|
364
|
+
this.addWatchFile(resolved.id);
|
|
365
|
+
this.emitFile({
|
|
366
|
+
type: "chunk",
|
|
367
|
+
id: resolved.id,
|
|
368
|
+
fileName
|
|
369
|
+
});
|
|
370
|
+
moduleToChunkMap.set(req, fileName);
|
|
371
|
+
moduleInfoMap.set(req, {
|
|
372
|
+
fileName,
|
|
373
|
+
resolvedId: resolved.id
|
|
374
|
+
});
|
|
375
|
+
} else {
|
|
376
|
+
console.warn(`Could not resolve module: ${req}`);
|
|
377
|
+
}
|
|
378
|
+
} catch (error) {
|
|
379
|
+
console.error(`Error resolving module ${req}:`, error);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
} catch (error) {
|
|
383
|
+
console.error("Error in buildStart:", error);
|
|
384
|
+
throw error;
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
renderChunk(code, chunk, options) {
|
|
388
|
+
try {
|
|
389
|
+
const additionalChunkNames = Array.from(moduleToChunkMap.values());
|
|
390
|
+
if (additionalChunkNames.includes(chunk.fileName)) {
|
|
391
|
+
chunk.fileName = chunk.fileName + getFileExtension(options.format);
|
|
392
|
+
}
|
|
393
|
+
if (chunk.name !== inputName) {
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
const transformedCode = transformRequireToChunkReferences(
|
|
397
|
+
code,
|
|
398
|
+
options.format
|
|
399
|
+
);
|
|
400
|
+
return {
|
|
401
|
+
code: transformedCode,
|
|
402
|
+
map: null
|
|
403
|
+
};
|
|
404
|
+
} catch (error) {
|
|
405
|
+
console.error("Error in renderChunk:", error);
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
const dtsPlugin = "default" in maybeDtsPlugin ? maybeDtsPlugin.default : maybeDtsPlugin;
|
|
259
412
|
const rozenitePlugin = () => {
|
|
260
413
|
const isServer = process.env.VITE_ROZENITE_TARGET === "server";
|
|
261
414
|
const isReactNative = process.env.VITE_ROZENITE_TARGET === "react-native";
|
|
262
415
|
if (isServer) {
|
|
263
|
-
return [rozeniteServerPlugin()];
|
|
416
|
+
return [rozeniteServerPlugin(), dtsPlugin()];
|
|
264
417
|
} else if (isReactNative) {
|
|
265
418
|
return [
|
|
266
419
|
react(),
|
|
267
|
-
|
|
420
|
+
requirePlugin(),
|
|
268
421
|
rozeniteReactNativePlugin(),
|
|
269
|
-
dtsPlugin(
|
|
422
|
+
dtsPlugin()
|
|
270
423
|
];
|
|
271
424
|
}
|
|
272
425
|
return [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-json.d.ts","sourceRoot":"","sources":["../src/package-json.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"package-json.d.ts","sourceRoot":"","sources":["../src/package-json.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,aAAa,MAAM,KAClB,OAAO,CAAC,WAAW,CAIrB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-native-plugin.d.ts","sourceRoot":"","sources":["../src/react-native-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAG9B,eAAO,MAAM,yBAAyB,QAAO,
|
|
1
|
+
{"version":3,"file":"react-native-plugin.d.ts","sourceRoot":"","sources":["../src/react-native-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAG9B,eAAO,MAAM,yBAAyB,QAAO,MA0C5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-plugin.d.ts","sourceRoot":"","sources":["../src/require-plugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAgB9B,MAAM,CAAC,OAAO,UAAU,aAAa,IAAI,MAAM,CAuL9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-plugin.d.ts","sourceRoot":"","sources":["../src/server-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,eAAO,MAAM,oBAAoB,QAAO,
|
|
1
|
+
{"version":3,"file":"server-plugin.d.ts","sourceRoot":"","sources":["../src/server-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,eAAO,MAAM,oBAAoB,QAAO,MAsBvC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rozenite/vite-plugin",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.10",
|
|
4
4
|
"description": "Vite plugin for developing React Native DevTools plugins with hot reload and development tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -39,8 +39,7 @@
|
|
|
39
39
|
"@vitejs/plugin-react": "^4.3.4",
|
|
40
40
|
"ejs": "^3.1.9",
|
|
41
41
|
"vite-plugin-dts": "~4.5.0",
|
|
42
|
-
"vite-plugin-react-native-web": "^2.1.1"
|
|
43
|
-
"vite-require": "^0.2.3"
|
|
42
|
+
"vite-plugin-react-native-web": "^2.1.1"
|
|
44
43
|
},
|
|
45
44
|
"peerDependencies": {
|
|
46
45
|
"vite": "^6.0.0"
|
|
@@ -50,8 +49,5 @@
|
|
|
50
49
|
},
|
|
51
50
|
"engines": {
|
|
52
51
|
"node": ">=22"
|
|
53
|
-
},
|
|
54
|
-
"scripts": {
|
|
55
|
-
"build": "vite build"
|
|
56
52
|
}
|
|
57
53
|
}
|