From 0e5fa3aaf92680c42bd7c6d12747f0b2a7963a21 Mon Sep 17 00:00:00 2001 From: Caleb Curry Date: Fri, 3 Nov 2023 21:39:45 -0400 Subject: [PATCH] Add typescript template (#785) * copy react-leo to react-typescript * work in progress but was able to build * ts template in cli * make typescript a variant * rename to react-ts --------- Signed-off-by: Caleb Curry --- create-aleo-app/src/index.ts | 5 + create-aleo-app/template-react-ts/.babelrc | 7 ++ .../template-react-ts/.eslintrc.cjs | 20 ++++ create-aleo-app/template-react-ts/README.md | 90 ++++++++++++++ create-aleo-app/template-react-ts/_gitignore | 24 ++++ create-aleo-app/template-react-ts/_headers | 3 + .../template-react-ts/helloworld/.env.example | 2 + .../template-react-ts/helloworld/.gitignore | 5 + .../template-react-ts/helloworld/README.md | 13 ++ .../helloworld/build/main.aleo | 7 ++ .../helloworld/build/program.json | 6 + .../helloworld/inputs/helloworld.in | 4 + .../template-react-ts/helloworld/program.json | 6 + .../template-react-ts/helloworld/src/main.leo | 7 ++ create-aleo-app/template-react-ts/index.html | 88 ++++++++++++++ create-aleo-app/template-react-ts/install.sh | 30 +++++ .../template-react-ts/package.json | 49 ++++++++ .../template-react-ts/public/favicon.ico | Bin 0 -> 3984 bytes create-aleo-app/template-react-ts/src/App.css | 42 +++++++ create-aleo-app/template-react-ts/src/App.tsx | 103 ++++++++++++++++ .../template-react-ts/src/assets/aleo.svg | 5 + .../template-react-ts/src/assets/react.svg | 1 + .../template-react-ts/src/custom.d.ts | 16 +++ .../template-react-ts/src/index.css | 69 +++++++++++ .../template-react-ts/src/main.tsx | 10 ++ .../src/workers/AleoWorker.ts | 21 ++++ .../template-react-ts/src/workers/worker.ts | 73 ++++++++++++ .../template-react-ts/tsconfig.json | 16 +++ .../template-react-ts/vite.config.ts | 16 +++ .../template-react-ts/webpack.config.ts | 112 ++++++++++++++++++ 30 files changed, 850 insertions(+) create mode 100644 create-aleo-app/template-react-ts/.babelrc create mode 100644 create-aleo-app/template-react-ts/.eslintrc.cjs create mode 100644 create-aleo-app/template-react-ts/README.md create mode 100644 create-aleo-app/template-react-ts/_gitignore create mode 100644 create-aleo-app/template-react-ts/_headers create mode 100644 create-aleo-app/template-react-ts/helloworld/.env.example create mode 100644 create-aleo-app/template-react-ts/helloworld/.gitignore create mode 100644 create-aleo-app/template-react-ts/helloworld/README.md create mode 100644 create-aleo-app/template-react-ts/helloworld/build/main.aleo create mode 100644 create-aleo-app/template-react-ts/helloworld/build/program.json create mode 100644 create-aleo-app/template-react-ts/helloworld/inputs/helloworld.in create mode 100644 create-aleo-app/template-react-ts/helloworld/program.json create mode 100644 create-aleo-app/template-react-ts/helloworld/src/main.leo create mode 100644 create-aleo-app/template-react-ts/index.html create mode 100755 create-aleo-app/template-react-ts/install.sh create mode 100644 create-aleo-app/template-react-ts/package.json create mode 100644 create-aleo-app/template-react-ts/public/favicon.ico create mode 100644 create-aleo-app/template-react-ts/src/App.css create mode 100644 create-aleo-app/template-react-ts/src/App.tsx create mode 100644 create-aleo-app/template-react-ts/src/assets/aleo.svg create mode 100644 create-aleo-app/template-react-ts/src/assets/react.svg create mode 100644 create-aleo-app/template-react-ts/src/custom.d.ts create mode 100644 create-aleo-app/template-react-ts/src/index.css create mode 100644 create-aleo-app/template-react-ts/src/main.tsx create mode 100644 create-aleo-app/template-react-ts/src/workers/AleoWorker.ts create mode 100644 create-aleo-app/template-react-ts/src/workers/worker.ts create mode 100644 create-aleo-app/template-react-ts/tsconfig.json create mode 100644 create-aleo-app/template-react-ts/vite.config.ts create mode 100644 create-aleo-app/template-react-ts/webpack.config.ts diff --git a/create-aleo-app/src/index.ts b/create-aleo-app/src/index.ts index 33de7fa71..1e8d1bb6c 100755 --- a/create-aleo-app/src/index.ts +++ b/create-aleo-app/src/index.ts @@ -48,6 +48,11 @@ const FRAMEWORKS: Framework[] = [ display: "JavaScript + Leo", color: lightGreen, }, + { + name: 'react-ts', + display: "React + TypeScript", + color: red + }, { name: "nextjs-ts", display: "TypeScript + Next.js", diff --git a/create-aleo-app/template-react-ts/.babelrc b/create-aleo-app/template-react-ts/.babelrc new file mode 100644 index 000000000..f292b5026 --- /dev/null +++ b/create-aleo-app/template-react-ts/.babelrc @@ -0,0 +1,7 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-typescript", + ["@babel/preset-react", { "runtime": "automatic" }] + ] +} diff --git a/create-aleo-app/template-react-ts/.eslintrc.cjs b/create-aleo-app/template-react-ts/.eslintrc.cjs new file mode 100644 index 000000000..4dcb43901 --- /dev/null +++ b/create-aleo-app/template-react-ts/.eslintrc.cjs @@ -0,0 +1,20 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: '18.2' } }, + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, +} diff --git a/create-aleo-app/template-react-ts/README.md b/create-aleo-app/template-react-ts/README.md new file mode 100644 index 000000000..2b48090db --- /dev/null +++ b/create-aleo-app/template-react-ts/README.md @@ -0,0 +1,90 @@ +# React + Aleo + Leo + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/fork/github/AleoHQ/sdk/tree/testnet3/create-aleo-app/template-react) + +This template provides a minimal setup to get React and Aleo working in Vite +with HMR and some ESLint rules. + +This template includes a Leo program that is loaded by the web app located in +the `helloworld` directory. + +Note: Webpack is currently used for production builds due to a +[bug](https://github.com/vitejs/vite/issues/13367) with Vite related to nested +workers. + +### Start in development mode + +```bash +npm run dev +``` + +Your app should be running on http://localhost:5173/ + +### Build Leo program + +1. Copy the `helloworld/.env.example` to `helloworld/.env` (this will be ignored + by Git): + + ```bash + cd helloworld + cp .env.example .env + ``` + +2. Replace `PRIVATE_KEY=user1PrivateKey` in the `.env` with your own key (you + can use an existing one or generate your own at https://aleo.tools/account) + +3. Follow instructions to install Leo here: https://github.com/AleoHQ/leo + +4. You can edit `helloworld/src/main.leo` and run `leo run` to compile and update the + Aleo instructions under `build` which are loaded by the web app. + +## Deploy program from web app + +> [!WARNING] +> This is for demonstration purposes or local testing only, in production applications you +> should avoid building a public facing web app with private key information + +Information on generating a private key, seeding a wallet with funds, and finding a spendable record can be found here +if you are unfamiliar: https://developer.aleo.org/testnet/getting_started/deploy_execute_demo + +Aleo programs deployed require unique names, make sure to edit the program's name to something unique in `helloworld/src/main.leo`, `helloworld/program.json`, rename `helloworld/inputs/helloworld.in` and rebuild. + +1. In the `worker.js` file modify the privateKey to be an account with available + funds + + ```js + // Use existing account with funds + const account = new Account({ + privateKey: "user1PrivateKey", + }); + ``` + +2. (Optional) Provide a fee record manually (located in commented code within `worker.js`) + + If you do not provide a manual fee record, the SDK will attempt to scan for a record starting at the latest block. A simple way to speed this up would be to make a public transaction to this account right before deploying. + +3. Run the web app and hit the deploy button + +## Production deployment + +### Build + +`npm run build` + +Upload `dist` folder to your host of choice. + +### ⚠️ Header warnings + +`DOMException: Failed to execute 'postMessage' on 'Worker': SharedArrayBuffer transfer requires self.crossOriginIsolated` + +If you get a warning similar to this when deploying your application, you need +to make sure your web server is configured with the following headers: + +``` +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp +``` + +We've included a `_headers` file that works with some web hosts (e.g. Netlify) +but depending on your host / server setup you may need to configure the headers +manually. diff --git a/create-aleo-app/template-react-ts/_gitignore b/create-aleo-app/template-react-ts/_gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/create-aleo-app/template-react-ts/_gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/create-aleo-app/template-react-ts/_headers b/create-aleo-app/template-react-ts/_headers new file mode 100644 index 000000000..6e0d001fd --- /dev/null +++ b/create-aleo-app/template-react-ts/_headers @@ -0,0 +1,3 @@ +/* + Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/helloworld/.env.example b/create-aleo-app/template-react-ts/helloworld/.env.example new file mode 100644 index 000000000..11b672e98 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/.env.example @@ -0,0 +1,2 @@ +NETWORK=testnet3 +PRIVATE_KEY=user1PrivateKey \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/helloworld/.gitignore b/create-aleo-app/template-react-ts/helloworld/.gitignore new file mode 100644 index 000000000..f721f7f6f --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/.gitignore @@ -0,0 +1,5 @@ +.env +*.avm +*.prover +*.verifier +outputs/ diff --git a/create-aleo-app/template-react-ts/helloworld/README.md b/create-aleo-app/template-react-ts/helloworld/README.md new file mode 100644 index 000000000..2456ef654 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/README.md @@ -0,0 +1,13 @@ +# helloworld.aleo + +## Build Guide + +To compile this Aleo program, run: +```bash +snarkvm build +``` + +To execute this Aleo program, run: +```bash +snarkvm run hello +``` diff --git a/create-aleo-app/template-react-ts/helloworld/build/main.aleo b/create-aleo-app/template-react-ts/helloworld/build/main.aleo new file mode 100644 index 000000000..88fd8a3f5 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/build/main.aleo @@ -0,0 +1,7 @@ +program helloworld.aleo; + +function main: + input r0 as u32.public; + input r1 as u32.private; + add r0 r1 into r2; + output r2 as u32.private; diff --git a/create-aleo-app/template-react-ts/helloworld/build/program.json b/create-aleo-app/template-react-ts/helloworld/build/program.json new file mode 100644 index 000000000..df13181a2 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/build/program.json @@ -0,0 +1,6 @@ +{ + "program": "helloworld.aleo", + "version": "0.0.0", + "description": "", + "license": "MIT" +} diff --git a/create-aleo-app/template-react-ts/helloworld/inputs/helloworld.in b/create-aleo-app/template-react-ts/helloworld/inputs/helloworld.in new file mode 100644 index 000000000..2908f3dee --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/inputs/helloworld.in @@ -0,0 +1,4 @@ +// The program input for helloworld/src/main.leo +[main] +public a: u32 = 1u32; +b: u32 = 2u32; diff --git a/create-aleo-app/template-react-ts/helloworld/program.json b/create-aleo-app/template-react-ts/helloworld/program.json new file mode 100644 index 000000000..df13181a2 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/program.json @@ -0,0 +1,6 @@ +{ + "program": "helloworld.aleo", + "version": "0.0.0", + "description": "", + "license": "MIT" +} diff --git a/create-aleo-app/template-react-ts/helloworld/src/main.leo b/create-aleo-app/template-react-ts/helloworld/src/main.leo new file mode 100644 index 000000000..9aa61dacf --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/src/main.leo @@ -0,0 +1,7 @@ +// The 'helloworld' program. +program helloworld.aleo { + transition main(public a: u32, b: u32) -> u32 { + let c: u32 = a + b; + return c; + } +} diff --git a/create-aleo-app/template-react-ts/index.html b/create-aleo-app/template-react-ts/index.html new file mode 100644 index 000000000..4da12f5b5 --- /dev/null +++ b/create-aleo-app/template-react-ts/index.html @@ -0,0 +1,88 @@ + + + + + + + Aleo + React + + + +
+
+
+
+
+
+ + + diff --git a/create-aleo-app/template-react-ts/install.sh b/create-aleo-app/template-react-ts/install.sh new file mode 100755 index 000000000..add482688 --- /dev/null +++ b/create-aleo-app/template-react-ts/install.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# script exists immediately if command fails +set -e + +# check for dependencies +command -v git >/dev/null 2>&1 || { echo >&2 "git is required but it's not installed. Aborting."; exit 1; } +command -v cargo >/dev/null 2>&1 || { echo >&2 "cargo is required but it's not installed. Aborting."; exit 1; } + +INSTALL_DIR="${INSTALL_DIR:-$HOME/.leo}" + +# ask for confirmation +read -p "This script will install Leo into $INSTALL_DIR. Do you want to continue? (y/N) " choice +case "$choice" in + y|Y ) echo "Continuing installation...";; + * ) echo "Aborting."; exit;; +esac + +# clone or update the repo +if [ -d "$INSTALL_DIR" ]; then + echo "Directory $INSTALL_DIR exists. Updating repository..." + git -C "$INSTALL_DIR" pull +else + echo "Cloning repository into $INSTALL_DIR..." + git clone https://github.com/AleoHQ/leo "$INSTALL_DIR" +fi + +# build and install +echo "Building and installing from source..." +cargo install --path "$INSTALL_DIR" diff --git a/create-aleo-app/template-react-ts/package.json b/create-aleo-app/template-react-ts/package.json new file mode 100644 index 000000000..2d85c2715 --- /dev/null +++ b/create-aleo-app/template-react-ts/package.json @@ -0,0 +1,49 @@ +{ + "name": "aleo-react-typescript-starter", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "webpack", + "dev-webpack": "webpack serve", + "build:vite": "vite build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview", + "install-leo": "./install.sh" + }, + "dependencies": { + "@aleohq/sdk": "^0.6.2", + "comlink": "^4.4.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@babel/core": "^7.17.2", + "@babel/preset-env": "^7.16.11", + "@babel/preset-react": "^7.22.15", + "@babel/preset-typescript": "^7.23.2", + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@types/babel__generator": "^7.6.6", + "@types/node": "^20.8.7", + "@vitejs/plugin-react": "^4.0.4", + "babel-loader": "^8.2.3", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.6.0", + "eslint": "^8.45.0", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "raw-loader": "^4.0.2", + "style-loader": "^3.3.1", + "svg-url-loader": "^8.0.0", + "ts-node": "^10.9.1", + "typescript": "^5.2.2", + "vite": "^4.4.5", + "webpack": "^5.76.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + } +} diff --git a/create-aleo-app/template-react-ts/public/favicon.ico b/create-aleo-app/template-react-ts/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9c80066445f069d7fef09d10f52eb9f405973a5a GIT binary patch literal 3984 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 { + const key = await aleoWorker.getPrivateKey(); + setAccount(await key.to_string()); + }; + + async function execute() { + setExecuting(true); + const result = await aleoWorker.localProgramExecution( + helloworld_program, + "main", + ["5u32", "5u32"], + ); + setExecuting(false); + + alert(JSON.stringify(result)); + } + + async function deploy() { + setDeploying(true); + try { + const result = await aleoWorker.deployProgram(helloworld_program); + console.log("Transaction:") + console.log("https://explorer.hamp.app/transaction?id=" + result) + alert("Transaction ID: " + result); + } catch (e) { + console.log(e) + alert("Error with deployment, please check console for details"); + } + setDeploying(false); + } + + return ( + <> + +

Aleo + React

+
+ +

+ +

+

+ +

+

+ Edit src/App.jsx and save to test HMR +

+
+ + {/* Advanced Section */} +
+

Advanced Actions

+

+ Deployment on Aleo requires certain prerequisites like seeding your + wallet with credits and retrieving a fee record. Check README for more + details. +

+

+ +

+
+

+ Click on the Aleo and React logos to learn more +

+ + ); +} + +export default App; diff --git a/create-aleo-app/template-react-ts/src/assets/aleo.svg b/create-aleo-app/template-react-ts/src/assets/aleo.svg new file mode 100644 index 000000000..d507e1eb4 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/assets/aleo.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/src/assets/react.svg b/create-aleo-app/template-react-ts/src/assets/react.svg new file mode 100644 index 000000000..6c87de9bb --- /dev/null +++ b/create-aleo-app/template-react-ts/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/src/custom.d.ts b/create-aleo-app/template-react-ts/src/custom.d.ts new file mode 100644 index 000000000..3aa72e286 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/custom.d.ts @@ -0,0 +1,16 @@ +declare module '*.svg' { + const content: any; + export default content; + } + + declare module '*.aleo' { + const content: string; + export default content; + } + + declare module '*?raw' { + const content: string; + export default content; + } + + \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/src/index.css b/create-aleo-app/template-react-ts/src/index.css new file mode 100644 index 000000000..2c3fac689 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/index.css @@ -0,0 +1,69 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/create-aleo-app/template-react-ts/src/main.tsx b/create-aleo-app/template-react-ts/src/main.tsx new file mode 100644 index 000000000..e2aaf9ff6 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/main.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import "./index.css"; + +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + , +); diff --git a/create-aleo-app/template-react-ts/src/workers/AleoWorker.ts b/create-aleo-app/template-react-ts/src/workers/AleoWorker.ts new file mode 100644 index 000000000..218021ba4 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/workers/AleoWorker.ts @@ -0,0 +1,21 @@ +//@ts-nocheck +import { wrap } from "comlink"; + +let singletonWorker = null; + +const AleoWorker = () => { + if (!singletonWorker) { + const worker = new Worker(new URL("worker", import.meta.url), { + type: "module", + }); + + worker.onerror = function(event) { + console.error("Error in worker: " + event?.message); + }; + + singletonWorker = wrap(worker); + } + return singletonWorker; +}; + +export { AleoWorker }; \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/src/workers/worker.ts b/create-aleo-app/template-react-ts/src/workers/worker.ts new file mode 100644 index 000000000..af3f3f24e --- /dev/null +++ b/create-aleo-app/template-react-ts/src/workers/worker.ts @@ -0,0 +1,73 @@ +//@ts-nocheck +import { + Account, + ProgramManager, + PrivateKey, + initThreadPool, + AleoKeyProvider, + AleoNetworkClient, + NetworkRecordProvider, +} from "@aleohq/sdk"; +import { expose, proxy } from "comlink"; + +await initThreadPool(); + +async function localProgramExecution(program, aleoFunction, inputs) { + const programManager = new ProgramManager(); + + // Create a temporary account for the execution of the program + const account = new Account(); + programManager.setAccount(account); + + const executionResponse = await programManager.executeOffline( + program, + aleoFunction, + inputs, + false, + ); + return executionResponse.getOutputs(); +} + +async function getPrivateKey() { + const key = new PrivateKey(); + return proxy(key); +} + +async function deployProgram(program) { + const keyProvider = new AleoKeyProvider(); + keyProvider.useCache(true); + + // Create a record provider that will be used to find records and transaction data for Aleo programs + const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); + + // Use existing account with funds + const account = new Account({ + privateKey: "user1PrivateKey", + }); + + const recordProvider = new NetworkRecordProvider(account, networkClient); + + // Initialize a program manager to talk to the Aleo network with the configured key and record providers + const programManager = new ProgramManager( + "https://vm.aleo.org/api", + keyProvider, + recordProvider, + ); + + programManager.setAccount(account); + + // Define a fee to pay to deploy the program + const fee = 1.9; // 1.9 Aleo credits + + // Deploy the program to the Aleo network + const tx_id = await programManager.deploy(program, fee); + + // Optional: Pass in fee record manually to avoid long scan times + // const feeRecord = "{ owner: aleo1xxx...xxx.private, microcredits: 2000000u64.private, _nonce: 123...789group.public}"; + // const tx_id = await programManager.deploy(program, fee, undefined, feeRecord); + + return tx_id; +} + +const workerMethods = { localProgramExecution, getPrivateKey, deployProgram }; +expose(workerMethods); diff --git a/create-aleo-app/template-react-ts/tsconfig.json b/create-aleo-app/template-react-ts/tsconfig.json new file mode 100644 index 000000000..a5b674b1c --- /dev/null +++ b/create-aleo-app/template-react-ts/tsconfig.json @@ -0,0 +1,16 @@ +{ + "include": ["src", "__tests__", "src/custom.d.ts"], + "compilerOptions": { + "outDir": "dist", + "target": "ES2015", + "moduleResolution": "Bundler", + "strict": true, + "skipLibCheck": true, + "declaration": false, + "sourceMap": false, + "noUnusedLocals": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "jsx":"react-jsx", + } +} diff --git a/create-aleo-app/template-react-ts/vite.config.ts b/create-aleo-app/template-react-ts/vite.config.ts new file mode 100644 index 000000000..a83386670 --- /dev/null +++ b/create-aleo-app/template-react-ts/vite.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + optimizeDeps: { + exclude: ["@aleohq/wasm", "@aleohq/sdk"], + }, + server: { + headers: { + "Cross-Origin-Opener-Policy": "same-origin", + "Cross-Origin-Embedder-Policy": "require-corp", + }, + }, +}); diff --git a/create-aleo-app/template-react-ts/webpack.config.ts b/create-aleo-app/template-react-ts/webpack.config.ts new file mode 100644 index 000000000..f6d23cb6f --- /dev/null +++ b/create-aleo-app/template-react-ts/webpack.config.ts @@ -0,0 +1,112 @@ +#!/usr/bin/env ts-node +import CopyPlugin from "copy-webpack-plugin"; +import TerserPlugin from "terser-webpack-plugin"; +import HtmlWebpackPlugin from "html-webpack-plugin"; + +import path from "path"; + +const appConfig = { + mode: "production", + entry: { + index: "./src/main.tsx", + }, + output: { + path: path.resolve("dist"), + filename: "[name].bundle.js", + }, + resolve: { + extensions: [".ts", ".tsx", ".js", ".wasm", ".jsx"], + }, + devServer: { + port: 3000, + headers: { + "Cross-Origin-Opener-Policy": "same-origin", + "Cross-Origin-Embedder-Policy": "require-corp", + }, + client: { + overlay: false, + }, + }, + module: { + rules: [ + { + test: /\.(ts|tsx|js|jsx)$/, + //exclude: /node_modules/, + use: { + loader: "babel-loader", + // options: { + // presets: [ + // '@babel/preset-env', + // '@babel/preset-react', + // '@babel/preset-typescript', + // ], + // }, + }, + }, + { + test: /\.css$/, + use: ["style-loader", "css-loader"], + }, + { + test: /\.(png|jpe?g|gif)$/i, + use: [ + { + loader: "file-loader", + options: { + name: "[path][name].[ext]", + }, + }, + ], + }, + { + test: /\.svg$/, + use: [ + { + loader: "svg-url-loader", + options: { + limit: 8192, + noquotes: true, + }, + }, + ], + }, + { + test: /\.aleo$/i, + use: 'raw-loader', + }, + ], + }, + plugins: [ + new CopyPlugin({ + patterns: [{ from: "public", to: "public" }, { from: "_headers", to: "." }, + { from: 'src/assets', to: 'dist/assets' } + ], + }), + new HtmlWebpackPlugin({ + template: "./index.html", + }), + ], + performance: { + hints: false, + maxAssetSize: 13 * 1024 * 1024, // 12 MiB + maxEntrypointSize: 13 * 1024 * 1024, // 12 MiB + }, + optimization: { + minimize: true, + minimizer: [new TerserPlugin({ + terserOptions: { + module: true, + } + })], + }, + stats: { + warnings: false, + }, + experiments: { + asyncWebAssembly: true, + topLevelAwait: true, + }, + devtool: "source-map", +}; + +export default [appConfig];