@vxrn/vite-plugin-metro 1.1.501-1751155612296
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/cjs/index.cjs +28 -0
- package/dist/cjs/index.js +22 -0
- package/dist/cjs/index.js.map +6 -0
- package/dist/cjs/index.native.js +28 -0
- package/dist/cjs/index.native.js.map +6 -0
- package/dist/cjs/plugins/expoManifestRequestHandlerPlugin.cjs +56 -0
- package/dist/cjs/plugins/expoManifestRequestHandlerPlugin.js +49 -0
- package/dist/cjs/plugins/expoManifestRequestHandlerPlugin.js.map +6 -0
- package/dist/cjs/plugins/expoManifestRequestHandlerPlugin.native.js +48 -0
- package/dist/cjs/plugins/expoManifestRequestHandlerPlugin.native.js.map +6 -0
- package/dist/cjs/plugins/metroPlugin.cjs +214 -0
- package/dist/cjs/plugins/metroPlugin.js +186 -0
- package/dist/cjs/plugins/metroPlugin.js.map +6 -0
- package/dist/cjs/plugins/metroPlugin.native.js +179 -0
- package/dist/cjs/plugins/metroPlugin.native.js.map +6 -0
- package/dist/cjs/transformer/babel-core.cjs +27 -0
- package/dist/cjs/transformer/babel-core.js +22 -0
- package/dist/cjs/transformer/babel-core.js.map +6 -0
- package/dist/cjs/transformer/babel-core.native.js +28 -0
- package/dist/cjs/transformer/babel-core.native.js.map +6 -0
- package/dist/cjs/transformer/babel-transformer.cjs +148 -0
- package/dist/cjs/transformer/babel-transformer.js +129 -0
- package/dist/cjs/transformer/babel-transformer.js.map +6 -0
- package/dist/cjs/transformer/babel-transformer.native.js +135 -0
- package/dist/cjs/transformer/babel-transformer.native.js.map +6 -0
- package/dist/cjs/transformer/loadBabelConfig.cjs +53 -0
- package/dist/cjs/transformer/loadBabelConfig.js +46 -0
- package/dist/cjs/transformer/loadBabelConfig.js.map +6 -0
- package/dist/cjs/transformer/loadBabelConfig.native.js +55 -0
- package/dist/cjs/transformer/loadBabelConfig.native.js.map +6 -0
- package/dist/cjs/transformer/transformSync.cjs +64 -0
- package/dist/cjs/transformer/transformSync.js +53 -0
- package/dist/cjs/transformer/transformSync.js.map +6 -0
- package/dist/cjs/transformer/transformSync.native.js +58 -0
- package/dist/cjs/transformer/transformSync.native.js.map +6 -0
- package/dist/cjs/utils/getTerminalReporter.cjs +59 -0
- package/dist/cjs/utils/getTerminalReporter.js +48 -0
- package/dist/cjs/utils/getTerminalReporter.js.map +6 -0
- package/dist/cjs/utils/getTerminalReporter.native.js +53 -0
- package/dist/cjs/utils/getTerminalReporter.native.js.map +6 -0
- package/dist/cjs/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.cjs +35 -0
- package/dist/cjs/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.js +30 -0
- package/dist/cjs/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.js.map +6 -0
- package/dist/cjs/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.native.js +37 -0
- package/dist/cjs/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.native.js.map +6 -0
- package/dist/cjs/utils/projectImport.cjs +56 -0
- package/dist/cjs/utils/projectImport.js +43 -0
- package/dist/cjs/utils/projectImport.js.map +6 -0
- package/dist/cjs/utils/projectImport.native.js +54 -0
- package/dist/cjs/utils/projectImport.native.js.map +6 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +6 -0
- package/dist/esm/index.mjs +4 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +4 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/plugins/expoManifestRequestHandlerPlugin.js +35 -0
- package/dist/esm/plugins/expoManifestRequestHandlerPlugin.js.map +6 -0
- package/dist/esm/plugins/expoManifestRequestHandlerPlugin.mjs +33 -0
- package/dist/esm/plugins/expoManifestRequestHandlerPlugin.mjs.map +1 -0
- package/dist/esm/plugins/expoManifestRequestHandlerPlugin.native.js +34 -0
- package/dist/esm/plugins/expoManifestRequestHandlerPlugin.native.js.map +1 -0
- package/dist/esm/plugins/metroPlugin.js +168 -0
- package/dist/esm/plugins/metroPlugin.js.map +6 -0
- package/dist/esm/plugins/metroPlugin.mjs +180 -0
- package/dist/esm/plugins/metroPlugin.mjs.map +1 -0
- package/dist/esm/plugins/metroPlugin.native.js +189 -0
- package/dist/esm/plugins/metroPlugin.native.js.map +1 -0
- package/dist/esm/transformer/babel-core.js +9 -0
- package/dist/esm/transformer/babel-core.js.map +6 -0
- package/dist/esm/transformer/babel-core.mjs +3 -0
- package/dist/esm/transformer/babel-core.mjs.map +1 -0
- package/dist/esm/transformer/babel-core.native.js +3 -0
- package/dist/esm/transformer/babel-core.native.js.map +1 -0
- package/dist/esm/transformer/babel-transformer.js +110 -0
- package/dist/esm/transformer/babel-transformer.js.map +6 -0
- package/dist/esm/transformer/babel-transformer.mjs +122 -0
- package/dist/esm/transformer/babel-transformer.mjs.map +1 -0
- package/dist/esm/transformer/babel-transformer.native.js +136 -0
- package/dist/esm/transformer/babel-transformer.native.js.map +1 -0
- package/dist/esm/transformer/loadBabelConfig.js +23 -0
- package/dist/esm/transformer/loadBabelConfig.js.map +6 -0
- package/dist/esm/transformer/loadBabelConfig.mjs +19 -0
- package/dist/esm/transformer/loadBabelConfig.mjs.map +1 -0
- package/dist/esm/transformer/loadBabelConfig.native.js +23 -0
- package/dist/esm/transformer/loadBabelConfig.native.js.map +1 -0
- package/dist/esm/transformer/transformSync.js +29 -0
- package/dist/esm/transformer/transformSync.js.map +6 -0
- package/dist/esm/transformer/transformSync.mjs +30 -0
- package/dist/esm/transformer/transformSync.mjs.map +1 -0
- package/dist/esm/transformer/transformSync.native.js +31 -0
- package/dist/esm/transformer/transformSync.native.js.map +1 -0
- package/dist/esm/utils/getTerminalReporter.js +25 -0
- package/dist/esm/utils/getTerminalReporter.js.map +6 -0
- package/dist/esm/utils/getTerminalReporter.mjs +25 -0
- package/dist/esm/utils/getTerminalReporter.mjs.map +1 -0
- package/dist/esm/utils/getTerminalReporter.native.js +26 -0
- package/dist/esm/utils/getTerminalReporter.native.js.map +1 -0
- package/dist/esm/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.js +14 -0
- package/dist/esm/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.js.map +6 -0
- package/dist/esm/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.mjs +12 -0
- package/dist/esm/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.mjs.map +1 -0
- package/dist/esm/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.native.js +14 -0
- package/dist/esm/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.native.js.map +1 -0
- package/dist/esm/utils/projectImport.js +20 -0
- package/dist/esm/utils/projectImport.js.map +6 -0
- package/dist/esm/utils/projectImport.mjs +20 -0
- package/dist/esm/utils/projectImport.mjs.map +1 -0
- package/dist/esm/utils/projectImport.native.js +22 -0
- package/dist/esm/utils/projectImport.native.js.map +1 -0
- package/empty.js +0 -0
- package/package.json +68 -0
- package/src/index.ts +4 -0
- package/src/plugins/expoManifestRequestHandlerPlugin.ts +75 -0
- package/src/plugins/metroPlugin.ts +314 -0
- package/src/transformer/babel-core.ts +7 -0
- package/src/transformer/babel-transformer.ts +211 -0
- package/src/transformer/loadBabelConfig.ts +53 -0
- package/src/transformer/transformSync.ts +54 -0
- package/src/utils/getTerminalReporter.ts +42 -0
- package/src/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.ts +27 -0
- package/src/utils/projectImport.ts +32 -0
- package/types/index.d.ts +5 -0
- package/types/index.d.ts.map +1 -0
- package/types/plugins/expoManifestRequestHandlerPlugin.d.ts +14 -0
- package/types/plugins/expoManifestRequestHandlerPlugin.d.ts.map +1 -0
- package/types/plugins/metroPlugin.d.ts +22 -0
- package/types/plugins/metroPlugin.d.ts.map +1 -0
- package/types/transformer/babel-core.d.ts +2 -0
- package/types/transformer/babel-core.d.ts.map +1 -0
- package/types/transformer/babel-transformer.d.ts +18 -0
- package/types/transformer/babel-transformer.d.ts.map +1 -0
- package/types/transformer/loadBabelConfig.d.ts +10 -0
- package/types/transformer/loadBabelConfig.d.ts.map +1 -0
- package/types/transformer/transformSync.d.ts +11 -0
- package/types/transformer/transformSync.d.ts.map +1 -0
- package/types/utils/getTerminalReporter.d.ts +3 -0
- package/types/utils/getTerminalReporter.d.ts.map +1 -0
- package/types/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.d.ts +5 -0
- package/types/utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName.d.ts.map +1 -0
- package/types/utils/projectImport.d.ts +12 -0
- package/types/utils/projectImport.d.ts.map +1 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
import { parse } from 'node:url'
|
|
4
|
+
import type { PluginOption } from 'vite'
|
|
5
|
+
import launchEditor from 'launch-editor'
|
|
6
|
+
|
|
7
|
+
// For Metro and Expo, we only import types here.
|
|
8
|
+
// We use `projectImport` to dynamically import the actual modules
|
|
9
|
+
// at runtime to ensure they are loaded from the user's project root.
|
|
10
|
+
import type MetroT from 'metro'
|
|
11
|
+
import type { loadConfig as loadConfigT } from 'metro'
|
|
12
|
+
import type MetroHmrServerT from 'metro/src/HmrServer'
|
|
13
|
+
import type createWebsocketServerT from 'metro/src/lib/createWebsocketServer'
|
|
14
|
+
import type { getDefaultConfig as getDefaultConfigT } from '@expo/metro-config'
|
|
15
|
+
import type { createDevMiddleware as createDevMiddlewareT } from '@react-native/dev-middleware'
|
|
16
|
+
|
|
17
|
+
import { projectImport, projectResolve } from '../utils/projectImport'
|
|
18
|
+
import { getTerminalReporter } from '../utils/getTerminalReporter'
|
|
19
|
+
import { patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName } from '../utils/patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName'
|
|
20
|
+
import type { TransformOptions } from '../transformer/babel-core'
|
|
21
|
+
|
|
22
|
+
type MetroYargArguments = Parameters<typeof loadConfigT>[0]
|
|
23
|
+
type MetroInputConfig = Parameters<typeof loadConfigT>[1]
|
|
24
|
+
|
|
25
|
+
export type MetroPluginOptions = {
|
|
26
|
+
argv?: MetroYargArguments
|
|
27
|
+
defaultConfigOverrides?:
|
|
28
|
+
| MetroInputConfig
|
|
29
|
+
| ((defaultConfig: MetroInputConfig) => MetroInputConfig)
|
|
30
|
+
babelConfig?: TransformOptions
|
|
31
|
+
/**
|
|
32
|
+
* Overrides the main module name which is normally defined as the `main` field in `package.json`.
|
|
33
|
+
*
|
|
34
|
+
* This will affect how `/.expo/.virtual-metro-entry.bundle` behaves.
|
|
35
|
+
*
|
|
36
|
+
* It can be used to change the entry point of the React Native app without the need of using
|
|
37
|
+
* the `main` field in `package.json`.
|
|
38
|
+
*/
|
|
39
|
+
mainModuleName?: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function metroPlugin({
|
|
43
|
+
argv,
|
|
44
|
+
defaultConfigOverrides,
|
|
45
|
+
babelConfig,
|
|
46
|
+
mainModuleName,
|
|
47
|
+
}: MetroPluginOptions = {}): PluginOption {
|
|
48
|
+
// let projectRoot = ''
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
name: 'metro',
|
|
52
|
+
// configResolved(config) {
|
|
53
|
+
// projectRoot = config.root
|
|
54
|
+
// },
|
|
55
|
+
|
|
56
|
+
async configureServer(server) {
|
|
57
|
+
const { logger, root: projectRoot } = server.config
|
|
58
|
+
|
|
59
|
+
const { default: Metro, loadConfig } = await projectImport<{
|
|
60
|
+
default: typeof MetroT
|
|
61
|
+
loadConfig: typeof loadConfigT
|
|
62
|
+
}>(projectRoot, 'metro')
|
|
63
|
+
const { default: MetroHmrServer } = await projectImport<{
|
|
64
|
+
default: typeof MetroHmrServerT
|
|
65
|
+
}>(projectRoot, 'metro/src/HmrServer')
|
|
66
|
+
const { default: createWebsocketServer } = await projectImport<{
|
|
67
|
+
default: typeof createWebsocketServerT
|
|
68
|
+
}>(projectRoot, 'metro/src/lib/createWebsocketServer')
|
|
69
|
+
const { getDefaultConfig } = await projectImport<{
|
|
70
|
+
getDefaultConfig: typeof getDefaultConfigT
|
|
71
|
+
}>(projectRoot, '@expo/metro-config')
|
|
72
|
+
const { createDevMiddleware } = await projectImport<{
|
|
73
|
+
createDevMiddleware: typeof createDevMiddlewareT
|
|
74
|
+
}>(projectRoot, '@react-native/dev-middleware')
|
|
75
|
+
|
|
76
|
+
const _defaultConfig: MetroInputConfig = getDefaultConfig(projectRoot) as any
|
|
77
|
+
|
|
78
|
+
if (mainModuleName) {
|
|
79
|
+
const origRewriteRequestUrl = _defaultConfig!.server!.rewriteRequestUrl!
|
|
80
|
+
|
|
81
|
+
// We need to patch Expo's default `config.server.rewriteRequestUrl`
|
|
82
|
+
// to change how URLs like '/.expo/.virtual-metro-entry.bundle?' are
|
|
83
|
+
// rewritten.
|
|
84
|
+
// But since that function is difficult to override, here we borrow
|
|
85
|
+
// the ExpoGoManifestHandlerMiddleware and use it to resolve the
|
|
86
|
+
// URL to the main module name.
|
|
87
|
+
const resolveMainModuleName: (p: { platform: 'ios' | 'android' }) => string =
|
|
88
|
+
await (async () => {
|
|
89
|
+
const ExpoGoManifestHandlerMiddleware = (
|
|
90
|
+
await projectImport(
|
|
91
|
+
projectRoot,
|
|
92
|
+
'@expo/cli/build/src/start/server/middleware/ExpoGoManifestHandlerMiddleware.js'
|
|
93
|
+
)
|
|
94
|
+
).default.ExpoGoManifestHandlerMiddleware
|
|
95
|
+
|
|
96
|
+
const manifestHandlerMiddleware = new ExpoGoManifestHandlerMiddleware(projectRoot, {})
|
|
97
|
+
|
|
98
|
+
patchExpoGoManifestHandlerMiddlewareWithCustomMainModuleName(
|
|
99
|
+
manifestHandlerMiddleware,
|
|
100
|
+
mainModuleName
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return (p) => {
|
|
104
|
+
return manifestHandlerMiddleware.resolveMainModuleName({
|
|
105
|
+
pkg: { main: mainModuleName },
|
|
106
|
+
platform: p.platform,
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
})()
|
|
110
|
+
|
|
111
|
+
_defaultConfig!.server!.rewriteRequestUrl = (url) => {
|
|
112
|
+
if (url.includes('/.expo/.virtual-metro-entry.bundle?')) {
|
|
113
|
+
const resolvedMainModulePath = resolveMainModuleName({
|
|
114
|
+
platform: 'ios', // we probably need to handle android here, but currently in our use case this won't affect the result
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return url.replace('.expo/.virtual-metro-entry', resolvedMainModulePath)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return origRewriteRequestUrl(url)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const defaultConfig: MetroInputConfig = {
|
|
125
|
+
..._defaultConfig,
|
|
126
|
+
resolver: {
|
|
127
|
+
..._defaultConfig?.resolver,
|
|
128
|
+
sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx', 'mjs', 'cjs'], // `one` related packages are using `.mjs` extensions. This somehow fixes `.native` files not being resolved correctly when `.mjs` files are present.
|
|
129
|
+
resolveRequest: (context, moduleName, platform) => {
|
|
130
|
+
const origResolveRequestFn =
|
|
131
|
+
_defaultConfig?.resolver?.resolveRequest || context.resolveRequest
|
|
132
|
+
|
|
133
|
+
// HACK: Do not assert the "import" condition for `@babel/runtime`. This
|
|
134
|
+
// is a workaround for ESM <-> CJS interop, as we need the CJS versions of
|
|
135
|
+
// `@babel/runtime` helpers.
|
|
136
|
+
//
|
|
137
|
+
// This hack is originally made in Metro and was removed in `v0.81.3`, but
|
|
138
|
+
// we somehow still need it.
|
|
139
|
+
// See: https://github.com/facebook/metro/commit/9552a64a0487af64cd86d8591e203a55c59c9686#diff-b03f1b511a2be7abd755b9c2561e47f513f84931466f2cc20a17a4238d70f12bL370-L378
|
|
140
|
+
//
|
|
141
|
+
// Resolves the "TypeError: _interopRequireDefault is not a function (it is Object)" error.
|
|
142
|
+
if (moduleName.startsWith('@babel/runtime')) {
|
|
143
|
+
const contextOverride = {
|
|
144
|
+
...context,
|
|
145
|
+
unstable_conditionNames: context.unstable_conditionNames.filter(
|
|
146
|
+
(c) => c !== 'import'
|
|
147
|
+
),
|
|
148
|
+
}
|
|
149
|
+
return origResolveRequestFn(contextOverride, moduleName, platform)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return origResolveRequestFn(context, moduleName, platform)
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
transformer: {
|
|
156
|
+
..._defaultConfig?.transformer,
|
|
157
|
+
babelTransformerPath: projectResolve(
|
|
158
|
+
projectRoot,
|
|
159
|
+
'@vxrn/vite-plugin-metro/babel-transformer'
|
|
160
|
+
),
|
|
161
|
+
// TODO: This is what Expo is doing, but do we really need this?
|
|
162
|
+
publicPath: '/assets/?unstable_path=.',
|
|
163
|
+
},
|
|
164
|
+
reporter: await getTerminalReporter(projectRoot),
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const config = await loadConfig(
|
|
168
|
+
{
|
|
169
|
+
cwd: projectRoot,
|
|
170
|
+
projectRoot,
|
|
171
|
+
'reset-cache': !!process.env.METRO_RESET_CACHE,
|
|
172
|
+
...argv,
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
...defaultConfig,
|
|
176
|
+
...(typeof defaultConfigOverrides === 'function'
|
|
177
|
+
? defaultConfigOverrides(defaultConfig)
|
|
178
|
+
: defaultConfigOverrides),
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
const { middleware, end, metroServer } = await Metro.createConnectMiddleware(config, {
|
|
183
|
+
// Force enable file watching, even on CI.
|
|
184
|
+
// This is needed for HMR tests to work on CI.
|
|
185
|
+
watch: true,
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
// Patch transformFile to inject custom transform options.
|
|
189
|
+
const originalTransformFile = metroServer
|
|
190
|
+
.getBundler()
|
|
191
|
+
.getBundler()
|
|
192
|
+
.transformFile.bind(metroServer.getBundler().getBundler())
|
|
193
|
+
metroServer.getBundler().getBundler().transformFile = async (
|
|
194
|
+
filePath: string,
|
|
195
|
+
transformOptions: Parameters<typeof originalTransformFile>[1],
|
|
196
|
+
fileBuffer?: Parameters<typeof originalTransformFile>[2]
|
|
197
|
+
) => {
|
|
198
|
+
return originalTransformFile(
|
|
199
|
+
filePath,
|
|
200
|
+
{
|
|
201
|
+
...transformOptions,
|
|
202
|
+
customTransformOptions: {
|
|
203
|
+
...transformOptions.customTransformOptions,
|
|
204
|
+
vite: {
|
|
205
|
+
babelConfig,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
fileBuffer
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const hmrServer = new MetroHmrServer(
|
|
214
|
+
metroServer.getBundler(),
|
|
215
|
+
metroServer.getCreateModuleId(),
|
|
216
|
+
config
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
const reactNativeDevToolsUrl = `http://${typeof server.config.server.host === 'boolean' ? 'localhost' : server.config.server.host}:${server.config.server.port}`
|
|
220
|
+
const { middleware: rnDevtoolsMiddleware, websocketEndpoints: rnDevtoolsWebsocketEndpoints } =
|
|
221
|
+
createDevMiddleware({
|
|
222
|
+
projectRoot,
|
|
223
|
+
serverBaseUrl: reactNativeDevToolsUrl,
|
|
224
|
+
logger: console,
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
server.middlewares.use(async (req, res, next) => {
|
|
228
|
+
try {
|
|
229
|
+
// Just for debugging purposes.
|
|
230
|
+
if (req.url?.includes('.bundle')) {
|
|
231
|
+
const VITE_METRO_DEBUG_BUNDLE = process.env.VITE_METRO_DEBUG_BUNDLE
|
|
232
|
+
if (VITE_METRO_DEBUG_BUNDLE) {
|
|
233
|
+
if (existsSync(VITE_METRO_DEBUG_BUNDLE)) {
|
|
234
|
+
console.info(` !!! - serving debug bundle from`, VITE_METRO_DEBUG_BUNDLE)
|
|
235
|
+
const content = await readFile(VITE_METRO_DEBUG_BUNDLE, 'utf-8')
|
|
236
|
+
res.setHeader('Content-Type', 'application/javascript')
|
|
237
|
+
res.end(content)
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Handle `isPackagerRunning` request from native app.
|
|
244
|
+
// Without this, people may see a `No script URL provided. Make sure the packager is running or you have embedded a JS bundle in your application bundle.`, `unsanitizedScriptURLString = (null)` error in their native app running with the "Debug" configuration.
|
|
245
|
+
// See: https://github.com/facebook/react-native/blob/v0.80.0-rc.4/packages/react-native/React/Base/RCTBundleURLProvider.mm#L87-L113
|
|
246
|
+
if (
|
|
247
|
+
req.url === '/status' &&
|
|
248
|
+
req.headers['user-agent']?.includes(
|
|
249
|
+
'CFNetwork/'
|
|
250
|
+
) /* The path (`/status`) is too general and may conflict with the user's web app, so we also check the User-Agent header to ensure it's a request from a native app. */ /* TODO: Android */
|
|
251
|
+
) {
|
|
252
|
+
res.statusCode = 200
|
|
253
|
+
res.end('packager-status:running')
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (req.url === '/open-stack-frame' && req.method === 'POST') {
|
|
258
|
+
let body = ''
|
|
259
|
+
|
|
260
|
+
req.on('data', (chunk) => {
|
|
261
|
+
body += chunk.toString()
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
req.on('end', () => {
|
|
265
|
+
try {
|
|
266
|
+
const frame = JSON.parse(body)
|
|
267
|
+
|
|
268
|
+
// https://github.com/yyx990803/launch-editor/blob/master/packages/launch-editor-middleware/index.js
|
|
269
|
+
launchEditor(frame.file)
|
|
270
|
+
res.statusCode = 200
|
|
271
|
+
res.end('Stack frame opened in editor')
|
|
272
|
+
} catch (e) {
|
|
273
|
+
console.error('Failed to parse stack frame:', e)
|
|
274
|
+
res.statusCode = 400
|
|
275
|
+
return res.end('Invalid stack frame JSON')
|
|
276
|
+
}
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// this is the actual Metro middleware that handles bundle requests
|
|
283
|
+
await (middleware as any)(req, res, next)
|
|
284
|
+
} catch (error) {
|
|
285
|
+
// TODO: handle errors from Metro middleware?
|
|
286
|
+
console.error('Metro middleware error:', error)
|
|
287
|
+
next()
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
server.middlewares.use(rnDevtoolsMiddleware)
|
|
292
|
+
|
|
293
|
+
const websocketEndpoints = {
|
|
294
|
+
'/hot': createWebsocketServer({
|
|
295
|
+
websocketServer: hmrServer,
|
|
296
|
+
}),
|
|
297
|
+
...rnDevtoolsWebsocketEndpoints,
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
server.httpServer?.on('upgrade', (request, socket, head) => {
|
|
301
|
+
const { pathname } = parse(request.url!)
|
|
302
|
+
|
|
303
|
+
if (pathname != null && websocketEndpoints[pathname]) {
|
|
304
|
+
websocketEndpoints[pathname].handleUpgrade(request, socket, head, (ws) => {
|
|
305
|
+
websocketEndpoints[pathname].emit('connection', ws, request)
|
|
306
|
+
})
|
|
307
|
+
} else {
|
|
308
|
+
// TODO: Do we need this?
|
|
309
|
+
// socket.destroy()
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
},
|
|
313
|
+
}
|
|
314
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 650 Industries (Expo). All rights reserved.
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
// A fork of the upstream babel-transformer that uses Expo-specific babel defaults
|
|
9
|
+
// and adds support for web and Node.js environments via `isServer` on the Babel caller.
|
|
10
|
+
// See:
|
|
11
|
+
// * https://github.com/facebook/metro/blob/main/packages/metro-babel-transformer/src/index.js
|
|
12
|
+
// * https://github.com/expo/expo/blob/main/packages/%40expo/metro-config/src/babel-transformer.ts
|
|
13
|
+
import type { BabelTransformer, BabelTransformerArgs } from 'metro-babel-transformer'
|
|
14
|
+
import assert from 'node:assert'
|
|
15
|
+
|
|
16
|
+
import type { TransformOptions } from './babel-core'
|
|
17
|
+
import { loadBabelConfig } from './loadBabelConfig'
|
|
18
|
+
import { transformSync } from './transformSync'
|
|
19
|
+
|
|
20
|
+
export type ExpoBabelCaller = TransformOptions['caller'] & {
|
|
21
|
+
supportsReactCompiler?: boolean
|
|
22
|
+
isReactServer?: boolean
|
|
23
|
+
isHMREnabled?: boolean
|
|
24
|
+
isServer?: boolean
|
|
25
|
+
isNodeModule?: boolean
|
|
26
|
+
preserveEnvVars?: boolean
|
|
27
|
+
isDev?: boolean
|
|
28
|
+
asyncRoutes?: boolean
|
|
29
|
+
baseUrl?: string
|
|
30
|
+
engine?: string
|
|
31
|
+
bundler?: 'metro' | (string & object)
|
|
32
|
+
platform?: string | null
|
|
33
|
+
routerRoot?: string
|
|
34
|
+
projectRoot: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const debug = require('debug')('expo:metro-config:babel-transformer') as typeof console.log
|
|
38
|
+
|
|
39
|
+
function isCustomTruthy(value: any): boolean {
|
|
40
|
+
return String(value) === 'true'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function memoize<T extends (...args: any[]) => any>(fn: T): T {
|
|
44
|
+
const cache = new Map<string, ReturnType<T>>()
|
|
45
|
+
return ((...args: any[]) => {
|
|
46
|
+
const key = JSON.stringify(args)
|
|
47
|
+
if (cache.has(key)) {
|
|
48
|
+
return cache.get(key)
|
|
49
|
+
}
|
|
50
|
+
const result = fn(...args)
|
|
51
|
+
cache.set(key, result)
|
|
52
|
+
return result
|
|
53
|
+
}) as T
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const memoizeWarning = memoize((message: string) => {
|
|
57
|
+
debug(message)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
function getBabelCaller({
|
|
61
|
+
filename,
|
|
62
|
+
options,
|
|
63
|
+
}: Pick<BabelTransformerArgs, 'filename' | 'options'>): ExpoBabelCaller {
|
|
64
|
+
const isNodeModule = filename.includes('node_modules')
|
|
65
|
+
const isReactServer = options.customTransformOptions?.environment === 'react-server'
|
|
66
|
+
const isGenericServer = options.customTransformOptions?.environment === 'node'
|
|
67
|
+
const isServer = isReactServer || isGenericServer
|
|
68
|
+
|
|
69
|
+
const routerRoot =
|
|
70
|
+
typeof options.customTransformOptions?.routerRoot === 'string'
|
|
71
|
+
? decodeURI(options.customTransformOptions.routerRoot)
|
|
72
|
+
: undefined
|
|
73
|
+
|
|
74
|
+
if (routerRoot == null) {
|
|
75
|
+
memoizeWarning(
|
|
76
|
+
'Warning: Missing transform.routerRoot option in Metro bundling request, falling back to `app` as routes directory. This can occur if you bundle without Expo CLI or expo/metro-config.'
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
name: 'metro',
|
|
82
|
+
bundler: 'metro',
|
|
83
|
+
platform: options.platform,
|
|
84
|
+
// Empower the babel preset to know the env it's bundling for.
|
|
85
|
+
// Metro automatically updates the cache to account for the custom transform options.
|
|
86
|
+
isServer,
|
|
87
|
+
|
|
88
|
+
// Enable React Server Component rules for AST. The naming maps to the resolver property `--conditions=react-server`.
|
|
89
|
+
isReactServer,
|
|
90
|
+
|
|
91
|
+
// The base url to make requests from, used for hosting from non-standard locations.
|
|
92
|
+
baseUrl:
|
|
93
|
+
typeof options.customTransformOptions?.baseUrl === 'string'
|
|
94
|
+
? decodeURI(options.customTransformOptions.baseUrl)
|
|
95
|
+
: '',
|
|
96
|
+
|
|
97
|
+
// Ensure we always use a mostly-valid router root.
|
|
98
|
+
routerRoot: routerRoot ?? 'app',
|
|
99
|
+
|
|
100
|
+
isDev: options.dev,
|
|
101
|
+
|
|
102
|
+
// This value indicates if the user has disabled the feature or not.
|
|
103
|
+
// Other criteria may still cause the feature to be disabled, but all inputs used are
|
|
104
|
+
// already considered in the cache key.
|
|
105
|
+
preserveEnvVars: isCustomTruthy(options.customTransformOptions?.preserveEnvVars)
|
|
106
|
+
? true
|
|
107
|
+
: undefined,
|
|
108
|
+
asyncRoutes: isCustomTruthy(options.customTransformOptions?.asyncRoutes) ? true : undefined,
|
|
109
|
+
// Pass the engine to babel so we can automatically transpile for the correct
|
|
110
|
+
// target environment.
|
|
111
|
+
engine: stringOrUndefined(options.customTransformOptions?.engine),
|
|
112
|
+
|
|
113
|
+
// Provide the project root for accurately reading the Expo config.
|
|
114
|
+
projectRoot: options.projectRoot,
|
|
115
|
+
|
|
116
|
+
isNodeModule,
|
|
117
|
+
|
|
118
|
+
isHMREnabled: options.hot,
|
|
119
|
+
|
|
120
|
+
// Set the standard Babel flag to disable ESM transformations.
|
|
121
|
+
supportsStaticESM:
|
|
122
|
+
isCustomTruthy(options.customTransformOptions?.optimize) || options.experimentalImportSupport,
|
|
123
|
+
|
|
124
|
+
// Enable React compiler support in Babel.
|
|
125
|
+
// TODO: Remove this in the future when compiler is on by default.
|
|
126
|
+
supportsReactCompiler: isCustomTruthy(options.customTransformOptions?.reactCompiler)
|
|
127
|
+
? true
|
|
128
|
+
: undefined,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function stringOrUndefined(value: unknown): string | undefined {
|
|
133
|
+
return typeof value === 'string' ? value : undefined
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const transform: BabelTransformer['transform'] = ({
|
|
137
|
+
filename,
|
|
138
|
+
src,
|
|
139
|
+
options,
|
|
140
|
+
// `plugins` is used for `functionMapBabelPlugin` from `metro-source-map`. Could make sense to move this to `babel-preset-expo` too.
|
|
141
|
+
plugins,
|
|
142
|
+
}: BabelTransformerArgs): ReturnType<BabelTransformer['transform']> => {
|
|
143
|
+
const customOptionsFromVite: {
|
|
144
|
+
[key: string]: unknown
|
|
145
|
+
} = options.customTransformOptions?.vite || ({} as any)
|
|
146
|
+
const babelConfigFromVitePlugin: TransformOptions = customOptionsFromVite.babelConfig || {}
|
|
147
|
+
|
|
148
|
+
const OLD_BABEL_ENV = process.env.BABEL_ENV
|
|
149
|
+
process.env.BABEL_ENV = options.dev ? 'development' : process.env.BABEL_ENV || 'production'
|
|
150
|
+
try {
|
|
151
|
+
const babelConfig: TransformOptions = {
|
|
152
|
+
// ES modules require sourceType='module' but OSS may not always want that
|
|
153
|
+
sourceType: 'unambiguous',
|
|
154
|
+
|
|
155
|
+
// The output we want from Babel methods
|
|
156
|
+
ast: true,
|
|
157
|
+
code: false,
|
|
158
|
+
// NOTE(EvanBacon): We split the parse/transform steps up to accommodate
|
|
159
|
+
// Hermes parsing, but this defaults to cloning the AST which increases
|
|
160
|
+
// the transformation time by a fair amount.
|
|
161
|
+
// You get this behavior by default when using Babel's `transform` method directly.
|
|
162
|
+
cloneInputAst: false,
|
|
163
|
+
|
|
164
|
+
// Options for debugging
|
|
165
|
+
cwd: options.projectRoot,
|
|
166
|
+
filename,
|
|
167
|
+
highlightCode: true,
|
|
168
|
+
|
|
169
|
+
...babelConfigFromVitePlugin,
|
|
170
|
+
|
|
171
|
+
...loadBabelConfig(options),
|
|
172
|
+
|
|
173
|
+
babelrc:
|
|
174
|
+
typeof options.enableBabelRCLookup === 'boolean' ? options.enableBabelRCLookup : true,
|
|
175
|
+
|
|
176
|
+
plugins: [...(babelConfigFromVitePlugin.plugins || []), ...(plugins as any)],
|
|
177
|
+
|
|
178
|
+
// NOTE(EvanBacon): We heavily leverage the caller functionality to mutate the babel config.
|
|
179
|
+
// This compensates for the lack of a format plugin system in Metro. Users can modify the
|
|
180
|
+
// all (most) of the transforms in their local Babel config.
|
|
181
|
+
// This also helps us keep the transform layers small and focused on a single task. We can also use this to
|
|
182
|
+
// ensure the Babel config caching is more accurate.
|
|
183
|
+
// Additionally, by moving everything Babel-related to the Babel preset, it makes it easier for users to reason
|
|
184
|
+
// about the requirements of an Expo project, making it easier to migrate to other transpilers in the future.
|
|
185
|
+
caller: getBabelCaller({ filename, options }),
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const result = transformSync(src, babelConfig, options)
|
|
189
|
+
|
|
190
|
+
// The result from `transformFromAstSync` can be null (if the file is ignored)
|
|
191
|
+
if (!result) {
|
|
192
|
+
// BabelTransformer specifies that the `ast` can never be null but
|
|
193
|
+
// the function returns here. Discovered when typing `BabelNode`.
|
|
194
|
+
// @ts-expect-error: see https://github.com/facebook/react-native/blob/401991c3f073bf734ee04f9220751c227d2abd31/packages/react-native-babel-transformer/src/index.js#L220-L224
|
|
195
|
+
return { ast: null }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
assert(result.ast)
|
|
199
|
+
return { ast: result.ast, metadata: result.metadata }
|
|
200
|
+
} finally {
|
|
201
|
+
if (OLD_BABEL_ENV) {
|
|
202
|
+
process.env.BABEL_ENV = OLD_BABEL_ENV
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const babelTransformer: BabelTransformer = {
|
|
208
|
+
transform,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = babelTransformer
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 650 Industries (Expo). All rights reserved.
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'node:fs'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
|
|
11
|
+
import type { TransformOptions } from './babel-core'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Returns a memoized function that checks for the existence of a
|
|
15
|
+
* project-level .babelrc file. If it doesn't exist, it reads the
|
|
16
|
+
* default React Native babelrc file and uses that.
|
|
17
|
+
*/
|
|
18
|
+
export const loadBabelConfig = (() => {
|
|
19
|
+
let babelRC: Pick<TransformOptions, 'extends' | 'presets'> | null = null
|
|
20
|
+
|
|
21
|
+
return function _getBabelRC({ projectRoot }: { projectRoot: string }) {
|
|
22
|
+
if (babelRC !== null) {
|
|
23
|
+
return babelRC
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
babelRC = {}
|
|
27
|
+
|
|
28
|
+
if (projectRoot) {
|
|
29
|
+
// Check for various babel config files in the project root
|
|
30
|
+
// TODO(EvanBacon): We might want to disable babelrc lookup when the user specifies `enableBabelRCLookup: false`.
|
|
31
|
+
const possibleBabelRCPaths = ['.babelrc', '.babelrc.js', 'babel.config.js']
|
|
32
|
+
|
|
33
|
+
const foundBabelRCPath = possibleBabelRCPaths.find((configFileName) =>
|
|
34
|
+
fs.existsSync(path.resolve(projectRoot, configFileName))
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
// Extend the config if a babel config file is found
|
|
38
|
+
if (foundBabelRCPath) {
|
|
39
|
+
babelRC.extends = path.resolve(projectRoot, foundBabelRCPath)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Use the default preset for react-native if no babel config file is found
|
|
44
|
+
if (!babelRC.extends) {
|
|
45
|
+
babelRC.presets = [
|
|
46
|
+
// { plugins: [transformImportMetaGlobPlugin] }, // Added to support Vite's `import.meta.glob`
|
|
47
|
+
require('babel-preset-expo'),
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return babelRC
|
|
52
|
+
}
|
|
53
|
+
})()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 650 Industries (Expo). All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import * as babel from './babel-core';
|
|
8
|
+
|
|
9
|
+
// TS detection conditions copied from @react-native/babel-preset
|
|
10
|
+
function isTypeScriptSource(fileName: string): boolean {
|
|
11
|
+
return fileName?.endsWith('.ts');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isTSXSource(fileName: string): boolean {
|
|
15
|
+
return fileName?.endsWith('.tsx');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function transformSync(
|
|
19
|
+
src: string,
|
|
20
|
+
babelConfig: babel.TransformOptions,
|
|
21
|
+
{ hermesParser }: { hermesParser?: boolean }
|
|
22
|
+
) {
|
|
23
|
+
const isTypeScript =
|
|
24
|
+
isTypeScriptSource(babelConfig.filename!) || isTSXSource(babelConfig.filename!);
|
|
25
|
+
|
|
26
|
+
if (isTypeScript) {
|
|
27
|
+
return parseWithBabel(src, babelConfig);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (
|
|
31
|
+
!isTypeScript &&
|
|
32
|
+
// The Hermes parser doesn't support comments or babel proposals such as export default from, meaning it has lower compatibility with larger parts
|
|
33
|
+
// of the ecosystem.
|
|
34
|
+
// However, React Native ships with flow syntax that isn't supported in Babel so we need to use Hermes for those files.
|
|
35
|
+
// We can try to quickly detect if the file uses flow syntax by checking for the @flow pragma which is present in every React Native file.
|
|
36
|
+
(hermesParser || src.includes(' @flow'))
|
|
37
|
+
) {
|
|
38
|
+
return parseWithHermes(src, babelConfig);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return parseWithBabel(src, babelConfig);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function parseWithHermes(src: string, babelConfig: babel.TransformOptions) {
|
|
45
|
+
const sourceAst = require('hermes-parser').parse(src, {
|
|
46
|
+
babel: true,
|
|
47
|
+
sourceType: babelConfig.sourceType,
|
|
48
|
+
});
|
|
49
|
+
return babel.transformFromAstSync(sourceAst, src, babelConfig);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function parseWithBabel(src: string, babelConfig: babel.TransformOptions) {
|
|
53
|
+
return babel.transformSync(src, babelConfig);
|
|
54
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// For Metro and Expo, we only import types here.
|
|
2
|
+
// We use `projectImport` to dynamically import the actual modules
|
|
3
|
+
// at runtime to ensure they are loaded from the user's project root.
|
|
4
|
+
import type { TerminalReporter as TerminalReporterT, Terminal as TerminalT } from 'metro'
|
|
5
|
+
import colors from 'picocolors'
|
|
6
|
+
|
|
7
|
+
import { projectImport } from './projectImport'
|
|
8
|
+
|
|
9
|
+
export async function getTerminalReporter(projectRoot: string) {
|
|
10
|
+
const { Terminal, TerminalReporter } = await projectImport<{
|
|
11
|
+
Terminal: typeof TerminalT
|
|
12
|
+
TerminalReporter: typeof TerminalReporterT
|
|
13
|
+
}>(projectRoot, 'metro')
|
|
14
|
+
|
|
15
|
+
let metroWelcomeMessagePrinted = false
|
|
16
|
+
|
|
17
|
+
const terminal = new Terminal(process.stdout)
|
|
18
|
+
;(terminal as any)._log = terminal.log
|
|
19
|
+
terminal.log = (message, ...rest) => {
|
|
20
|
+
// Minimal Metro welcome message.
|
|
21
|
+
// See: https://github.com/facebook/metro/blob/v0.82.4/packages/metro/src/lib/TerminalReporter.js#L278-L283
|
|
22
|
+
if (!metroWelcomeMessagePrinted) {
|
|
23
|
+
const match = message.match(/Welcome to Metro.+v(\d+\.\d+\.\d+)/)
|
|
24
|
+
if (match) {
|
|
25
|
+
const version = match[1]
|
|
26
|
+
metroWelcomeMessagePrinted = true
|
|
27
|
+
return (terminal as any)._log(colors.dim(`\n Using Metro Bundler v${version}`), ...rest)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (terminal as any)._log(message, ...rest)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// See: https://github.com/facebook/metro/blob/v0.82.4/packages/metro/src/lib/TerminalReporter.js
|
|
35
|
+
const terminalReporter = new TerminalReporter(terminal)
|
|
36
|
+
|
|
37
|
+
// Do not print a giant Metro logo on start.
|
|
38
|
+
// See: https://github.com/facebook/metro/blob/v0.82.4/packages/metro/src/lib/TerminalReporter.js#L230-L232
|
|
39
|
+
;(terminalReporter as any)._logInitializing = () => {}
|
|
40
|
+
|
|
41
|
+
return terminalReporter
|
|
42
|
+
}
|