Develop contract with frontend templates
This guide picks up where Build a Dapp Frontend left off. From there, we'll:
- Search GitHub for other Soroban templates
- Build our own simple template
Building our own template will be a great way to learn how they work. They're not that complicated!
Search GitHub for other Soroban templates
The official template maintained by Stellar Development Foundation (SDF), as used in Build a Dapp Frontend, lives on GitHub at stellar/soroban-template-astro. It uses the Astro web framework. While Astro works with React, Vue, Svelte, and any other UI library, the template opts not to use them, preferring Astro's own templating language, which uses vanilla JavaScript with no UI library.
(You may wonder why it makes this unpopular choice. A fair question! The team wanted to balance actual utility with broad approachability. Not everyone learning Stellar and Soroban is familiar with React, or any other UI library. It also demonstrates that core Soroban libraries all work with any JavaScript project.)
To use other templates, we will clone them from their repositories, and then copy these files into the root of the existing soroban-hello-world
directory:
# For example, you could clone this repository
git clone https://github.com/stellar/soroban-examples
Now copy files into the root of soroban-hello-world
.
So how can you find other valid frontend templates?
At some point we may set up a DAO or other voting system to curate a list of high-quality templates, but for now... search GitHub! And GitLab. And any other source code site you know about.
In GitHub, in the main search bar, search for "soroban-template-"
. With the quotes. Here's a direct link to the search results: github.com/search?q=%22soroban-template-%22
You can copy this approach for any other source code website, such as GitLab.
How do you know if any of these are any good? Try them. Look at their source code. How many stars do they have? How active are their maintainers? None of these are perfect metrics, which is why a curated registry might be nice in the future.
If none of them suit, then it might be time to...
Make your own template
This will be easier than you might imagine. There are a few gotchas, but overall these templates are fairly standard Node projects.
But first, how are these projects organized?
When you run stellar contract init
, it always includes a Rust/Cargo project, with a Cargo.toml
that defines a workspace, and workspace members located in a contracts
folder. At a minimum, there's one contract, contracts/hello_world
, but you can get more by using --name
.
So keep that in mind. We're making a fairly simple Node project, and telling it about our Soroban stuff, like the contracts
folder.
1. Initialize an NPM project
So let's make a simple Node project! Rather than initializing an Astro project, like the official frontend template, let's try something new. The State of JS survey tells me that something called "Solid" is fairly new and well-loved. What does it say to do?
npx degit solidjs/templates/ts soroban-template-solid
cd soroban-template-solid
npm install
npm run dev
Ok, we have a running Solid template! Now let's turn it into a Soroban template!
2. git init
Commit early, commit often! You can stop running the dev server (the one you started with npm run dev
above; stop it with ctrlc, even on a Mac) if you want, or open a new terminal and:
git init
git add .
git commit -m "init from solid ts template"
3. Copy in the initialize.js
script
The SDF-maintained soroban-template-astro
has an initialize.js
script in its project root. Copy-paste it into your project.
If you're familiar with Node scripting, you should be able to figure out what it's doing. If not, it's a great way to learn! Tip: start at the bottom, where it does the generateAccount(); buildAll(); deployAll();
stuff.
That stuff at the end should give you a clue about what this script does. It does stuff that a Soroban app needs. Soroban apps make calls to Soroban.
So this script:
- generates a Soroban/Stellar account
- builds all contracts
- deploys all contracts (to a locally-running Soroban network; we'll recap this soon)
- binds contracts — that is, it creates NPM projects for each deployed contract by running
stellar contract bindings typescript
- imports the contracts for straightforward use in the rest of your project
Remember that it needs to do this all in a contract-agnostic way. The frontend template doesn't know what contracts it might find! But it needs to build, deploy, bind, and import whatever's there.
So this script does that.
But it needs a few other things.
A. devDependencies
The script uses a couple NPM packages. Install them:
npm install --save-dev dotenv glob
B. .env
The dotenv
package installed above parses environment variables from a .env
file. The official template includes a .env.example
. Go ahead and copy it into your own project. To set you up for testing it all out, you can also copy it to a local .env
.
cp .env.example .env
C. .gitignore
You'll want to ignore the .env
file you created above, as well as some other build artifacts created by the initialize.js
script. Paste the bottom of the official template's .gitignore
into your template's .gitignore
:
# environment variables
.env
.env.production
# generated contract clients
packages/*
# if you have other workspace packages, add them here
!packages/.gitkeep
# generated contract client imports
src/contracts/*
!src/contracts/util.ts
C. package.json
Make sure users of your template don't forget to run the initialize.js
script. Modify the scripts
section as follows:
- "start": "vite",
- "dev": "vite",
- "build": "vite build",
- "serve": "vite preview"
+ "init": "node initialize.js",
+ "start": "npm run init && vite",
+ "dev": "npm run init && vite",
+ "build": "npm run init && vite build",
+ "serve": "npm run init && vite preview"
Alternatively, rather than adding the repetitive npm run init
statements, you could opt to add a postinstall
script where you npm run init
, or just node initialize.js
in there.
You also need to tell NPM to treat this as a workspace. Yes, this project is a Cargo workspace and an NPM workspace! The bindAll
step of initialize.js
puts the generated NPM packages in packages/*
. At the bottom of package.json
, add:
"dependencies": {
"solid-js": "^1.8.11"
- }
+ },
+ "workspaces": [
+ "packages/*"
+ ]
}
Also make sure that this project is set up to allow the import
statements in the initialize.js
script. Add this at the top-level:
"description": "",
+ "type": "module",
"scripts": {
While you're here, you can also update the name
(maybe "soroban-template-solid"
) and description
.
E. src/contracts/util.ts
In the .gitignore
above, you may have noticed that this file is explicitly included. Copy it in from the official template. You'll need to create the src/contracts
folder.
As you can see, it just makes it easy to import { rpcUrl, networkPassphrase } from 'util'
in the files generated in the importAll
step.
F. README
You might want to start by copying the official template's README to explain how to cp .env.example .env
. From there, this might also be a good time to explain anything else that makes your template unique! Why might people want to use it?
4. git commit
Commit changes!
git add .
git commit -m "add initialize.js script and supporting changes"
5. Try it!
That's it! You have an NPM project with an initialize.js
script (and its supporting cast). That's all you really need!
Let's try it. First, make sure you're running a local Stellar network. Start Docker Desktop or whatever alternative you prefer, then:
stellar network container start local
Let's include one extra contract. Go to the increment example and copy increment files into the root directory.
Then we'll run the dev
script (which, remember, will run the initialize.js
script firs).
npm run dev
After you do this, you may notice lots of new changes in the project. All that Rust, Cargo, and Soroban stuff!
$ git status --short
?? .soroban/
?? Cargo.lock
?? Cargo.toml
?? contracts/
?? target/
Q: Should you commit this stuff?
A: NO!
Q: Should you gitignore this stuff?
A: NO!
The .soroban
and target
folders are gitignored by the core Rust/Cargo template. In projects that specify yours as their --frontend-template
, that .gitignore
will be merged with yours. No need to include those lines twice.
And projects that use yours will want to commit the Cargo.*
files and contracts
, but your template should not include them. That can cause problems with project initialization later. Nor should it gitignore them, because your .gitignore
will be part of projects started with your template! It would cause problems and confusion, if people didn't realize that some of their most important files were gitignored!
Alright. Go ahead and open the app in your browser. Solid runs its dev server on http://localhost:3000
. Does it load? It should! We didn't actually use the new src/contracts/*
stuff in the app itself!
6. Wait. Should the template actually use the contracts?
Good question!
You know that the hello_world
contract will always be there. So you could demonstrate to your users how to import and use it in an app file (like src/App.tsx
, in the Solid template). But remember: no other contracts are guaranteed to be there! So don't commit any changes that import and use something like increment
!
Here's a way you could demonstrate how to import and use the hello_world
contract in the Solid template's App.tsx
:
+import greeter from "./contracts/hello_world";
const App: Component = () => {
return (
<div class={styles.App}>
<header class={styles.header}>
+ <form
+ onSubmit={async (e) => {
+ e.preventDefault();
+ const { result } = await greeter.hello({
+ to: e.currentTarget.toWhom.value,
+ });
+ alert(result);
+ }}
+ >
+ <label>
+ Who you gonna call?
+ <input name="toWhom" value="World" />
+ </label>
+ <button type="submit">Say Hello</button>
+ </form>
7. Make it as complex as you want!
This is your template. Go ahead and add helpful dependencies and utility files that you always want, like wallet management or whatever. If you want to add a whole complex stack of UI components, styles, and state-management libraries, go ahead!
The official template strives for simplicity. For shallowness, even. It's meant as a teaching tool, for people with all different levels of JS and Soroban experience. Yours has no such constraints! It should be useful to you.
And templates are cheap to make! If you want to have one soroban-template-framework-x-basic
for a broader audience, and another soroban-template-framework-x-opinionated
for your own projects, you can do that!
Wrapping up
Some things we did in this section:
- Searched GitHub for new frontend templates
- Learned that some templates might not be on GitHub
- Saw how frontend templates work and interact with the "backend" template that always comes with
stellar contract init
- Built our own template by adding an
initialize.js
script to a basic NPM template
After you're done building your own frontend template, what's next? You choose! You can:
- See more complex example contracts in the Example Contracts section.
- Learn more about the internal architecture and design of Soroban.
Guides in this category:
📄️ Use Docker to build and run dapps
Understand Docker and use it to build applications
📄️ Comprehensive frontend guide for Stellar dapps
Learn how to build functional frontend interfaces for Stellar dapps using React, Tailwind CSS, and the Stellar SDK.
📄️ Initialize a dapp using scripts
Set up initialization correctly to ensure seamless setup for your dapp
📄️ Create a frontend for your dapp using React
Connect dapp frontends to contracts and Freighter wallet using @soroban-react
📄️ Develop contract with frontend templates
Understand, find, and create your own frontend templates for use with Stellar CLI's `stellar contract init` command
📄️ Implement state archival in dapps
Learn how to implement state archival in your dapp
📄️ Work with contract specs in Java, Python, and PHP
A guide to understanding and interacting with Soroban smart contracts in different programming languages