Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c069809
Add degit and template support for project creation
cxalem Apr 22, 2025
117ec77
Remove blockchain subproject from forge-std directory
cxalem Apr 22, 2025
f0a7c52
Update project configuration and add Dynamic Environment ID support
cxalem Apr 28, 2025
4bc5818
Comment out the React Web3 Starter template in templates.ts for futur…
cxalem Apr 28, 2025
efdc996
Update version in package.json from 1.0.3 to 1.0.6
cxalem Apr 28, 2025
ba4ba7a
Refactor package.json to manage 'degit' dependency
cxalem Apr 29, 2025
d5ef896
Comment out GitTemplate usage in cloneTemplate tests for future refer…
cxalem Apr 29, 2025
de6d2f9
Enhance project name validation in promptForProjectDetails function
cxalem Apr 29, 2025
0dd90fc
Add GitHub Actions workflow for publishing releases
cxalem Apr 30, 2025
8763647
Update package.json for project rebranding and configuration changes
cxalem Apr 30, 2025
865344f
Remove package-lock.json to streamline dependency management
cxalem Apr 30, 2025
b5482f7
Update package.json to include 'degit' in dependencies and maintain e…
cxalem May 6, 2025
31a9c30
fixes
May 8, 2025
16ff67e
Remove 'degit' and '@types/degit' from dependencies in package.json t…
cxalem May 8, 2025
e27692a
analytics enabled
cxalem May 19, 2025
3877e70
Update version to 1.1.2 and enhance analytics tracking
cxalem Jun 5, 2025
7877ad9
Remove logging of user Git email in project creation process to strea…
cxalem Jun 5, 2025
0b76545
Add note for Web3Auth client ID requirement in template selection
cxalem Jun 5, 2025
5059e70
Add pnpm installation prompt if not found in PATH
cxalem Jun 5, 2025
1b2473b
Update version to 1.1.3 in package.json and constants
cxalem Jun 5, 2025
4170d86
Update README to reflect new package name for Web3 app creation commands
cxalem Jun 5, 2025
0b7f9d3
Rename tooling prompt function for clarity and update project initial…
cxalem Jun 12, 2025
313badc
Update version to 1.1.5 in package.json and constants
cxalem Jun 12, 2025
f7a529c
Update project initialization command to include 'foundryup' for envi…
cxalem Jun 12, 2025
1eb5bb5
Add git availability check and new analytics event for missing Git in…
cxalem Jun 12, 2025
56526bd
Enhance project creation output with frontend development server inst…
cxalem Jun 12, 2025
76903a4
Fix typo in PACKAGE_MANAGER_CHOICES constant and update references in…
cxalem Jun 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: Publish Release

on:
push:
branches:
- main # Trigger on pushes to the main branch

# Keep workflow_call secrets definition for potential future use or reference
# workflow_call:
# secrets:
# NPM_TOKEN:
# required: true
# SLACK_WEBHOOK_URL:
# required: true
# PUBLISH_DOCS_TOKEN:
# required: true

jobs:
publish-release:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout and setup environment
uses: MetaMask/action-checkout-and-setup@v1
with:
is-high-risk-environment: true
ref: ${{ github.sha }}
# This assumes your build command is 'yarn build' and output is 'dist'
- run: yarn build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: publish-release-artifacts-${{ github.sha }}
retention-days: 4
include-hidden-files: true
path: |
./dist
./node_modules/.yarn-state.yml

publish-npm-dry-run:
needs: publish-release
runs-on: ubuntu-latest
steps:
- name: Checkout and setup environment
uses: MetaMask/action-checkout-and-setup@v1
with:
is-high-risk-environment: true
ref: ${{ github.sha }}
- name: Restore build artifacts
uses: actions/download-artifact@v4
with:
name: publish-release-artifacts-${{ github.sha }}
- name: Dry Run Publish
# omit npm-token token to perform dry run publish
uses: MetaMask/action-npm-publish@v5
with:
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
subteam: S042S7RE4AE # @metamask-npm-publishers
env:
SKIP_PREPACK: true

publish-npm:
needs: publish-npm-dry-run
runs-on: ubuntu-latest
environment: npm-publish
steps:
- name: Checkout and setup environment
uses: MetaMask/action-checkout-and-setup@v1
with:
is-high-risk-environment: true
ref: ${{ github.sha }}
- name: Restore build artifacts
uses: actions/download-artifact@v4
with:
name: publish-release-artifacts-${{ github.sha }}
- name: Publish
uses: MetaMask/action-npm-publish@v5
with:
npm-token: ${{ secrets.NPM_TOKEN }}
env:
SKIP_PREPACK: true

get-release-version:
needs: publish-npm
runs-on: ubuntu-latest
outputs:
RELEASE_VERSION: ${{ steps.get-release-version.outputs.RELEASE_VERSION }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.sha }}
- id: get-release-version
# Use Node.js to extract version from package.json
run: echo "RELEASE_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT

# The following jobs depend on ./.github/workflows/publish-docs.yml
# Commenting them out for now. Uncomment and create publish-docs.yml if needed.
# publish-release-to-gh-pages:
# name: Publish docs to ${{ needs.get-release-version.outputs.RELEASE_VERSION }} directory of gh-pages branch
# needs: get-release-version
# permissions:
# contents: write
# uses: ./.github/workflows/publish-docs.yml
# with:
# destination_dir: ${{ needs.get-release-version.outputs.RELEASE_VERSION }}
# secrets:
# PUBLISH_DOCS_TOKEN: ${{ secrets.PUBLISH_DOCS_TOKEN }} # Requires PUBLISH_DOCS_TOKEN secret

# publish-release-to-latest-gh-pages:
# name: Publish docs to latest directory of gh-pages branch
# needs: publish-npm
# permissions:
# contents: write
# uses: ./.github/workflows/publish-docs.yml
# with:
# destination_dir: latest
# secrets:
# PUBLISH_DOCS_TOKEN: ${{ secrets.PUBLISH_DOCS_TOKEN }} # Requires PUBLISH_DOCS_TOKEN secret
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
node_modules
demo
*.yaml
dist
dist
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
.env.development
.env.test
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ To create a new project using the Web3 Template CLI, run one of the following co
Using **pnpm**:

```bash
pnpm create @metamask/create-web3-app [project-name]
pnpm create @consensys/create-web3-app [project-name]
```

Using **npx**:

```bash
npx @metamask/create-web3-app [project-name]
npx @consensys/create-web3-app [project-name]
```

### Interactive Setup
Expand All @@ -42,7 +42,7 @@ After running the command, the CLI will guide you through the setup process with
### Example

```bash
npx @metamask/create-web3-app my-web3-project
npx @consensys/create-web3-app my-web3-project
```

## Project Structure
Expand Down
18 changes: 15 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
{
"name": "@metamask/create-web3-app",
"name": "@consensys/create-web3-app",
"type": "module",
"module": "dist/index.js",
"bin": {
"create-web3-app": "dist/index.js"
},
"version": "1.0.0",
"version": "1.1.5",
"description": "CLI tool for generating Web3 starter projects, streamlining the setup of monorepo structures with a frontend (Next.js or React) and blockchain tooling (HardHat or Foundry). It leverages the commander library for command-line interactions and guides users through selecting a framework, package manager (npm, yarn, pnpm), and blockchain stack.",
"main": "index.js",
"scripts": {
"dev": "tsc -w",
"build": "tsc",
"link-cli": "yarn unlink --global create-web3-app && yarn link --global create-web3-app",
"test": "vitest"
},
Expand All @@ -26,10 +27,17 @@
"author": "cxalem",
"license": "MIT",
"dependencies": {
"@segment/analytics-node": "^2.2.1",
"@types/degit": "^2.8.6",
"chalk": "^5.4.1",
"commander": "12.0.0",
"degit": "^2.8.4",
"dotenv": "^16.5.0",
"fs": "0.0.1-security",
"inquirer": "9.2.15",
"memfs": "^4.9.3"
"memfs": "^4.9.3",
"ora": "^8.2.0",
"uuid": "^11.1.0"
},
"devDependencies": {
"@types/inquirer": "9.0.7",
Expand All @@ -41,6 +49,10 @@
"type": "git",
"url": "git+https://github.com/MetaMask/create-web3-app.git"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"bugs": {
"url": "https://github.com/MetaMask/create-web3-app/issues"
},
Expand Down
52 changes: 52 additions & 0 deletions src/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import os from "os";
import { v4 as uuid } from "uuid";
import { Analytics } from "@segment/analytics-node";

const DEFAULT_WRITE_KEY = "AhYEnWamvR0lVj5JYLDsnxcySWdG6Q5J";
const WRITE_KEY = process.env.SEGMENT_WRITE_KEY ?? DEFAULT_WRITE_KEY;
const analyticsDisabled =
process.env.SEGMENT_OPT_OUT === "1" || process.env.CI === "true";

const enabled = Boolean(WRITE_KEY) && !analyticsDisabled;

type EVENTS =
| "project_created"
| "cli_started"
| "project_creation_failed"
| "foundry_not_installed"
| "git_not_installed"
| "cwd_not_writable";

const analytics = enabled
? new Analytics({ writeKey: WRITE_KEY })
: ({
track: () => {},
identify: () => {},
flush: () => Promise.resolve(),
} as unknown as Analytics);

const anonymousId = uuid();

export const identifyRun = () => {
if (!enabled) return;
analytics.identify({
anonymousId,
traits: {
os_platform: process.platform,
os_release: os.release(),
node_version: process.version,
},
});
};

export const track = (
event: EVENTS,
properties: Record<string, unknown> = {}
) =>
analytics.track({
event,
anonymousId,
properties,
});

export const flush = () => analytics.flush();
48 changes: 30 additions & 18 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { execAsync } from "../utils/index.js";
import { TEMPLATES } from "./templates.js";

export { TEMPLATES } from "./templates.js";

export const FRAMEWORK_CHOICES = [
{
name: "React (with Vite)",
value: "react",
},
{
name: "Next.js",
value: "nextjs",
value: "next-web3-starter",
},
] as const;

export const BLOCKCHAIN_TOOLING_CHOICES = [
{
name: "HardHat",
Expand All @@ -23,7 +25,7 @@ export const BLOCKCHAIN_TOOLING_CHOICES = [
},
] as const;

export const PACAKGE_MANAGER_CHOICES = [
export const PACKAGE_MANAGER_CHOICES = [
{
name: "Yarn",
value: "yarn",
Expand All @@ -38,17 +40,27 @@ export const PACAKGE_MANAGER_CHOICES = [
},
] as const;

export const NPM_COMMAND = (projectName: string, path: string) =>
path
? `cd ${path} && npm init vite@latest . -- --template react-ts`
: `npm init vite@latest ${projectName} -- --template react-ts`;
// Add a type helper to make working with templates easier
type Template = (typeof TEMPLATES)[number];

export type GitTemplate = Extract<Template, { repo_url: string }>;
export type DegitTemplate = Extract<Template, { degitSource: string }>;

export function isDegitTemplate(template: Template): template is DegitTemplate {
return "degitSource" in template;
}

export function isGitTemplate(template: Template): template is GitTemplate {
return "repo_url" in template;
}

export const YARN_COMMAND = (projectName: string, path: string) =>
path
? `cd ${path} && yarn create vite . --template react-ts`
: `yarn create vite ${projectName} --template react-ts`;
export const isGitAvailable = async (): Promise<boolean> => {
try {
await execAsync("git --version");
return true;
} catch {
return false;
}
};

export const PNPM_COMMAND = (projectName: string, path: string) =>
path
? `cd ${path} && pnpm create vite . --template react-ts`
: `pnpm create vite ${projectName} --template react-ts`;
export const CLI_VERSION = "1.1.5";
21 changes: 13 additions & 8 deletions src/constants/templates.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
export const TEMPLATES = [
{
name: "Next Web3 Starter",
id: "next-web3-starter",
repo_url: "https://github.com/Consensys/next-web3-starter.git",
packageName: "@consensys/web3-starter",
name: "MetaMask <-> Next.js Wagmi Quickstart",
id: "metamask-nextjs-wagmi",
degitSource: "MetaMask/metamask-sdk-examples/examples/quickstart",
},
{
name: "React Web3 Starter",
id: "react-web3-starter",
repo_url: "https://github.com/Consensys/react-web3-starter.git",
packageName: "@consensys/react-web3-starter",
name: "MetaMask <-> Web3Auth Quickstart",
id: "metamask-web3auth",
repo_url: "https://github.com/MetaMask/metamask-web3auth.git",
packageName: "metamask-web3auth",
},
{
name: "MetaMask <-> Dynamic Quickstart",
id: "metamask-dynamic",
repo_url: "https://github.com/MetaMask/metamask-dynamic.git",
packageName: "metamask-dynamic",
},
] as const;
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env node

import "dotenv/config";

import { Command } from "commander";
import { createProject } from "./utils/index.js";

Expand Down
Loading