diff --git a/README.md b/README.md index 8351b04..08bb7db 100644 --- a/README.md +++ b/README.md @@ -30,16 +30,9 @@ The frontend template can be generated two ways: - `loam init` - `soroban contract init [project-name] --frontend-template https://github.com/loambuild/template` -Using the `soroban contract init` variant will automatically install `loam-cli` -using a `post-init` hook that we will add to soroban-cli as part of our initial -grant. +Using the `soroban contract init` variant will automatically install `loam-cli` using a `post-init` hook that we will add to soroban-cli as part of our initial grant. -The differentiating feature of Loam's frontend template: a declarative -`environments.toml` configuration file. In this file, you describe the network -settings, accounts, and contracts for each environment your team builds -against. `loam-cli` handles the rest. - -Check out [an example `environments.toml` here](./environments.toml). +The differentiating feature of Loam's frontend template: a declarative `environments.toml` configuration file ([example here](./environments.toml)). In this file, you describe the network settings, accounts, and contracts for each environment your team builds against. `loam-cli` handles the rest. Aside from `loam init`, `loam-cli` will ship with two main commands: @@ -50,65 +43,64 @@ The most complex of these is `loam dev`. Let's break it down. ## `loam dev` -1. Defaults to `development` environment. This environment setting can be - changed with either the `--env` flag or with the `LOAM_ENV` environment - variable. +When you run this command, it will do everything everything in between having-contracts-created/deployed and running-the-frontend. + +```text +contracts created/deployed <-- loam dev --> frontend app +``` + +`loam dev` is the contract-dependencies-to-NPM-dependencies toolchain. It turns the contracts you depend on (contract dependencies) into frontend packages (NPM dependencies), getting your app to the point where it is ready to build or run with its own dev server, such as `astro dev`. (This template uses Astro, but `loam-cli` itself is agnostic to how you run your JavaScript frontend. It would work equally well with `next dev`, or with Svelte or Vue or any other JavaScript frontend tool.) + +It will also watch your `contracts/*` directory and your `environments.toml` file for changes, and re-run your setup logic when things change. + +Here's a full list of everything `loam dev` will do: + +1. Default to `development` environment. This environment setting can be changed with either the `--env` flag or with the `LOAM_ENV` environment variable. -2. Inspects the `environments.toml` file and gets things to the specified - predictable starting state: +2. Inspect the `environments.toml` file and get things to the specified predictable starting state: - - starts the specified network - - creates and/or funds accounts + - connect to the specified network, or run it with `soroban network start` + - create and/or fund accounts → on mainnet, will instead check that accounts exist and are funded - For specified contracts: - For an environment which uses a **local network**: - For contracts which have **`workspace = true`**: - - **build** & **deploy** the contracts, saving the IDs so that on - subsequent runs it can instead - verify contracts are deployed and update them if needed. - - **initialize** the contracts: runs any specified `init` commands - (see `environments.toml` below) - - [Beyond the scope of initial grant]: For contracts which instead - specify an `environment`, `address`, and `at-ledger-sequence`: - - **spoon** the specified contract's state, at time of specified - ledger sequence, into the current environment's network. - - For an environment which uses **futurenet**, **testnet**, **mainnet** - or some other live network: - - **check** that the contracts exist on that network. Note: Loam does - not yet have plans to help with deploying the contracts. It only - checks that you have successfully done so yourself. + - **build** & **deploy** the contracts, saving the IDs so that on subsequent runs it can instead verify contracts are deployed and update them if needed. + - **initialize** the contracts: runs any specified `init` commands (see `environments.toml` below) + - [Beyond the scope of initial grant]: For contracts which instead specify an `environment`, `address`, and `at-ledger-sequence`: + - **spoon** the specified contract's state, at time of specified ledger sequence, into the current environment's network. + - For an environment which uses **futurenet**, **testnet**, **mainnet** or some other live network: + - **check** that the contracts exist on that network. Note: Loam does not yet have plans to help with deploying the contracts. It only checks that you have successfully done so yourself. - For all environments: - **bind** the contracts - run `soroban contract bindings typescript` for each - - save each generated library to gitignored `packages/*`, part of the - [NPM workspace](https://docs.npmjs.com/cli/v10/using-npm/workspaces), - using the name specified in `environments.toml` - - **modify `networks` export** for each, to include all networks - specified in `environments.toml` - - **import** the contracts for use in the frontend. That is, create - gitignored `src/contracts/*` files for each, which import the - `Contract` class and `networks` object and export an instantiated - version for the current environment's network. - -3. Watch the `contracts/*` directory for changes, re-running all startup - logic when anything changes, to make sure the frontend stays up-to-date - with the contracts. - -This gets the frontend server ready to run. If using strict TypeScript, it also -means the frontend logic will be type-checked against the contract clients -generated for the given environment. If a production contract is slightly -different than a development/staging contract but has the same name, app -authors will need to add `LOAM_ENV` checks to their app logic, and build & -deploy separate frontends for each environment. + - save each generated library to gitignored `packages/*`, part of the [NPM workspace](https://docs.npmjs.com/cli/v10/using-npm/workspaces), using the name specified in `environments.toml` + - **modify `networks` export** for each, to include all networks specified in `environments.toml` + - **import** the contracts for use in the frontend. That is, create gitignored `src/contracts/*` files for each, which import the `Contract` class and `networks` object and export an instantiated version for the current environment's network. + +3. Watch the `contracts/*` directory for changes, re-running all startup logic when anything changes, to make sure the frontend stays up-to-date with the contracts. `loam build` flows easily out of this. ## `loam build` -This has the same behavior as `loam dev`, but defaults to -`LOAM_ENV=production`. It also only runs once, rather than watching -`contracts/*` for changes +This has the same behavior as `loam dev`, but defaults to `LOAM_ENV=production`. It also only runs once, rather than watching `contracts/*` for changes. + +Note that Loam's convention and suggestion is that you build separate frontend apps for different environments. Given that a browser-extension wallet allows a user to switch networks, some dapps prefer to ship single frontends that can deal with multiple networks. Then, if a user selects Testnet in their wallet, the app will automatically switch to Testnet mode. We think this leads to more complicated development and error-prone user flows. + +Instead, we suggest that you build one version of your frontend for mainnet and host it at, say, the root domain, `example.com`. Then build a separate version for testnet and host it at a separate domain, maybe `staging.example.com`. If a user to `example.com` has their Testnet wallet selected, you can present a warning and give them the option of visiting `staging.example.com`. Most users, of course, will only ever visit your production app. + +This means that each frontend has separate contract dependencies, deployed on separate networks. These separate versions may differ! For example, a Testnet contract may have backdoors or other admin features that would not be safe for Mainnet. (You can use [Cargo features](https://doc.rust-lang.org/cargo/reference/features.html) to compile separate versions of a contract for Testnet and Mainnet.) Let's think through how this would affect a frontend app, progressing from staging/Testnet to production/Mainnet environments: + +1. First, when trying things in your staging environment, you will `LOAM_ENV=staging loam build` + - This will fetch Testnet contracts and generate contract client NPM packages for them. + - Then you can use `astro build` (or any other frontend build tool) to build your frontend. +2. Later, when you are ready to deploy to production, you will `loam build`, which defaults to `LOAM_ENV=production` + - This will fetch your Mainnet contracts and generate NPM packages for them, _replacing the previous Testnet-targeting contract clients_. + - At this point, when you `astro build` (or similar), your type-checker may complain that you are using methods that don't exist. That is, if you have strict TypeScript, which we strongly recommend! + +How to fix those type errors? Easy. Add environment checks to your app, to only include certain routes or functionality in your staging & local versions. That is, check the value of `process.env.LOAM_ENV` or, if you're using newer, more-fully-ECMAscript Modules syntax, `import.meta.env.LOAM_ENV`. # Milestones @@ -122,7 +114,7 @@ Given the above, within our initial grant roadmap, we have the following milesto 2. Update `soroban contract init` command to safely honor a `post-init` hook specified by the target `--frontend-template`, so that Loam's template can install `loam-cli` -3. Expand the `loambuild/template` frontend template to include an example +3. Expand the `loambuild/template` frontend template to actually make use of its example `environments.toml` In a future grant, we have the following milestone: