@backtickjs/expo 0.2.2 → 0.2.4
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/README.md +15 -1
- package/dist/app.plugin.d.ts +15 -0
- package/dist/app.plugin.js +24 -0
- package/dist/app.plugin.js.map +1 -0
- package/dist/plugin.d.ts +12 -12
- package/dist/plugin.js +32 -18
- package/dist/plugin.js.map +1 -1
- package/package.json +11 -4
- package/src/app.plugin.ts +35 -0
- package/src/plugin.ts +44 -28
- package/app.plugin.js +0 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @backtickjs/expo
|
|
2
2
|
|
|
3
|
-
[Backtick](https://backtickjs.com) for Expo apps: a config plugin that records the versions your app is built with, so it can tell your server which modules it carries
|
|
3
|
+
[Backtick](https://backtickjs.com) for Expo apps: a config plugin that records the versions your app is built with, so it can tell your server which modules it carries; a compile step that writes your scripts as Expo writes your app's own code; and a call that reloads the app when your server restarts in development.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -42,10 +42,24 @@ serve({ fetch: app.fetch, port: 3000 }, () => reloadExpo());
|
|
|
42
42
|
|
|
43
43
|
Without Expo running, as on a deployed server, it does nothing.
|
|
44
44
|
|
|
45
|
+
**Your scripts are compiled as Expo compiles your app's own code**, by its Babel preset for Hermes, after your framework's compile step. Hermes V1 has bugs Expo works around in your app's code, as an async arrow with a default parameter losing its first `await`; your scripts get the same workarounds:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
// package.json
|
|
49
|
+
{
|
|
50
|
+
"backtick": {
|
|
51
|
+
"plugins": ["@backtickjs/jsx-react/plugin", "@backtickjs/expo/plugin"]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
A script is compiled once for every client, so it isn't told which platform it's for: `process.env.EXPO_OS` is `null` in one. Use `Platform.OS`.
|
|
57
|
+
|
|
45
58
|
## API
|
|
46
59
|
|
|
47
60
|
- `@backtickjs/expo` in `app.json`'s `plugins`: the config plugin, which sets `extra.backtick.installedPackages` to `installedPackages(projectRoot)` from `@backtickjs/core/node`.
|
|
48
61
|
- `getBacktickExtra(expoConfig)`: what the plugin recorded, `{ installedPackages }`, from `Constants.expoConfig`. Throws as the app starts if the plugin isn't in `app.json`.
|
|
62
|
+
- `@backtickjs/expo/plugin` in `package.json`'s `backtick.plugins`: the compile step, Expo's Babel preset for Hermes, from the app's own `expo`.
|
|
49
63
|
- `reloadExpo(port?)`, from `@backtickjs/expo/server`: reloads the apps Expo serves, as pressing `r` in its terminal does. `port` is Expo's, 8081 or `RCT_METRO_PORT` by default.
|
|
50
64
|
|
|
51
65
|
## Related
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type ExpoConfig = {
|
|
2
|
+
extra?: Record<string, unknown>;
|
|
3
|
+
_internal?: {
|
|
4
|
+
projectRoot?: string;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* The config plugin, as `"plugins": ["@backtickjs/expo"]` in app.json: puts
|
|
9
|
+
* the installed version of each of the app's dependencies in the config,
|
|
10
|
+
* `extra.backtick.installedPackages`, which `getBacktickExtra` reads.
|
|
11
|
+
*/
|
|
12
|
+
export default function withBacktickExtra<Config extends ExpoConfig>(config: Config): Config & {
|
|
13
|
+
extra: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { installedPackages } from "@backtickjs/core/node";
|
|
2
|
+
/**
|
|
3
|
+
* The config plugin, as `"plugins": ["@backtickjs/expo"]` in app.json: puts
|
|
4
|
+
* the installed version of each of the app's dependencies in the config,
|
|
5
|
+
* `extra.backtick.installedPackages`, which `getBacktickExtra` reads.
|
|
6
|
+
*/
|
|
7
|
+
export default function withBacktickExtra(config) {
|
|
8
|
+
const projectRoot = config._internal?.projectRoot;
|
|
9
|
+
if (projectRoot === undefined) {
|
|
10
|
+
throw new Error("@backtickjs/expo: Expo gave the config no projectRoot.");
|
|
11
|
+
}
|
|
12
|
+
const backtick = config.extra?.backtick;
|
|
13
|
+
return {
|
|
14
|
+
...config,
|
|
15
|
+
extra: {
|
|
16
|
+
...config.extra,
|
|
17
|
+
backtick: {
|
|
18
|
+
...backtick,
|
|
19
|
+
installedPackages: installedPackages(projectRoot),
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=app.plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.plugin.js","sourceRoot":"","sources":["../src/app.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAS1D;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACvC,MAAc;IAEd,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC;IAClD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,EAAE,QAElB,CAAC;IACd,OAAO;QACL,GAAG,MAAM;QACT,KAAK,EAAE;YACL,GAAG,MAAM,CAAC,KAAK;YACf,QAAQ,EAAE;gBACR,GAAG,QAAQ;gBACX,iBAAiB,EAAE,iBAAiB,CAAC,WAAW,CAAC;aAClD;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
type ExpoConfig = {
|
|
2
|
-
extra?: Record<string, unknown>;
|
|
3
|
-
_internal?: {
|
|
4
|
-
projectRoot?: string;
|
|
5
|
-
};
|
|
6
|
-
};
|
|
7
1
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
2
|
+
* Expo's Babel preset as a build's compile step, after the framework's:
|
|
3
|
+
* each script as Metro compiles the app's own code for Hermes, so a script
|
|
4
|
+
* gets what Expo works around in Hermes V1, as an async arrow with a default
|
|
5
|
+
* parameter losing its first `await`. Babel and the preset are the ones the
|
|
6
|
+
* app's own `expo` brings. A script is compiled once for every client, so no
|
|
7
|
+
* platform is given: `process.env.EXPO_OS` is `null` in one, and
|
|
8
|
+
* `Platform.OS` says the platform.
|
|
9
|
+
*
|
|
10
|
+
* Listed in `package.json`: `"backtick": { "plugins": ["@backtickjs/jsx-react/plugin", "@backtickjs/expo/plugin"] }`.
|
|
11
11
|
*/
|
|
12
|
-
export default function
|
|
13
|
-
|
|
12
|
+
export default function expo(): (code: string, id: string) => {
|
|
13
|
+
code: string;
|
|
14
|
+
map: string;
|
|
14
15
|
};
|
|
15
|
-
export {};
|
package/dist/plugin.js
CHANGED
|
@@ -1,24 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Expo's Babel preset as a build's compile step, after the framework's:
|
|
4
|
+
* each script as Metro compiles the app's own code for Hermes, so a script
|
|
5
|
+
* gets what Expo works around in Hermes V1, as an async arrow with a default
|
|
6
|
+
* parameter losing its first `await`. Babel and the preset are the ones the
|
|
7
|
+
* app's own `expo` brings. A script is compiled once for every client, so no
|
|
8
|
+
* platform is given: `process.env.EXPO_OS` is `null` in one, and
|
|
9
|
+
* `Platform.OS` says the platform.
|
|
10
|
+
*
|
|
11
|
+
* Listed in `package.json`: `"backtick": { "plugins": ["@backtickjs/jsx-react/plugin", "@backtickjs/expo/plugin"] }`.
|
|
6
12
|
*/
|
|
7
|
-
export default function
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
export default function expo() {
|
|
14
|
+
const fromExpo = createRequire(createRequire(import.meta.url).resolve("expo/package.json"));
|
|
15
|
+
const preset = fromExpo.resolve("babel-preset-expo");
|
|
16
|
+
const babel = createRequire(preset)("@babel/core");
|
|
17
|
+
return (code, id) => {
|
|
18
|
+
const compiled = babel.transformSync(code, {
|
|
19
|
+
filename: id,
|
|
20
|
+
babelrc: false,
|
|
21
|
+
configFile: false,
|
|
22
|
+
// readable, as the framework's step left it
|
|
23
|
+
compact: false,
|
|
24
|
+
comments: true,
|
|
25
|
+
sourceMaps: true,
|
|
26
|
+
// the module's imports kept, for the compiler to find
|
|
27
|
+
presets: [[preset, { disableImportExportTransform: true }]],
|
|
28
|
+
caller: {
|
|
29
|
+
name: "metro",
|
|
30
|
+
bundler: "metro",
|
|
31
|
+
engine: "hermes",
|
|
32
|
+
supportsStaticESM: true,
|
|
20
33
|
},
|
|
21
|
-
}
|
|
34
|
+
});
|
|
35
|
+
return { code: compiled.code, map: JSON.stringify(compiled.map) };
|
|
22
36
|
};
|
|
23
37
|
}
|
|
24
38
|
//# sourceMappingURL=plugin.js.map
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAU5C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,UAAU,IAAI;IAI1B,MAAM,QAAQ,GAAG,aAAa,CAC5B,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAC5D,CAAC;IACF,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,aAAa,CAAU,CAAC;IAC5D,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE;QAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE;YACzC,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,KAAK;YACjB,4CAA4C;YAC5C,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,IAAI;YACd,UAAU,EAAE,IAAI;YAChB,sDAAsD;YACtD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,4BAA4B,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,MAAM,EAAE;gBACN,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,OAAO;gBAChB,MAAM,EAAE,QAAQ;gBAChB,iBAAiB,EAAE,IAAI;aACxB;SACF,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,QAAS,CAAC,IAAK,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,QAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IACvE,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backtickjs/expo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Backtick for Expo apps: the config plugin that records the app's installed packages, and reloading apps when the server restarts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"backtick",
|
|
@@ -29,10 +29,13 @@
|
|
|
29
29
|
"types": "./dist/server.d.ts",
|
|
30
30
|
"default": "./dist/server.js"
|
|
31
31
|
},
|
|
32
|
-
"./
|
|
32
|
+
"./plugin": {
|
|
33
|
+
"types": "./dist/plugin.d.ts",
|
|
34
|
+
"default": "./dist/plugin.js"
|
|
35
|
+
},
|
|
36
|
+
"./app.plugin": "./dist/app.plugin.js"
|
|
33
37
|
},
|
|
34
38
|
"files": [
|
|
35
|
-
"app.plugin.js",
|
|
36
39
|
"dist",
|
|
37
40
|
"!dist/._cache",
|
|
38
41
|
"src"
|
|
@@ -41,11 +44,15 @@
|
|
|
41
44
|
"access": "public"
|
|
42
45
|
},
|
|
43
46
|
"dependencies": {
|
|
44
|
-
"@backtickjs/core": "^0.2.
|
|
47
|
+
"@backtickjs/core": "^0.2.4"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"expo": "*"
|
|
45
51
|
},
|
|
46
52
|
"devDependencies": {
|
|
47
53
|
"@types/node": "^25.9.1",
|
|
48
54
|
"@types/ws": "^8.18.2",
|
|
55
|
+
"expo": "~57.0.26",
|
|
49
56
|
"prettier": "^3.6.2",
|
|
50
57
|
"typescript": "^6.0.3",
|
|
51
58
|
"ws": "^8.22.0"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { installedPackages } from "@backtickjs/core/node";
|
|
2
|
+
|
|
3
|
+
// The part of an Expo config this plugin reads and writes: `projectRoot` is
|
|
4
|
+
// set by Expo as it reads the config.
|
|
5
|
+
type ExpoConfig = {
|
|
6
|
+
extra?: Record<string, unknown>;
|
|
7
|
+
_internal?: { projectRoot?: string };
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The config plugin, as `"plugins": ["@backtickjs/expo"]` in app.json: puts
|
|
12
|
+
* the installed version of each of the app's dependencies in the config,
|
|
13
|
+
* `extra.backtick.installedPackages`, which `getBacktickExtra` reads.
|
|
14
|
+
*/
|
|
15
|
+
export default function withBacktickExtra<Config extends ExpoConfig>(
|
|
16
|
+
config: Config,
|
|
17
|
+
): Config & { extra: Record<string, unknown> } {
|
|
18
|
+
const projectRoot = config._internal?.projectRoot;
|
|
19
|
+
if (projectRoot === undefined) {
|
|
20
|
+
throw new Error("@backtickjs/expo: Expo gave the config no projectRoot.");
|
|
21
|
+
}
|
|
22
|
+
const backtick = config.extra?.backtick as
|
|
23
|
+
| Record<string, unknown>
|
|
24
|
+
| undefined;
|
|
25
|
+
return {
|
|
26
|
+
...config,
|
|
27
|
+
extra: {
|
|
28
|
+
...config.extra,
|
|
29
|
+
backtick: {
|
|
30
|
+
...backtick,
|
|
31
|
+
installedPackages: installedPackages(projectRoot),
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
package/src/plugin.ts
CHANGED
|
@@ -1,35 +1,51 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
3
|
+
// What this uses of Babel, which the app's `expo` brings with its preset.
|
|
4
|
+
interface Babel {
|
|
5
|
+
transformSync(
|
|
6
|
+
code: string,
|
|
7
|
+
options: object,
|
|
8
|
+
): { code?: string | null; map?: object | null } | null;
|
|
9
|
+
}
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Expo's Babel preset as a build's compile step, after the framework's:
|
|
13
|
+
* each script as Metro compiles the app's own code for Hermes, so a script
|
|
14
|
+
* gets what Expo works around in Hermes V1, as an async arrow with a default
|
|
15
|
+
* parameter losing its first `await`. Babel and the preset are the ones the
|
|
16
|
+
* app's own `expo` brings. A script is compiled once for every client, so no
|
|
17
|
+
* platform is given: `process.env.EXPO_OS` is `null` in one, and
|
|
18
|
+
* `Platform.OS` says the platform.
|
|
19
|
+
*
|
|
20
|
+
* Listed in `package.json`: `"backtick": { "plugins": ["@backtickjs/jsx-react/plugin", "@backtickjs/expo/plugin"] }`.
|
|
14
21
|
*/
|
|
15
|
-
export default function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
export default function expo(): (
|
|
23
|
+
code: string,
|
|
24
|
+
id: string,
|
|
25
|
+
) => { code: string; map: string } {
|
|
26
|
+
const fromExpo = createRequire(
|
|
27
|
+
createRequire(import.meta.url).resolve("expo/package.json"),
|
|
28
|
+
);
|
|
29
|
+
const preset = fromExpo.resolve("babel-preset-expo");
|
|
30
|
+
const babel = createRequire(preset)("@babel/core") as Babel;
|
|
31
|
+
return (code, id) => {
|
|
32
|
+
const compiled = babel.transformSync(code, {
|
|
33
|
+
filename: id,
|
|
34
|
+
babelrc: false,
|
|
35
|
+
configFile: false,
|
|
36
|
+
// readable, as the framework's step left it
|
|
37
|
+
compact: false,
|
|
38
|
+
comments: true,
|
|
39
|
+
sourceMaps: true,
|
|
40
|
+
// the module's imports kept, for the compiler to find
|
|
41
|
+
presets: [[preset, { disableImportExportTransform: true }]],
|
|
42
|
+
caller: {
|
|
43
|
+
name: "metro",
|
|
44
|
+
bundler: "metro",
|
|
45
|
+
engine: "hermes",
|
|
46
|
+
supportsStaticESM: true,
|
|
32
47
|
},
|
|
33
|
-
}
|
|
48
|
+
});
|
|
49
|
+
return { code: compiled!.code!, map: JSON.stringify(compiled!.map) };
|
|
34
50
|
};
|
|
35
51
|
}
|
package/app.plugin.js
DELETED