@rozenite/vite-plugin 1.0.0-alpha.0 → 1.0.0-alpha.3

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 ADDED
@@ -0,0 +1,82 @@
1
+ ![rozenite-baner](https://github.com/user-attachments/assets/6d21839f-e624-4d8b-85a2-5f7ef1600b28)
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,MA4KvC,CAAC"}
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,7 +1,6 @@
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
6
  const fs = require("node:fs");
@@ -10,7 +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 dtsPlugin = require("vite-plugin-dts");
12
+ const maybeDtsPlugin = require("vite-plugin-dts");
13
+ const assert = require("node:assert");
14
14
  var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
15
15
  const resolveFileWithExtensions = (directory, baseName) => {
16
16
  const extensions = [".tsx", ".ts", ".jsx", ".js"];
@@ -168,8 +168,14 @@ const rozeniteClientPlugin = () => {
168
168
  const packageJSON = await getPackageJSON(projectRoot);
169
169
  server.middlewares.use((req, res, next) => {
170
170
  res.setHeader("Access-Control-Allow-Origin", "*");
171
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
172
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
171
+ res.setHeader(
172
+ "Access-Control-Allow-Methods",
173
+ "GET, POST, PUT, DELETE, OPTIONS"
174
+ );
175
+ res.setHeader(
176
+ "Access-Control-Allow-Headers",
177
+ "Content-Type, Authorization"
178
+ );
173
179
  if (req.method === "OPTIONS") {
174
180
  res.statusCode = 200;
175
181
  res.end();
@@ -179,15 +185,21 @@ const rozeniteClientPlugin = () => {
179
185
  const url = req.url || "/";
180
186
  if (url === "/rozenite.json") {
181
187
  res.setHeader("Content-Type", "application/json");
182
- res.end(JSON.stringify({
183
- name: packageJSON.name,
184
- version: packageJSON.version,
185
- description: packageJSON.description,
186
- panels: panels.map((panel2) => ({
187
- name: panel2.label,
188
- source: panel2.htmlFile
189
- }))
190
- }, null, 2));
188
+ res.end(
189
+ JSON.stringify(
190
+ {
191
+ name: packageJSON.name,
192
+ version: packageJSON.version,
193
+ description: packageJSON.description,
194
+ panels: panels.map((panel2) => ({
195
+ name: panel2.label,
196
+ source: "/" + panel2.htmlFile
197
+ }))
198
+ },
199
+ null,
200
+ 2
201
+ )
202
+ );
191
203
  return;
192
204
  }
193
205
  const panel = panels.find((panel2) => "/" + panel2.htmlFile === url);
@@ -229,7 +241,7 @@ const rozeniteClientPlugin = () => {
229
241
  description: packageJSON.description,
230
242
  panels: panels.map((panel) => ({
231
243
  name: panel.label,
232
- source: panel.htmlFile
244
+ source: "/" + panel.htmlFile
233
245
  }))
234
246
  })
235
247
  });
@@ -259,6 +271,103 @@ const rozeniteReactNativePlugin = () => {
259
271
  }
260
272
  };
261
273
  };
274
+ function requirePlugin() {
275
+ let input = "";
276
+ let inputName = "";
277
+ let isDevMode = false;
278
+ const moduleToChunkMap = /* @__PURE__ */ new Map();
279
+ return {
280
+ name: "vite-require-plugin",
281
+ configResolved(config) {
282
+ isDevMode = config.command === "serve";
283
+ },
284
+ transform(code, id) {
285
+ if (!isDevMode || id !== input) {
286
+ return null;
287
+ }
288
+ let transformedCode = code;
289
+ const imports = [];
290
+ const importMap = /* @__PURE__ */ new Map();
291
+ const requireRegex = /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
292
+ let match;
293
+ while ((match = requireRegex.exec(code)) !== null) {
294
+ const moduleName = match[1];
295
+ if (moduleName && !importMap.has(moduleName)) {
296
+ const importName = `__import_${importMap.size}`;
297
+ importMap.set(moduleName, importName);
298
+ imports.push(`import * as ${importName} from '${moduleName}';`);
299
+ }
300
+ }
301
+ transformedCode = transformedCode.replace(
302
+ /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
303
+ (match2, moduleName) => {
304
+ const importName = importMap.get(moduleName);
305
+ return importName || match2;
306
+ }
307
+ );
308
+ if (imports.length > 0) {
309
+ transformedCode = imports.join("\n") + "\n" + transformedCode;
310
+ }
311
+ return {
312
+ code: transformedCode,
313
+ map: null
314
+ };
315
+ },
316
+ async buildStart(options) {
317
+ assert(Array.isArray(options.input), "input must be an array");
318
+ assert(
319
+ options.input.length === 1,
320
+ "input must be an array with one entry"
321
+ );
322
+ input = options.input[0];
323
+ inputName = path.basename(input).replace(/\.[^/.]+$/, "");
324
+ const code = fs.readFileSync(input, "utf-8");
325
+ const requires = /* @__PURE__ */ new Set();
326
+ const requireRegex = /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
327
+ let match;
328
+ while ((match = requireRegex.exec(code)) !== null) {
329
+ const moduleName = match[1];
330
+ if (moduleName) {
331
+ requires.add(moduleName);
332
+ }
333
+ }
334
+ for (const req of requires) {
335
+ const resolved = await this.resolve(req, input);
336
+ if (resolved) {
337
+ const fileName = path.basename(resolved.id).replace(/\.[^/.]+$/, "") + ".js";
338
+ this.addWatchFile(resolved.id);
339
+ this.emitFile({
340
+ type: "chunk",
341
+ id: resolved.id,
342
+ fileName
343
+ });
344
+ moduleToChunkMap.set(req, fileName);
345
+ }
346
+ }
347
+ },
348
+ renderChunk(code, chunk) {
349
+ if (chunk.name !== inputName) {
350
+ return null;
351
+ }
352
+ let transformedCode = code;
353
+ transformedCode = transformedCode.replace(
354
+ /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
355
+ (match, moduleName) => {
356
+ const chunkName = moduleToChunkMap.get(moduleName);
357
+ if (chunkName) {
358
+ return `require('./${chunkName}')`;
359
+ }
360
+ return match;
361
+ }
362
+ );
363
+ return {
364
+ code: transformedCode,
365
+ map: null
366
+ };
367
+ }
368
+ };
369
+ }
370
+ const dtsPlugin = "default" in maybeDtsPlugin ? maybeDtsPlugin.default : maybeDtsPlugin;
262
371
  const rozenitePlugin = () => {
263
372
  const isServer = process.env.VITE_ROZENITE_TARGET === "server";
264
373
  const isReactNative = process.env.VITE_ROZENITE_TARGET === "react-native";
@@ -267,7 +376,7 @@ const rozenitePlugin = () => {
267
376
  } else if (isReactNative) {
268
377
  return [
269
378
  react(),
270
- viteRequire.viteRequire(),
379
+ requirePlugin(),
271
380
  rozeniteReactNativePlugin(),
272
381
  dtsPlugin({ rollupTypes: true })
273
382
  ];
@@ -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;AASzC,eAAO,MAAM,cAAc,QAAO,YAAY,EAqB7C,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,14 +1,14 @@
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";
4
+ import fs, { readFileSync } from "node:fs";
6
5
  import path from "node:path";
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 dtsPlugin from "vite-plugin-dts";
10
+ import maybeDtsPlugin from "vite-plugin-dts";
11
+ import assert from "node:assert";
12
12
  const resolveFileWithExtensions = (directory, baseName) => {
13
13
  const extensions = [".tsx", ".ts", ".jsx", ".js"];
14
14
  for (const ext of extensions) {
@@ -165,8 +165,14 @@ const rozeniteClientPlugin = () => {
165
165
  const packageJSON = await getPackageJSON(projectRoot);
166
166
  server.middlewares.use((req, res, next) => {
167
167
  res.setHeader("Access-Control-Allow-Origin", "*");
168
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
169
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
168
+ res.setHeader(
169
+ "Access-Control-Allow-Methods",
170
+ "GET, POST, PUT, DELETE, OPTIONS"
171
+ );
172
+ res.setHeader(
173
+ "Access-Control-Allow-Headers",
174
+ "Content-Type, Authorization"
175
+ );
170
176
  if (req.method === "OPTIONS") {
171
177
  res.statusCode = 200;
172
178
  res.end();
@@ -176,15 +182,21 @@ const rozeniteClientPlugin = () => {
176
182
  const url = req.url || "/";
177
183
  if (url === "/rozenite.json") {
178
184
  res.setHeader("Content-Type", "application/json");
179
- res.end(JSON.stringify({
180
- name: packageJSON.name,
181
- version: packageJSON.version,
182
- description: packageJSON.description,
183
- panels: panels.map((panel2) => ({
184
- name: panel2.label,
185
- source: panel2.htmlFile
186
- }))
187
- }, null, 2));
185
+ res.end(
186
+ JSON.stringify(
187
+ {
188
+ name: packageJSON.name,
189
+ version: packageJSON.version,
190
+ description: packageJSON.description,
191
+ panels: panels.map((panel2) => ({
192
+ name: panel2.label,
193
+ source: "/" + panel2.htmlFile
194
+ }))
195
+ },
196
+ null,
197
+ 2
198
+ )
199
+ );
188
200
  return;
189
201
  }
190
202
  const panel = panels.find((panel2) => "/" + panel2.htmlFile === url);
@@ -226,7 +238,7 @@ const rozeniteClientPlugin = () => {
226
238
  description: packageJSON.description,
227
239
  panels: panels.map((panel) => ({
228
240
  name: panel.label,
229
- source: panel.htmlFile
241
+ source: "/" + panel.htmlFile
230
242
  }))
231
243
  })
232
244
  });
@@ -256,6 +268,103 @@ const rozeniteReactNativePlugin = () => {
256
268
  }
257
269
  };
258
270
  };
271
+ function requirePlugin() {
272
+ let input = "";
273
+ let inputName = "";
274
+ let isDevMode = false;
275
+ const moduleToChunkMap = /* @__PURE__ */ new Map();
276
+ return {
277
+ name: "vite-require-plugin",
278
+ configResolved(config) {
279
+ isDevMode = config.command === "serve";
280
+ },
281
+ transform(code, id) {
282
+ if (!isDevMode || id !== input) {
283
+ return null;
284
+ }
285
+ let transformedCode = code;
286
+ const imports = [];
287
+ const importMap = /* @__PURE__ */ new Map();
288
+ const requireRegex = /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
289
+ let match;
290
+ while ((match = requireRegex.exec(code)) !== null) {
291
+ const moduleName = match[1];
292
+ if (moduleName && !importMap.has(moduleName)) {
293
+ const importName = `__import_${importMap.size}`;
294
+ importMap.set(moduleName, importName);
295
+ imports.push(`import * as ${importName} from '${moduleName}';`);
296
+ }
297
+ }
298
+ transformedCode = transformedCode.replace(
299
+ /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
300
+ (match2, moduleName) => {
301
+ const importName = importMap.get(moduleName);
302
+ return importName || match2;
303
+ }
304
+ );
305
+ if (imports.length > 0) {
306
+ transformedCode = imports.join("\n") + "\n" + transformedCode;
307
+ }
308
+ return {
309
+ code: transformedCode,
310
+ map: null
311
+ };
312
+ },
313
+ async buildStart(options) {
314
+ assert(Array.isArray(options.input), "input must be an array");
315
+ assert(
316
+ options.input.length === 1,
317
+ "input must be an array with one entry"
318
+ );
319
+ input = options.input[0];
320
+ inputName = path.basename(input).replace(/\.[^/.]+$/, "");
321
+ const code = readFileSync(input, "utf-8");
322
+ const requires = /* @__PURE__ */ new Set();
323
+ const requireRegex = /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
324
+ let match;
325
+ while ((match = requireRegex.exec(code)) !== null) {
326
+ const moduleName = match[1];
327
+ if (moduleName) {
328
+ requires.add(moduleName);
329
+ }
330
+ }
331
+ for (const req of requires) {
332
+ const resolved = await this.resolve(req, input);
333
+ if (resolved) {
334
+ const fileName = path.basename(resolved.id).replace(/\.[^/.]+$/, "") + ".js";
335
+ this.addWatchFile(resolved.id);
336
+ this.emitFile({
337
+ type: "chunk",
338
+ id: resolved.id,
339
+ fileName
340
+ });
341
+ moduleToChunkMap.set(req, fileName);
342
+ }
343
+ }
344
+ },
345
+ renderChunk(code, chunk) {
346
+ if (chunk.name !== inputName) {
347
+ return null;
348
+ }
349
+ let transformedCode = code;
350
+ transformedCode = transformedCode.replace(
351
+ /require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
352
+ (match, moduleName) => {
353
+ const chunkName = moduleToChunkMap.get(moduleName);
354
+ if (chunkName) {
355
+ return `require('./${chunkName}')`;
356
+ }
357
+ return match;
358
+ }
359
+ );
360
+ return {
361
+ code: transformedCode,
362
+ map: null
363
+ };
364
+ }
365
+ };
366
+ }
367
+ const dtsPlugin = "default" in maybeDtsPlugin ? maybeDtsPlugin.default : maybeDtsPlugin;
259
368
  const rozenitePlugin = () => {
260
369
  const isServer = process.env.VITE_ROZENITE_TARGET === "server";
261
370
  const isReactNative = process.env.VITE_ROZENITE_TARGET === "react-native";
@@ -264,7 +373,7 @@ const rozenitePlugin = () => {
264
373
  } else if (isReactNative) {
265
374
  return [
266
375
  react(),
267
- viteRequire(),
376
+ requirePlugin(),
268
377
  rozeniteReactNativePlugin(),
269
378
  dtsPlugin({ rollupTypes: true })
270
379
  ];
@@ -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,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,WAAW,CAI7E,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"}
@@ -0,0 +1,3 @@
1
+ import { Plugin } from 'vite';
2
+ export default function requirePlugin(): Plugin;
3
+ //# sourceMappingURL=require-plugin.d.ts.map
@@ -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;AAE9B,MAAM,CAAC,OAAO,UAAU,aAAa,IAAI,MAAM,CAsH9C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rozenite/vite-plugin",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.0-alpha.3",
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
  }