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 000000000..9c8006644 Binary files /dev/null and b/create-aleo-app/template-react-ts/public/favicon.ico differ diff --git a/create-aleo-app/template-react-ts/src/App.css b/create-aleo-app/template-react-ts/src/App.css new file mode 100644 index 000000000..b9d355df2 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/create-aleo-app/template-react-ts/src/App.tsx b/create-aleo-app/template-react-ts/src/App.tsx new file mode 100644 index 000000000..eccad348a --- /dev/null +++ b/create-aleo-app/template-react-ts/src/App.tsx @@ -0,0 +1,103 @@ +import { useState } from "react"; +import reactLogo from "./assets/react.svg"; +import aleoLogo from "./assets/aleo.svg"; +import "./App.css"; +import helloworld_program from "../helloworld/build/main.aleo?raw"; +import { AleoWorker } from "./workers/AleoWorker"; + +const aleoWorker = AleoWorker(); +function App() { + const [count, setCount] = useState(0); + const [account, setAccount] = useState(null); + const [executing, setExecuting] = useState(false); + const [deploying, setDeploying] = useState(false); + + const generateAccount = async () => { + 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 logo + + + React logo + +
+

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];