@backtickjs/expo 0.2.2 → 0.2.3

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 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, and a call that reloads the app when your server restarts in development.
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
- * 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.
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 withBacktickExtra<Config extends ExpoConfig>(config: Config): Config & {
13
- extra: Record<string, unknown>;
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 { installedPackages } from "@backtickjs/core/node";
1
+ import { createRequire } from "node:module";
2
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.
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 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),
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
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/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"}
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.2",
3
+ "version": "0.2.3",
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
- "./app.plugin.js": "./app.plugin.js"
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.2"
47
+ "@backtickjs/core": "^0.2.3"
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 { installedPackages } from "@backtickjs/core/node";
1
+ import { createRequire } from "node:module";
2
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
- };
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
- * 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.
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 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),
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
@@ -1,3 +0,0 @@
1
- // Where Expo looks for a package's config plugin, as
2
- // `"plugins": ["@backtickjs/expo"]` names it.
3
- export { default } from "./dist/plugin.js";