Develop contract initialization frontend templates
This guide picks up where Build a Dapp Frontend left off, taking a deeper look at the --frontend-template
used there. 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.)
But note that the CLI's contract init
command was made to work with any frontend template. It need not even live on GitHub! Simply pass another valid git URL to the command, and it will clone that instead of the official repository:
# the following is NOT a valid git repository, and will not work π
stellar contract init my-new-project --frontend-template https://whatever.cool/project/you/want
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 --with-example
.
Separately, you may include a --frontend-template
. Frontend templates so far have all been Node projects, which have a package.json
in the root. In the final composite project, the Node project and Rust project live side-by-side, and the frontend template expects the Rust project to be there. It expects a contracts
folder with one or more subfolders, and it expects a target
directory with all the Rust build artifacts.
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. That is, the --frontend-template
choice is separate from the --with-example
choice. 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!
To try it, soon we will run stellar contract init .
in this project to add the Cargo stuff and a contracts
folder. But be careful! You don't want to commit these changes! You can git restore .
at the end of your testing to get rid of the new files.
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
Now we can run contract init
. Let's include one extra contract. Then we'll run the dev
script (which, remember, will run the initialize.js
script first):
stellar contract init . --with-example increment
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 initialization 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