expo-desktop 0.1.19 → 0.1.23
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.
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import
|
|
4
|
+
import process from "node:process";
|
|
5
5
|
import readline from "node:readline";
|
|
6
6
|
import { stripVTControlCharacters } from "node:util";
|
|
7
7
|
/**
|
|
8
8
|
* Clack {@link Task} that runs a subprocess; piped stdout/stderr lines are sent
|
|
9
|
-
* through the task `message` callback (not `log.message`). Lines are also kept
|
|
10
|
-
* an interleaved buffer; on failure they are written under
|
|
11
|
-
* {@link SpawnOptions.cwd} or the current working
|
|
9
|
+
* through the task `message` callback (not `log.message`). Lines are also kept
|
|
10
|
+
* in an interleaved buffer; on failure they are written under
|
|
11
|
+
* {@link debugLogDir} or {@link SpawnOptions.cwd} or the current working
|
|
12
|
+
* directory.
|
|
12
13
|
*/
|
|
13
14
|
export function promisifiedSpawnTask({ title, command, args, options = {}, debugLogDir, }) {
|
|
14
15
|
return {
|
|
@@ -16,7 +17,16 @@ export function promisifiedSpawnTask({ title, command, args, options = {}, debug
|
|
|
16
17
|
task: (message) => runPromisifiedSpawn({
|
|
17
18
|
command,
|
|
18
19
|
args,
|
|
19
|
-
options
|
|
20
|
+
options: {
|
|
21
|
+
// On Windows, Volta-managed package managers are spawned via .cmd
|
|
22
|
+
// shims which require shell interpretation. Although I've been having
|
|
23
|
+
// luck with `shell: false` with Volta-managed package managers on
|
|
24
|
+
// macOS, I'd rather just go with one consistent approach across all
|
|
25
|
+
// platforms, and `shell: true` will tend to reduce surprises.
|
|
26
|
+
// https://github.com/shirakaba/expo-desktop/issues/4
|
|
27
|
+
shell: true,
|
|
28
|
+
...options,
|
|
29
|
+
},
|
|
20
30
|
logLine: message,
|
|
21
31
|
...(debugLogDir !== undefined ? { debugLogDir } : {}),
|
|
22
32
|
}),
|
|
@@ -129,7 +139,7 @@ function envWithForcedColorIfPiped(options) {
|
|
|
129
139
|
const stdoutMode = Array.isArray(stdio) ? stdio.at(1) : stdio;
|
|
130
140
|
const stderrMode = Array.isArray(stdio) ? stdio.at(2) : stdio;
|
|
131
141
|
const capturesOutput = stdoutMode !== "inherit" || stderrMode !== "inherit";
|
|
132
|
-
const base = { ...env, ...options?.env };
|
|
142
|
+
const base = { ...process.env, ...options?.env };
|
|
133
143
|
if (!capturesOutput || base.NO_COLOR !== undefined) {
|
|
134
144
|
return base;
|
|
135
145
|
}
|
|
@@ -87,11 +87,20 @@ export async function createExpoDesktopApp({ localDev, name, packageManager, tem
|
|
|
87
87
|
title("Installing Cocoapods for the macOS app…", { spacing: 1 });
|
|
88
88
|
await podInstall({ projectPath, type: "macos" });
|
|
89
89
|
}
|
|
90
|
+
// react-native config seems to return `windows: null` on non-Windows
|
|
91
|
+
// platforms (while returning a populated object for Windows). If you force it
|
|
92
|
+
// to non-null for development on macOS, macOS runs the autolinking command
|
|
93
|
+
// successfully but writes out erroneous output, so
|
|
94
|
+
// there's no point.
|
|
95
|
+
if (platform === "win32") {
|
|
96
|
+
title("Autolinking the Windows app…", { spacing: 1 });
|
|
97
|
+
await autolinkWindows({ projectPath });
|
|
98
|
+
}
|
|
90
99
|
title("Adding Expo support to the Metro config…", { spacing: 1 });
|
|
91
100
|
await improveMetroConfig({ projectPath });
|
|
101
|
+
await addWindowsExpoPolyfill({ projectPath });
|
|
92
102
|
title("Adding Expo support to the Babel config…", { spacing: 1 });
|
|
93
103
|
await writeBabelConfig({ projectPath });
|
|
94
|
-
// TODO: Set up Windows app.cpp entrypoint
|
|
95
104
|
}
|
|
96
105
|
async function createExpoApp({ localDev, name, packageManager, versions, }) {
|
|
97
106
|
// `create-expo-app` aggravatingly reconfigures your workspace to use
|
|
@@ -249,19 +258,24 @@ async function updatePackageJson({ localDev, name, projectPath, task, versions,
|
|
|
249
258
|
}
|
|
250
259
|
packageJson.scripts.macos = "rnc-cli run-macos";
|
|
251
260
|
packageJson.scripts.windows = "rnc-cli run-windows";
|
|
261
|
+
packageJson.scripts["autolink-windows"] = "react-native autolink-windows";
|
|
252
262
|
}
|
|
253
263
|
else {
|
|
254
264
|
if (!packageJson.dependencies) {
|
|
255
265
|
packageJson.dependencies = {};
|
|
256
266
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
267
|
+
const monorepoDeps = {
|
|
268
|
+
// expo-desktop-prebuild-config itself depends on
|
|
269
|
+
// expo-desktop-config-plugins.
|
|
270
|
+
["expo-desktop-prebuild-config"]: "^1.0.0",
|
|
271
|
+
["expo-desktop-modules-core"]: `^${versions.expoMajor}.0.0`,
|
|
272
|
+
["expo-desktop-stubs"]: `^${versions.expoMajor}.0.0`,
|
|
273
|
+
};
|
|
274
|
+
for (const [key, value] of Object.entries(monorepoDeps)) {
|
|
275
|
+
// TODO: Try replacing this `localDev` logic with `linkWorkspacePackages`:
|
|
276
|
+
// - https://pnpm.io/workspaces#linkworkspacepackages
|
|
277
|
+
// - https://pnpm.io/workspaces#workspace-protocol-workspace
|
|
278
|
+
packageJson.dependencies[key] = localDev ? `file:../../${key}` : value;
|
|
265
279
|
}
|
|
266
280
|
packageJson.dependencies["react-native-macos"] = versions.macos;
|
|
267
281
|
packageJson.dependencies["react-native-windows"] = versions.windows;
|
|
@@ -428,6 +442,27 @@ async function podInstall({ projectPath, type }) {
|
|
|
428
442
|
}
|
|
429
443
|
console.log(`\n${green("◆")} Installed Cocoapods for the ${type === "ios" ? "iOS" : "macOS"} app.\n`);
|
|
430
444
|
}
|
|
445
|
+
async function autolinkWindows({ projectPath }) {
|
|
446
|
+
const command = "node";
|
|
447
|
+
const args = ["--run", "autolink-windows"];
|
|
448
|
+
const printedCommand = `${command} ${args.join(" ")}`;
|
|
449
|
+
console.log(`${cyan("◆")} Running: ${yellow(printedCommand)}\n`);
|
|
450
|
+
try {
|
|
451
|
+
await tasks([
|
|
452
|
+
promisifiedSpawnTask({
|
|
453
|
+
title: "react-native autolink-windows",
|
|
454
|
+
command,
|
|
455
|
+
args,
|
|
456
|
+
options: { cwd: projectPath, stdio: "inherit" },
|
|
457
|
+
}),
|
|
458
|
+
]);
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
log.error(`Error running ${yellow(printedCommand)}${error instanceof Error ? `: ${error.message}` : "."}`);
|
|
462
|
+
process.exit(1);
|
|
463
|
+
}
|
|
464
|
+
console.log(`\n${green("◆")} Autolinked the Windows app.\n`);
|
|
465
|
+
}
|
|
431
466
|
async function improveMetroConfig({ projectPath }) {
|
|
432
467
|
const metroConfigPath = path.resolve(projectPath, "metro.config.js");
|
|
433
468
|
console.log(`${cyan("◆")} Overwriting metro.config.js…\n`);
|
|
@@ -437,6 +472,17 @@ const { getDefaultConfig } = require("@expo/metro-config");
|
|
|
437
472
|
const { makeMetroConfig } = require("@rnx-kit/metro-config");
|
|
438
473
|
|
|
439
474
|
const config = makeMetroConfig(getDefaultConfig(__dirname));
|
|
475
|
+
|
|
476
|
+
const getPolyfills = config.serializer.getPolyfills;
|
|
477
|
+
const windowsExpoPolyfill = require.resolve("./expo-polyfill.windows.js");
|
|
478
|
+
config.serializer.getPolyfills = (platform) => {
|
|
479
|
+
const polyfills = getPolyfills(platform);
|
|
480
|
+
if (platform === "windows") {
|
|
481
|
+
polyfills.push(windowsExpoPolyfill);
|
|
482
|
+
}
|
|
483
|
+
return polyfills;
|
|
484
|
+
};
|
|
485
|
+
|
|
440
486
|
module.exports = config;
|
|
441
487
|
`.trim() + "\n", "utf-8");
|
|
442
488
|
}
|
|
@@ -446,6 +492,69 @@ module.exports = config;
|
|
|
446
492
|
}
|
|
447
493
|
console.log(`\n${green("◆")} Overwrote metro.config.js.\n`);
|
|
448
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
*/
|
|
497
|
+
async function addWindowsExpoPolyfill({ projectPath }) {
|
|
498
|
+
await fs.writeFile(path.resolve(projectPath, "expo-polyfill.windows.js"), `
|
|
499
|
+
try {
|
|
500
|
+
// Until we can configure TurboModules for eager initialisation (which is
|
|
501
|
+
// waiting on https://github.com/microsoft/react-native-windows/pull/16093), we
|
|
502
|
+
// need to trigger the lazy-init of our TurboModule by accessing it for the
|
|
503
|
+
// first time, which causes the TurboModuleManager to call its REACT_INIT
|
|
504
|
+
// method.
|
|
505
|
+
//
|
|
506
|
+
// We can't do any imports inside getPolyfills(), but can use the global proxy:
|
|
507
|
+
globalThis.nativeModuleProxy.ExpoMainRuntimeInstaller;
|
|
508
|
+
|
|
509
|
+
// TODO: Implement Expo's NativeModulesProxy and make all of this
|
|
510
|
+
// lazy-initialised (and actually populate \`exportedMethods\`, etc.).
|
|
511
|
+
|
|
512
|
+
// Below are temporary stubs to suppress these warnings:
|
|
513
|
+
// WARN The "EXNativeModulesProxy" native module is not exported through NativeModules; verify that expo-modules-core's native code is linked properly
|
|
514
|
+
// WARN No native ExponentConstants module found, are you sure the expo-constants's module is linked properly?
|
|
515
|
+
// WARN No native ExponentConstants module found, are you sure the expo-constants's module is linked properly?
|
|
516
|
+
|
|
517
|
+
// Funnily enough, although expo-modules-core prefers to access
|
|
518
|
+
// global.expo?.modules?.NativeModulesProxy over the deprecated
|
|
519
|
+
// NativeModules?.NativeUnimoduleProxy, we still need the latter to exist in
|
|
520
|
+
// order for it to check the former. And it's only
|
|
521
|
+
globalThis.nativeModuleProxy.NativeUnimoduleProxy;
|
|
522
|
+
const { ExpoAsset } = globalThis.nativeModuleProxy;
|
|
523
|
+
|
|
524
|
+
const ExponentConstants = {};
|
|
525
|
+
|
|
526
|
+
globalThis.expo.modules = {
|
|
527
|
+
ExpoAsset,
|
|
528
|
+
ExponentConstants,
|
|
529
|
+
// - JS: apps/demo/node_modules/expo-modules-core/src/NativeModulesProxy.native.ts
|
|
530
|
+
// - iOS:
|
|
531
|
+
// - NativeUnimoduleProxy: apps/demo/node_modules/expo-modules-core/ios/Legacy/NativeModulesProxy/NativeModulesProxyModule.swift
|
|
532
|
+
// - NativeModulesProxy: apps/demo/node_modules/expo-modules-core/ios/Legacy/NativeModulesProxy/EXNativeModulesProxy.mm
|
|
533
|
+
// - Android:
|
|
534
|
+
// - NativeUnimoduleProxy: apps/demo/node_modules/expo-modules-core/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java
|
|
535
|
+
// - NativeModulesProxy: apps/demo/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/defaultmodules/NativeModulesProxyModule.kt
|
|
536
|
+
NativeModulesProxy: {
|
|
537
|
+
exportedMethods: {
|
|
538
|
+
ExpoAsset: [],
|
|
539
|
+
ExponentConstants: [],
|
|
540
|
+
},
|
|
541
|
+
modulesConstants: {
|
|
542
|
+
ExpoAsset: [],
|
|
543
|
+
ExponentConstants: [],
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
// Now expo-modules-core can populate its fileprivate
|
|
549
|
+
// \`const NativeModulesProxy: Record<string, ProxyNativeModule = {}\` from our
|
|
550
|
+
// global.expo?.modules?.NativeModulesProxy. This avoids the warning about
|
|
551
|
+
// EXNativeModulesProxy being missing.
|
|
552
|
+
} catch (error) {
|
|
553
|
+
console.error("Polyfill failed", error);
|
|
554
|
+
throw error;
|
|
555
|
+
}
|
|
556
|
+
`.trim() + "\n", "utf-8");
|
|
557
|
+
}
|
|
449
558
|
async function updatePodfile({ projectPath }) {
|
|
450
559
|
const appJsonPath = path.resolve(projectPath, "macos/Podfile");
|
|
451
560
|
let contents;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-desktop",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"description": "Best-effort desktop support for Expo",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"android",
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"@clack/prompts": "^1.2.0",
|
|
38
38
|
"arktype": "^2.2.0",
|
|
39
39
|
"citty": "^0.2.2",
|
|
40
|
+
"expo-desktop-config-plugins": "^1.1.22",
|
|
41
|
+
"expo-desktop-prebuild-config": "^1.0.11",
|
|
40
42
|
"glob": "^10.5.0",
|
|
41
43
|
"kleur": "^4.1.5",
|
|
42
44
|
"mustache": "^4.2.0",
|
|
43
|
-
"toml": "^4.1.1"
|
|
44
|
-
"expo-desktop-config-plugins": "1.1.19",
|
|
45
|
-
"expo-desktop-prebuild-config": "1.0.8"
|
|
45
|
+
"toml": "^4.1.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@expo/config": "^12.0.13",
|