vite-plugin-rnw 0.0.4 → 0.0.6

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/dist/index.cjs CHANGED
@@ -25,6 +25,7 @@ const node_path = __toESM(require("node:path"));
25
25
  const node_url = __toESM(require("node:url"));
26
26
  const node_fs = __toESM(require("node:fs"));
27
27
  const vite = __toESM(require("vite"));
28
+ const __bunchtogether_vite_plugin_flow = __toESM(require("@bunchtogether/vite-plugin-flow"));
28
29
  const vite_plugin_commonjs = __toESM(require("vite-plugin-commonjs"));
29
30
  const __rolldown_pluginutils = __toESM(require("@rolldown/pluginutils"));
30
31
 
@@ -103,6 +104,70 @@ function removeLineBreaksIfNeeded(code, enabled) {
103
104
  return enabled ? code.replace(/\n/g, "") : code;
104
105
  }
105
106
 
107
+ //#endregion
108
+ //#region src/transforms.ts
109
+ /**
110
+ * Code transformation utilities for fixing React Native package compatibility issues
111
+ */
112
+ /**
113
+ * Analyzes require statements in code and maps them to module imports.
114
+ * Handles patterns like: varName = require('path').prop or require('path').default
115
+ */
116
+ function analyzeRequireStatements(originalCode, exportedVars) {
117
+ const importMap = /* @__PURE__ */ new Map();
118
+ for (const varName of exportedVars) {
119
+ const requirePattern = new RegExp(`${varName}\\s*=\\s*[\\s\\S]*?require\\(['"]([^'"]+)['"]\\)(?:\\.([\\w]+))?`, "g");
120
+ const requireMatch = requirePattern.exec(originalCode);
121
+ if (requireMatch) {
122
+ const [, modulePath, prop] = requireMatch;
123
+ const key = `${modulePath}:${prop || "default"}`;
124
+ if (!importMap.has(key)) importMap.set(key, []);
125
+ importMap.get(key).push(varName);
126
+ }
127
+ }
128
+ return importMap;
129
+ }
130
+ /**
131
+ * Removes try/catch blocks that contain require statements and export let declarations.
132
+ * This cleans up the problematic CommonJS patterns.
133
+ */
134
+ function removeTryCatchRequireBlocks(code) {
135
+ let transformed = code.replace(/try\s*\{[^{}]*?require\([^)]+\)[^{}]*?\}\s*catch[^{}]*?\{[^{}]*?\}/gs, "");
136
+ transformed = transformed.replace(/export let \w+;/g, "");
137
+ return transformed;
138
+ }
139
+ /**
140
+ * Generates direct export statements from the import map.
141
+ * Creates modern ESM exports like: export { default as varName } from 'module';
142
+ */
143
+ function generateDirectExports(importMap) {
144
+ let exports$1 = "";
145
+ for (const [key, vars] of importMap) {
146
+ const [modulePath, prop] = key.split(":");
147
+ if (prop === "default") for (const varName of vars) exports$1 += `export { default as ${varName} } from '${modulePath}';\n`;
148
+ else for (const varName of vars) exports$1 += `export { ${prop} as ${varName} } from '${modulePath}';\n`;
149
+ }
150
+ return exports$1;
151
+ }
152
+ /**
153
+ * Transforms React Native Reanimated webUtils files to fix problematic
154
+ * export let + try/catch + require patterns by converting them to proper ESM.
155
+ *
156
+ * This transformation handles the incompatible module patterns in React Native Reanimated
157
+ * that cause build errors in Vite due to mixing CommonJS require() with ESM exports.
158
+ */
159
+ function transformReanimatedWebUtils(toTransform, originalCode, id, isProduction) {
160
+ if (!isProduction || !id.includes("node_modules/react-native-reanimated") || !id.includes("ReanimatedModule/js-reanimated/webUtils") || !originalCode.includes("export let") || !originalCode.includes("try") || !originalCode.includes("require")) return toTransform;
161
+ const exportLetMatches = Array.from(originalCode.matchAll(/export let (\w+);/g));
162
+ const exportedVars = exportLetMatches.map((match) => match[1]);
163
+ if (exportedVars.length === 0) return toTransform;
164
+ const importMap = analyzeRequireStatements(originalCode, exportedVars);
165
+ toTransform = removeTryCatchRequireBlocks(toTransform);
166
+ const exports$1 = generateDirectExports(importMap);
167
+ if (exports$1) toTransform = `${toTransform}\n${exports$1}`;
168
+ return toTransform;
169
+ }
170
+
106
171
  //#endregion
107
172
  //#region src/index.ts
108
173
  const silenceUseClientWarning = (userConfig) => ({ rollupOptions: { onwarn(warning, defaultHandler) {
@@ -182,17 +247,28 @@ function rnw(opts = {}) {
182
247
  _WORKLET: false,
183
248
  __DEV__: JSON.stringify(development),
184
249
  "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || env.mode),
250
+ EXPO_OS: JSON.stringify("web"),
251
+ "process.env.EXPO_OS": JSON.stringify("web"),
185
252
  "global.Error": "Error"
186
253
  },
187
254
  optimizeDeps: {
188
255
  ...initialOptions.optimizeDeps,
189
- include: ["react-native-reanimated"],
190
256
  esbuildOptions: {
191
257
  ...(_initialOptions$optim = initialOptions.optimizeDeps) === null || _initialOptions$optim === void 0 ? void 0 : _initialOptions$optim.esbuildOptions,
192
258
  resolveExtensions: extensions,
193
- loader: { ".js": "jsx" }
259
+ loader: { ".js": "jsx" },
260
+ plugins: [(0, __bunchtogether_vite_plugin_flow.esbuildFlowPlugin)(/* @__PURE__ */ new RegExp(/\.(flow|jsx?)$/), (_path) => "jsx")]
194
261
  }
195
262
  },
263
+ build: { rollupOptions: {
264
+ treeshake: "safest",
265
+ plugins: [{
266
+ name: "nativewind-fix",
267
+ async transform(code, id) {
268
+ if (id.includes("react-native-css-interop")) return { moduleSideEffects: "no-treeshake" };
269
+ }
270
+ }]
271
+ } },
196
272
  resolve: {
197
273
  extensions,
198
274
  alias: { "react-native": "react-native-web" }
@@ -253,16 +329,7 @@ function rnw(opts = {}) {
253
329
  if (tsRE.test(filepath)) parserPlugins.push("typescript");
254
330
  const babel$1 = await loadBabel();
255
331
  let toTransform = code;
256
- if (isProduction && id.includes("node_modules/react-native-reanimated") && id.includes("ReanimatedModule/js-reanimated/webUtils") && code.includes("require")) toTransform = `
257
-
258
- import createReactDOMStyle from 'react-native-web/dist/exports/StyleSheet/compiler/createReactDOMStyle';
259
- import {
260
- createTextShadowValue,
261
- createTransformValue,
262
- } from 'react-native-web/dist/exports/StyleSheet/preprocess';
263
-
264
- export { createReactDOMStyle, createTextShadowValue, createTransformValue };
265
- `;
332
+ toTransform = transformReanimatedWebUtils(toTransform, code, id, isProduction);
266
333
  const result = await babel$1.transformAsync(toTransform, {
267
334
  ...babelOptions,
268
335
  root: projectRoot,
@@ -334,6 +401,7 @@ function rnw(opts = {}) {
334
401
  }
335
402
  };
336
403
  return [
404
+ (0, __bunchtogether_vite_plugin_flow.flowPlugin)({ exclude }),
337
405
  {
338
406
  name: "treat-js-files-as-jsx",
339
407
  async transform(code, id) {
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { fileURLToPath } from "node:url";
3
3
  import { readFileSync } from "node:fs";
4
4
  import * as vite from "vite";
5
5
  import { createFilter } from "vite";
6
+ import { esbuildFlowPlugin, flowPlugin } from "@bunchtogether/vite-plugin-flow";
6
7
  import commonjs from "vite-plugin-commonjs";
7
8
  import { exactRegex, makeIdFiltersToMatchWithQuery } from "@rolldown/pluginutils";
8
9
 
@@ -81,6 +82,70 @@ function removeLineBreaksIfNeeded(code, enabled) {
81
82
  return enabled ? code.replace(/\n/g, "") : code;
82
83
  }
83
84
 
85
+ //#endregion
86
+ //#region src/transforms.ts
87
+ /**
88
+ * Code transformation utilities for fixing React Native package compatibility issues
89
+ */
90
+ /**
91
+ * Analyzes require statements in code and maps them to module imports.
92
+ * Handles patterns like: varName = require('path').prop or require('path').default
93
+ */
94
+ function analyzeRequireStatements(originalCode, exportedVars) {
95
+ const importMap = /* @__PURE__ */ new Map();
96
+ for (const varName of exportedVars) {
97
+ const requirePattern = new RegExp(`${varName}\\s*=\\s*[\\s\\S]*?require\\(['"]([^'"]+)['"]\\)(?:\\.([\\w]+))?`, "g");
98
+ const requireMatch = requirePattern.exec(originalCode);
99
+ if (requireMatch) {
100
+ const [, modulePath, prop] = requireMatch;
101
+ const key = `${modulePath}:${prop || "default"}`;
102
+ if (!importMap.has(key)) importMap.set(key, []);
103
+ importMap.get(key).push(varName);
104
+ }
105
+ }
106
+ return importMap;
107
+ }
108
+ /**
109
+ * Removes try/catch blocks that contain require statements and export let declarations.
110
+ * This cleans up the problematic CommonJS patterns.
111
+ */
112
+ function removeTryCatchRequireBlocks(code) {
113
+ let transformed = code.replace(/try\s*\{[^{}]*?require\([^)]+\)[^{}]*?\}\s*catch[^{}]*?\{[^{}]*?\}/gs, "");
114
+ transformed = transformed.replace(/export let \w+;/g, "");
115
+ return transformed;
116
+ }
117
+ /**
118
+ * Generates direct export statements from the import map.
119
+ * Creates modern ESM exports like: export { default as varName } from 'module';
120
+ */
121
+ function generateDirectExports(importMap) {
122
+ let exports = "";
123
+ for (const [key, vars] of importMap) {
124
+ const [modulePath, prop] = key.split(":");
125
+ if (prop === "default") for (const varName of vars) exports += `export { default as ${varName} } from '${modulePath}';\n`;
126
+ else for (const varName of vars) exports += `export { ${prop} as ${varName} } from '${modulePath}';\n`;
127
+ }
128
+ return exports;
129
+ }
130
+ /**
131
+ * Transforms React Native Reanimated webUtils files to fix problematic
132
+ * export let + try/catch + require patterns by converting them to proper ESM.
133
+ *
134
+ * This transformation handles the incompatible module patterns in React Native Reanimated
135
+ * that cause build errors in Vite due to mixing CommonJS require() with ESM exports.
136
+ */
137
+ function transformReanimatedWebUtils(toTransform, originalCode, id, isProduction) {
138
+ if (!isProduction || !id.includes("node_modules/react-native-reanimated") || !id.includes("ReanimatedModule/js-reanimated/webUtils") || !originalCode.includes("export let") || !originalCode.includes("try") || !originalCode.includes("require")) return toTransform;
139
+ const exportLetMatches = Array.from(originalCode.matchAll(/export let (\w+);/g));
140
+ const exportedVars = exportLetMatches.map((match) => match[1]);
141
+ if (exportedVars.length === 0) return toTransform;
142
+ const importMap = analyzeRequireStatements(originalCode, exportedVars);
143
+ toTransform = removeTryCatchRequireBlocks(toTransform);
144
+ const exports = generateDirectExports(importMap);
145
+ if (exports) toTransform = `${toTransform}\n${exports}`;
146
+ return toTransform;
147
+ }
148
+
84
149
  //#endregion
85
150
  //#region src/index.ts
86
151
  const silenceUseClientWarning = (userConfig) => ({ rollupOptions: { onwarn(warning, defaultHandler) {
@@ -160,17 +225,28 @@ function rnw(opts = {}) {
160
225
  _WORKLET: false,
161
226
  __DEV__: JSON.stringify(development),
162
227
  "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || env.mode),
228
+ EXPO_OS: JSON.stringify("web"),
229
+ "process.env.EXPO_OS": JSON.stringify("web"),
163
230
  "global.Error": "Error"
164
231
  },
165
232
  optimizeDeps: {
166
233
  ...initialOptions.optimizeDeps,
167
- include: ["react-native-reanimated"],
168
234
  esbuildOptions: {
169
235
  ...(_initialOptions$optim = initialOptions.optimizeDeps) === null || _initialOptions$optim === void 0 ? void 0 : _initialOptions$optim.esbuildOptions,
170
236
  resolveExtensions: extensions,
171
- loader: { ".js": "jsx" }
237
+ loader: { ".js": "jsx" },
238
+ plugins: [esbuildFlowPlugin(/* @__PURE__ */ new RegExp(/\.(flow|jsx?)$/), (_path) => "jsx")]
172
239
  }
173
240
  },
241
+ build: { rollupOptions: {
242
+ treeshake: "safest",
243
+ plugins: [{
244
+ name: "nativewind-fix",
245
+ async transform(code, id) {
246
+ if (id.includes("react-native-css-interop")) return { moduleSideEffects: "no-treeshake" };
247
+ }
248
+ }]
249
+ } },
174
250
  resolve: {
175
251
  extensions,
176
252
  alias: { "react-native": "react-native-web" }
@@ -231,16 +307,7 @@ function rnw(opts = {}) {
231
307
  if (tsRE.test(filepath)) parserPlugins.push("typescript");
232
308
  const babel$1 = await loadBabel();
233
309
  let toTransform = code;
234
- if (isProduction && id.includes("node_modules/react-native-reanimated") && id.includes("ReanimatedModule/js-reanimated/webUtils") && code.includes("require")) toTransform = `
235
-
236
- import createReactDOMStyle from 'react-native-web/dist/exports/StyleSheet/compiler/createReactDOMStyle';
237
- import {
238
- createTextShadowValue,
239
- createTransformValue,
240
- } from 'react-native-web/dist/exports/StyleSheet/preprocess';
241
-
242
- export { createReactDOMStyle, createTextShadowValue, createTransformValue };
243
- `;
310
+ toTransform = transformReanimatedWebUtils(toTransform, code, id, isProduction);
244
311
  const result = await babel$1.transformAsync(toTransform, {
245
312
  ...babelOptions,
246
313
  root: projectRoot,
@@ -312,6 +379,7 @@ function rnw(opts = {}) {
312
379
  }
313
380
  };
314
381
  return [
382
+ flowPlugin({ exclude }),
315
383
  {
316
384
  name: "treat-js-files-as-jsx",
317
385
  async transform(code, id) {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.4",
2
+ "version": "0.0.6",
3
3
  "name": "vite-plugin-rnw",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
@@ -32,7 +32,9 @@
32
32
  "scripts": {
33
33
  "dev": "tsdown --watch",
34
34
  "build": "tsdown",
35
- "prepublishOnly": "npm run build"
35
+ "prepublishOnly": "npm run build",
36
+ "test": "node --no-warnings --experimental-strip-types --test --experimental-test-coverage src/**/*.test.ts",
37
+ "test:watch": "node --no-warnings --experimental-strip-types --test --watch src/**/*.test.ts"
36
38
  },
37
39
  "engines": {
38
40
  "node": "^14.18.0 || >=16.0.0"
@@ -53,9 +55,11 @@
53
55
  },
54
56
  "dependencies": {
55
57
  "@babel/core": "^7.28.0",
58
+ "@babel/plugin-transform-flow-strip-types": "^7.27.1",
56
59
  "@babel/plugin-transform-modules-commonjs": "^7.27.1",
57
60
  "@babel/plugin-transform-react-jsx-self": "^7.27.1",
58
61
  "@babel/plugin-transform-react-jsx-source": "^7.27.1",
62
+ "@bunchtogether/vite-plugin-flow": "^1.0.2",
59
63
  "@rolldown/pluginutils": "1.0.0-beta.24",
60
64
  "@types/babel__core": "^7.20.5",
61
65
  "react-refresh": "^0.17.0",