@expo/cli 54.0.10 → 54.1.0-canary-20251003-7b9d7ff
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/build/bin/cli +1 -1
- package/build/src/run/ios/runIosAsync.js +0 -8
- package/build/src/run/ios/runIosAsync.js.map +1 -1
- package/build/src/start/interface/cliExtensionMenuItemHandler.js +173 -0
- package/build/src/start/interface/cliExtensionMenuItemHandler.js.map +1 -0
- package/build/src/start/interface/createDevToolsMenuItems.js +159 -0
- package/build/src/start/interface/createDevToolsMenuItems.js.map +1 -0
- package/build/src/start/interface/interactiveActions.js +8 -12
- package/build/src/start/interface/interactiveActions.js.map +1 -1
- package/build/src/start/platforms/android/adb.js +1 -1
- package/build/src/start/platforms/android/adb.js.map +1 -1
- package/build/src/start/server/DevToolsPlugin.js +60 -0
- package/build/src/start/server/DevToolsPlugin.js.map +1 -0
- package/build/src/start/server/DevToolsPlugin.schema.js +79 -0
- package/build/src/start/server/DevToolsPlugin.schema.js.map +1 -0
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js +119 -0
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js.map +1 -0
- package/build/src/start/server/DevToolsPluginCliExtensionResults.js +61 -0
- package/build/src/start/server/DevToolsPluginCliExtensionResults.js.map +1 -0
- package/build/src/start/server/DevToolsPluginManager.js +4 -8
- package/build/src/start/server/DevToolsPluginManager.js.map +1 -1
- package/build/src/start/server/metro/MetroBundlerDevServer.js +125 -9
- package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
- package/build/src/start/server/metro/createServerRouteMiddleware.js +2 -2
- package/build/src/start/server/metro/createServerRouteMiddleware.js.map +1 -1
- package/build/src/start/server/middleware/DataLoaderModuleMiddleware.js +75 -0
- package/build/src/start/server/middleware/DataLoaderModuleMiddleware.js.map +1 -0
- package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
- package/build/src/utils/telemetry/utils/context.js +1 -1
- package/package.json +20 -20
|
@@ -108,6 +108,7 @@ const _BundlerDevServer = require("../BundlerDevServer");
|
|
|
108
108
|
const _getStaticRenderFunctions = require("../getStaticRenderFunctions");
|
|
109
109
|
const _ContextModuleSourceMapsMiddleware = require("../middleware/ContextModuleSourceMapsMiddleware");
|
|
110
110
|
const _CreateFileMiddleware = require("../middleware/CreateFileMiddleware");
|
|
111
|
+
const _DataLoaderModuleMiddleware = require("../middleware/DataLoaderModuleMiddleware");
|
|
111
112
|
const _DevToolsPluginMiddleware = require("../middleware/DevToolsPluginMiddleware");
|
|
112
113
|
const _DomComponentsMiddleware = require("../middleware/DomComponentsMiddleware");
|
|
113
114
|
const _FaviconMiddleware = require("../middleware/FaviconMiddleware");
|
|
@@ -319,7 +320,9 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
319
320
|
})
|
|
320
321
|
};
|
|
321
322
|
}
|
|
322
|
-
|
|
323
|
+
/**
|
|
324
|
+
* This function is invoked when exporting via `expo export`
|
|
325
|
+
*/ async getStaticRenderFunctionAsync() {
|
|
323
326
|
var _exp_extra, _exp_extra1;
|
|
324
327
|
const url = this.getDevServerUrlOrAssert();
|
|
325
328
|
const { getStaticContent, getManifest, getBuildTimeServerManifestAsync } = await this.ssrLoadModule('expo-router/node/render.js', {
|
|
@@ -328,10 +331,11 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
328
331
|
environment: 'node'
|
|
329
332
|
});
|
|
330
333
|
const { exp } = (0, _config().getConfig)(this.projectRoot);
|
|
334
|
+
const serverManifest = await getBuildTimeServerManifestAsync({
|
|
335
|
+
...(_exp_extra = exp.extra) == null ? void 0 : _exp_extra.router
|
|
336
|
+
});
|
|
331
337
|
return {
|
|
332
|
-
serverManifest
|
|
333
|
-
...(_exp_extra = exp.extra) == null ? void 0 : _exp_extra.router
|
|
334
|
-
}),
|
|
338
|
+
serverManifest,
|
|
335
339
|
// Get routes from Expo Router.
|
|
336
340
|
manifest: await getManifest({
|
|
337
341
|
preserveApiRoutes: false,
|
|
@@ -367,7 +371,10 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
367
371
|
bytecode: false
|
|
368
372
|
});
|
|
369
373
|
}
|
|
370
|
-
|
|
374
|
+
/**
|
|
375
|
+
* This function is invoked when running in development via `expo start`
|
|
376
|
+
*/ async getStaticPageAsync(pathname, route) {
|
|
377
|
+
const { exp } = (0, _config().getConfig)(this.projectRoot);
|
|
371
378
|
const { mode, isExporting, clientBoundaries, baseUrl, reactCompiler, routerRoot, asyncRoutes } = this.instanceMetroOptions;
|
|
372
379
|
(0, _assert().default)(mode != null && isExporting != null && baseUrl != null && reactCompiler != null && routerRoot != null && asyncRoutes != null, 'The server must be started before calling getStaticPageAsync.');
|
|
373
380
|
const platform = 'web';
|
|
@@ -389,6 +396,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
389
396
|
bytecode: false
|
|
390
397
|
});
|
|
391
398
|
const bundleStaticHtml = async ()=>{
|
|
399
|
+
var _exp_extra_router, _exp_extra;
|
|
392
400
|
const { getStaticContent } = await this.ssrLoadModule('expo-router/node/render.js', {
|
|
393
401
|
// This must always use the legacy rendering resolution (no `react-server`) because it leverages
|
|
394
402
|
// the previous React SSG utilities which aren't available in React 19.
|
|
@@ -398,7 +406,17 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
398
406
|
platform
|
|
399
407
|
});
|
|
400
408
|
const location = new URL(pathname, this.getDevServerUrlOrAssert());
|
|
401
|
-
|
|
409
|
+
const useServerDataLoaders = (_exp_extra = exp.extra) == null ? void 0 : (_exp_extra_router = _exp_extra.router) == null ? void 0 : _exp_extra_router.unstable_useServerDataLoaders;
|
|
410
|
+
if (useServerDataLoaders) {
|
|
411
|
+
const data = await this.executeServerDataLoaderAsync(location, route);
|
|
412
|
+
return await getStaticContent(location, {
|
|
413
|
+
loader: {
|
|
414
|
+
data
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
} else {
|
|
418
|
+
return await getStaticContent(location);
|
|
419
|
+
}
|
|
402
420
|
};
|
|
403
421
|
const [{ artifacts: resources }, staticHtml] = await Promise.all([
|
|
404
422
|
this.getStaticResourcesAsync({
|
|
@@ -806,6 +824,14 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
806
824
|
middleware.use(new _CreateFileMiddleware.CreateFileMiddleware(this.projectRoot).getHandler());
|
|
807
825
|
// Append support for redirecting unhandled requests to the index.html page on web.
|
|
808
826
|
if (this.isTargetingWeb()) {
|
|
827
|
+
var _exp_extra_router1, _exp_extra2;
|
|
828
|
+
if ((_exp_extra2 = exp.extra) == null ? void 0 : (_exp_extra_router1 = _exp_extra2.router) == null ? void 0 : _exp_extra_router1.unstable_useServerDataLoaders) {
|
|
829
|
+
const loaderModuleMiddleware = new _DataLoaderModuleMiddleware.DataLoaderModuleMiddleware(this.projectRoot, appDir, async (location, route)=>{
|
|
830
|
+
return this.executeServerDataLoaderAsync(location, route);
|
|
831
|
+
}, ()=>this.getDevServerUrlOrAssert());
|
|
832
|
+
// This MUST be before ServeStaticMiddleware so it doesn't treat the loader files as static assets
|
|
833
|
+
middleware.use(loaderModuleMiddleware.getHandler());
|
|
834
|
+
}
|
|
809
835
|
// This MUST be after the manifest middleware so it doesn't have a chance to serve the template `public/index.html`.
|
|
810
836
|
middleware.use(new _ServeStaticMiddleware.ServeStaticMiddleware(this.projectRoot).getHandler());
|
|
811
837
|
// This should come after the static middleware so it doesn't serve the favicon from `public/favicon.ico`.
|
|
@@ -816,6 +842,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
816
842
|
metro,
|
|
817
843
|
server
|
|
818
844
|
}, (events)=>{
|
|
845
|
+
var _exp_extra_router, _exp_extra;
|
|
819
846
|
if (hasApiRoutes) {
|
|
820
847
|
// NOTE(EvanBacon): We aren't sure what files the API routes are using so we'll just invalidate
|
|
821
848
|
// aggressively to ensure we always have the latest. The only caching we really get here is for
|
|
@@ -834,6 +861,15 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
834
861
|
}
|
|
835
862
|
}
|
|
836
863
|
}
|
|
864
|
+
// Handle loader file changes for HMR
|
|
865
|
+
if ((_exp_extra = exp.extra) == null ? void 0 : (_exp_extra_router = _exp_extra.router) == null ? void 0 : _exp_extra_router.unstable_useServerDataLoaders) {
|
|
866
|
+
for (const event of events){
|
|
867
|
+
var _event_metadata1;
|
|
868
|
+
if (((_event_metadata1 = event.metadata) == null ? void 0 : _event_metadata1.type) !== 'd') {
|
|
869
|
+
this.handleLoaderFileChange(event.filePath);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
837
873
|
});
|
|
838
874
|
}
|
|
839
875
|
// If React 19 is enabled, then add RSC middleware to the dev server.
|
|
@@ -867,7 +903,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
867
903
|
bundleApiRoute: (functionFilePath)=>this.ssrImportApiRoute(functionFilePath, {
|
|
868
904
|
platform: 'web'
|
|
869
905
|
}),
|
|
870
|
-
getStaticPageAsync: async (pathname)=>{
|
|
906
|
+
getStaticPageAsync: async (pathname, route)=>{
|
|
871
907
|
// TODO: Add server rendering when RSC is enabled.
|
|
872
908
|
if (isReactServerComponentsEnabled) {
|
|
873
909
|
// NOTE: This is a temporary hack to return the SPA/template index.html in development when RSC is enabled.
|
|
@@ -878,7 +914,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
878
914
|
};
|
|
879
915
|
}
|
|
880
916
|
// Non-RSC apps will bundle the static HTML for a given pathname and respond with it.
|
|
881
|
-
return this.getStaticPageAsync(pathname);
|
|
917
|
+
return this.getStaticPageAsync(pathname, route);
|
|
882
918
|
}
|
|
883
919
|
}));
|
|
884
920
|
}
|
|
@@ -1112,6 +1148,62 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1112
1148
|
invalidateApiRouteCache() {
|
|
1113
1149
|
this.pendingRouteOperations.clear();
|
|
1114
1150
|
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Execute a route's loader function. Used during SSR/SSG to fetch data required by routes.
|
|
1153
|
+
*
|
|
1154
|
+
* This function is used during development and production builds, and **must** receive a valid
|
|
1155
|
+
* matched route.
|
|
1156
|
+
*
|
|
1157
|
+
* @experimental
|
|
1158
|
+
*/ async executeServerDataLoaderAsync(location, route) {
|
|
1159
|
+
var _exp_extra;
|
|
1160
|
+
const { exp } = (0, _config().getConfig)(this.projectRoot);
|
|
1161
|
+
const { unstable_useServerDataLoaders } = (_exp_extra = exp.extra) == null ? void 0 : _exp_extra.router;
|
|
1162
|
+
if (!unstable_useServerDataLoaders) {
|
|
1163
|
+
throw new _errors.CommandError('LOADERS_NOT_ENABLED', 'Server data loaders are not enabled. Add `unstable_useServerDataLoaders` to your `expo-router` plugin config.');
|
|
1164
|
+
}
|
|
1165
|
+
// If the route is unmatched, we can ignore it
|
|
1166
|
+
// TODO(@hassankhan): Is this the best way of determining the route is unmatched?
|
|
1167
|
+
if (route.page === '/+not-found') {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const { routerRoot } = this.instanceMetroOptions;
|
|
1171
|
+
(0, _assert().default)(routerRoot != null, 'The server must be started before calling executeRouteLoaderAsync.');
|
|
1172
|
+
let loaderData;
|
|
1173
|
+
try {
|
|
1174
|
+
debug('Matched route loader to file: ', route.file);
|
|
1175
|
+
// TODO(@hassankhan): This should move to a util function
|
|
1176
|
+
const params = {};
|
|
1177
|
+
const match = route.namedRegex.exec(location.pathname);
|
|
1178
|
+
if (match == null ? void 0 : match.groups) {
|
|
1179
|
+
for (const [key, value] of Object.entries(match.groups)){
|
|
1180
|
+
const namedKey = route.routeKeys[key];
|
|
1181
|
+
params[namedKey] = value;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
let modulePath = route.file;
|
|
1185
|
+
const appDir = _path().default.join(this.projectRoot, routerRoot);
|
|
1186
|
+
modulePath = _path().default.isAbsolute(modulePath) ? modulePath : _path().default.join(appDir, modulePath);
|
|
1187
|
+
modulePath = modulePath.replace(/\.(js|ts)x?$/, '');
|
|
1188
|
+
debug('Using loader module path: ', modulePath);
|
|
1189
|
+
const routeModule = await this.ssrLoadModule(modulePath, {
|
|
1190
|
+
environment: 'node'
|
|
1191
|
+
});
|
|
1192
|
+
if (routeModule.loader) {
|
|
1193
|
+
// Register this module for loader HMR
|
|
1194
|
+
this.setupLoaderHmr(modulePath);
|
|
1195
|
+
loaderData = await routeModule.loader({
|
|
1196
|
+
params,
|
|
1197
|
+
// NOTE(@hassankhan): The `request` object should only be available when using SSR
|
|
1198
|
+
request: null
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
} catch (error) {
|
|
1202
|
+
throw new _errors.CommandError('LOADER_EXECUTION_FAILED', `Failed to execute loader for route "${location.pathname}": ${error.message}`);
|
|
1203
|
+
}
|
|
1204
|
+
debug('Loader data:', loaderData, ' for location:', location.pathname);
|
|
1205
|
+
return loaderData;
|
|
1206
|
+
}
|
|
1115
1207
|
// Ensure the global is available for SSR CSS modules to inject client updates.
|
|
1116
1208
|
bindRSCDevModuleInjectionHandler() {
|
|
1117
1209
|
// Used by SSR CSS modules to broadcast client updates.
|
|
@@ -1150,6 +1242,30 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1150
1242
|
};
|
|
1151
1243
|
this.registerSsrHmrAsync(url.toString(), onReload);
|
|
1152
1244
|
}
|
|
1245
|
+
setupLoaderHmr(modulePath) {
|
|
1246
|
+
if (this.watchedLoaderFiles.has(modulePath)) {
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
this.watchedLoaderFiles.add(modulePath);
|
|
1250
|
+
debug('[Loader HMR] Registering loader file for HMR:', modulePath);
|
|
1251
|
+
}
|
|
1252
|
+
handleLoaderFileChange(changedFilePath) {
|
|
1253
|
+
for (const loaderPath of this.watchedLoaderFiles){
|
|
1254
|
+
const possibleExtensions = [
|
|
1255
|
+
'.tsx',
|
|
1256
|
+
'.ts',
|
|
1257
|
+
'.jsx',
|
|
1258
|
+
'.js'
|
|
1259
|
+
];
|
|
1260
|
+
const isLoaderFile = possibleExtensions.some((ext)=>changedFilePath === loaderPath + ext || changedFilePath === loaderPath);
|
|
1261
|
+
if (isLoaderFile) {
|
|
1262
|
+
debug('[Loader HMR] Loader file changed, triggering reload:', changedFilePath);
|
|
1263
|
+
this.broadcastMessage('sendDevCommand', {
|
|
1264
|
+
name: 'reload'
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1153
1269
|
// Direct Metro access
|
|
1154
1270
|
// Emulates the Metro dev server .bundle endpoint without having to go through a server.
|
|
1155
1271
|
async _bundleDirectAsync(resolvedEntryFilePath, { transformOptions, resolverOptions, graphOptions, serializerOptions }) {
|
|
@@ -1367,7 +1483,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1367
1483
|
}
|
|
1368
1484
|
return (0, _getStaticRenderFunctions.evalMetroAndWrapFunctions)(this.projectRoot, res.src, res.filename, specificOptions.isExporting ?? this.instanceMetroOptions.isExporting);
|
|
1369
1485
|
}, this.rscRenderer = null, this.onReloadRscEvent = null, // API Routes
|
|
1370
|
-
this.pendingRouteOperations = new Map();
|
|
1486
|
+
this.pendingRouteOperations = new Map(), this.watchedLoaderFiles = new Set();
|
|
1371
1487
|
}
|
|
1372
1488
|
}
|
|
1373
1489
|
function getBuildID(buildNumber) {
|