vxrn 2.7.6 → 2.8.0
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/config/getBaseViteConfigOnly.mjs +1 -1
- package/dist/config/getBaseViteConfigOnly.mjs.map +1 -1
- package/dist/config/getBaseViteConfigOnly.native.js +1 -1
- package/dist/config/getBaseViteConfigOnly.native.js.map +1 -1
- package/dist/config/getOptimizeDeps.mjs +1 -1
- package/dist/config/getOptimizeDeps.mjs.map +1 -1
- package/dist/config/getOptimizeDeps.native.js +3 -1
- package/dist/config/getOptimizeDeps.native.js.map +1 -1
- package/dist/config/getReactNativePlugins.mjs +1 -2
- package/dist/config/getReactNativePlugins.mjs.map +1 -1
- package/dist/config/getReactNativePlugins.native.js +4 -2
- package/dist/config/getReactNativePlugins.native.js.map +1 -1
- package/dist/exports/prebuildWithoutExpo.mjs +26 -97
- package/dist/exports/prebuildWithoutExpo.mjs.map +1 -1
- package/dist/exports/prebuildWithoutExpo.native.js +47 -133
- package/dist/exports/prebuildWithoutExpo.native.js.map +1 -1
- package/dist/plugins/autoDepOptimizePlugin.mjs +5 -2
- package/dist/plugins/autoDepOptimizePlugin.mjs.map +1 -1
- package/dist/plugins/autoDepOptimizePlugin.native.js +10 -7
- package/dist/plugins/autoDepOptimizePlugin.native.js.map +1 -1
- package/dist/rn-commands/bundle/buildBundle.mjs +5 -4
- package/dist/rn-commands/bundle/buildBundle.mjs.map +1 -1
- package/dist/rn-commands/bundle/buildBundle.native.js +5 -4
- package/dist/rn-commands/bundle/buildBundle.native.js.map +1 -1
- package/dist/utils/createNativeDevEngine.mjs +30 -7
- package/dist/utils/createNativeDevEngine.mjs.map +1 -1
- package/dist/utils/createNativeDevEngine.native.js +64 -10
- package/dist/utils/createNativeDevEngine.native.js.map +1 -1
- package/package.json +27 -20
- package/src/config/getBaseViteConfigOnly.ts +1 -1
- package/src/config/getOptimizeDeps.ts +3 -1
- package/src/config/getReactNativePlugins.ts +8 -4
- package/src/config/ssrVendorOptimization.test.ts +115 -0
- package/src/exports/prebuildWithoutExpo.test.ts +62 -157
- package/src/exports/prebuildWithoutExpo.ts +31 -125
- package/src/plugins/autoDepOptimizeExternal.test.ts +101 -0
- package/src/plugins/autoDepOptimizePlugin.ts +12 -6
- package/src/plugins/rnCodegenPlugin.ts +1 -2
- package/src/rn-commands/bundle/buildBundle.ts +8 -7
- package/src/utils/createNativeDevEngine.test.ts +308 -9
- package/src/utils/createNativeDevEngine.ts +71 -29
- package/types/config/getOptimizeDeps.d.ts.map +1 -1
- package/types/config/getReactNativePlugins.d.ts +3 -2
- package/types/config/getReactNativePlugins.d.ts.map +1 -1
- package/types/exports/prebuildWithoutExpo.d.ts.map +1 -1
- package/types/plugins/autoDepOptimizePlugin.d.ts +1 -0
- package/types/plugins/autoDepOptimizePlugin.d.ts.map +1 -1
- package/types/plugins/rnCodegenPlugin.d.ts.map +1 -1
- package/types/rn-commands/bundle/buildBundle.d.ts +1 -1
- package/types/rn-commands/bundle/buildBundle.d.ts.map +1 -1
- package/types/utils/createNativeDevEngine.d.ts +3 -4
- package/types/utils/createNativeDevEngine.d.ts.map +1 -1
- package/src/plugins/autoDepOptimizePlugin.test.ts +0 -42
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vxrn",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -57,7 +57,6 @@
|
|
|
57
57
|
"files": [
|
|
58
58
|
"src",
|
|
59
59
|
"types",
|
|
60
|
-
"patches",
|
|
61
60
|
"dist",
|
|
62
61
|
"run.mjs",
|
|
63
62
|
"expo-plugin.cjs",
|
|
@@ -77,19 +76,18 @@
|
|
|
77
76
|
"@hono/node-server": "^1.19.14",
|
|
78
77
|
"@jridgewell/remapping": "^2.3.0",
|
|
79
78
|
"@jridgewell/trace-mapping": "^0.3.25",
|
|
80
|
-
"@react-native/codegen": "^0.
|
|
79
|
+
"@react-native/codegen": "^0.88.0",
|
|
81
80
|
"@react-native-community/cli": "^20.2.0",
|
|
82
81
|
"@react-native-community/cli-config": "^20.2.0",
|
|
83
|
-
"@react-native/dev-middleware": "^0.
|
|
84
|
-
"@vxrn/compiler": "2.
|
|
85
|
-
"@vxrn/debug": "2.
|
|
86
|
-
"@vxrn/query-string": "2.
|
|
87
|
-
"@vxrn/resolve": "2.
|
|
88
|
-
"@vxrn/url-parse": "2.
|
|
89
|
-
"@vxrn/utils": "2.
|
|
90
|
-
"@vxrn/vendor": "2.
|
|
91
|
-
"@vxrn/vite-flow": "2.
|
|
92
|
-
"@vxrn/vite-plugin-metro": "2.7.6",
|
|
82
|
+
"@react-native/dev-middleware": "^0.88.0",
|
|
83
|
+
"@vxrn/compiler": "2.8.0",
|
|
84
|
+
"@vxrn/debug": "2.8.0",
|
|
85
|
+
"@vxrn/query-string": "2.8.0",
|
|
86
|
+
"@vxrn/resolve": "2.8.0",
|
|
87
|
+
"@vxrn/url-parse": "2.8.0",
|
|
88
|
+
"@vxrn/utils": "2.8.0",
|
|
89
|
+
"@vxrn/vendor": "2.8.0",
|
|
90
|
+
"@vxrn/vite-flow": "2.8.0",
|
|
93
91
|
"citty": "^0.1.6",
|
|
94
92
|
"dotenv": "^17.2.1",
|
|
95
93
|
"dotenv-expand": "^12.0.2",
|
|
@@ -117,23 +115,32 @@
|
|
|
117
115
|
"sucrase": "3.35.1"
|
|
118
116
|
},
|
|
119
117
|
"devDependencies": {
|
|
120
|
-
"@biomejs/biome": "2.
|
|
118
|
+
"@biomejs/biome": "2.5.15",
|
|
121
119
|
"@jridgewell/gen-mapping": "^0.3.5",
|
|
122
|
-
"@tamagui/build": "3.0.
|
|
120
|
+
"@tamagui/build": "3.0.18",
|
|
123
121
|
"@types/find-node-modules": "^2.1.2",
|
|
124
122
|
"@types/node": "^24.10.0",
|
|
125
123
|
"@types/ws": "^8.18.1",
|
|
126
124
|
"depcheck": "^1.4.7",
|
|
127
|
-
"hermes-compiler": "
|
|
128
|
-
"metro-source-map": "0.
|
|
129
|
-
"react-native": "0.
|
|
125
|
+
"hermes-compiler": "260318099.0.4",
|
|
126
|
+
"metro-source-map": "0.87.1",
|
|
127
|
+
"react-native": "0.88.0",
|
|
130
128
|
"typescript": "7.0.2",
|
|
131
|
-
"vitest": "^4.1.0"
|
|
129
|
+
"vitest": "^4.1.0",
|
|
130
|
+
"@vxrn/vite-plugin-metro": "2.8.0"
|
|
132
131
|
},
|
|
133
132
|
"publishConfig": {
|
|
134
133
|
"access": "public"
|
|
135
134
|
},
|
|
136
|
-
"
|
|
135
|
+
"peerDependencies": {
|
|
136
|
+
"@vxrn/vite-plugin-metro": "2.8.0"
|
|
137
|
+
},
|
|
138
|
+
"peerDependenciesMeta": {
|
|
139
|
+
"@vxrn/vite-plugin-metro": {
|
|
140
|
+
"optional": true
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"releaseSourceCommit": "9435b113ae773ceebeef9e0a7144d5401b2c986f",
|
|
137
144
|
"repository": {
|
|
138
145
|
"type": "git",
|
|
139
146
|
"url": "git+https://github.com/onejs/one.git",
|
|
@@ -97,7 +97,7 @@ export async function getBaseViteConfig(
|
|
|
97
97
|
// have these native-only subpaths
|
|
98
98
|
{
|
|
99
99
|
find: /^react-native\/Libraries\/.*/,
|
|
100
|
-
replacement: resolvePath('@vxrn/
|
|
100
|
+
replacement: resolvePath('@vxrn/utils/empty', import.meta.dirname),
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
// react native 0.87 removed @react-native/assets-registry, but libraries
|
|
@@ -52,7 +52,9 @@ export function getOptimizeDeps(mode: 'build' | 'serve') {
|
|
|
52
52
|
]
|
|
53
53
|
|
|
54
54
|
const depsToOptimize = [
|
|
55
|
-
|
|
55
|
+
// patched React entries reach the vendor transitively when needed; forcing
|
|
56
|
+
// every vendor entry also bundles a second, unused runtime for React 19 apps.
|
|
57
|
+
...needsInterop.filter((dep) => !dep.startsWith('@vxrn/vendor/react')),
|
|
56
58
|
|
|
57
59
|
'fast-xml-parser',
|
|
58
60
|
'set-cookie-parser',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { MetroPluginOptions } from '@vxrn/vite-plugin-metro'
|
|
2
|
+
import type { PluginOption } from 'vite'
|
|
2
3
|
|
|
3
4
|
import type { VXRNOptionsFilled } from './getOptionsFilled'
|
|
4
5
|
import { DEFAULT_ASSET_EXTS } from '../constants/defaults'
|
|
@@ -17,7 +18,7 @@ export function getReactNativePlugins(
|
|
|
17
18
|
/** Passing a non-null value will enable metro mode */
|
|
18
19
|
metro?: MetroPluginOptions | null
|
|
19
20
|
} = {}
|
|
20
|
-
) {
|
|
21
|
+
): PluginOption[] {
|
|
21
22
|
// when native is disabled (via one's `native: false`), skip all RN / metro
|
|
22
23
|
// plugins so web-only projects don't spin up the RN dev server, middleware,
|
|
23
24
|
// websockets, or rolldown native engine.
|
|
@@ -27,8 +28,11 @@ export function getReactNativePlugins(
|
|
|
27
28
|
|
|
28
29
|
const metroOptions: typeof metro = metro || globalThis['__vxrnMetroOptions__']
|
|
29
30
|
if (metroOptions) {
|
|
30
|
-
//
|
|
31
|
-
return [
|
|
31
|
+
// metro mode. metro is an optional peer, so only this mode loads it
|
|
32
|
+
return [
|
|
33
|
+
applyBuiltInPatchesPlugin(),
|
|
34
|
+
import('@vxrn/vite-plugin-metro').then(({ metroPlugin }) => metroPlugin(metroOptions)),
|
|
35
|
+
]
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
return [
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cpSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
mkdtempSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
realpathSync,
|
|
7
|
+
rmSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from 'node:fs'
|
|
10
|
+
import { createRequire } from 'node:module'
|
|
11
|
+
import { tmpdir } from 'node:os'
|
|
12
|
+
import { dirname, join, resolve } from 'node:path'
|
|
13
|
+
import { createServer } from 'vite'
|
|
14
|
+
import { expect, it } from 'vitest'
|
|
15
|
+
import { builtInDepPatches } from '../patches/builtInDepPatches'
|
|
16
|
+
import { getOptimizeDeps } from './getOptimizeDeps'
|
|
17
|
+
|
|
18
|
+
const require = createRequire(import.meta.url)
|
|
19
|
+
|
|
20
|
+
it.each([false, true])(
|
|
21
|
+
'renders with shared React through patched entrypoints: %s',
|
|
22
|
+
async (patched) => {
|
|
23
|
+
const root = realpathSync(mkdtempSync(join(tmpdir(), 'vxrn-ssr-react-')))
|
|
24
|
+
const modules = join(root, 'node_modules')
|
|
25
|
+
mkdirSync(modules)
|
|
26
|
+
writeFileSync(join(root, 'package.json'), '{"private":true}')
|
|
27
|
+
for (const name of ['react', 'react-dom']) {
|
|
28
|
+
const target = join(modules, name)
|
|
29
|
+
cpSync(dirname(require.resolve(`${name}/package.json`)), target, {
|
|
30
|
+
recursive: true,
|
|
31
|
+
dereference: true,
|
|
32
|
+
})
|
|
33
|
+
if (patched) {
|
|
34
|
+
const patch = builtInDepPatches.find(({ module }) => module === name)!
|
|
35
|
+
// use the existing wrapper bytes and export conditions with real runtimes.
|
|
36
|
+
for (const [file, value] of Object.entries(patch.patchFiles)) {
|
|
37
|
+
if (file === 'version') continue
|
|
38
|
+
if (typeof value === 'string') writeFileSync(join(target, file), value)
|
|
39
|
+
}
|
|
40
|
+
const manifest = join(target, 'package.json')
|
|
41
|
+
const pkg = JSON.parse(readFileSync(manifest, 'utf8'))
|
|
42
|
+
pkg.version = '18.3.1'
|
|
43
|
+
const patchManifest = patch.patchFiles['package.json']
|
|
44
|
+
if (typeof patchManifest !== 'function')
|
|
45
|
+
throw new Error('missing React export patch')
|
|
46
|
+
writeFileSync(manifest, patchManifest(JSON.stringify(pkg)) as string)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const vendor = join(modules, '@vxrn/vendor')
|
|
50
|
+
mkdirSync(vendor, { recursive: true })
|
|
51
|
+
const source = resolve(import.meta.dirname, '../../../vendor')
|
|
52
|
+
cpSync(join(source, 'package.json'), join(vendor, 'package.json'))
|
|
53
|
+
for (const name of ['react', 'react-dom']) {
|
|
54
|
+
cpSync(join(source, name), join(vendor, name), { recursive: true })
|
|
55
|
+
}
|
|
56
|
+
writeFileSync(
|
|
57
|
+
join(root, 'entry.js'),
|
|
58
|
+
`import React, { useState } from 'react'
|
|
59
|
+
import { renderToString } from 'react-dom/server.browser'
|
|
60
|
+
function Page() {
|
|
61
|
+
const [text] = useState('ready')
|
|
62
|
+
return React.createElement('h1', null, text)
|
|
63
|
+
}
|
|
64
|
+
export const html = renderToString(React.createElement(Page))
|
|
65
|
+
`
|
|
66
|
+
)
|
|
67
|
+
const loadedVendor = new Set<string>()
|
|
68
|
+
const { optimizeDeps } = getOptimizeDeps('serve')
|
|
69
|
+
const include = optimizeDeps.include.filter((id) =>
|
|
70
|
+
/^(react(?:-dom)?(?:\/|$)|@vxrn\/vendor\/react)/.test(id)
|
|
71
|
+
)
|
|
72
|
+
const server = await createServer({
|
|
73
|
+
configFile: false,
|
|
74
|
+
root,
|
|
75
|
+
server: { middlewareMode: true },
|
|
76
|
+
optimizeDeps: { noDiscovery: true },
|
|
77
|
+
ssr: { noExternal: include },
|
|
78
|
+
environments: {
|
|
79
|
+
ssr: {
|
|
80
|
+
resolve: { conditions: ['vxrn-web'] },
|
|
81
|
+
optimizeDeps: {
|
|
82
|
+
...optimizeDeps,
|
|
83
|
+
include: [...include, 'react-dom/server.browser'],
|
|
84
|
+
noDiscovery: true,
|
|
85
|
+
rolldownOptions: {
|
|
86
|
+
...optimizeDeps.rolldownOptions,
|
|
87
|
+
plugins: [
|
|
88
|
+
{
|
|
89
|
+
name: 'record-vendored-react-loads',
|
|
90
|
+
load(id) {
|
|
91
|
+
if (id.startsWith(vendor)) loadedVendor.add(id)
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
try {
|
|
101
|
+
expect(server.environments.ssr.depsOptimizer).toBeDefined()
|
|
102
|
+
await server.environments.ssr.listen(server)
|
|
103
|
+
const result = await server.ssrLoadModule(join(root, 'entry.js'))
|
|
104
|
+
expect(result.html).toBe('<h1>ready</h1>')
|
|
105
|
+
if (patched) {
|
|
106
|
+
expect(loadedVendor.size).toBeGreaterThan(0)
|
|
107
|
+
} else {
|
|
108
|
+
expect([...loadedVendor]).toEqual([])
|
|
109
|
+
}
|
|
110
|
+
} finally {
|
|
111
|
+
await server.close()
|
|
112
|
+
rmSync(root, { recursive: true, force: true })
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
)
|
|
@@ -49,15 +49,17 @@ const app = {
|
|
|
49
49
|
android: { applicationId: 'dev.one.myapp', minSdk: 28 },
|
|
50
50
|
} satisfies PrebuildAppConfig
|
|
51
51
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
const templateFile = (file: string) =>
|
|
53
|
+
readFileSync(
|
|
54
|
+
fileURLToPath(
|
|
55
|
+
new URL(
|
|
56
|
+
`../../../../node_modules/@react-native-community/template/template/ios/${file}`,
|
|
57
|
+
import.meta.url
|
|
58
|
+
)
|
|
59
|
+
),
|
|
60
|
+
'utf8'
|
|
61
|
+
)
|
|
62
|
+
const templateAppDelegate = templateFile('HelloWorld/AppDelegate.swift')
|
|
61
63
|
|
|
62
64
|
describe('native.app prebuild validation', () => {
|
|
63
65
|
// smoke for the shared definition re-export; the full cases live beside
|
|
@@ -149,10 +151,13 @@ describe('native.app prebuild validation', () => {
|
|
|
149
151
|
})
|
|
150
152
|
})
|
|
151
153
|
|
|
152
|
-
// the template's
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
// the template's app and scene source entries and two app-target plist settings,
|
|
155
|
+
// beside which the bridging header setting lands
|
|
156
|
+
const APP_DELEGATE_PBXPROJ = ` 761780EF2CA45674006654EF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EE2CA45674006654EF /* SceneDelegate.swift */; };
|
|
157
|
+
761780EE2CA45674006654EF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SceneDelegate.swift; path = HelloWorld/SceneDelegate.swift; sourceTree = "<group>"; };
|
|
158
|
+
761780EE2CA45674006654EF /* SceneDelegate.swift */,
|
|
159
|
+
761780EF2CA45674006654EF /* SceneDelegate.swift in Sources */,
|
|
160
|
+
\t\t761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
|
|
156
161
|
\t\t761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = HelloWorld/AppDelegate.swift; sourceTree = "<group>"; };
|
|
157
162
|
\t\t\t\t761780EC2CA45674006654EE /* AppDelegate.swift */,
|
|
158
163
|
\t\t\t\t761780ED2CA45674006654EE /* AppDelegate.swift in Sources */,
|
|
@@ -485,6 +490,30 @@ extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autoli
|
|
|
485
490
|
expect(noPedometerManifest.content).not.toContain('ACTIVITY_RECOGNITION')
|
|
486
491
|
})
|
|
487
492
|
|
|
493
|
+
it('defaults the ios deployment target to the 17.0 floor when unset', () => {
|
|
494
|
+
// one requires ios 17 (see schema minimumVersion and One.podspec);
|
|
495
|
+
// leaving the template's react native 15.1 default fails pod install.
|
|
496
|
+
const noTarget = { ...app, ios: { bundleId: 'dev.one.myapp' } }
|
|
497
|
+
const podfile = renderPrebuildFile({
|
|
498
|
+
relativePath: 'Podfile',
|
|
499
|
+
content:
|
|
500
|
+
"platform :ios, min_ios_version_supported\ntarget 'HelloWorld' do\n config = use_native_modules!\n post_install do |installer|\n react_native_post_install(\n installer\n )\n end\nend",
|
|
501
|
+
platform: 'ios',
|
|
502
|
+
app: noTarget,
|
|
503
|
+
})
|
|
504
|
+
expect(podfile.content).toContain("platform :ios, '17.0'")
|
|
505
|
+
expect(podfile.content).toContain(
|
|
506
|
+
"config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '17.0'"
|
|
507
|
+
)
|
|
508
|
+
const pbxproj = renderPrebuildFile({
|
|
509
|
+
relativePath: 'HelloWorld.xcodeproj/project.pbxproj',
|
|
510
|
+
content: `IPHONEOS_DEPLOYMENT_TARGET = 15.1; target HelloWorld\nshellScript = ${JSON.stringify('REACT_NATIVE_XCODE="$REACT_NATIVE_PATH/scripts/react-native-xcode.sh"\n/bin/sh -c "\\"$WITH_ENVIRONMENT\\" \\"$REACT_NATIVE_XCODE\\""\n')};\n${APP_DELEGATE_PBXPROJ}`,
|
|
511
|
+
platform: 'ios',
|
|
512
|
+
app: noTarget,
|
|
513
|
+
})
|
|
514
|
+
expect(pbxproj.content).toContain('IPHONEOS_DEPLOYMENT_TARGET = 17.0;')
|
|
515
|
+
})
|
|
516
|
+
|
|
488
517
|
it('stamps the brightness write-settings permission from native.app', () => {
|
|
489
518
|
const content =
|
|
490
519
|
'<manifest>\n <uses-permission android:name="android.permission.INTERNET" />\n <activity>\n </activity>\n </application>'
|
|
@@ -829,36 +858,7 @@ extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autoli
|
|
|
829
858
|
|
|
830
859
|
const appDelegate = renderPrebuildFile({
|
|
831
860
|
relativePath: 'HelloWorld/AppDelegate.swift',
|
|
832
|
-
content:
|
|
833
|
-
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
834
|
-
var window: UIWindow?
|
|
835
|
-
|
|
836
|
-
var reactNativeDelegate: ReactNativeDelegate?
|
|
837
|
-
var reactNativeFactory: RCTReactNativeFactory?
|
|
838
|
-
|
|
839
|
-
func application(
|
|
840
|
-
_ application: UIApplication,
|
|
841
|
-
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
842
|
-
) -> Bool {
|
|
843
|
-
let delegate = ReactNativeDelegate()
|
|
844
|
-
let factory = RCTReactNativeFactory(delegate: delegate)
|
|
845
|
-
delegate.dependencyProvider = RCTAppDependencyProvider()
|
|
846
|
-
|
|
847
|
-
reactNativeDelegate = delegate
|
|
848
|
-
reactNativeFactory = factory
|
|
849
|
-
|
|
850
|
-
window = UIWindow(frame: UIScreen.main.bounds)
|
|
851
|
-
|
|
852
|
-
factory.startReactNative(
|
|
853
|
-
withModuleName: "HelloWorld",
|
|
854
|
-
in: window,
|
|
855
|
-
launchOptions: launchOptions
|
|
856
|
-
)
|
|
857
|
-
|
|
858
|
-
return true
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
class ReactNativeDelegate:${templateRnDelegate}`,
|
|
861
|
+
content: templateAppDelegate,
|
|
862
862
|
platform: 'ios',
|
|
863
863
|
app: push,
|
|
864
864
|
})
|
|
@@ -1163,42 +1163,10 @@ extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autoli
|
|
|
1163
1163
|
})
|
|
1164
1164
|
|
|
1165
1165
|
describe('ios scene lifecycle', () => {
|
|
1166
|
-
|
|
1167
|
-
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
1168
|
-
var window: UIWindow?
|
|
1169
|
-
|
|
1170
|
-
var reactNativeDelegate: ReactNativeDelegate?
|
|
1171
|
-
var reactNativeFactory: RCTReactNativeFactory?
|
|
1172
|
-
|
|
1173
|
-
func application(
|
|
1174
|
-
_ application: UIApplication,
|
|
1175
|
-
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
1176
|
-
) -> Bool {
|
|
1177
|
-
let delegate = ReactNativeDelegate()
|
|
1178
|
-
let factory = RCTReactNativeFactory(delegate: delegate)
|
|
1179
|
-
delegate.dependencyProvider = RCTAppDependencyProvider()
|
|
1180
|
-
|
|
1181
|
-
reactNativeDelegate = delegate
|
|
1182
|
-
reactNativeFactory = factory
|
|
1183
|
-
|
|
1184
|
-
window = UIWindow(frame: UIScreen.main.bounds)
|
|
1185
|
-
|
|
1186
|
-
factory.startReactNative(
|
|
1187
|
-
withModuleName: "HelloWorld",
|
|
1188
|
-
in: window,
|
|
1189
|
-
launchOptions: launchOptions
|
|
1190
|
-
)
|
|
1191
|
-
|
|
1192
|
-
return true
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
`
|
|
1196
|
-
|
|
1197
|
-
it('trims the AppDelegate to app-level work and keeps the RN delegate', () => {
|
|
1166
|
+
it('registers the app-level factory and keeps the RN launch screen delegate', () => {
|
|
1198
1167
|
const rendered = renderPrebuildFile({
|
|
1199
1168
|
relativePath: 'HelloWorld/AppDelegate.swift',
|
|
1200
|
-
content:
|
|
1201
|
-
class ReactNativeDelegate:${templateRnDelegate}`,
|
|
1169
|
+
content: templateAppDelegate,
|
|
1202
1170
|
platform: 'ios',
|
|
1203
1171
|
app,
|
|
1204
1172
|
})
|
|
@@ -1212,13 +1180,15 @@ class ReactNativeDelegate:${templateRnDelegate}`,
|
|
|
1212
1180
|
expect(rendered.content).toContain('OneHoldLaunchScreen(rootView)')
|
|
1213
1181
|
})
|
|
1214
1182
|
|
|
1215
|
-
it('
|
|
1216
|
-
|
|
1183
|
+
it('requests Hermes dev bytecode from the generated RN delegate', () => {
|
|
1184
|
+
const rendered = renderPrebuildFile({
|
|
1217
1185
|
relativePath: 'HelloWorld/AppDelegate.swift',
|
|
1218
|
-
content:
|
|
1186
|
+
content: templateAppDelegate,
|
|
1219
1187
|
platform: 'ios',
|
|
1220
1188
|
app,
|
|
1221
|
-
})
|
|
1189
|
+
})
|
|
1190
|
+
expect(rendered.content).toContain('URLQueryItem(name: "bytecode", value: "hermes")')
|
|
1191
|
+
expect(rendered.content).toContain('if bundleURL.isFileURL { return bundleURL }')
|
|
1222
1192
|
})
|
|
1223
1193
|
|
|
1224
1194
|
it('throws instead of shipping a non-scene AppDelegate', () => {
|
|
@@ -1232,10 +1202,10 @@ class ReactNativeDelegate:${templateRnDelegate}`,
|
|
|
1232
1202
|
).toThrow('changed shape')
|
|
1233
1203
|
})
|
|
1234
1204
|
|
|
1235
|
-
it('
|
|
1205
|
+
it('preserves the upstream scene manifest and renders the RN delegate', () => {
|
|
1236
1206
|
const infoPlist = renderPrebuildFile({
|
|
1237
1207
|
relativePath: 'HelloWorld/Info.plist',
|
|
1238
|
-
content: '
|
|
1208
|
+
content: templateFile('HelloWorld/Info.plist'),
|
|
1239
1209
|
platform: 'ios',
|
|
1240
1210
|
app,
|
|
1241
1211
|
})
|
|
@@ -1254,25 +1224,9 @@ class ReactNativeDelegate:${templateRnDelegate}`,
|
|
|
1254
1224
|
expect(sceneDelegate).toContain('continue userActivity')
|
|
1255
1225
|
expect(sceneDelegate).toContain('RCTLinkingManager')
|
|
1256
1226
|
expect(sceneDelegate).toContain('appDelegate.reactNativeFactory')
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
expect(() =>
|
|
1261
|
-
renderPrebuildFile({
|
|
1262
|
-
relativePath: 'HelloWorld/Info.plist',
|
|
1263
|
-
content: '<dict>\n</dict>',
|
|
1264
|
-
platform: 'ios',
|
|
1265
|
-
app,
|
|
1266
|
-
})
|
|
1267
|
-
).toThrow('LSRequiresIPhoneOS')
|
|
1268
|
-
expect(() =>
|
|
1269
|
-
renderPrebuildFile({
|
|
1270
|
-
relativePath: 'HelloWorld.xcodeproj/project.pbxproj',
|
|
1271
|
-
content: `shellScript = ${JSON.stringify('REACT_NATIVE_XCODE="$REACT_NATIVE_PATH/scripts/react-native-xcode.sh"\n/bin/sh -c "\\"$WITH_ENVIRONMENT\\" \\"$REACT_NATIVE_XCODE\\""\n')};\nno app delegate here`,
|
|
1272
|
-
platform: 'ios',
|
|
1273
|
-
app,
|
|
1274
|
-
})
|
|
1275
|
-
).toThrow('AppDelegate.swift anchor')
|
|
1227
|
+
expect(sceneDelegate).toContain('connectionOptions: connectionOptions')
|
|
1228
|
+
expect(sceneDelegate).toContain('RCTLinkingManager.scene(scene, openURLContexts: URLContexts)')
|
|
1229
|
+
expect(sceneDelegate).toContain('RCTLinkingManager.scene(scene, continue: userActivity)')
|
|
1276
1230
|
})
|
|
1277
1231
|
|
|
1278
1232
|
it('bundles native.app fonts into both platforms from the real template', async () => {
|
|
@@ -1364,7 +1318,7 @@ class ReactNativeDelegate:${templateRnDelegate}`,
|
|
|
1364
1318
|
expect(appDelegate).toContain('class ReactNativeDelegate')
|
|
1365
1319
|
|
|
1366
1320
|
const infoPlist = readFileSync(join(output, 'ios', 'MyApp', 'Info.plist'), 'utf8')
|
|
1367
|
-
expect(infoPlist
|
|
1321
|
+
expect(infoPlist.split('<key>UIApplicationSceneManifest</key>')).toHaveLength(2)
|
|
1368
1322
|
expect(infoPlist).toContain('<key>OneNativeNotificationsEnabled</key>')
|
|
1369
1323
|
// orientation default opens the phone list to all four; ipad keeps its own.
|
|
1370
1324
|
const phoneOrientations = infoPlist
|
|
@@ -1387,7 +1341,7 @@ class ReactNativeDelegate:${templateRnDelegate}`,
|
|
|
1387
1341
|
'utf8'
|
|
1388
1342
|
)
|
|
1389
1343
|
expect(project).toContain('path = MyApp/SceneDelegate.swift')
|
|
1390
|
-
expect(project
|
|
1344
|
+
expect(project.split('/* SceneDelegate.swift in Sources */,')).toHaveLength(2)
|
|
1391
1345
|
// no push flag: no entitlements file and no entitlement wiring.
|
|
1392
1346
|
expect(project).not.toContain('CODE_SIGN_ENTITLEMENTS')
|
|
1393
1347
|
expect(() => statSync(join(output, 'ios', 'MyApp', 'MyApp.entitlements'))).toThrow()
|
|
@@ -2357,55 +2311,6 @@ describe('one updates prebuild', () => {
|
|
|
2357
2311
|
updates: { url: 'https://updates.example.com', runtimeVersion: 'test-1' },
|
|
2358
2312
|
} satisfies PrebuildAppConfig
|
|
2359
2313
|
|
|
2360
|
-
const templateAppDelegate = `import UIKit
|
|
2361
|
-
import React
|
|
2362
|
-
import React_RCTAppDelegate
|
|
2363
|
-
import ReactAppDependencyProvider
|
|
2364
|
-
|
|
2365
|
-
@main
|
|
2366
|
-
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
2367
|
-
var window: UIWindow?
|
|
2368
|
-
|
|
2369
|
-
var reactNativeDelegate: ReactNativeDelegate?
|
|
2370
|
-
var reactNativeFactory: RCTReactNativeFactory?
|
|
2371
|
-
|
|
2372
|
-
func application(
|
|
2373
|
-
_ application: UIApplication,
|
|
2374
|
-
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
2375
|
-
) -> Bool {
|
|
2376
|
-
let delegate = ReactNativeDelegate()
|
|
2377
|
-
let factory = RCTReactNativeFactory(delegate: delegate)
|
|
2378
|
-
delegate.dependencyProvider = RCTAppDependencyProvider()
|
|
2379
|
-
|
|
2380
|
-
reactNativeDelegate = delegate
|
|
2381
|
-
reactNativeFactory = factory
|
|
2382
|
-
|
|
2383
|
-
window = UIWindow(frame: UIScreen.main.bounds)
|
|
2384
|
-
|
|
2385
|
-
factory.startReactNative(
|
|
2386
|
-
withModuleName: "HelloWorld",
|
|
2387
|
-
in: window,
|
|
2388
|
-
launchOptions: launchOptions
|
|
2389
|
-
)
|
|
2390
|
-
|
|
2391
|
-
return true
|
|
2392
|
-
}
|
|
2393
|
-
}
|
|
2394
|
-
|
|
2395
|
-
class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
|
|
2396
|
-
override func sourceURL(for bridge: RCTBridge) -> URL? {
|
|
2397
|
-
self.bundleURL()
|
|
2398
|
-
}
|
|
2399
|
-
|
|
2400
|
-
override func bundleURL() -> URL? {
|
|
2401
|
-
#if DEBUG
|
|
2402
|
-
RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
|
|
2403
|
-
#else
|
|
2404
|
-
Bundle.main.url(forResource: "main", withExtension: "jsbundle")
|
|
2405
|
-
#endif
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
`
|
|
2409
2314
|
|
|
2410
2315
|
it('validates the updates config', () => {
|
|
2411
2316
|
expect(() => validatePrebuildApp(updatesApp)).not.toThrow()
|
|
@@ -2484,15 +2389,15 @@ buildSettings = {
|
|
|
2484
2389
|
).toThrow('bridging header')
|
|
2485
2390
|
})
|
|
2486
2391
|
|
|
2487
|
-
it('
|
|
2392
|
+
it('rejects an incompatible app delegate with updates configured', () => {
|
|
2488
2393
|
expect(() =>
|
|
2489
2394
|
renderPrebuildFile({
|
|
2490
2395
|
relativePath: 'HelloWorld/AppDelegate.swift',
|
|
2491
|
-
content: templateAppDelegate.replace('
|
|
2396
|
+
content: templateAppDelegate.replace(' true', ' false'),
|
|
2492
2397
|
platform: 'ios',
|
|
2493
2398
|
app: updatesApp,
|
|
2494
2399
|
})
|
|
2495
|
-
).toThrow('
|
|
2400
|
+
).toThrow('changed shape')
|
|
2496
2401
|
})
|
|
2497
2402
|
|
|
2498
2403
|
it('locks userInterfaceStyle on both platforms, and follows the system when unset', () => {
|
|
@@ -2803,7 +2708,7 @@ import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
|
|
|
2803
2708
|
platform: 'android',
|
|
2804
2709
|
app: updatesApp,
|
|
2805
2710
|
})
|
|
2806
|
-
).toThrow('
|
|
2711
|
+
).toThrow('changed shape')
|
|
2807
2712
|
})
|
|
2808
2713
|
|
|
2809
2714
|
it('stamps the updates config into the android manifest', () => {
|