diff --git a/.changeset/many-pens-join.md b/.changeset/many-pens-join.md new file mode 100644 index 00000000..1aa8aa8e --- /dev/null +++ b/.changeset/many-pens-join.md @@ -0,0 +1,8 @@ +--- +"ferric-cli": minor +"@react-native-node-api/test-app": minor +--- + +- Created `init` command to generate / scaffold the project. +- Replacing `ferric-example` with `app-test`, scaffolding the project there. +- Added `Cargo.toml` optimizations for size. diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 52aa06c7..a7a53aac 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -41,7 +41,6 @@ jobs: # Bootstrap host package to get weak-node-api and ferric-example to get types # TODO: Solve this by adding an option to ferric to build only types or by committing the types into the repo as a fixture for an "init" command - run: npm run bootstrap --workspace react-native-node-api - - run: npm run bootstrap --workspace @react-native-node-api/ferric-example - run: npm run lint env: DEBUG: eslint:eslint @@ -152,9 +151,9 @@ jobs: - name: Build weak-node-api for all architectures run: npm run build-weak-node-api -- --android working-directory: packages/host - - name: Build ferric-example for all architectures + - name: Build lib_in_rust for android architectures run: npm run build -- --android - working-directory: packages/ferric-example + working-directory: apps/test-app/lib_in_rust - name: Run tests (Android) timeout-minutes: 75 uses: reactivecircus/android-emulator-runner@v2 diff --git a/apps/test-app/App.tsx b/apps/test-app/App.tsx index 62c59944..3efcc002 100644 --- a/apps/test-app/App.tsx +++ b/apps/test-app/App.tsx @@ -23,14 +23,12 @@ type Context = { allTests?: boolean; nodeAddonExamples?: boolean; nodeTests?: boolean; - ferricExample?: boolean; }; function loadTests({ allTests = false, nodeAddonExamples = allTests, nodeTests = allTests, - ferricExample = allTests, }: Context) { describeIf(nodeAddonExamples, "Node Addon Examples", () => { for (const [suiteName, examples] of Object.entries( @@ -67,18 +65,6 @@ function loadTests({ registerTestSuite(nodeTestsSuites); }); - - describeIf(ferricExample, "ferric-example", () => { - it("exports a callable sum function", () => { - const exampleAddon = - /* eslint-disable-next-line @typescript-eslint/no-require-imports -- TODO: Determine why a dynamic import doesn't work on Android */ - require("ferric-example") as typeof import("ferric-example"); - const result = exampleAddon.sum(1, 3); - if (result !== 4) { - throw new Error(`Expected 1 + 3 to equal 4, but got ${result}`); - } - }); - }); } export default function App() { diff --git a/apps/test-app/lib_in_rust/.gitignore b/apps/test-app/lib_in_rust/.gitignore new file mode 100644 index 00000000..24a51298 --- /dev/null +++ b/apps/test-app/lib_in_rust/.gitignore @@ -0,0 +1,8 @@ +target +Cargo.lock + +*.xcframework/ +*.apple.node/ +*.android.node/ + +dist diff --git a/packages/ferric-example/Cargo.toml b/apps/test-app/lib_in_rust/Cargo.toml similarity index 87% rename from packages/ferric-example/Cargo.toml rename to apps/test-app/lib_in_rust/Cargo.toml index 2524a0e8..a743d2d6 100644 --- a/packages/ferric-example/Cargo.toml +++ b/apps/test-app/lib_in_rust/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ferric-example" +name = "lib_in_rust" version = "1.0.0" edition = "2021" license = "MIT" @@ -23,3 +23,5 @@ napi-build = "2" [profile.release] lto = true codegen-units = 1 +strip = "symbols" +opt-level = "z" diff --git a/packages/ferric-example/build.rs b/apps/test-app/lib_in_rust/build.rs similarity index 100% rename from packages/ferric-example/build.rs rename to apps/test-app/lib_in_rust/build.rs diff --git a/apps/test-app/lib_in_rust/package.json b/apps/test-app/lib_in_rust/package.json new file mode 100644 index 00000000..bcf6bc14 --- /dev/null +++ b/apps/test-app/lib_in_rust/package.json @@ -0,0 +1,14 @@ +{ + "name": "lib_in_rust", + "private": true, + "version": "0.1.0", + "main": "dist/lib_in_rust.js", + "types": "dist/lib_in_rust.d.ts", + "scripts": { + "build": "ferric build", + "build:release": "npm run build -- --configuration release" + }, + "devDependencies": { + "ferric-cli": "latest" + } +} diff --git a/packages/ferric-example/src/lib.rs b/apps/test-app/lib_in_rust/src/lib.rs similarity index 87% rename from packages/ferric-example/src/lib.rs rename to apps/test-app/lib_in_rust/src/lib.rs index ecfd7ab1..1064d5bf 100644 --- a/packages/ferric-example/src/lib.rs +++ b/apps/test-app/lib_in_rust/src/lib.rs @@ -2,5 +2,5 @@ use napi_derive::napi; #[napi] pub fn sum(a: i32, b: i32) -> i32 { - a + b + a + b } diff --git a/apps/test-app/package.json b/apps/test-app/package.json index f77dabf5..5d7edd24 100644 --- a/apps/test-app/package.json +++ b/apps/test-app/package.json @@ -15,8 +15,10 @@ "test:ios": "mocha-remote --exit-on-error -- concurrently --passthrough-arguments --kill-others-on-fail npm:metro 'npm:ios -- {@}' --", "test:ios:allTests": "MOCHA_REMOTE_CONTEXT=allTests npm run test:ios -- ", "test:ios:nodeAddonExamples": "MOCHA_REMOTE_CONTEXT=nodeAddonExamples npm run test:ios -- ", - "test:ios:nodeTests": "MOCHA_REMOTE_CONTEXT=nodeTests npm run test:ios -- ", - "test:ios:ferricExample": "MOCHA_REMOTE_CONTEXT=ferricExample npm run test:ios -- " + "gen:rs": "ferric init lib_in_rust", + "build:rs": "ferric build --cwd lib_in_rust", + "build:rs:release": "npm run build:rs -- --configuration release", + "test:ios:nodeTests": "MOCHA_REMOTE_CONTEXT=nodeTests npm run test:ios -- " }, "dependencies": { "@babel/core": "^7.26.10", @@ -34,7 +36,7 @@ "@types/mocha": "^10.0.10", "@types/react": "^19.0.0", "concurrently": "^9.1.2", - "ferric-example": "^0.1.0", + "ferric-cli": "*", "mocha": "^11.6.0", "mocha-remote-cli": "^1.13.2", "mocha-remote-react-native": "^1.13.2", diff --git a/eslint.config.js b/eslint.config.js index c0af837e..33a3bb74 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -13,9 +13,6 @@ export default tseslint.config( "apps/test-app/ios/**", "packages/host/hermes/**", "packages/node-addon-examples/examples/**", - "packages/ferric-example/ferric_example.js", - "packages/ferric-example/ferric_example.d.ts", - "packages/ferric-example/target/**", "packages/node-tests/node/**", "packages/node-tests/tests/**", "packages/node-tests/*.generated.js", diff --git a/package-lock.json b/package-lock.json index 051c13fb..22d3cfcd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,7 @@ "packages/ferric", "packages/host", "packages/node-addon-examples", - "packages/node-tests", - "packages/ferric-example" + "packages/node-tests" ], "devDependencies": { "@changesets/cli": "^2.29.5", @@ -30,7 +29,7 @@ "prettier": "^3.6.2", "react-native": "0.79.5", "tsx": "^4.20.3", - "typescript": "^5.8", + "typescript": "^5.8.0", "typescript-eslint": "^8.38.0" } }, @@ -53,7 +52,7 @@ "@types/mocha": "^10.0.10", "@types/react": "^19.0.0", "concurrently": "^9.1.2", - "ferric-example": "^0.1.0", + "ferric-cli": "*", "mocha": "^11.6.0", "mocha-remote-cli": "^1.13.2", "mocha-remote-react-native": "^1.13.2", @@ -4077,9 +4076,9 @@ } }, "node_modules/@napi-rs/cli": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-3.0.3.tgz", - "integrity": "sha512-5PxtOcax9PoOriYWYf8BFNgOzUnsogYUDRM8p2leT2VtG/NTMZCyoRQMzSMB0qEaw+Durkefc5jXCpEF6wrWbA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-3.1.1.tgz", + "integrity": "sha512-fwg/YgV0caxXwZjgq+jOadmb0R5apmlQ9XkU4r1StmgHs+1CXsiGJshVetOnbBMpJ7wdvFGfbFKkXGgTPBMMDg==", "license": "MIT", "dependencies": { "@inquirer/prompts": "^7.4.0", @@ -4094,8 +4093,7 @@ "js-yaml": "^4.1.0", "lodash-es": "^4.17.21", "semver": "^7.7.1", - "typanion": "^3.14.0", - "wasm-sjlj": "^1.0.6" + "typanion": "^3.14.0" }, "bin": { "napi": "dist/cli.js", @@ -5892,10 +5890,6 @@ "node": "^12.20.0 || >=14" } }, - "node_modules/@react-native-node-api/ferric-example": { - "resolved": "packages/ferric-example", - "link": true - }, "node_modules/@react-native-node-api/node-addon-examples": { "resolved": "packages/node-addon-examples", "link": true @@ -8202,6 +8196,67 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "license": "MIT" }, + "node_modules/copyfiles": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", + "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "untildify": "^4.0.0", + "yargs": "^16.1.0" + }, + "bin": { + "copyfiles": "copyfiles", + "copyup": "copyfiles" + } + }, + "node_modules/copyfiles/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/copyfiles/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/copyfiles/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/core-js-compat": { "version": "3.41.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", @@ -8215,6 +8270,13 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", @@ -9083,10 +9145,6 @@ "resolved": "packages/ferric", "link": true }, - "node_modules/ferric-example": { - "resolved": "packages/ferric-example", - "link": true - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -10143,6 +10201,13 @@ "node": ">=8" } }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -11630,6 +11695,37 @@ "url": "https://github.com/sponsors/antelle" } }, + "node_modules/noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", + "dev": true, + "license": "ISC", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + } + }, + "node_modules/noms/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/noms/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true, + "license": "MIT" + }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -12228,6 +12324,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, "node_modules/promise": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", @@ -13650,6 +13753,57 @@ "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", "license": "MIT" }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -13933,6 +14087,16 @@ "node": ">= 0.8" } }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -14054,12 +14218,6 @@ "makeerror": "1.0.12" } }, - "node_modules/wasm-sjlj": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/wasm-sjlj/-/wasm-sjlj-1.0.6.tgz", - "integrity": "sha512-pjaKtLJejlWm6+okPV2X1A6nIsRDD4qeK97eCh8DP8KXi3Nzn/HY01vpHhZHlhDri12eZqipjm8HhdTVw+ATxw==", - "license": "MIT" - }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -14205,6 +14363,16 @@ "async-limiter": "~1.0.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -14341,7 +14509,7 @@ "cmake-js": "^7.3.1", "commander": "^13.1.0", "ora": "^8.2.0", - "react-native-node-api": "0.3.2" + "react-native-node-api": "*" }, "bin": { "cmake-rn": "bin/cmake-rn.js" @@ -14569,7 +14737,7 @@ "version": "0.2.3", "dependencies": { "@commander-js/extra-typings": "^13.1.0", - "@napi-rs/cli": "~3.0.3", + "@napi-rs/cli": "^3.1", "bufout": "^0.3.2", "chalk": "^5.4.1", "commander": "^13.1.0", @@ -14578,13 +14746,9 @@ }, "bin": { "ferric": "bin/ferric.js" - } - }, - "packages/ferric-example": { - "name": "@react-native-node-api/ferric-example", - "version": "0.1.0", + }, "devDependencies": { - "ferric-cli": "*" + "copyfiles": "^2.4.1" } }, "packages/ferric/node_modules/@commander-js/extra-typings": { diff --git a/package.json b/package.json index 677d8c50..51652bfd 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,7 @@ "packages/ferric", "packages/host", "packages/node-addon-examples", - "packages/node-tests", - "packages/ferric-example" + "packages/node-tests" ], "homepage": "https://github.com/callstackincubator/react-native-node-api#readme", "scripts": { diff --git a/packages/cmake-rn/package.json b/packages/cmake-rn/package.json index 4f56012f..b272bddf 100644 --- a/packages/cmake-rn/package.json +++ b/packages/cmake-rn/package.json @@ -28,7 +28,7 @@ "cmake-js": "^7.3.1", "commander": "^13.1.0", "ora": "^8.2.0", - "react-native-node-api": "0.3.2" + "react-native-node-api": "*" }, "peerDependencies": { "node-addon-api": "^8.3.1", diff --git a/packages/ferric-example/.gitignore b/packages/ferric-example/.gitignore deleted file mode 100644 index 31c8570c..00000000 --- a/packages/ferric-example/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -/target -Cargo.lock - -/*.xcframework/ -/*.apple.node/ -/*.android.node/ - -# Generated files -/ferric_example.d.ts -/ferric_example.js diff --git a/packages/ferric-example/package.json b/packages/ferric-example/package.json deleted file mode 100644 index 2365f4e5..00000000 --- a/packages/ferric-example/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@react-native-node-api/ferric-example", - "private": true, - "type": "commonjs", - "version": "0.1.0", - "homepage": "https://github.com/callstackincubator/react-native-node-api", - "repository": { - "type": "git", - "url": "git+https://github.com/callstackincubator/react-native-node-api.git", - "directory": "packages/ferric-example" - }, - "main": "ferric_example.js", - "types": "ferric_example.d.ts", - "scripts": { - "build": "ferric build", - "bootstrap": "npm run build" - }, - "devDependencies": { - "ferric-cli": "*" - } -} diff --git a/packages/ferric/README.md b/packages/ferric/README.md index c61bdb9a..6bde1021 100644 --- a/packages/ferric/README.md +++ b/packages/ferric/README.md @@ -1,3 +1,62 @@ # `ferric` A wrapper around Cargo making it easier to produce prebuilt binaries targeting iOS and Android matching the [the prebuilt binary specification](https://github.com/callstackincubator/react-native-node-api/blob/main/docs/PREBUILDS.md) as well as [napi.rs](https://napi.rs/) to generate bindings from annotated Rust code. + +## Install the project + +
+ npm + +``` + npm install --save-dev ferric-cli +``` + +
+ +
+ pnpm + +``` + pnpm install -D ferric-cli +``` + +
+ +
+ yarn + +``` + yarn add -D ferric-cli +``` + +
+ +## Add scripts + +```json +"scripts": { + "gen:rs": "ferric init lib_name", + "build": "ferric build --cwd lib_name", + "build:release": "npm run build -- --configuration release" +} +``` + +### Project Structure + +After generating the project, a folder would be created with the following file structure for the lib. + +```markdown +lib_name +│ Cargo.toml +│ build.rs +│ .gitignore +└───src +│ │ lib.rs +└───dist (after build) +│ │ index.js +│ │ index.d.ts +│ │ native_android_folder +│ │ native_ios_folder +``` + +> Example project seen in `apps/test-app/lib_in_rust`. diff --git a/packages/ferric/package.json b/packages/ferric/package.json index d862a1a9..c0803a69 100644 --- a/packages/ferric/package.json +++ b/packages/ferric/package.json @@ -13,15 +13,21 @@ "ferric": "./bin/ferric.js" }, "scripts": { - "start": "tsx src/run.ts" + "start": "tsx src/run.ts", + "build": "tsc --build && npm run copy-templates", + "test": "tsx --test --test-reporter=@reporters/github --test-reporter-destination=stdout --test-reporter=spec --test-reporter-destination=stdout src/**/*.test.ts", + "copy-templates": "copyfiles -u 1 src/templates/**/* dist" }, "dependencies": { - "@napi-rs/cli": "~3.0.3", "@commander-js/extra-typings": "^13.1.0", + "@napi-rs/cli": "^3.1", "bufout": "^0.3.2", "chalk": "^5.4.1", "commander": "^13.1.0", - "react-native-node-api": "0.3.2", - "ora": "^8.2.0" + "ora": "^8.2.0", + "react-native-node-api": "0.3.2" + }, + "devDependencies": { + "copyfiles": "^2.4.1" } } diff --git a/packages/ferric/src/init.ts b/packages/ferric/src/init.ts new file mode 100644 index 00000000..c0420538 --- /dev/null +++ b/packages/ferric/src/init.ts @@ -0,0 +1,70 @@ +import { Command } from "@commander-js/extra-typings"; +import fs from "node:fs"; +import fsPromise from "node:fs/promises"; +import path from "node:path"; +import { oraPromise } from "ora"; +import { prettyPath } from "react-native-node-api"; + +export const initCommand = new Command("init") + .description("Generate the project scaffold") + .argument("", "Type the project name") + .action(async (str) => { + const projectName = str && str.length > 0 ? str : "ferric_project"; + const generatePath = path.join(process.cwd(), projectName); + await oraPromise( + generateProject({ outputPath: generatePath, projectName }), + { + text: "Generating project", + successText: `Generated project ${prettyPath(generatePath)}`, + failText: (error) => `Failed to generate the project: ${error.message}`, + }, + ); + }); + +async function replaceStrInFile( + filePath: string, + oldStr: string, + newStr: string, +) { + const content = await fsPromise.readFile(filePath, "utf8"); + const updatedContent = content.replaceAll(oldStr, newStr); + await fsPromise.writeFile(filePath, updatedContent, "utf8"); +} + +function createFolder(path: string) { + if (!fs.existsSync(path)) { + fs.mkdirSync(path); + } +} + +async function copyAllTemplateFiles(outputFilePath: string) { + const templateDir = path.join(import.meta.dirname, "templates"); + await fsPromise.cp(templateDir, outputFilePath, { + recursive: true, + }); + await moveFile(`${outputFilePath}/lib.rs`, `${outputFilePath}/src/lib.rs`); + await moveFile(`${outputFilePath}/gitignore`, `${outputFilePath}/.gitignore`); +} + +async function moveFile(currentPath: string, newPath: string) { + await fsPromise.rename(currentPath, newPath); +} + +async function generateProject({ + outputPath, + projectName, +}: { + outputPath: string; + projectName: string; +}) { + createFolder(outputPath); + createFolder(`${outputPath}/src`); + await copyAllTemplateFiles(outputPath); + const strToReplace = "project_name"; + await replaceStrInFile( + `${outputPath}/package.json`, + strToReplace, + projectName, + ); + await replaceStrInFile(`${outputPath}/Cargo.toml`, strToReplace, projectName); +} diff --git a/packages/ferric/src/program.ts b/packages/ferric/src/program.ts index f8059c48..0474fde2 100644 --- a/packages/ferric/src/program.ts +++ b/packages/ferric/src/program.ts @@ -2,8 +2,10 @@ import { Command } from "@commander-js/extra-typings"; import { printBanner } from "./banner.js"; import { buildCommand } from "./build.js"; +import { initCommand } from "./init.js"; export const program = new Command("ferric") .hook("preAction", () => printBanner()) .description("Rust Node-API Modules for React Native") - .addCommand(buildCommand); + .addCommand(buildCommand) + .addCommand(initCommand); diff --git a/packages/ferric/src/templates/Cargo.toml b/packages/ferric/src/templates/Cargo.toml new file mode 100644 index 00000000..06d60062 --- /dev/null +++ b/packages/ferric/src/templates/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "project_name" +version = "1.0.0" +edition = "2021" +license = "MIT" + +[lib] +crate-type = ["cdylib"] + +[dependencies.napi] +version = "3" +default-features = false +# see https://nodejs.org/api/n-api.html#node-api-version-matrix +features = ["napi3"] + +[dependencies.napi-derive] +version = "3" +features = ["type-def"] + +[build-dependencies] +napi-build = "2" + +[profile.release] +lto = true +codegen-units = 1 +strip = "symbols" +opt-level = "z" diff --git a/packages/ferric/src/templates/build.rs b/packages/ferric/src/templates/build.rs new file mode 100644 index 00000000..bbfc9e4b --- /dev/null +++ b/packages/ferric/src/templates/build.rs @@ -0,0 +1,3 @@ +fn main() { + napi_build::setup(); +} diff --git a/packages/ferric/src/templates/gitignore b/packages/ferric/src/templates/gitignore new file mode 100644 index 00000000..24a51298 --- /dev/null +++ b/packages/ferric/src/templates/gitignore @@ -0,0 +1,8 @@ +target +Cargo.lock + +*.xcframework/ +*.apple.node/ +*.android.node/ + +dist diff --git a/packages/ferric/src/templates/lib.rs b/packages/ferric/src/templates/lib.rs new file mode 100644 index 00000000..1064d5bf --- /dev/null +++ b/packages/ferric/src/templates/lib.rs @@ -0,0 +1,6 @@ +use napi_derive::napi; + +#[napi] +pub fn sum(a: i32, b: i32) -> i32 { + a + b +} diff --git a/packages/ferric/src/templates/package.json b/packages/ferric/src/templates/package.json new file mode 100644 index 00000000..516e41cc --- /dev/null +++ b/packages/ferric/src/templates/package.json @@ -0,0 +1,14 @@ +{ + "name": "project_name", + "private": true, + "version": "0.1.0", + "main": "dist/project_name.js", + "types": "dist/project_name.d.ts", + "scripts": { + "build": "ferric build", + "build:release": "npm run build -- --configuration release" + }, + "devDependencies": { + "ferric-cli": "latest" + } +} diff --git a/packages/ferric/tsconfig.json b/packages/ferric/tsconfig.json index a678ba53..02cf7169 100644 --- a/packages/ferric/tsconfig.json +++ b/packages/ferric/tsconfig.json @@ -5,6 +5,7 @@ "declarationMap": true, "outDir": "dist", "rootDir": "src", + "esModuleInterop": true, "types": ["node"] }, "include": ["src/**/*.ts"],