create-crossbind 2.0.0-beta.66 → 2.0.0-beta.69
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 +1 -0
- package/package.json +2 -2
- package/src/extension.js +67 -0
- package/src/index.js +11 -1
- package/src/manifest.json +10 -4
- package/templates/app-extension/README.md +33 -0
- package/templates/app-extension/_gitignore +1 -0
- package/templates/app-extension/crossbind.extension.js +11 -0
- package/templates/app-extension/index.d.ts +2 -0
- package/templates/app-extension/index.js +8 -0
- package/templates/app-extension/native/starter.cpp +12 -0
- package/templates/app-extension/package.json +34 -0
- package/templates/backend-nodejs-native/README.md +2 -2
- package/templates/backend-nodejs-native/package.json +3 -3
- package/templates/backend-nodejs-standalone/package.json +1 -1
- package/templates/backend-nodejs-wasm/package.json +2 -2
- package/templates/cloud-cloudflare-worker/package.json +1 -1
- package/templates/desktop-app/README.md +3 -2
- package/templates/desktop-app/package.json +4 -4
- package/templates/desktop-electron/README.md +2 -2
- package/templates/desktop-electron/package.json +4 -4
- package/templates/lib-cmake/package.json +1 -1
- package/templates/lib-prebuilt/package.json +2 -2
- package/templates/lib-source/package.json +1 -1
- package/templates/mobile-reactnative-cli/AGENTS.md +0 -28
- package/templates/mobile-reactnative-cli/package.json +15 -15
- package/templates/mobile-reactnative-expo/package.json +7 -19
- package/templates/native-executable/package.json +2 -2
- package/templates/web-react-rspack/package.json +3 -3
- package/templates/web-react-vite/package.json +2 -2
- package/templates/web-svelte-vite/package.json +2 -2
- package/templates/web-vanilla/package.json +2 -2
- package/templates/web-vue-vite/package.json +2 -2
- package/templates/mobile-reactnative-cli/ci/crossbind-snapshot/cache.json +0 -12
- package/templates/mobile-reactnative-expo/package-lock.json +0 -8891
package/README.md
CHANGED
|
@@ -54,6 +54,7 @@ npm create crossbind@beta -- my-app Web React Vite
|
|
|
54
54
|
npm create crossbind@beta -- my-app Desktop Electron
|
|
55
55
|
npm create crossbind@beta -- my-tool Native Executable
|
|
56
56
|
npm create crossbind@beta -- my-lib Library Prebuilt
|
|
57
|
+
npm create crossbind@beta -- my-extension Extension
|
|
57
58
|
```
|
|
58
59
|
|
|
59
60
|
When you are ready to ship your app to production, run the following:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-crossbind",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.69",
|
|
4
4
|
"description": "Create crossbind Applications",
|
|
5
5
|
"homepage": "https://github.com/crossbind/crossbind/tree/main/tooling/create-app#readme",
|
|
6
6
|
"repository": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"main": "src/index.js",
|
|
12
12
|
"type": "module",
|
|
13
13
|
"engines": {
|
|
14
|
-
"node": ">=
|
|
14
|
+
"node": ">=26"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"src",
|
package/src/extension.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { renameInReadme } from './readme.js';
|
|
4
|
+
|
|
5
|
+
// The extension the app-extension template carries, which a scaffold names after its project: every word starter in
|
|
6
|
+
// the template's text files is its name, so the template uses the word for nothing else.
|
|
7
|
+
const TEMPLATE_NAME = 'starter';
|
|
8
|
+
// An extension's name, as crossbind takes it: lowercase letters and digits, dashes between, from a letter.
|
|
9
|
+
const NAME = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
10
|
+
const TEXT_FILE = /\.(js|ts|md|cpp|h|mm|java)$/;
|
|
11
|
+
const TEMPLATE_WORD = new RegExp(`crossbind_extension_${TEMPLATE_NAME}\\b|\\b${TEMPLATE_NAME}\\b`, 'g');
|
|
12
|
+
// The words module code keeps, which can name neither the template's default export nor its import in the README.
|
|
13
|
+
const RESERVED = new Set(('arguments await break case catch class const continue debugger default delete do else enum eval '
|
|
14
|
+
+ 'export extends false finally for function if implements import in instanceof interface let new null package private '
|
|
15
|
+
+ 'protected public return static super switch this throw true try typeof var void while with yield').split(' '));
|
|
16
|
+
|
|
17
|
+
// The extension name of a project's folder, or null when it makes none: the folder's own name in lowercase, with a dash
|
|
18
|
+
// for each run of other characters and without a crossbind-extension- of its own.
|
|
19
|
+
export function extensionName(folder) {
|
|
20
|
+
const name = path.basename(path.resolve(folder)).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
|
|
21
|
+
.replace(/^crossbind-extension(-|$)/, '');
|
|
22
|
+
return NAME.test(name) ? name : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// The JavaScript name of an extension: camelCase, with Extension after a word module code keeps.
|
|
26
|
+
function identifierOf(name) {
|
|
27
|
+
const camel = name.replace(/-([a-z0-9])/g, (_, letter) => letter.toUpperCase());
|
|
28
|
+
return RESERVED.has(camel) ? `${camel}Extension` : camel;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// A template's text with its extension named: the C++ entry with underscores for dashes, the name itself before a dot
|
|
32
|
+
// or in quotes, and its JavaScript name elsewhere. One pass, so a name that holds the template's stays whole.
|
|
33
|
+
export function renamedText(text, name) {
|
|
34
|
+
const identifier = identifierOf(name);
|
|
35
|
+
return text.replace(TEMPLATE_WORD, (word, at) => {
|
|
36
|
+
if (word !== TEMPLATE_NAME) return `crossbind_extension_${name.replaceAll('-', '_')}`;
|
|
37
|
+
const before = text[at - 1];
|
|
38
|
+
const after = text[at + word.length];
|
|
39
|
+
return after === '.' || ((before === "'" || before === '"') && after === before) ? name : identifier;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// The text files the template gave the project, and those named after the template's extension; a file of the folder's
|
|
44
|
+
// own is left as it is.
|
|
45
|
+
async function renameFiles(template, dir, name) {
|
|
46
|
+
for (const entry of await fsp.readdir(template, { withFileTypes: true, recursive: true })) {
|
|
47
|
+
if (!entry.isFile() || !TEXT_FILE.test(entry.name)) continue;
|
|
48
|
+
const file = path.join(dir, path.relative(template, entry.parentPath), entry.name);
|
|
49
|
+
await fsp.writeFile(file, renamedText(await fsp.readFile(file, 'utf8'), name));
|
|
50
|
+
if (entry.name.startsWith(`${TEMPLATE_NAME}.`)) {
|
|
51
|
+
await fsp.rename(file, path.join(path.dirname(file), `${name}${entry.name.slice(TEMPLATE_NAME.length)}`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Names a scaffolded extension after its project: its files, then its package, whose name the README takes last so a
|
|
57
|
+
// name that holds the template's word stays whole.
|
|
58
|
+
export async function nameExtension(template, dir, name) {
|
|
59
|
+
await renameFiles(template, dir, name);
|
|
60
|
+
const pjPath = path.join(dir, 'package.json');
|
|
61
|
+
// private keeps the template's sample out of the repository's releases; an extension is a package to publish.
|
|
62
|
+
const { name: templateName, private: _, ...fields } = JSON.parse(await fsp.readFile(pjPath, 'utf8'));
|
|
63
|
+
const pkg = { name: `crossbind-extension-${name}`, ...fields };
|
|
64
|
+
await fsp.writeFile(pjPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
65
|
+
const readmePath = path.join(dir, 'README.md');
|
|
66
|
+
await fsp.writeFile(readmePath, renameInReadme(await fsp.readFile(readmePath, 'utf8'), templateName, pkg.name));
|
|
67
|
+
}
|
package/src/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
6
6
|
import { styleText } from 'node:util';
|
|
7
7
|
import * as p from '@clack/prompts';
|
|
8
8
|
import { unpackDotfiles } from './dotfiles.js';
|
|
9
|
+
import { extensionName, nameExtension } from './extension.js';
|
|
9
10
|
import { renameInReadme } from './readme.js';
|
|
10
11
|
import { pkgManager } from './utils.js';
|
|
11
12
|
|
|
@@ -101,6 +102,7 @@ function usage() {
|
|
|
101
102
|
' npm create crossbind@beta -- my-app Web Vanilla',
|
|
102
103
|
' npm create crossbind@beta -- my-app Web React Vite',
|
|
103
104
|
' npm create crossbind@beta -- my-lib Library Prebuilt',
|
|
105
|
+
' npm create crossbind@beta -- my-extension Extension',
|
|
104
106
|
'',
|
|
105
107
|
'Templates:',
|
|
106
108
|
...rows,
|
|
@@ -142,6 +144,12 @@ async function main() {
|
|
|
142
144
|
await ensureEmpty(cwd);
|
|
143
145
|
|
|
144
146
|
const entry = await pickTemplate(argGroup, argFirst, argSecond);
|
|
147
|
+
// An extension is named after its project, so a project name that makes none stops before a file is written.
|
|
148
|
+
const extension = entry.kind === 'extension' ? extensionName(name) : null;
|
|
149
|
+
if (entry.kind === 'extension' && !extension) {
|
|
150
|
+
p.cancel(`No extension name in ${name}: an extension's name is lowercase letters and digits, dashes between, from a letter.`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
145
153
|
const src = path.join(TEMPLATES_DIR, entry.key);
|
|
146
154
|
if (!fs.existsSync(src)) {
|
|
147
155
|
p.cancel(`Template missing: ${entry.key} (expected ${src}). Did you publish with prepublishOnly?`);
|
|
@@ -156,7 +164,9 @@ async function main() {
|
|
|
156
164
|
|
|
157
165
|
const pjPath = path.join(cwd, 'package.json');
|
|
158
166
|
let scripts = {};
|
|
159
|
-
if (
|
|
167
|
+
if (extension) {
|
|
168
|
+
await nameExtension(src, cwd, extension);
|
|
169
|
+
} else if (fs.existsSync(pjPath)) {
|
|
160
170
|
const pkg = JSON.parse(await fsp.readFile(pjPath, 'utf8'));
|
|
161
171
|
const templateName = pkg.name;
|
|
162
172
|
pkg.name = entry.kind === 'lib' ? `crossbind-lib-${name}` : name;
|
package/src/manifest.json
CHANGED
|
@@ -56,8 +56,7 @@
|
|
|
56
56
|
"label": "Expo",
|
|
57
57
|
"kind": "app",
|
|
58
58
|
"source": "examples/mobile-reactnative-expo",
|
|
59
|
-
"nativeFolders": false
|
|
60
|
-
"keepLockfile": true
|
|
59
|
+
"nativeFolders": false
|
|
61
60
|
},
|
|
62
61
|
{
|
|
63
62
|
"key": "desktop-app",
|
|
@@ -92,8 +91,7 @@
|
|
|
92
91
|
"framework": "Node.js",
|
|
93
92
|
"label": "Node-API",
|
|
94
93
|
"kind": "app",
|
|
95
|
-
"source": "examples/backend-nodejs-native"
|
|
96
|
-
"workspaceOnly": ["ci"]
|
|
94
|
+
"source": "examples/backend-nodejs-native"
|
|
97
95
|
},
|
|
98
96
|
{
|
|
99
97
|
"key": "backend-nodejs-standalone",
|
|
@@ -147,5 +145,13 @@
|
|
|
147
145
|
"label": "CMake",
|
|
148
146
|
"kind": "lib",
|
|
149
147
|
"source": "examples/lib-cmake"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"key": "app-extension",
|
|
151
|
+
"group": "Extension",
|
|
152
|
+
"framework": null,
|
|
153
|
+
"label": "App",
|
|
154
|
+
"kind": "extension",
|
|
155
|
+
"source": "examples/app-extension"
|
|
150
156
|
}
|
|
151
157
|
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @crossbind/example-app-extension
|
|
2
|
+
|
|
3
|
+
An app extension: a function of the app's native code, which its page calls on macOS, iOS, Android, Windows and Linux.
|
|
4
|
+
[The contract](https://github.com/crossbind/crossbind/blob/main/docs/api/extensions.md) says what an extension is, and
|
|
5
|
+
[the playbook](https://github.com/crossbind/crossbind/blob/main/docs/playbooks/new-extension.md) the order of the work
|
|
6
|
+
of making this one your own.
|
|
7
|
+
|
|
8
|
+
## Use
|
|
9
|
+
|
|
10
|
+
Once it is on npm, `npx crossbind add @crossbind/example-app-extension` installs it in an app and lists it in the app's
|
|
11
|
+
`crossbind.config.js`, whose host builds its native code in; until then, `crossbind add` takes the tarball `npm pack`
|
|
12
|
+
makes. The config it writes:
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import starter from '@crossbind/example-app-extension/crossbind.extension.js';
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
target: { runtimeEnv: 'app' },
|
|
19
|
+
extensions: [starter()],
|
|
20
|
+
};
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { greet } from '@crossbind/example-app-extension';
|
|
25
|
+
|
|
26
|
+
console.log(await greet('crossbind')); // Hello, crossbind, from <the app's name>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Files
|
|
30
|
+
|
|
31
|
+
- `crossbind.extension.js`: the extension, named 'starter', and the sources each platform compiles.
|
|
32
|
+
- `native/starter.cpp`: its entry, which adds the functions the page calls as `starter.<function>`.
|
|
33
|
+
- `index.js` and `index.d.ts`: the page's functions, which call the extension's with `invoke` from `crossbind/app`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node_modules
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// The extension's functions, from an app's page.
|
|
2
|
+
import { invoke } from 'crossbind/app';
|
|
3
|
+
|
|
4
|
+
// What the app's native code says to the name given.
|
|
5
|
+
export const greet = async (name) => {
|
|
6
|
+
if (typeof name !== 'string') throw new TypeError('crossbind: starter.greet takes a string.');
|
|
7
|
+
return invoke('starter.greet', { name });
|
|
8
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// The extension's functions, which the page calls through its package, the same on every platform.
|
|
2
|
+
#include "crossbind/extension.h"
|
|
3
|
+
|
|
4
|
+
#include <stdexcept>
|
|
5
|
+
|
|
6
|
+
void crossbind_extension_starter(crossbind::Registry ®istry) {
|
|
7
|
+
registry.function("starter.greet", [](crossbind::Call call) {
|
|
8
|
+
const crossbind::Value &name = call.options()["name"];
|
|
9
|
+
if (!name.isString()) throw std::invalid_argument("crossbind: starter.greet takes a name");
|
|
10
|
+
call.resolve("Hello, " + name.asString() + ", from " + crossbind::appName());
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crossbind/example-app-extension",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"description": "crossbind app extension: a function of the app's native code, which its page calls",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"default": "./index.js"
|
|
12
|
+
},
|
|
13
|
+
"./crossbind.extension.js": "./crossbind.extension.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"crossbind.extension.js",
|
|
17
|
+
"index.d.ts",
|
|
18
|
+
"index.js",
|
|
19
|
+
"native"
|
|
20
|
+
],
|
|
21
|
+
"crossbind": {
|
|
22
|
+
"extension": "./crossbind.extension.js"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"crossbind": "^2.0.0-beta.69"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"crossbind": "^2.0.0-beta.69"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"crossbind-extension",
|
|
32
|
+
"app"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -15,8 +15,8 @@ which loads the addons the same library ships prebuilt.
|
|
|
15
15
|
# Getting Started
|
|
16
16
|
|
|
17
17
|
>**Note**: Make sure you have completed the [crossbind - Prerequisites](https://crossbind.dev/docs/guide/getting-started/prerequisites) instructions.
|
|
18
|
-
The
|
|
19
|
-
host with Xcode's command line tools.
|
|
18
|
+
The Linux and Windows addons build in Docker, and so do the bindings but on a Mac, where
|
|
19
|
+
`@crossbind/bridge-tools` generates them; the macOS addons build on a macOS host with Xcode's command line tools.
|
|
20
20
|
|
|
21
21
|
## Setup
|
|
22
22
|
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"e2e:prod": "node e2e/run.mjs"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.
|
|
15
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.69"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@crossbind/core-embind-napi": "^2.0.0-beta.
|
|
19
|
-
"crossbind": "^2.0.0-beta.
|
|
18
|
+
"@crossbind/core-embind-napi": "^2.0.0-beta.69",
|
|
19
|
+
"crossbind": "^2.0.0-beta.69"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
22
|
"crossbind-sample",
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"build": "crossbind build -p wasm -a wasm32 -r st -e node -b release"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.
|
|
13
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.69"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"crossbind": "^2.0.0-beta.
|
|
16
|
+
"crossbind": "^2.0.0-beta.69"
|
|
17
17
|
},
|
|
18
18
|
"keywords": [
|
|
19
19
|
"crossbind-sample",
|
|
@@ -11,8 +11,9 @@ Windows and Android System WebView on Android.
|
|
|
11
11
|
|
|
12
12
|
>**Note**: Make sure you have completed the [crossbind - Prerequisites](https://crossbind.dev/docs/guide/getting-started/prerequisites) instructions.
|
|
13
13
|
Apps build on macOS with Xcode's command line tools, iOS apps with Xcode and its iOS platform, and Linux, Windows and
|
|
14
|
-
Android apps in crossbind's linux, windows and android-app images, which carry everything they build with
|
|
15
|
-
bindings are generated in Docker
|
|
14
|
+
Android apps in crossbind's linux, windows and android-app images, which carry everything they build with. The
|
|
15
|
+
bindings are generated in Docker, but on a Mac `@crossbind/bridge-tools` generates every app's but Android's. A macOS or
|
|
16
|
+
iOS build fetches React Native's Hermes once into `~/.crossbind/hermes`.
|
|
16
17
|
|
|
17
18
|
## Setup
|
|
18
19
|
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
"e2e:prod": "node e2e/run.mjs"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.
|
|
22
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.69"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@crossbind/core-app-host": "^2.0.0-beta.
|
|
26
|
-
"@crossbind/plugin-vite": "^2.0.0-beta.
|
|
27
|
-
"crossbind": "^2.0.0-beta.
|
|
25
|
+
"@crossbind/core-app-host": "^2.0.0-beta.69",
|
|
26
|
+
"@crossbind/plugin-vite": "^2.0.0-beta.69",
|
|
27
|
+
"crossbind": "^2.0.0-beta.69",
|
|
28
28
|
"vite": "^8.2.1"
|
|
29
29
|
},
|
|
30
30
|
"keywords": [
|
|
@@ -11,8 +11,8 @@ version and nothing for `electron-rebuild` to do.
|
|
|
11
11
|
# Getting Started
|
|
12
12
|
|
|
13
13
|
>**Note**: Make sure you have completed the [crossbind - Prerequisites](https://crossbind.dev/docs/guide/getting-started/prerequisites) instructions.
|
|
14
|
-
The
|
|
15
|
-
host with Xcode's command line tools.
|
|
14
|
+
The Linux and Windows addons build in Docker, and so do the bindings but on a Mac, where
|
|
15
|
+
`@crossbind/bridge-tools` generates them; the macOS addons build on a macOS host with Xcode's command line tools.
|
|
16
16
|
|
|
17
17
|
## Setup
|
|
18
18
|
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"e2e:prod": "electron-builder --dir && playwright test --project=packaged"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@crossbind/core-embind-napi": "^2.0.0-beta.
|
|
20
|
-
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.
|
|
19
|
+
"@crossbind/core-embind-napi": "^2.0.0-beta.69",
|
|
20
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.69",
|
|
21
21
|
"@playwright/test": "^1.63.0",
|
|
22
|
-
"crossbind": "^2.0.0-beta.
|
|
23
|
-
"electron": "^
|
|
22
|
+
"crossbind": "^2.0.0-beta.69",
|
|
23
|
+
"electron": "^45.0.0",
|
|
24
24
|
"electron-builder": "^26.15.3"
|
|
25
25
|
},
|
|
26
26
|
"keywords": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossbind/example-lib-cmake",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.69",
|
|
4
4
|
"description": "crossbind sample library: simple cmake library",
|
|
5
5
|
"homepage": "https://github.com/crossbind/crossbind/tree/main/examples/lib-cmake#readme",
|
|
6
6
|
"repository": "https://github.com/crossbind/crossbind.git",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossbind/example-lib-prebuilt-matrix",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.69",
|
|
4
4
|
"description": "crossbind sample prebuilt library: matrix multiplier",
|
|
5
5
|
"homepage": "https://github.com/crossbind/crossbind/tree/main/examples/lib-prebuilt-matrix#readme",
|
|
6
6
|
"repository": "https://github.com/crossbind/crossbind.git",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"prepublishOnly": "crossbind build"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"crossbind": "^2.0.0-beta.
|
|
21
|
+
"crossbind": "^2.0.0-beta.69"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"crossbind-sample",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossbind/example-lib-source",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.69",
|
|
4
4
|
"description": "crossbind sample library: simple source library",
|
|
5
5
|
"homepage": "https://github.com/crossbind/crossbind/tree/main/examples/lib-source#readme",
|
|
6
6
|
"repository": "https://github.com/crossbind/crossbind.git",
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
- A minimal RN-cli app that loads `@crossbind/example-lib-prebuilt-matrix` and calls into it from JS.
|
|
8
8
|
- Reference for `metro.config.js` + `crossbind.config.mjs` shape in a bare RN project.
|
|
9
|
-
- Source of the **CI bridge cache** used by `.github/workflows/test-ios-sample.yml` to skip SWIG bridge generation in CI.
|
|
10
9
|
|
|
11
10
|
## Layout
|
|
12
11
|
|
|
@@ -14,12 +13,6 @@
|
|
|
14
13
|
examples/mobile-reactnative-cli/
|
|
15
14
|
├── android/ ← bare RN Android project
|
|
16
15
|
├── ios/ ← bare RN iOS project (Podfile + Podfile.lock)
|
|
17
|
-
├── ci/
|
|
18
|
-
│ └── crossbind-snapshot/ ← bridge fixtures restored by iOS workflow
|
|
19
|
-
│ ├── build/bridge/native.i.cpp
|
|
20
|
-
│ ├── build/bridge/native.i.cpp.exports.json
|
|
21
|
-
│ ├── build/interface/native.i
|
|
22
|
-
│ └── cache.json
|
|
23
16
|
├── src/ ← RN app and native bridge input
|
|
24
17
|
├── __tests__/ ← Jest component smoke
|
|
25
18
|
├── app.json
|
|
@@ -33,24 +26,6 @@ examples/mobile-reactnative-cli/
|
|
|
33
26
|
|
|
34
27
|
- **`metro.config.js`** — exact wiring for `@crossbind/plugin-metro`. Used as the canonical example in `docs/playbooks/integration/react-native-cli.md`.
|
|
35
28
|
- **`crossbind.config.mjs`** — shows how to consume a workspace dep (`@crossbind/example-lib-prebuilt-matrix`).
|
|
36
|
-
- **`ci/crossbind-snapshot/`** — git-tracked fixtures. **Do not delete.** The iOS workflow's `cp -r ci/crossbind-snapshot/. .crossbind/` step depends on them.
|
|
37
|
-
|
|
38
|
-
## CI bridge cache pattern
|
|
39
|
-
|
|
40
|
-
The directory is named `crossbind-snapshot/` (not `.crossbind/`) on purpose: `pnpm clear:cache:examples` and similar globs match `*/.crossbind`, which would otherwise wipe these fixtures. Renaming the snapshot dir survives clear globs.
|
|
41
|
-
|
|
42
|
-
The iOS workflow restores the snapshot **before** `pod install` so SWIG / bridge generation can be skipped in CI:
|
|
43
|
-
|
|
44
|
-
```yaml
|
|
45
|
-
- name: Restore cached bridge files
|
|
46
|
-
run: |
|
|
47
|
-
mkdir -p ./examples/.../my-app/.crossbind
|
|
48
|
-
cp -r ./examples/.../my-app/ci/crossbind-snapshot/. ./examples/.../my-app/.crossbind/
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
The trailing `/.` + `mkdir -p` keeps the merge nesting-safe regardless of pre-existing state in the runner.
|
|
52
|
-
|
|
53
|
-
If you regenerate the snapshot, re-commit the four files under `ci/crossbind-snapshot/build/...` and `ci/crossbind-snapshot/cache.json`.
|
|
54
29
|
|
|
55
30
|
## Validation
|
|
56
31
|
|
|
@@ -76,8 +51,6 @@ CI: `.github/workflows/test-ios-sample.yml` and `test-android-sample.yml`.
|
|
|
76
51
|
|
|
77
52
|
## Common pitfalls
|
|
78
53
|
|
|
79
|
-
- **Deleting `ci/crossbind-snapshot/`** with a careless `rm -rf` or assuming it's regenerable — it isn't (well, it is, but only after a full local build that we skip in CI).
|
|
80
|
-
- **Renaming back to `ci/.crossbind`.** `pnpm run clear`-style globs will eat it.
|
|
81
54
|
- **Skipping `pod install`** after touching the RN plugin's `react-native-crossbind.podspec`. Cached pods will be wrong.
|
|
82
55
|
- **Editing the `monorepo` `watchFolders` config** in `metro.config.js` to point elsewhere. The default `require('path').resolve('../../')` is intentional — Metro must see the workspace root to resolve the crossbind plugin packages.
|
|
83
56
|
- **Adding `ios/Pods/` or `android/.gradle/` to git.** They're ignored; build artifacts.
|
|
@@ -87,4 +60,3 @@ CI: `.github/workflows/test-ios-sample.yml` and `test-android-sample.yml`.
|
|
|
87
60
|
- RN-cli playbook: `docs/playbooks/integration/react-native-cli.md`
|
|
88
61
|
- Plugin source: `plugins/react-native/AGENTS.md`
|
|
89
62
|
- iOS CI workflow: `.github/workflows/test-ios-sample.yml`
|
|
90
|
-
- Snapshot restoration logic in CI: see "Restore cached bridge files" step
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
"e2e:android": "pnpm run run:android && pnpm run maestro:android"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@crossbind/core-embind-jsi": "^2.0.0-beta.
|
|
24
|
-
"@crossbind/plugin-react-native": "^2.0.0-beta.
|
|
25
|
-
"@crossbind/plugin-react-native-ios-helper": "^2.0.0-beta.
|
|
26
|
-
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.
|
|
23
|
+
"@crossbind/core-embind-jsi": "^2.0.0-beta.69",
|
|
24
|
+
"@crossbind/plugin-react-native": "^2.0.0-beta.69",
|
|
25
|
+
"@crossbind/plugin-react-native-ios-helper": "^2.0.0-beta.69",
|
|
26
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.69",
|
|
27
27
|
"react": "19.3.1",
|
|
28
|
-
"react-native": "0.88.
|
|
28
|
+
"react-native": "0.88.1",
|
|
29
29
|
"react-native-safe-area-context": "^5.8.0",
|
|
30
|
-
"hermes-compiler": "
|
|
30
|
+
"hermes-compiler": "260318099.0.4"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@babel/core": "^7.29.7",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"@react-native-community/cli": "20.2.0",
|
|
37
37
|
"@react-native-community/cli-platform-android": "20.2.0",
|
|
38
38
|
"@react-native-community/cli-platform-ios": "20.2.0",
|
|
39
|
-
"@react-native/babel-preset": "0.88.
|
|
40
|
-
"@react-native/codegen": "0.88.
|
|
41
|
-
"@react-native/eslint-config": "0.88.
|
|
42
|
-
"@react-native/jest-preset": "0.88.
|
|
43
|
-
"@react-native/gradle-plugin": "0.88.
|
|
44
|
-
"@react-native/metro-config": "0.88.
|
|
45
|
-
"@react-native/typescript-config": "0.88.
|
|
39
|
+
"@react-native/babel-preset": "0.88.1",
|
|
40
|
+
"@react-native/codegen": "0.88.1",
|
|
41
|
+
"@react-native/eslint-config": "0.88.1",
|
|
42
|
+
"@react-native/jest-preset": "0.88.1",
|
|
43
|
+
"@react-native/gradle-plugin": "0.88.1",
|
|
44
|
+
"@react-native/metro-config": "0.88.1",
|
|
45
|
+
"@react-native/typescript-config": "0.88.1",
|
|
46
46
|
"@types/jest": "^29.5.13",
|
|
47
47
|
"@types/react": "^19.3.0",
|
|
48
48
|
"@types/react-test-renderer": "^19.3.0",
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
"prettier": "3.9.10",
|
|
52
52
|
"react-test-renderer": "19.3.1",
|
|
53
53
|
"typescript": "^6.0.3",
|
|
54
|
-
"@crossbind/plugin-metro": "^2.0.0-beta.
|
|
54
|
+
"@crossbind/plugin-metro": "^2.0.0-beta.69"
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
|
-
"node": ">=
|
|
57
|
+
"node": ">=26"
|
|
58
58
|
},
|
|
59
59
|
"keywords": [
|
|
60
60
|
"crossbind-sample",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"e2e:android": "npm run run:android && npm run maestro:android"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@crossbind/core-embind-jsi": "2.0.0-beta.
|
|
27
|
-
"@crossbind/plugin-react-native": "2.0.0-beta.
|
|
28
|
-
"@crossbind/plugin-react-native-ios-helper": "2.0.0-beta.
|
|
29
|
-
"@crossbind/example-lib-prebuilt-matrix": "2.0.0-beta.
|
|
26
|
+
"@crossbind/core-embind-jsi": "^2.0.0-beta.69",
|
|
27
|
+
"@crossbind/plugin-react-native": "^2.0.0-beta.69",
|
|
28
|
+
"@crossbind/plugin-react-native-ios-helper": "^2.0.0-beta.69",
|
|
29
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.69",
|
|
30
30
|
"hermes-compiler": "260318099.0.4",
|
|
31
31
|
"expo": "~58.0.14",
|
|
32
32
|
"expo-constants": "~58.0.12",
|
|
@@ -54,21 +54,9 @@
|
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/react": "~19.3.0",
|
|
56
56
|
"typescript": "~6.0.3",
|
|
57
|
-
"
|
|
58
|
-
"@crossbind/
|
|
59
|
-
|
|
60
|
-
"overrides": {
|
|
61
|
-
"uuid": "11.1.1",
|
|
62
|
-
"replace": {
|
|
63
|
-
"minimatch": "3.1.4"
|
|
64
|
-
},
|
|
65
|
-
"brace-expansion@5": "^5.0.12",
|
|
66
|
-
"shell-quote": "^1.12.0",
|
|
67
|
-
"js-yaml@4": "^4.3.1",
|
|
68
|
-
"nanoid@3": "^3.3.18",
|
|
69
|
-
"postcss": "^8.5.26",
|
|
70
|
-
"ws@7": "^7.5.13",
|
|
71
|
-
"@babel/core@7": "^7.29.7"
|
|
57
|
+
"metro-config": "^0.87.1",
|
|
58
|
+
"@crossbind/typescript-config": "^2.0.0-beta.69",
|
|
59
|
+
"@crossbind/plugin-metro": "^2.0.0-beta.69"
|
|
72
60
|
},
|
|
73
61
|
"keywords": [
|
|
74
62
|
"crossbind-sample",
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
"e2e:prod": "node e2e/run.mjs"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.
|
|
15
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.69"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"crossbind": "^2.0.0-beta.
|
|
18
|
+
"crossbind": "^2.0.0-beta.69"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"crossbind-sample",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"react": "^19.3.0",
|
|
18
18
|
"react-dom": "^19.3.0",
|
|
19
|
-
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.
|
|
19
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.69"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@rspack/plugin-react-refresh": "^2.0.2",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"react-refresh": "^0.19.0",
|
|
30
30
|
"@playwright/test": "^1.63.0",
|
|
31
31
|
"serve": "^14.2.6",
|
|
32
|
-
"@crossbind/plugin-webpack": "^2.0.0-beta.
|
|
33
|
-
"@crossbind/plugin-webpack-loader": "^2.0.0-beta.
|
|
32
|
+
"@crossbind/plugin-webpack": "^2.0.0-beta.69",
|
|
33
|
+
"@crossbind/plugin-webpack-loader": "^2.0.0-beta.69"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"crossbind-sample",
|