create-crossbind 2.0.0-beta.62 → 2.0.0-beta.64

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.
Files changed (81) hide show
  1. package/README.md +3 -1
  2. package/package.json +1 -1
  3. package/src/index.js +8 -1
  4. package/src/manifest.json +44 -6
  5. package/src/readme.js +12 -0
  6. package/templates/backend-nodejs-native/README.md +47 -0
  7. package/templates/backend-nodejs-native/_gitignore +3 -0
  8. package/templates/backend-nodejs-native/crossbind.config.mjs +14 -0
  9. package/templates/backend-nodejs-native/e2e/run.mjs +14 -0
  10. package/templates/backend-nodejs-native/package.json +29 -0
  11. package/templates/backend-nodejs-native/src/index.js +5 -0
  12. package/templates/backend-nodejs-native/src/index.mjs +5 -0
  13. package/templates/backend-nodejs-native/src/native/native.cpp +9 -0
  14. package/templates/backend-nodejs-native/src/native/native.h +12 -0
  15. package/templates/backend-nodejs-standalone/README.md +33 -0
  16. package/templates/backend-nodejs-standalone/_gitignore +1 -0
  17. package/templates/backend-nodejs-standalone/e2e/run.mjs +14 -0
  18. package/templates/backend-nodejs-standalone/package.json +23 -0
  19. package/templates/backend-nodejs-standalone/src/index.js +6 -0
  20. package/templates/backend-nodejs-standalone/src/index.mjs +5 -0
  21. package/templates/backend-nodejs-wasm/README.md +0 -3
  22. package/templates/backend-nodejs-wasm/package.json +2 -2
  23. package/templates/cloud-cloudflare-worker/Readme.md +0 -3
  24. package/templates/cloud-cloudflare-worker/package.json +2 -2
  25. package/templates/desktop-electron/README.md +53 -0
  26. package/templates/desktop-electron/_gitignore +6 -0
  27. package/templates/desktop-electron/crossbind.config.mjs +14 -0
  28. package/templates/desktop-electron/e2e/crossbind.spec.cjs +30 -0
  29. package/templates/desktop-electron/electron-builder.yml +11 -0
  30. package/templates/desktop-electron/package.json +33 -0
  31. package/templates/desktop-electron/playwright.config.cjs +15 -0
  32. package/templates/desktop-electron/pnpm-workspace.yaml +2 -0
  33. package/templates/desktop-electron/src/index.html +16 -0
  34. package/templates/desktop-electron/src/main.js +29 -0
  35. package/templates/desktop-electron/src/native/native.cpp +9 -0
  36. package/templates/desktop-electron/src/native/native.h +12 -0
  37. package/templates/desktop-electron/src/preload.js +5 -0
  38. package/templates/desktop-electron/src/renderer.js +5 -0
  39. package/templates/lib-cmake/README.md +2 -2
  40. package/templates/lib-cmake/package.json +1 -1
  41. package/templates/lib-prebuilt/AGENTS.md +3 -0
  42. package/templates/lib-prebuilt/README.md +23 -11
  43. package/templates/lib-prebuilt/edge/wasm +1 -0
  44. package/templates/lib-prebuilt/edge/wasm.d.ts +1 -0
  45. package/templates/lib-prebuilt/node/napi +1 -0
  46. package/templates/lib-prebuilt/node/napi.d.ts +1 -0
  47. package/templates/lib-prebuilt/node/wasm +1 -0
  48. package/templates/lib-prebuilt/node/wasm.d.ts +1 -0
  49. package/templates/lib-prebuilt/package.json +15 -3
  50. package/templates/lib-source/README.md +2 -2
  51. package/templates/lib-source/package.json +1 -1
  52. package/templates/mobile-reactnative-cli/README.md +0 -3
  53. package/templates/mobile-reactnative-cli/__mocks__/native-header.js +5 -0
  54. package/templates/mobile-reactnative-cli/__tests__/App.test.tsx +1 -1
  55. package/templates/mobile-reactnative-cli/ci/crossbind-snapshot/cache.json +3 -3
  56. package/templates/mobile-reactnative-cli/jest.config.js +3 -0
  57. package/templates/mobile-reactnative-cli/package.json +8 -8
  58. package/templates/mobile-reactnative-expo/README.md +12 -3
  59. package/templates/mobile-reactnative-expo/package-lock.json +1852 -2068
  60. package/templates/mobile-reactnative-expo/package.json +34 -33
  61. package/templates/mobile-reactnative-expo/src/app/index.tsx +1 -2
  62. package/templates/mobile-reactnative-expo/src/components/animated-icon.tsx +1 -1
  63. package/templates/mobile-reactnative-expo/src/components/app-tabs.tsx +2 -2
  64. package/templates/mobile-reactnative-expo/src/components/app-tabs.web.tsx +1 -1
  65. package/templates/mobile-reactnative-expo/src/hooks/use-theme.ts +1 -1
  66. package/templates/native-executable/README.md +50 -0
  67. package/templates/native-executable/_gitignore +3 -0
  68. package/templates/native-executable/crossbind.config.mjs +14 -0
  69. package/templates/native-executable/e2e/run.mjs +27 -0
  70. package/templates/native-executable/package.json +26 -0
  71. package/templates/native-executable/src/native/main.cpp +10 -0
  72. package/templates/web-react-rspack/README.md +0 -3
  73. package/templates/web-react-rspack/package.json +3 -3
  74. package/templates/web-react-vite/README.md +0 -3
  75. package/templates/web-react-vite/package.json +2 -2
  76. package/templates/web-svelte-vite/README.md +0 -3
  77. package/templates/web-svelte-vite/package.json +2 -2
  78. package/templates/web-vanilla/README.md +0 -3
  79. package/templates/web-vanilla/package.json +2 -2
  80. package/templates/web-vue-vite/README.md +0 -3
  81. package/templates/web-vue-vite/package.json +2 -2
@@ -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
+ }
@@ -0,0 +1,12 @@
1
+ #ifndef _NATIVE_H
2
+ #define _NATIVE_H
3
+
4
+ #include <string>
5
+ #include <memory>
6
+
7
+ class Native {
8
+ public:
9
+ static std::string sample();
10
+ };
11
+
12
+ #endif
@@ -0,0 +1,5 @@
1
+ const { contextBridge, ipcRenderer } = require('electron');
2
+
3
+ contextBridge.exposeInMainWorld('native', {
4
+ sample: () => ipcRenderer.invoke('native:sample'),
5
+ });
@@ -0,0 +1,5 @@
1
+ const message = document.querySelector('#cppMessage');
2
+
3
+ window.native.sample()
4
+ .then((result) => { message.textContent = result; })
5
+ .catch((error) => { message.textContent = error.message; });
@@ -2,7 +2,7 @@
2
2
  **crossbind sample library: simple cmake library**
3
3
 
4
4
  <a href="https://www.npmjs.com/package/@crossbind/example-lib-cmake">
5
- <img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-lib-cmake?style=for-the-badge" />
5
+ <img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-lib-cmake/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" />
@@ -12,7 +12,7 @@
12
12
  Start by installing these package with the following command:
13
13
 
14
14
  ```sh
15
- npm install @crossbind/example-lib-cmake
15
+ npm install @crossbind/example-lib-cmake@beta
16
16
  ```
17
17
 
18
18
  To enable the library, modify the crossbind.config.js file as shown below.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossbind/example-lib-cmake",
3
- "version": "2.0.0-beta.62",
3
+ "version": "2.0.0-beta.64",
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",
@@ -41,8 +41,11 @@ pnpm --filter=@crossbind/example-lib-prebuilt-matrix run build
41
41
  pnpm --filter=@crossbind/example-lib-prebuilt-matrix run build:wasm
42
42
  pnpm --filter=@crossbind/example-lib-prebuilt-matrix run build:android
43
43
  pnpm --filter=@crossbind/example-lib-prebuilt-matrix run build:ios # macOS only
44
+ pnpm --filter=@crossbind/example-lib-prebuilt-matrix run build:desktop # darwin on macOS; linux, linuxmusl, win32 in Docker
44
45
  ```
45
46
 
47
+ The desktop archives are what `examples/backend-nodejs-native`, `examples/desktop-electron` and `examples/native-executable` link. `build:desktop` also builds the package's own Node-API addons, which `node/napi` loads (`examples/backend-nodejs-standalone`); `node/wasm` and `edge/wasm` load its WebAssembly builds. The release train builds the archives on the runners of their platforms and the addons on its node runners.
48
+
46
49
  `prepublishOnly` runs `crossbind build` so `pnpm publish` always ships fresh artifacts.
47
50
 
48
51
  ## Common pitfalls
@@ -2,7 +2,7 @@
2
2
  **Simple matrix multiplier**
3
3
 
4
4
  <a href="https://www.npmjs.com/package/@crossbind/example-lib-prebuilt-matrix">
5
- <img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-lib-prebuilt-matrix?style=for-the-badge" />
5
+ <img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-lib-prebuilt-matrix/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" />
@@ -12,7 +12,7 @@
12
12
  Start by installing these package with the following command:
13
13
 
14
14
  ```sh
15
- npm install @crossbind/example-lib-prebuilt-matrix
15
+ npm install @crossbind/example-lib-prebuilt-matrix@beta
16
16
  ```
17
17
 
18
18
  To enable the library, modify the crossbind.config.js file as shown below.
@@ -58,7 +58,7 @@ console.log(result.get(0));
58
58
 
59
59
  ### Usage in JavaScript Code (web, without plugin)
60
60
  ```js
61
- import 'node_modules/@crossbind/example-lib-prebuilt-matrix/dist/crossbind-example-lib-prebuilt-matrix.browser.js';
61
+ import 'node_modules/@crossbind/example-lib-prebuilt-matrix/dist/crossbind-example-lib-prebuilt-matrix-wasm-wasm32-st-release.browser.js';
62
62
 
63
63
  initNative({ path: 'node_modules/@crossbind/example-lib-prebuilt-matrix/dist' }).then(({ Matrix }) => {
64
64
  const a = new Matrix(1210000, 1);
@@ -68,14 +68,26 @@ initNative({ path: 'node_modules/@crossbind/example-lib-prebuilt-matrix/dist' })
68
68
  });
69
69
  ```
70
70
 
71
- ### Usage in JavaScript Code (node.js)
71
+ ### Usage in JavaScript Code (Node.js)
72
+ The package ships prebuilt Node-API addons for macOS, Linux (glibc and musl) and Windows, and a WebAssembly build for Node.js. Each entry exports `Matrix` once `initNative()` resolves; `require()` of an entry needs Node.js 22.12 or later.
72
73
  ```js
73
- import 'node_modules/@crossbind/example-lib-prebuilt-matrix/dist/crossbind-example-lib-prebuilt-matrix.node.js';
74
+ import { initNative, Matrix } from '@crossbind/example-lib-prebuilt-matrix/node/napi'; // or '/node/wasm'
74
75
 
75
- initNative().then(({ Matrix }) => {
76
- const a = new Matrix(1210000, 1);
77
- const b = new Matrix(1210000, 2);
78
- const result = a.multiple(b);
79
- console.log(result.get(0));
80
- });
76
+ await initNative();
77
+ const a = new Matrix(1210000, 1);
78
+ const b = new Matrix(1210000, 2);
79
+ console.log(a.multiple(b).get(0));
80
+ ```
81
+
82
+ ### Usage in JavaScript Code (Cloudflare Workers)
83
+ Wrangler bundles the WebAssembly module the entry imports.
84
+ ```js
85
+ import { initNative, Matrix } from '@crossbind/example-lib-prebuilt-matrix/edge/wasm';
86
+
87
+ export default {
88
+ async fetch() {
89
+ await initNative();
90
+ return new Response(String(new Matrix(4, 2).get(0)));
91
+ },
92
+ };
81
93
  ```
@@ -0,0 +1 @@
1
+ export * from '../dist/edge/wasm.mjs';
@@ -0,0 +1 @@
1
+ export * from '../dist/edge/wasm.mjs';
@@ -0,0 +1 @@
1
+ export * from '../dist/node/napi.mjs';
@@ -0,0 +1 @@
1
+ export * from '../dist/node/napi.mjs';
@@ -0,0 +1 @@
1
+ export * from '../dist/node/wasm.mjs';
@@ -0,0 +1 @@
1
+ export * from '../dist/node/wasm.mjs';
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossbind/example-lib-prebuilt-matrix",
3
- "version": "2.0.0-beta.62",
3
+ "version": "2.0.0-beta.64",
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",
@@ -13,22 +13,34 @@
13
13
  "build:android": "crossbind build -p android",
14
14
  "build:ios": "crossbind build -p ios",
15
15
  "build:darwin": "crossbind build -p darwin",
16
+ "build:desktop": "crossbind build -p darwin,linux,linuxmusl,win32 -e node",
16
17
  "clear": "rm -rf .crossbind dist *.xcframework",
17
18
  "prepublishOnly": "crossbind build"
18
19
  },
19
20
  "devDependencies": {
20
- "crossbind": "^2.0.0-beta.62"
21
+ "crossbind": "^2.0.0-beta.64"
21
22
  },
22
23
  "keywords": [
23
24
  "crossbind-sample",
24
25
  "matrix",
25
26
  "crossbind-sample",
26
27
  "webassembly",
27
- "react-native"
28
+ "react-native",
29
+ "node",
30
+ "node-api"
28
31
  ],
29
32
  "types": "./dist/types/index.d.ts",
30
33
  "typesVersions": {
31
34
  "*": {
35
+ "node/napi": [
36
+ "./node/napi.d.ts"
37
+ ],
38
+ "node/wasm": [
39
+ "./node/wasm.d.ts"
40
+ ],
41
+ "edge/wasm": [
42
+ "./edge/wasm.d.ts"
43
+ ],
32
44
  "*.h": [
33
45
  "./dist/types/index.d.ts"
34
46
  ]
@@ -2,7 +2,7 @@
2
2
  **crossbind sample library: simple source library**
3
3
 
4
4
  <a href="https://www.npmjs.com/package/@crossbind/example-lib-source">
5
- <img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-lib-source?style=for-the-badge" />
5
+ <img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-lib-source/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" />
@@ -12,7 +12,7 @@
12
12
  Start by installing these package with the following command:
13
13
 
14
14
  ```sh
15
- npm install @crossbind/example-lib-source
15
+ npm install @crossbind/example-lib-source@beta
16
16
  ```
17
17
 
18
18
  To enable the library, modify the crossbind.config.js file as shown below.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossbind/example-lib-source",
3
- "version": "2.0.0-beta.62",
3
+ "version": "2.0.0-beta.64",
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",
@@ -1,9 +1,6 @@
1
1
  # @crossbind/example-mobile-reactnative-cli
2
2
  **crossbind React Native sample**
3
3
 
4
- <a href="https://www.npmjs.com/package/@crossbind/example-mobile-reactnative-cli">
5
- <img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-mobile-reactnative-cli?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,5 @@
1
+ // A test renders the app without its native module: the header's exports as the app uses them.
2
+ module.exports = {
3
+ initNative: () => Promise.resolve(),
4
+ Native: { sample: () => 'hello' },
5
+ };
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React from 'react';
6
6
  import ReactTestRenderer from 'react-test-renderer';
7
- import App from '../App';
7
+ import App from '../src/App';
8
8
 
9
9
  test('renders correctly', async () => {
10
10
  await ReactTestRenderer.act(() => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "hashes": {
3
- "/Users/runner/work/crossbind/crossbind/examples/mobile-reactnative-cli/src/native/native.h": "swig-macros-1\nd105082c6e8c8652ea461e161c501e824b6b625f7b819490102c5c0699744249\nconstants:Native",
4
- "/Users/runner/work/crossbind/crossbind/examples/mobile-reactnative-cli/.crossbind/build/interface/native.i": "swig-constants-1\nd2951a720fdd54191e27157df067c64d7d7839b41c14494d63aef4f3a4eae3a2\nd105082c6e8c8652ea461e161c501e824b6b625f7b819490102c5c0699744249"
3
+ "/Users/runner/work/crossbind/crossbind/examples/mobile-reactnative-cli/src/native/native.h": "swig-macros-4\nd105082c6e8c8652ea461e161c501e824b6b625f7b819490102c5c0699744249\nconstants:Native\nnamed:Native",
4
+ "/Users/runner/work/crossbind/crossbind/examples/mobile-reactnative-cli/.crossbind/build/interface/native.i": "swig-extras-2\nd2951a720fdd54191e27157df067c64d7d7839b41c14494d63aef4f3a4eae3a2\nd105082c6e8c8652ea461e161c501e824b6b625f7b819490102c5c0699744249\nnamed:Native"
5
5
  },
6
6
  "interfaces": {
7
7
  "/Users/runner/work/crossbind/crossbind/examples/mobile-reactnative-cli/src/native/native.h": "/Users/runner/work/crossbind/crossbind/examples/mobile-reactnative-cli/.crossbind/build/interface/native.i"
@@ -9,4 +9,4 @@
9
9
  "bridges": {
10
10
  "/Users/runner/work/crossbind/crossbind/examples/mobile-reactnative-cli/.crossbind/build/interface/native.i": "/Users/runner/work/crossbind/crossbind/examples/mobile-reactnative-cli/.crossbind/build/bridge/native.i.cpp"
11
11
  }
12
- }
12
+ }
@@ -1,3 +1,6 @@
1
1
  module.exports = {
2
2
  preset: '@react-native/jest-preset',
3
+ // pnpm keeps packages under node_modules/.pnpm, which the preset's pattern does not look past.
4
+ transformIgnorePatterns: ['node_modules/(?!(\\.pnpm|(jest-)?react-native|@react-native(-community)?)/)'],
5
+ moduleNameMapper: { '\\.h$': '<rootDir>/__mocks__/native-header.js' },
3
6
  };
@@ -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.62",
24
- "@crossbind/plugin-react-native": "^2.0.0-beta.62",
25
- "@crossbind/plugin-react-native-ios-helper": "^2.0.0-beta.62",
26
- "@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.62",
23
+ "@crossbind/core-embind-jsi": "^2.0.0-beta.64",
24
+ "@crossbind/plugin-react-native": "^2.0.0-beta.64",
25
+ "@crossbind/plugin-react-native-ios-helper": "^2.0.0-beta.64",
26
+ "@crossbind/example-lib-prebuilt-matrix": "^2.0.0-beta.64",
27
27
  "react": "19.3.0",
28
28
  "react-native": "0.87.1",
29
29
  "react-native-safe-area-context": "^5.8.0",
30
- "hermes-compiler": "*"
30
+ "hermes-compiler": "250829098.0.17"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@babel/core": "^7.29.7",
@@ -48,10 +48,10 @@
48
48
  "@types/react-test-renderer": "^19.3.0",
49
49
  "eslint": "^8.19.0",
50
50
  "jest": "^29.6.3",
51
- "prettier": "3.9.8",
51
+ "prettier": "3.9.10",
52
52
  "react-test-renderer": "19.3.0",
53
- "typescript": "^5.8.3",
54
- "@crossbind/plugin-metro": "^2.0.0-beta.62"
53
+ "typescript": "^6.0.3",
54
+ "@crossbind/plugin-metro": "^2.0.0-beta.64"
55
55
  },
56
56
  "engines": {
57
57
  "node": ">=24"
@@ -1,9 +1,6 @@
1
1
  # @crossbind/example-mobile-reactnative-expo
2
2
  **crossbind Expo sample**
3
3
 
4
- <a href="https://www.npmjs.com/package/@crossbind/example-mobile-reactnative-expo">
5
- <img alt="NPM version" src="https://img.shields.io/npm/v/@crossbind/example-mobile-reactnative-expo?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>
@@ -32,3 +29,15 @@
32
29
  ```bash
33
30
  npm run android
34
31
  ```
32
+
33
+ 4. Start the web app (the C++ runs as WebAssembly)
34
+
35
+ ```bash
36
+ npm run web
37
+ ```
38
+
39
+ 5. Export the web app to `dist`
40
+
41
+ ```bash
42
+ npm run export:web
43
+ ```