Skip to content

Commit

Permalink
Add create-sei-app package (#185)
Browse files Browse the repository at this point in the history
* template first draft

* update templates

* readme

* update all

* undo

* restore next files

* upload changeset

* update template names

* update chain

* update css

* lint fix

* exclude templates

* remove linting for tempalte projects

* add main

* rename to create-sei

* create-sei

* update readmes

* update next wagmi template

* update css

* vite wagmi

* update vite cosmos

* update next cosmos

* comments docs

* comments

* readme changes

* add options and app

* changes

* update templates

* changeset
  • Loading branch information
mj850 authored Jul 19, 2024
1 parent 13afac1 commit e3a4c8e
Show file tree
Hide file tree
Showing 103 changed files with 33,975 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/tame-jeans-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sei-js/create-sei': major
---

First release
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ npm-debug.log
yarn-error.log
testem.log
/typings
.next

# System Files
.DS_Store
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ SeiJS consists of smaller NPM packages within the @sei-js namespace. For more de
| [@sei-js/evm](packages/evm) | Typescript library containing helper functions for interacting with the EVM on Sei. |
| [@sei-js/proto](packages/proto) | TypeScript library for Sei protobuf generated using [Telescope](https://github.com/osmosis-labs/telescope) |
| [@sei-js/registry](packages/proto) | TypeScript library exporting constants from the [Sei chain-registry](https://github.com/sei-protocol/chain-registry) and the [community asset list](https://github.com/Sei-Public-Goods/sei-assetlist) |
| [@sei-js/create-sei](packages/create-sei) | CLI Tool used to quickly spin up Sei Projects and dApps in either the cosmos or EVM ecosystem |

## Development
To build all packages and docs, run `yarn install` then `yarn build:all`
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"postinstall": "yarn update-submodules",
"update-submodules": "git submodule update --init --recursive",
"docs": "npx typedoc",
"lint:all": "nx run-many --target=lint",
"lint:all": "nx run-many --target=lint --exclude=template-*",
"lint:since": "nx affected --target=lint",
"prerelease": "yarn build:all",
"release": "changeset publish",
Expand Down
2 changes: 2 additions & 0 deletions packages/create-sei/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
5 changes: 5 additions & 0 deletions packages/create-sei/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
dist

test
```
78 changes: 78 additions & 0 deletions packages/create-sei/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# @sei-js/create-sei-app

## 0.0.0-internal-20240718212746

### Major Changes

- test

## 0.0.0-internal-20240718212405

### Major Changes

- test ver final

## 0.0.0-internal-20240717005255

### Major Changes

- edit

## 0.0.0-internal-20240717005002

### Major Changes

- with options

## 0.0.0-internal-20240717003256

### Major Changes

- First version

## 0.0.0-internal-20240716075531

### Major Changes

- first v

## 0.0.0-internal-20240716074905

### Major Changes

- First version

## 0.0.0-internal-20240708205128

### Major Changes

- first release

## 0.0.0-internal-20240708184136

### Major Changes

- First release

## 0.0.0-internal-20240708170805

### Major Changes

- release create sei

## 0.0.0-internal-20240708163140

### Major Changes

- Update Templates
- 0917789: Major release

## 0.0.0-internal-20240701161539

### Major Changes

- 6b3cf5a: Instantiates the Create Sei App package

### Minor Changes

- changes
40 changes: 40 additions & 0 deletions packages/create-sei/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Create Sei App

This repository contains various templates for kick starting a Sei application out of the box, as well as a CLI (Command Line Interface) tool that can be used to create projects using the given templates.

You can use either:
- Next.js
- Vite.js

to scaffold your project.

## Getting Started
1. Install dependencies by running `yarn` or `npm`

2. Install this package globally by running `npm install -g @sei-js/create-sei`

3. Run `create-sei` and follow the prompts

## EVM Applications (Reccommended)
Building on our EVM (Ethereum Virtual Machine) is the easiest way to get your dApp kick started on Sei! The mature EVM ecosystem provides many tools out of the box to help developers build faster, including deploying smart contracts and other helpful connection libraries.

This tool will offer multiple variants of EVM tooling, including
- [Wagmi](https://wagmi.sh/core/getting-started) ([Viem](https://viem.sh/)): Recommended
- [Ethers](https://docs.ethers.org/v6/)

Both variants use [@sei-js/evm](https://sei-protocol.github.io/sei-js/modules/evm.html)

If you are new to Web3 development, we reccommend using Wagmi since it provides helpful hooks out of the box.

## Cosmos Applications
Cosmos based Sei Applications interact with the CosmWasm VM on the chain. Use this if you are a seasoned CosmWasm developer, or if you intend to interact with CosmWasm Smart Contracts, as well as other chains in the Cosmos ecosystem.

If you think your app might require interaction with native Cosmos modules, you should check the list of [precompiles](https://www.docs.sei.io/dev-interoperability/precompiles/addr) to determine if the same support can be offered by the EVM.

Cosmos Applications use
- [CosmosKit](https://cosmology.zone/products/cosmos-kit)
- [@sei-js/cosmjs](https://sei-protocol.github.io/sei-js/modules/cosmjs.html)
- [Cosmjs](https://github.com/cosmos/cosmjs)

## Contributing
We love contributions from the amazing Sei community! If you have a dApp template to contribute, do make a Pull Request into the [sei-js](https://github.com/sei-protocol/sei-js) repository.
3 changes: 3 additions & 0 deletions packages/create-sei/eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["../../eslint.base.json"]
}
28 changes: 28 additions & 0 deletions packages/create-sei/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@sei-js/create-sei",
"version": "0.0.0-internal-20240718212746",
"module": "dist/main.js",
"type": "module",
"bin": {
"create-sei": "./dist/main.js"
},
"scripts": {
"build": "tsc && cp -r ./templates ./dist/templates",
"dev": "node --loader ts-node/esm src/main.ts",
"lint": "eslint --ext .ts"
},
"dependencies": {
"boxen": "^7.1.1",
"commander": "^12.1.0",
"inquirer": "^9.2.15"
},
"devDependencies": {
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@tanstack/react-query": "^5.25.0",
"@types/boxen": "^3.0.1",
"@types/inquirer": "^9.0.7",
"autoprefixer": "^10.4.18",
"copyfiles": "^2.4.1",
"degit": "^2.8.4"
}
}
200 changes: 200 additions & 0 deletions packages/create-sei/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#!/usr/bin/env node
import inquirer from 'inquirer';
import boxen from 'boxen';

import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { Command } from 'commander';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const program = new Command();

// Print welcome message
const printWelcomeMessage = () => {
console.log(
boxen('Welcome to the SEI DApp Generator!', {
padding: 1,
margin: 1,
borderStyle: 'double',
borderColor: '#932C23'
})
);
}


enum FrontendScaffolding {
Vite = 'vite',
Next = 'next'
}

export enum RPCIntegrationType {
EVM = 'evm',
CosmJS = 'cosmos'
}

export enum EVMLibrary {
Wagmi = 'wagmi'
}

interface WizardOptions {
name?: string;
framework?: FrontendScaffolding;
ecosystem?: RPCIntegrationType;
library?: EVMLibrary;
}

const promptFramework = async () => {
const {appFramework} = await inquirer.prompt([
{
type: 'list',
name: 'appFramework',
message: 'Select an app framework to use?',
choices: Object.values(FrontendScaffolding)
}
]);

return appFramework;
}

const promptRpcIntegrations = async () => {
const {rpcIntegrationType} = await inquirer.prompt([
{
type: 'list',
name: 'rpcIntegrationType',
message: 'Select the wallet connection type you want to include:',
choices: Object.values(RPCIntegrationType)
}
]);

return rpcIntegrationType;
};

const promptEVMLibrary = async () => {
const {evmLibrary} = await inquirer.prompt([
{
type: 'list',
name: 'evmLibrary',
message: 'Choose your preferred EVM library:',
choices: Object.values(EVMLibrary)
}
]);

return evmLibrary;
};

function isValidDirectoryName(dirName) {
const illegalRe = /[<>:"/\\|?*\x00-\x1F]/g;
const windowsReservedRe = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;
const trailingRe = /[. ]+$/;
const validNpmPackageRe = /^(?:@[a-z0-9-*~][a-z0-9-*._~]*)?[a-z0-9-~][a-z0-9-._~]*$/;

if (typeof dirName !== 'string' || dirName.length === 0) {
return false;
}

if (illegalRe.test(dirName) || windowsReservedRe.test(dirName) || trailingRe.test(dirName) || !validNpmPackageRe.test(dirName)) {
return false;
}

return true;
}

const validateOptions = (options: WizardOptions): boolean => {
let valid = true;

if (options.name) {
if (!isValidDirectoryName(options.name)) {
console.log('Invalid package name. Please use a valid npm package name.');
valid = false;
}
}

if (options.framework) {
const validFrameworks = Object.values(FrontendScaffolding);
if (!validFrameworks.includes(options.framework)) {
console.log(`Invalid Framework '${options.framework}' provided. Framework must be one of: [${validFrameworks.join(', ')}]`);
valid = false;
}
}

if (options.ecosystem) {
const validEcosystems = Object.values(RPCIntegrationType);
if (!validEcosystems.includes(options.ecosystem)) {
console.log(`Invalid Ecosystem '${options.ecosystem}' provided. Framework must be one of: [${validEcosystems.join(', ')}]`);
valid = false;
}
}

if (options.library) {
const validEVMLibraries = Object.values(EVMLibrary);
if (!validEVMLibraries.includes(options.library)) {
console.log(`Invalid EVM Library '${options.library}' provided. Framework must be one of: [${validEVMLibraries.join(', ')}]`);
valid = false;
}
}

return valid;
}

async function runWizard(options: WizardOptions): Promise<void> {
if (!validateOptions(options)) {
return;
}

printWelcomeMessage();

let dAppName = '';
if (options.name) {
dAppName = options.name
}
else {
const promptResult = await inquirer.prompt([
{
type: 'input',
name: 'dAppName',
message: 'What is your dApp (project) name?',
validate: (input: string) => {
return isValidDirectoryName(input) || 'Invalid package name. Please use a valid npm package name.';
}
}
]);

dAppName = promptResult.dAppName
}

const appFramework = options.framework || await promptFramework();
let appConnectionType = options.ecosystem || await promptRpcIntegrations();
if (appConnectionType == RPCIntegrationType.EVM) {
appConnectionType = options.library || await promptEVMLibrary();
}

const templateName = `${appFramework}-${appConnectionType}-template`;
const templatePath = path.join(__dirname, 'templates', templateName)
const dst = path.join(process.cwd(), dAppName)
await fs.promises.cp(templatePath, dst, {recursive: true})

console.log(`Project setup complete! Using template ${templateName}\n`);
console.log(`To start your app, run: \n > cd ${dAppName} \n > yarn \n > yarn dev\n`);
}

program
.command('app')
.description('Create a new SEI dApp')
.option('-n, --name <name>', `Specify the name of your dApp. Name must be a valid package name.`)
.option('-f, --framework <framework>', `Specify the app framework to use: [${Object.values(FrontendScaffolding).join(', ')}]`)
.option('-e, --ecosystem <ecosystem>', `Specify the ecosystem to use: [${Object.values(RPCIntegrationType).join(', ')}]`)
.option('-l, --library <library>', `Specify the EVM library to use: [${Object.values(EVMLibrary).join(', ')}]. Only used if ecosystem chosen is 'EVM'`)
.action(async (options: WizardOptions) => {
try {
await runWizard(options);
} catch (error) {
console.error('An error occurred:', error);
}
});

program.parse(process.argv);

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
Loading

0 comments on commit e3a4c8e

Please sign in to comment.