one 1.2.45 → 1.2.46

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.
Files changed (28) hide show
  1. package/dist/cjs/babel-plugins/remove-server-code.cjs +105 -0
  2. package/dist/cjs/babel-plugins/remove-server-code.js +125 -0
  3. package/dist/cjs/babel-plugins/remove-server-code.js.map +6 -0
  4. package/dist/cjs/babel-plugins/remove-server-code.native.js +153 -0
  5. package/dist/cjs/babel-plugins/remove-server-code.native.js.map +1 -0
  6. package/dist/cjs/metro-config/getViteMetroPluginOptions.cjs +8 -3
  7. package/dist/cjs/metro-config/getViteMetroPluginOptions.js +9 -1
  8. package/dist/cjs/metro-config/getViteMetroPluginOptions.js.map +1 -1
  9. package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js +8 -3
  10. package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js.map +1 -1
  11. package/dist/esm/babel-plugins/remove-server-code.js +102 -0
  12. package/dist/esm/babel-plugins/remove-server-code.js.map +6 -0
  13. package/dist/esm/babel-plugins/remove-server-code.mjs +71 -0
  14. package/dist/esm/babel-plugins/remove-server-code.mjs.map +1 -0
  15. package/dist/esm/babel-plugins/remove-server-code.native.js +116 -0
  16. package/dist/esm/babel-plugins/remove-server-code.native.js.map +1 -0
  17. package/dist/esm/metro-config/getViteMetroPluginOptions.js +9 -1
  18. package/dist/esm/metro-config/getViteMetroPluginOptions.js.map +1 -1
  19. package/dist/esm/metro-config/getViteMetroPluginOptions.mjs +7 -2
  20. package/dist/esm/metro-config/getViteMetroPluginOptions.mjs.map +1 -1
  21. package/dist/esm/metro-config/getViteMetroPluginOptions.native.js +7 -2
  22. package/dist/esm/metro-config/getViteMetroPluginOptions.native.js.map +1 -1
  23. package/package.json +14 -9
  24. package/src/babel-plugins/remove-server-code.ts +227 -0
  25. package/src/metro-config/getViteMetroPluginOptions.ts +10 -2
  26. package/types/babel-plugins/remove-server-code.d.ts +23 -0
  27. package/types/babel-plugins/remove-server-code.d.ts.map +1 -0
  28. package/types/metro-config/getViteMetroPluginOptions.d.ts.map +1 -1
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Babel plugin to remove server-only code (loader, generateStaticParams) from native bundles.
3
+ *
4
+ * This plugin transforms route files to remove server-only exports so they don't
5
+ * get included in the native bundle. It's the Metro equivalent of clientTreeShakePlugin.
6
+ *
7
+ * What it does:
8
+ * 1. Captures referenced identifiers BEFORE removing exports
9
+ * 2. Removes `export function loader() { ... }` and `export const loader = ...`
10
+ * 3. Removes `export function generateStaticParams() { ... }` and `export const generateStaticParams = ...`
11
+ * 4. Runs dead code elimination to remove imports that were only used by removed functions
12
+ * 5. Adds empty stubs back to prevent "missing export" errors
13
+ *
14
+ * Options:
15
+ * - routerRoot: The router root directory (e.g., 'app'). Only files in this directory are transformed.
16
+ */
17
+
18
+ import type { NodePath, PluginObj } from '@babel/core'
19
+ import * as t from '@babel/types'
20
+ import { deadCodeElimination, findReferencedIdentifiers } from 'babel-dead-code-elimination'
21
+
22
+ const SERVER_EXPORTS = ['loader', 'generateStaticParams'] as const
23
+
24
+ type ServerExport = (typeof SERVER_EXPORTS)[number]
25
+
26
+ type PluginOptions = {
27
+ routerRoot?: string
28
+ }
29
+
30
+ function removeServerCodePlugin(_: unknown, options: PluginOptions): PluginObj {
31
+ const { routerRoot = 'app' } = options
32
+
33
+ return {
34
+ name: 'one-remove-server-code',
35
+ visitor: {
36
+ Program: {
37
+ enter(path: NodePath<t.Program>, state: { filename?: string; referenced?: Set<string> }) {
38
+ const filename = state.filename
39
+
40
+ // Only process route files in the router root
41
+ if (!filename) {
42
+ return
43
+ }
44
+
45
+ // Check if file is in the router root directory
46
+ const routerRootPattern = new RegExp(`[/\\\\]${routerRoot}[/\\\\]`)
47
+ if (!routerRootPattern.test(filename)) {
48
+ return
49
+ }
50
+
51
+ // Skip node_modules
52
+ if (filename.includes('node_modules')) {
53
+ return
54
+ }
55
+
56
+ // Quick check if file even has these exports
57
+ const code = path.toString()
58
+ if (!/generateStaticParams|loader/.test(code)) {
59
+ return
60
+ }
61
+
62
+ // Capture referenced identifiers BEFORE removing exports
63
+ // This is critical for dead code elimination to work
64
+ try {
65
+ state.referenced = findReferencedIdentifiers(path.node as any) as any
66
+ } catch (error) {
67
+ console.warn(
68
+ `[one/metro] Skipping tree shaking for ${filename} due to identifier analysis error:`,
69
+ error instanceof Error ? error.message : String(error)
70
+ )
71
+ }
72
+ },
73
+
74
+ exit(path: NodePath<t.Program>, state: { filename?: string; referenced?: Set<string> }) {
75
+ const filename = state.filename
76
+
77
+ // Only process route files in the router root
78
+ if (!filename) {
79
+ return
80
+ }
81
+
82
+ // Check if file is in the router root directory
83
+ const routerRootPattern = new RegExp(`[/\\\\]${routerRoot}[/\\\\]`)
84
+ if (!routerRootPattern.test(filename)) {
85
+ return
86
+ }
87
+
88
+ // Skip node_modules
89
+ if (filename.includes('node_modules')) {
90
+ return
91
+ }
92
+
93
+ // If we don't have referenced set from enter, skip
94
+ if (!state.referenced) {
95
+ return
96
+ }
97
+
98
+ const removedExports: Set<ServerExport> = new Set()
99
+
100
+ // Find and remove server exports
101
+ // Note: babel-preset-expo may have already transformed async functions like:
102
+ // export async function loader() { ... }
103
+ // into:
104
+ // function _loader() { _loader = _asyncToGenerator(...); return _loader.apply(...) }
105
+ // export function loader() { return _loader.apply(...) }
106
+ // So we need to handle both the original form and the transformed form
107
+ path.traverse({
108
+ ExportNamedDeclaration(exportPath: NodePath<t.ExportNamedDeclaration>) {
109
+ const declaration = exportPath.node.declaration
110
+
111
+ // Handle: export function loader() { ... }
112
+ if (t.isFunctionDeclaration(declaration) && declaration.id) {
113
+ const name = declaration.id.name as ServerExport
114
+ if (SERVER_EXPORTS.includes(name)) {
115
+ removedExports.add(name)
116
+ exportPath.remove()
117
+ }
118
+ }
119
+ // Handle: export const loader = async () => { ... }
120
+ // Handle: export const loader = route.createLoader(...)
121
+ else if (t.isVariableDeclaration(declaration)) {
122
+ for (let i = declaration.declarations.length - 1; i >= 0; i--) {
123
+ const declarator = declaration.declarations[i]
124
+ if (t.isIdentifier(declarator.id)) {
125
+ const name = declarator.id.name as ServerExport
126
+ if (SERVER_EXPORTS.includes(name)) {
127
+ removedExports.add(name)
128
+
129
+ // Remove just this declarator
130
+ if (declaration.declarations.length === 1) {
131
+ exportPath.remove()
132
+ } else {
133
+ declaration.declarations.splice(i, 1)
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ },
140
+
141
+ // Also remove helper functions created by babel's async-to-generator transform
142
+ // These are named _loader, _generateStaticParams, etc.
143
+ FunctionDeclaration(funcPath: NodePath<t.FunctionDeclaration>) {
144
+ if (!funcPath.node.id) return
145
+ const name = funcPath.node.id.name
146
+ // Check for helper functions like _loader, _generateStaticParams
147
+ for (const serverExport of SERVER_EXPORTS) {
148
+ if (name === `_${serverExport}`) {
149
+ // Verify this is indeed a babel-generated async helper
150
+ // by checking if it contains _asyncToGenerator
151
+ let isAsyncHelper = false
152
+ funcPath.traverse({
153
+ Identifier(idPath) {
154
+ if (idPath.node.name === '_asyncToGenerator') {
155
+ isAsyncHelper = true
156
+ idPath.stop()
157
+ }
158
+ },
159
+ })
160
+ if (isAsyncHelper) {
161
+ removedExports.add(serverExport)
162
+ funcPath.remove()
163
+ }
164
+ }
165
+ }
166
+ },
167
+ })
168
+
169
+ // Only proceed if we removed something
170
+ if (removedExports.size === 0) {
171
+ return
172
+ }
173
+
174
+ // Run dead code elimination to remove imports that were only used by removed functions
175
+ try {
176
+ deadCodeElimination(path.node as any, state.referenced as any)
177
+ } catch (error) {
178
+ console.warn(
179
+ `[one/metro] Dead code elimination failed for ${filename}:`,
180
+ error instanceof Error ? error.message : String(error)
181
+ )
182
+ }
183
+
184
+ // Add back empty stubs for removed exports to prevent "missing export" errors
185
+ const stubs: t.Statement[] = []
186
+
187
+ if (removedExports.has('loader')) {
188
+ // export function loader() { return "__vxrn__loader__"; }
189
+ stubs.push(
190
+ t.exportNamedDeclaration(
191
+ t.functionDeclaration(
192
+ t.identifier('loader'),
193
+ [],
194
+ t.blockStatement([t.returnStatement(t.stringLiteral('__vxrn__loader__'))])
195
+ )
196
+ )
197
+ )
198
+ }
199
+
200
+ if (removedExports.has('generateStaticParams')) {
201
+ // export function generateStaticParams() { }
202
+ stubs.push(
203
+ t.exportNamedDeclaration(
204
+ t.functionDeclaration(
205
+ t.identifier('generateStaticParams'),
206
+ [],
207
+ t.blockStatement([])
208
+ )
209
+ )
210
+ )
211
+ }
212
+
213
+ // Add stubs at the end of the file
214
+ for (const stub of stubs) {
215
+ path.pushContainer('body', stub)
216
+ }
217
+
218
+ console.info(
219
+ ` 🧹 [one/metro] ${filename} removed ${removedExports.size} server-only exports`
220
+ )
221
+ },
222
+ },
223
+ },
224
+ }
225
+ }
226
+
227
+ export default removeServerCodePlugin
@@ -1,7 +1,7 @@
1
- import module from 'node:module'
2
- import path from 'node:path'
3
1
  import type { metroPlugin } from '@vxrn/vite-plugin-metro'
4
2
  import mm from 'micromatch'
3
+ import module from 'node:module'
4
+ import path from 'node:path'
5
5
  import tsconfigPaths from 'tsconfig-paths'
6
6
  import {
7
7
  API_ROUTE_GLOB_PATTERN,
@@ -154,6 +154,14 @@ export function getViteMetroPluginOptions({
154
154
  },
155
155
  babelConfig: {
156
156
  plugins: [
157
+ // Remove server-only code (loader, generateStaticParams) from route files
158
+ // This must run early to prevent server-only imports from being bundled
159
+ [
160
+ 'one/babel-plugin-remove-server-code',
161
+ {
162
+ routerRoot: relativeRouterRoot,
163
+ },
164
+ ],
157
165
  [
158
166
  'babel-plugin-module-resolver',
159
167
  {
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Babel plugin to remove server-only code (loader, generateStaticParams) from native bundles.
3
+ *
4
+ * This plugin transforms route files to remove server-only exports so they don't
5
+ * get included in the native bundle. It's the Metro equivalent of clientTreeShakePlugin.
6
+ *
7
+ * What it does:
8
+ * 1. Captures referenced identifiers BEFORE removing exports
9
+ * 2. Removes `export function loader() { ... }` and `export const loader = ...`
10
+ * 3. Removes `export function generateStaticParams() { ... }` and `export const generateStaticParams = ...`
11
+ * 4. Runs dead code elimination to remove imports that were only used by removed functions
12
+ * 5. Adds empty stubs back to prevent "missing export" errors
13
+ *
14
+ * Options:
15
+ * - routerRoot: The router root directory (e.g., 'app'). Only files in this directory are transformed.
16
+ */
17
+ import type { PluginObj } from '@babel/core';
18
+ type PluginOptions = {
19
+ routerRoot?: string;
20
+ };
21
+ declare function removeServerCodePlugin(_: unknown, options: PluginOptions): PluginObj;
22
+ export default removeServerCodePlugin;
23
+ //# sourceMappingURL=remove-server-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove-server-code.d.ts","sourceRoot":"","sources":["../../src/babel-plugins/remove-server-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAY,SAAS,EAAE,MAAM,aAAa,CAAA;AAQtD,KAAK,aAAa,GAAG;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,iBAAS,sBAAsB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,SAAS,CAmM7E;AAED,eAAe,sBAAsB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"getViteMetroPluginOptions.d.ts","sourceRoot":"","sources":["../../src/metro-config/getViteMetroPluginOptions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAQ1D,wBAAgB,yBAAyB,CAAC,EACxC,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,0BAA0B,EAC1B,SAAS,GACV,EAAE;IACD,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,iBAAiB,CAAC,EAAE,KAAK,CAAC,OAAO,MAAM,EAAE,CAAC,CAAA;IAC1C,0BAA0B,CAAC,EAAE,WAAW,CACtC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAClC,CAAC,wBAAwB,CAAC,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACzE,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CA6LpC"}
1
+ {"version":3,"file":"getViteMetroPluginOptions.d.ts","sourceRoot":"","sources":["../../src/metro-config/getViteMetroPluginOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAU1D,wBAAgB,yBAAyB,CAAC,EACxC,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,0BAA0B,EAC1B,SAAS,GACV,EAAE;IACD,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,iBAAiB,CAAC,EAAE,KAAK,CAAC,OAAO,MAAM,EAAE,CAAC,CAAA;IAC1C,0BAA0B,CAAC,EAAE,WAAW,CACtC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAClC,CAAC,wBAAwB,CAAC,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACzE,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAqMpC"}