create-crossbind 2.0.0-beta.62 → 2.0.0-beta.63
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 +3 -1
- package/package.json +1 -1
- package/src/index.js +1 -1
- package/src/manifest.json +44 -6
- package/templates/backend-nodejs-native/README.md +47 -0
- package/templates/backend-nodejs-native/_gitignore +3 -0
- package/templates/backend-nodejs-native/crossbind.config.mjs +14 -0
- package/templates/backend-nodejs-native/e2e/run.mjs +14 -0
- package/templates/backend-nodejs-native/package.json +29 -0
- package/templates/backend-nodejs-native/src/index.js +5 -0
- package/templates/backend-nodejs-native/src/index.mjs +5 -0
- package/templates/backend-nodejs-native/src/native/native.cpp +9 -0
- package/templates/backend-nodejs-native/src/native/native.h +12 -0
- package/templates/backend-nodejs-standalone/README.md +33 -0
- package/templates/backend-nodejs-standalone/_gitignore +1 -0
- package/templates/backend-nodejs-standalone/e2e/run.mjs +14 -0
- package/templates/backend-nodejs-standalone/package.json +23 -0
- package/templates/backend-nodejs-standalone/src/index.js +6 -0
- package/templates/backend-nodejs-standalone/src/index.mjs +5 -0
- package/templates/backend-nodejs-wasm/README.md +0 -3
- package/templates/backend-nodejs-wasm/package.json +2 -2
- package/templates/cloud-cloudflare-worker/Readme.md +0 -3
- package/templates/cloud-cloudflare-worker/package.json +1 -1
- package/templates/desktop-electron/README.md +53 -0
- package/templates/desktop-electron/_gitignore +6 -0
- package/templates/desktop-electron/crossbind.config.mjs +14 -0
- package/templates/desktop-electron/e2e/crossbind.spec.cjs +30 -0
- package/templates/desktop-electron/electron-builder.yml +11 -0
- package/templates/desktop-electron/package.json +33 -0
- package/templates/desktop-electron/playwright.config.cjs +15 -0
- package/templates/desktop-electron/pnpm-workspace.yaml +2 -0
- package/templates/desktop-electron/src/index.html +16 -0
- package/templates/desktop-electron/src/main.js +29 -0
- package/templates/desktop-electron/src/native/native.cpp +9 -0
- package/templates/desktop-electron/src/native/native.h +12 -0
- package/templates/desktop-electron/src/preload.js +5 -0
- package/templates/desktop-electron/src/renderer.js +5 -0
- package/templates/lib-cmake/README.md +2 -2
- package/templates/lib-cmake/package.json +1 -1
- package/templates/lib-prebuilt/AGENTS.md +3 -0
- package/templates/lib-prebuilt/README.md +22 -10
- package/templates/lib-prebuilt/edge/wasm +1 -0
- package/templates/lib-prebuilt/edge/wasm.d.ts +1 -0
- package/templates/lib-prebuilt/node/napi +1 -0
- package/templates/lib-prebuilt/node/napi.d.ts +1 -0
- package/templates/lib-prebuilt/node/wasm +1 -0
- package/templates/lib-prebuilt/node/wasm.d.ts +1 -0
- package/templates/lib-prebuilt/package.json +15 -3
- package/templates/lib-source/README.md +2 -2
- package/templates/lib-source/package.json +1 -1
- package/templates/mobile-reactnative-cli/README.md +0 -3
- package/templates/mobile-reactnative-cli/__mocks__/native-header.js +5 -0
- package/templates/mobile-reactnative-cli/__tests__/App.test.tsx +1 -1
- package/templates/mobile-reactnative-cli/ci/crossbind-snapshot/cache.json +3 -3
- package/templates/mobile-reactnative-cli/jest.config.js +3 -0
- package/templates/mobile-reactnative-cli/package.json +8 -8
- package/templates/mobile-reactnative-expo/README.md +12 -3
- package/templates/mobile-reactnative-expo/package-lock.json +184 -176
- package/templates/mobile-reactnative-expo/package.json +12 -11
- package/templates/mobile-reactnative-expo/src/app/index.tsx +1 -2
- package/templates/native-executable/README.md +50 -0
- package/templates/native-executable/_gitignore +3 -0
- package/templates/native-executable/crossbind.config.mjs +14 -0
- package/templates/native-executable/e2e/run.mjs +27 -0
- package/templates/native-executable/package.json +26 -0
- package/templates/native-executable/src/native/main.cpp +10 -0
- package/templates/web-react-rspack/README.md +0 -3
- package/templates/web-react-rspack/package.json +3 -3
- package/templates/web-react-vite/README.md +0 -3
- package/templates/web-react-vite/package.json +2 -2
- package/templates/web-svelte-vite/README.md +0 -3
- package/templates/web-svelte-vite/package.json +2 -2
- package/templates/web-vanilla/README.md +0 -3
- package/templates/web-vanilla/package.json +2 -2
- package/templates/web-vue-vite/README.md +0 -3
- package/templates/web-vue-vite/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
**Create crossbind Applications**
|
|
3
3
|
|
|
4
4
|
<a href="https://www.npmjs.com/package/create-crossbind">
|
|
5
|
-
<img alt="NPM version" src="https://img.shields.io/npm/v/create-crossbind?style=for-the-badge" />
|
|
5
|
+
<img alt="NPM version" src="https://img.shields.io/npm/v/create-crossbind/beta?style=for-the-badge" />
|
|
6
6
|
</a>
|
|
7
7
|
<a href="https://github.com/crossbind/crossbind/blob/main/LICENSE">
|
|
8
8
|
<img alt="License" src="https://img.shields.io/github/license/crossbind/crossbind?style=for-the-badge" />
|
|
@@ -51,6 +51,8 @@ Every prompt can be preselected positionally, which is what CI and scripted setu
|
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
53
|
npm create crossbind@beta -- my-app Web React Vite
|
|
54
|
+
npm create crossbind@beta -- my-app Desktop Electron
|
|
55
|
+
npm create crossbind@beta -- my-tool Native Executable
|
|
54
56
|
npm create crossbind@beta -- my-lib Library Prebuilt
|
|
55
57
|
```
|
|
56
58
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -80,7 +80,7 @@ function runSteps(entry, scripts, pm) {
|
|
|
80
80
|
}
|
|
81
81
|
if (entry.kind === 'lib') return [`${pm} run build`];
|
|
82
82
|
if (has('dev')) return [`${pm} run dev`];
|
|
83
|
-
if (has('start')) return [`${pm} start`];
|
|
83
|
+
if (has('start')) return has('build') ? [`${pm} run build`, `${pm} start`] : [`${pm} start`];
|
|
84
84
|
if (has('preview')) return [`${pm} run build`, `${pm} run preview`];
|
|
85
85
|
if (has('build')) return [`${pm} run build`];
|
|
86
86
|
return [];
|
package/src/manifest.json
CHANGED
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"label": "Native CLI",
|
|
47
47
|
"kind": "app",
|
|
48
48
|
"source": "examples/mobile-reactnative-cli",
|
|
49
|
-
"nativeFolders": true
|
|
49
|
+
"nativeFolders": true,
|
|
50
|
+
"workspaceOnly": ["eslint.config.mjs"]
|
|
50
51
|
},
|
|
51
52
|
{
|
|
52
53
|
"key": "mobile-reactnative-expo",
|
|
@@ -58,6 +59,17 @@
|
|
|
58
59
|
"nativeFolders": false,
|
|
59
60
|
"keepLockfile": true
|
|
60
61
|
},
|
|
62
|
+
{
|
|
63
|
+
"key": "desktop-electron",
|
|
64
|
+
"group": "Desktop",
|
|
65
|
+
"framework": null,
|
|
66
|
+
"label": "Electron",
|
|
67
|
+
"kind": "app",
|
|
68
|
+
"source": "examples/desktop-electron",
|
|
69
|
+
"allowBuilds": {
|
|
70
|
+
"electron-winstaller": false
|
|
71
|
+
}
|
|
72
|
+
},
|
|
61
73
|
{
|
|
62
74
|
"key": "backend-nodejs-wasm",
|
|
63
75
|
"group": "Backend",
|
|
@@ -66,6 +78,23 @@
|
|
|
66
78
|
"kind": "app",
|
|
67
79
|
"source": "examples/backend-nodejs-wasm"
|
|
68
80
|
},
|
|
81
|
+
{
|
|
82
|
+
"key": "backend-nodejs-native",
|
|
83
|
+
"group": "Backend",
|
|
84
|
+
"framework": "Node.js",
|
|
85
|
+
"label": "Node-API",
|
|
86
|
+
"kind": "app",
|
|
87
|
+
"source": "examples/backend-nodejs-native",
|
|
88
|
+
"workspaceOnly": ["ci"]
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"key": "backend-nodejs-standalone",
|
|
92
|
+
"group": "Backend",
|
|
93
|
+
"framework": "Node.js",
|
|
94
|
+
"label": "Standalone",
|
|
95
|
+
"kind": "app",
|
|
96
|
+
"source": "examples/backend-nodejs-standalone"
|
|
97
|
+
},
|
|
69
98
|
{
|
|
70
99
|
"key": "cloud-cloudflare-worker",
|
|
71
100
|
"group": "Cloud",
|
|
@@ -73,10 +102,18 @@
|
|
|
73
102
|
"label": "Cloudflare Worker",
|
|
74
103
|
"kind": "app",
|
|
75
104
|
"source": "examples/cloud-cloudflare-worker",
|
|
76
|
-
"allowBuilds":
|
|
77
|
-
"esbuild",
|
|
78
|
-
"workerd"
|
|
79
|
-
|
|
105
|
+
"allowBuilds": {
|
|
106
|
+
"esbuild": true,
|
|
107
|
+
"workerd": true
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"key": "native-executable",
|
|
112
|
+
"group": "Native",
|
|
113
|
+
"framework": null,
|
|
114
|
+
"label": "Executable",
|
|
115
|
+
"kind": "app",
|
|
116
|
+
"source": "examples/native-executable"
|
|
80
117
|
},
|
|
81
118
|
{
|
|
82
119
|
"key": "lib-prebuilt",
|
|
@@ -84,7 +121,8 @@
|
|
|
84
121
|
"framework": null,
|
|
85
122
|
"label": "Prebuilt",
|
|
86
123
|
"kind": "lib",
|
|
87
|
-
"source": "examples/lib-prebuilt-matrix"
|
|
124
|
+
"source": "examples/lib-prebuilt-matrix",
|
|
125
|
+
"workspaceOnly": ["LICENSE"]
|
|
88
126
|
},
|
|
89
127
|
{
|
|
90
128
|
"key": "lib-source",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# @crossbind/example-backend-nodejs-native
|
|
2
|
+
**crossbind Node.js native addon sample**
|
|
3
|
+
|
|
4
|
+
The same C++ code as
|
|
5
|
+
[backend-nodejs-wasm](https://github.com/crossbind/crossbind/tree/main/examples/backend-nodejs-wasm),
|
|
6
|
+
built as a Node-API addon instead of WebAssembly. `initNative()` resolves the same module shape on
|
|
7
|
+
both builds.
|
|
8
|
+
|
|
9
|
+
The app builds its own addon: crossbind generates the bindings of `src/native/native.h` and links
|
|
10
|
+
the matrix library's archives into one addon per platform. To use a library without building
|
|
11
|
+
anything, see
|
|
12
|
+
[backend-nodejs-standalone](https://github.com/crossbind/crossbind/tree/main/examples/backend-nodejs-standalone),
|
|
13
|
+
which loads the addons the same library ships prebuilt.
|
|
14
|
+
|
|
15
|
+
# Getting Started
|
|
16
|
+
|
|
17
|
+
>**Note**: Make sure you have completed the [crossbind - Prerequisites](https://crossbind.dev/docs/guide/getting-started/prerequisites) instructions.
|
|
18
|
+
The bindings and the Linux and Windows addons build in Docker; the macOS addons build on a macOS
|
|
19
|
+
host with Xcode's command line tools.
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
Install the dependencies:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm install
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Inside the crossbind repository, build the library's archives for the desktop platforms first:
|
|
30
|
+
`pnpm --filter @crossbind/example-lib-prebuilt-matrix run build:desktop`.
|
|
31
|
+
|
|
32
|
+
## Get Started
|
|
33
|
+
|
|
34
|
+
Build the addons of this machine's platform, for arm64 and x64, and their loader:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pnpm run build
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`pnpm run build:desktop` builds them for every desktop platform instead: `linux`, `linuxmusl` and
|
|
41
|
+
`win32`, plus `darwin` on a Mac.
|
|
42
|
+
|
|
43
|
+
Run it:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
node src/index.js
|
|
47
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Matrix from '@crossbind/example-lib-prebuilt-matrix/crossbind.config.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
general: {
|
|
5
|
+
name: 'crossbind-example-backend-nodejs-native',
|
|
6
|
+
},
|
|
7
|
+
dependencies: [
|
|
8
|
+
Matrix,
|
|
9
|
+
],
|
|
10
|
+
paths: {
|
|
11
|
+
config: import.meta.url,
|
|
12
|
+
output: 'dist',
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
// The loader picks the addon of this machine, from CommonJS and from ESM alike.
|
|
5
|
+
const EXPECTED = '= 6*J₃';
|
|
6
|
+
|
|
7
|
+
for (const entry of ['src/index.js', 'src/index.mjs']) {
|
|
8
|
+
const out = execFileSync(process.execPath, [entry], { cwd: resolve(import.meta.dirname, '..'), encoding: 'utf8' });
|
|
9
|
+
process.stdout.write(out);
|
|
10
|
+
if (!out.includes(EXPECTED)) {
|
|
11
|
+
console.error(`FAIL: ${entry} did not print "${EXPECTED}"`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crossbind/example-backend-nodejs-native",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"description": "crossbind - Node.js native addon sample",
|
|
6
|
+
"homepage": "https://github.com/crossbind/crossbind/tree/main/examples/backend-nodejs-native#readme",
|
|
7
|
+
"repository": "https://github.com/crossbind/crossbind.git",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "crossbind build -p host -e node -b release",
|
|
11
|
+
"build:desktop": "crossbind build -p darwin,linux,linuxmusl,win32 -e node -b release",
|
|
12
|
+
"e2e:prod": "node e2e/run.mjs"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.63"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@crossbind/core-embind-napi": "^2.0.0-beta.63",
|
|
19
|
+
"crossbind": "^2.0.0-beta.63"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"crossbind-sample",
|
|
23
|
+
"node",
|
|
24
|
+
"node-api",
|
|
25
|
+
"addon",
|
|
26
|
+
"bind",
|
|
27
|
+
"c++"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#include "native.h"
|
|
2
|
+
#include <Matrix.h>
|
|
3
|
+
|
|
4
|
+
std::string Native::sample() {
|
|
5
|
+
auto firstMatrix = std::make_shared<Matrix>(9, 1);
|
|
6
|
+
auto secondMatrix = std::make_shared<Matrix>(9, 2);
|
|
7
|
+
auto resultStr = std::to_string(firstMatrix->multiple(secondMatrix)->get(0));
|
|
8
|
+
return "J₃ * (2*J₃) = " + resultStr + "*J₃";
|
|
9
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @crossbind/example-backend-nodejs-standalone
|
|
2
|
+
**crossbind Node.js sample on a standalone Node-API package**
|
|
3
|
+
|
|
4
|
+
The app builds nothing: it installs the matrix library,
|
|
5
|
+
[@crossbind/example-lib-prebuilt-matrix](https://github.com/crossbind/crossbind/tree/main/examples/lib-prebuilt-matrix),
|
|
6
|
+
which ships prebuilt Node-API addons for macOS, Linux (glibc and musl) and Windows next to its
|
|
7
|
+
WebAssembly and mobile builds. It needs neither Docker nor a compiler, and crossbind is not one of
|
|
8
|
+
its dependencies.
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import { initNative, Matrix } from '@crossbind/example-lib-prebuilt-matrix/node/napi';
|
|
12
|
+
|
|
13
|
+
await initNative();
|
|
14
|
+
const product = new Matrix(9, 1).multiple(new Matrix(9, 2));
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Every name the library binds is ready once `initNative()` resolves, and the same import from
|
|
18
|
+
`/node/wasm` runs its WebAssembly build instead. A `@crossbind/port-<name>-standalone-napi` package
|
|
19
|
+
works the same way from its package root, e.g. `@crossbind/port-zlib-standalone-napi`. In an app of
|
|
20
|
+
your own, `npm install @crossbind/example-lib-prebuilt-matrix@beta` is the whole setup. To build an
|
|
21
|
+
addon from C++ of your own instead, start from
|
|
22
|
+
[backend-nodejs-native](https://github.com/crossbind/crossbind/tree/main/examples/backend-nodejs-native).
|
|
23
|
+
|
|
24
|
+
# Getting Started
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm install
|
|
28
|
+
pnpm start
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Inside the crossbind repository the library comes from the workspace, so build its addons first
|
|
32
|
+
(in Docker, and the macOS ones on a Mac):
|
|
33
|
+
`pnpm --filter @crossbind/example-lib-prebuilt-matrix run build:desktop`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node_modules
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
// The library's addon for this machine loads from CommonJS and from ESM alike.
|
|
5
|
+
const EXPECTED = '= 6*J₃';
|
|
6
|
+
|
|
7
|
+
for (const entry of ['src/index.js', 'src/index.mjs']) {
|
|
8
|
+
const out = execFileSync(process.execPath, [entry], { cwd: resolve(import.meta.dirname, '..'), encoding: 'utf8' });
|
|
9
|
+
process.stdout.write(out);
|
|
10
|
+
if (!out.includes(EXPECTED)) {
|
|
11
|
+
console.error(`FAIL: ${entry} did not print "${EXPECTED}"`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crossbind/example-backend-nodejs-standalone",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"description": "crossbind - Node.js sample on a standalone Node-API package, nothing to build",
|
|
6
|
+
"homepage": "https://github.com/crossbind/crossbind/tree/main/examples/backend-nodejs-standalone#readme",
|
|
7
|
+
"repository": "https://github.com/crossbind/crossbind.git",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node src/index.mjs",
|
|
11
|
+
"e2e:prod": "node e2e/run.mjs"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.63"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"crossbind-sample",
|
|
18
|
+
"node",
|
|
19
|
+
"node-api",
|
|
20
|
+
"standalone",
|
|
21
|
+
"c++"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
const matrix = require('@crossbind/example-lib-prebuilt-matrix/node/napi');
|
|
2
|
+
|
|
3
|
+
matrix.initNative().then(() => {
|
|
4
|
+
const product = new matrix.Matrix(9, 1).multiple(new matrix.Matrix(9, 2));
|
|
5
|
+
console.log(`Matrix multiplier with c++ => J₃ * (2*J₃) = ${product.get(0)}*J₃`);
|
|
6
|
+
});
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# @crossbind/example-backend-nodejs-wasm
|
|
2
2
|
**crossbind Node.js webassembly sample**
|
|
3
3
|
|
|
4
|
-
<a href="https://www.npmjs.com/package/@crossbind/example-backend-nodejs-wasm">
|
|
5
|
-
<img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-backend-nodejs-wasm?style=for-the-badge" />
|
|
6
|
-
</a>
|
|
7
4
|
<a href="https://github.com/crossbind/crossbind/blob/main/LICENSE">
|
|
8
5
|
<img alt="License" src="https://img.shields.io/github/license/crossbind/crossbind?style=for-the-badge" />
|
|
9
6
|
</a>
|
|
@@ -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.63"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"crossbind": "^2.0.0-beta.
|
|
16
|
+
"crossbind": "^2.0.0-beta.63"
|
|
17
17
|
},
|
|
18
18
|
"keywords": [
|
|
19
19
|
"crossbind-sample",
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# @crossbind/example-cloud-cloudflare-worker
|
|
2
2
|
**crossbind Cloudflare Worker sample**
|
|
3
3
|
|
|
4
|
-
<a href="https://www.npmjs.com/package/@crossbind/example-cloud-cloudflare-worker">
|
|
5
|
-
<img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-cloud-cloudflare-worker?style=for-the-badge" />
|
|
6
|
-
</a>
|
|
7
4
|
<a href="https://github.com/crossbind/crossbind/blob/main/LICENSE">
|
|
8
5
|
<img alt="License" src="https://img.shields.io/github/license/crossbind/crossbind?style=for-the-badge" />
|
|
9
6
|
</a>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @crossbind/example-desktop-electron
|
|
2
|
+
**crossbind Electron sample**
|
|
3
|
+
|
|
4
|
+
An Electron app whose main process runs C++: crossbind builds `src/native` and the matrix library
|
|
5
|
+
into a Node-API addon, the main process loads it (`src/main.js`), and the window asks it for results
|
|
6
|
+
over IPC (`src/preload.js`), so the window keeps Electron's sandbox and has no Node.js.
|
|
7
|
+
|
|
8
|
+
Node-API is ABI-stable: the addon Node.js loads loads in Electron too, with no rebuild per Electron
|
|
9
|
+
version and nothing for `electron-rebuild` to do.
|
|
10
|
+
|
|
11
|
+
# Getting Started
|
|
12
|
+
|
|
13
|
+
>**Note**: Make sure you have completed the [crossbind - Prerequisites](https://crossbind.dev/docs/guide/getting-started/prerequisites) instructions.
|
|
14
|
+
The bindings and the Linux and Windows addons build in Docker; the macOS addons build on a macOS
|
|
15
|
+
host with Xcode's command line tools.
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
Install the dependencies:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Inside the crossbind repository, build the library's archives for the desktop platforms first:
|
|
26
|
+
`pnpm --filter @crossbind/example-lib-prebuilt-matrix run build:desktop`.
|
|
27
|
+
|
|
28
|
+
## Get Started
|
|
29
|
+
|
|
30
|
+
Build the addon of this machine's platform, for arm64 and x64, and start the app:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pnpm run build
|
|
34
|
+
pnpm start
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`pnpm run build:desktop` builds the addons of macOS, Linux and Windows instead.
|
|
38
|
+
|
|
39
|
+
## Package
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pnpm run package
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
[electron-builder](https://www.electron.build) writes the app to `out/`; `npx electron-builder`
|
|
46
|
+
makes the installers. `electron-builder.yml` keeps `dist/` outside the asar archive: Electron loads
|
|
47
|
+
the addon from there as it is, and native code cannot read a library's data, such as `proj.db`,
|
|
48
|
+
inside the archive. Rename the app there (`productName`).
|
|
49
|
+
|
|
50
|
+
## Test
|
|
51
|
+
|
|
52
|
+
`pnpm run e2e:dev` opens the app from its sources with Playwright, `pnpm run e2e:prod` packages it
|
|
53
|
+
and opens the packaged app. On Linux they need a display, e.g. `xvfb-run -a pnpm run e2e:prod`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Matrix from '@crossbind/example-lib-prebuilt-matrix/crossbind.config.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
general: {
|
|
5
|
+
name: 'crossbind-example-desktop-electron',
|
|
6
|
+
},
|
|
7
|
+
dependencies: [
|
|
8
|
+
Matrix,
|
|
9
|
+
],
|
|
10
|
+
paths: {
|
|
11
|
+
config: import.meta.url,
|
|
12
|
+
output: 'dist',
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const { test: base, expect, _electron: electron } = require('@playwright/test');
|
|
4
|
+
|
|
5
|
+
const test = base.extend({ packaged: [false, { option: true }] });
|
|
6
|
+
|
|
7
|
+
const APP_DIR = path.resolve(__dirname, '..');
|
|
8
|
+
// A CI Linux has no setuid sandbox helper, and the test needs no sandbox.
|
|
9
|
+
const ARGS = process.platform === 'linux' ? ['--no-sandbox'] : [];
|
|
10
|
+
|
|
11
|
+
// The same Electron runs the app.asar `electron-builder --dir` wrote last, and reads what the archive
|
|
12
|
+
// keeps unpacked from the app.asar.unpacked beside it, as the packaged executable does.
|
|
13
|
+
function packagedApp() {
|
|
14
|
+
const out = path.join(APP_DIR, 'out');
|
|
15
|
+
const archives = fs.existsSync(out)
|
|
16
|
+
? fs.readdirSync(out, { recursive: true }).filter((file) => path.basename(file) === 'app.asar').map((file) => path.join(out, file))
|
|
17
|
+
: [];
|
|
18
|
+
if (archives.length === 0) throw new Error('no out/**/app.asar - run `electron-builder --dir` first');
|
|
19
|
+
return archives.reduce((newest, file) => (fs.statSync(file).mtimeMs > fs.statSync(newest).mtimeMs ? file : newest));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test('check string receiving from c++', async ({ packaged }) => {
|
|
23
|
+
const app = await electron.launch({ args: [...ARGS, packaged ? packagedApp() : APP_DIR] });
|
|
24
|
+
try {
|
|
25
|
+
const window = await app.firstWindow();
|
|
26
|
+
await expect(window.locator('#cppMessage')).toHaveText('J₃ * (2*J₃) = 6*J₃');
|
|
27
|
+
} finally {
|
|
28
|
+
await app.close();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# crossbind's output stays outside the asar archive: Electron loads the addon from there as it is,
|
|
2
|
+
# and native code cannot read files inside the archive.
|
|
3
|
+
productName: crossbind Electron sample
|
|
4
|
+
directories:
|
|
5
|
+
output: out
|
|
6
|
+
files:
|
|
7
|
+
- src/**
|
|
8
|
+
- dist/**
|
|
9
|
+
- '!dist/prebuilt'
|
|
10
|
+
asarUnpack:
|
|
11
|
+
- dist/**
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crossbind/example-desktop-electron",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"description": "crossbind - Electron desktop app sample",
|
|
6
|
+
"homepage": "https://github.com/crossbind/crossbind/tree/main/examples/desktop-electron#readme",
|
|
7
|
+
"repository": "https://github.com/crossbind/crossbind.git",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"main": "src/main.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "crossbind build -p host -e node -b release",
|
|
12
|
+
"build:desktop": "crossbind build -p darwin,linux,win32 -e node -b release",
|
|
13
|
+
"start": "electron .",
|
|
14
|
+
"package": "electron-builder --dir",
|
|
15
|
+
"e2e:dev": "playwright test --project=dev",
|
|
16
|
+
"e2e:prod": "electron-builder --dir && playwright test --project=packaged"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@crossbind/core-embind-napi": "^2.0.0-beta.63",
|
|
20
|
+
"@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.63",
|
|
21
|
+
"@playwright/test": "^1.63.0",
|
|
22
|
+
"crossbind": "^2.0.0-beta.63",
|
|
23
|
+
"electron": "^44.5.1",
|
|
24
|
+
"electron-builder": "^26.15.3"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"crossbind-sample",
|
|
28
|
+
"electron",
|
|
29
|
+
"desktop",
|
|
30
|
+
"node-api",
|
|
31
|
+
"c++"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { defineConfig } = require('@playwright/test');
|
|
2
|
+
|
|
3
|
+
// dev runs the app from its sources, packaged runs what `electron-builder --dir` wrote to out/.
|
|
4
|
+
module.exports = defineConfig({
|
|
5
|
+
testDir: './e2e',
|
|
6
|
+
timeout: 60 * 1000,
|
|
7
|
+
forbidOnly: !!process.env.CI,
|
|
8
|
+
retries: process.env.CI ? 2 : 0,
|
|
9
|
+
workers: 1,
|
|
10
|
+
reporter: 'list',
|
|
11
|
+
projects: [
|
|
12
|
+
{ name: 'dev', use: { packaged: false } },
|
|
13
|
+
{ name: 'packaged', use: { packaged: true } },
|
|
14
|
+
],
|
|
15
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
|
|
3
|
+
<html>
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="utf-8">
|
|
7
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
|
|
8
|
+
<title>crossbind Electron sample</title>
|
|
9
|
+
<script src="./renderer.js" defer></script>
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body>
|
|
13
|
+
<p>Matrix multiplier with c++ => <span id="cppMessage">loading ...</span></p>
|
|
14
|
+
</body>
|
|
15
|
+
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const path = require('node:path');
|
|
2
|
+
const { app, BrowserWindow, ipcMain } = require('electron');
|
|
3
|
+
const initNative = require('../dist/crossbind-example-desktop-electron.native.cjs');
|
|
4
|
+
|
|
5
|
+
// The addon runs in the main process, the one with Node.js; the window asks it over IPC.
|
|
6
|
+
ipcMain.handle('native:sample', async () => {
|
|
7
|
+
const { Native } = await initNative();
|
|
8
|
+
return Native.sample();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
function createWindow() {
|
|
12
|
+
const window = new BrowserWindow({
|
|
13
|
+
width: 640,
|
|
14
|
+
height: 360,
|
|
15
|
+
webPreferences: { preload: path.join(__dirname, 'preload.js') },
|
|
16
|
+
});
|
|
17
|
+
window.loadFile(path.join(__dirname, 'index.html'));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
app.whenReady().then(() => {
|
|
21
|
+
createWindow();
|
|
22
|
+
app.on('activate', () => {
|
|
23
|
+
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
app.on('window-all-closed', () => {
|
|
28
|
+
if (process.platform !== 'darwin') app.quit();
|
|
29
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#include "native.h"
|
|
2
|
+
#include <Matrix.h>
|
|
3
|
+
|
|
4
|
+
std::string Native::sample() {
|
|
5
|
+
auto firstMatrix = std::make_shared<Matrix>(9, 1);
|
|
6
|
+
auto secondMatrix = std::make_shared<Matrix>(9, 2);
|
|
7
|
+
auto resultStr = std::to_string(firstMatrix->multiple(secondMatrix)->get(0));
|
|
8
|
+
return "J₃ * (2*J₃) = " + resultStr + "*J₃";
|
|
9
|
+
}
|