Skip to content

Commit 5c980bd

Browse files
committed
deploy script
1 parent f53ee88 commit 5c980bd

File tree

5 files changed

+178
-39
lines changed

5 files changed

+178
-39
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
# production
1818
/build
19+
/dist
1920

2021
# misc
2122
.DS_Store
@@ -33,6 +34,9 @@ yarn-error.log*
3334
.vercel
3435
.turbo
3536

37+
# mf
38+
.__mf__temp
39+
3640
# typescript
3741
*.tsbuildinfo
3842
next-env.d.ts
@@ -46,4 +50,4 @@ next-env.d.ts
4650
yarn.lock
4751
package-lock.json
4852
pnpm-lock.yaml
49-
# bun.lockb
53+
# bun.lockb

README.md

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
- [Module Federation Configuration](#module-federation-configuration)
2424
- [Theming and Styling](#theming-and-styling)
2525
- [Building for Production](#building-for-production)
26-
- [Running Tests](#running-tests)
2726
- [Deploy to Web4](#deploy-to-web4)
2827
- [Contributing](#contributing)
2928

@@ -57,17 +56,11 @@ The development server is configured with hot module replacement for a smooth de
5756

5857
## Module Federation Configuration
5958

60-
This template is set up for module federation. The configuration can be found in `rsbuild.config.ts`. Key points:
59+
This template is set up for [module federation](https://module-federation.io/). The configuration can be found in `rsbuild.config.ts`. Key points:
6160

62-
- The profile module is exposed as `"./Profile"`.
63-
- The exposed component is now a TypeScript file: `./src/components/Profile.tsx`.
64-
- Shared dependencies are configured to utilize the dependencies of the host "gateway".
65-
66-
## Theming and Styling
67-
68-
- This project uses Tailwind CSS for styling.
69-
- Customize the theme in `tailwind.config.js`.
70-
- Use CSS variables for easy theming across your application.
61+
- The profile module is exposed as `"./Profile"`
62+
- It shares dependencies with the host/"gateway"
63+
- Feel free to install other packages and add components to the Profile, but do not modify [App](./src/App.tsx) or [bootstrap](./src/bootstrap.tsx).
7164

7265
## Building for Production
7366

@@ -79,43 +72,32 @@ bun run build
7972

8073
This will generate optimized files in the `dist` directory.
8174

82-
## Running Tests
83-
84-
Execute the test suite with:
85-
86-
```bash
87-
bun run test
88-
```
89-
90-
For more details on testing, see the [testing guide](./playwright-tests/README.md).
91-
9275
## Deploy to web4
9376

94-
1. Build the project
95-
96-
```cmd
97-
pnpm run build
98-
```
77+
To deploy your profile to web4, make sure you have built the project, then:
9978

100-
2. Create a web4 subaccount of your master account (this will be your domain).
79+
1. Run the deploy script:
10180

102-
```cmd
103-
near account create-account fund-myself web4.MASTER_ACCOUNT.testnet '1 NEAR' autogenerate-new-keypair save-to-keychain sign-as MASTER_ACCOUNT.testnet network-config testnet sign-with-keychain send
81+
```bash
82+
bun run deploy
10483
```
10584

106-
Be sure to "Store the access key in legacy keychain"!
85+
2. Follow the prompts in the terminal:
10786

108-
3. Run web4-deploy to upload production bundle to nearfs and deploy it to a minimum-web4 contract to your account.
87+
- Enter the network (mainnet/testnet)
88+
- Enter your account name (e.g., root.near)
10989

110-
```cmd
111-
npx github:vgrichina/web4-deploy dist web4.MASTER_ACCOUNT.testnet --deploy-contract --nearfs
112-
```
90+
The script will automatically:
91+
92+
- Create a web4 subaccount if it doesn't exist
93+
- Deploy your profile to the web4 contract
11394

114-
Deploy should be accessible and your website accessible at:
95+
You will be prompted to sign transactions through [near-cli-rs](https://github.com/near/near-cli-rs)
11596

116-
`testnet`: MASTER_ACCOUNT.testnet.page
97+
After successful deployment, your website will be accessible at:
11798

118-
`mainnet`: MASTER_ACCOUNT.near.page
99+
- Testnet: `ACCOUNT_NAME.testnet.page`
100+
- Mainnet: `ACCOUNT_NAME.near.page`
119101

120102
## Contributing
121103

bun.lockb

2.89 KB
Binary file not shown.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"build": "rsbuild build",
1616
"preview": "rsbuild preview",
1717
"fmt": "prettier --write '**/*.{js,jsx,ts,tsx,json}'",
18-
"fmt:check": "prettier --check '**/*.{js,jsx,ts,tsx,json}'"
18+
"fmt:check": "prettier --check '**/*.{js,jsx,ts,tsx,json}'",
19+
"deploy": "bun run --bun scripts/deploy.ts"
1920
},
2021
"browserslist": {
2122
"production": [
@@ -30,6 +31,8 @@
3031
]
3132
},
3233
"dependencies": {
34+
"@types/ora": "^3.2.0",
35+
"ora": "^8.1.1",
3336
"react": "^18.3.1",
3437
"react-dom": "^18.3.1",
3538
"react-markdown": "^9.0.3"

scripts/deploy.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { ChildProcess, spawn } from 'child_process';
2+
import ora from 'ora';
3+
4+
let currentProcess: ChildProcess | null = null;
5+
6+
async function promptUser(question: string): Promise<string> {
7+
const { default: readline } = await import('readline/promises');
8+
const rl = readline.createInterface({
9+
input: process.stdin,
10+
output: process.stdout,
11+
});
12+
const answer = await rl.question(question);
13+
rl.close();
14+
return answer;
15+
}
16+
17+
async function executeCommand(command: string[], cwd: string = process.cwd()): Promise<void> {
18+
return new Promise((resolve, reject) => {
19+
console.log('\nExecuting command:', command.join(' '));
20+
21+
currentProcess = spawn(command[0], command.slice(1), {
22+
cwd,
23+
stdio: 'inherit',
24+
shell: true
25+
});
26+
27+
currentProcess.on('close', (code) => {
28+
currentProcess = null;
29+
if (code === 0) {
30+
console.log('Command executed successfully');
31+
resolve();
32+
} else {
33+
reject(new Error(`Command failed with exit code ${code}`));
34+
}
35+
});
36+
37+
currentProcess.on('error', (err) => {
38+
currentProcess = null;
39+
reject(new Error(`Failed to start command: ${err.message}`));
40+
});
41+
});
42+
}
43+
44+
function cleanupAndExit() {
45+
console.log('\nInterrupted. Cleaning up...');
46+
if (currentProcess) {
47+
currentProcess.kill('SIGINT');
48+
}
49+
process.exit(0);
50+
}
51+
52+
// Set up SIGINT handler
53+
process.on('SIGINT', cleanupAndExit);
54+
55+
async function checkAccountExists(network: string, account: string): Promise<boolean> {
56+
try {
57+
const command = [
58+
'npx',
59+
'near-cli-rs',
60+
'account',
61+
'view-account-summary',
62+
account,
63+
'network-config',
64+
network,
65+
'now'
66+
];
67+
await executeCommand(command);
68+
return true;
69+
} catch (error) {
70+
return false;
71+
}
72+
}
73+
74+
async function createAccount(network: string, account: string): Promise<void> {
75+
const spinner = ora('Checking web4 subaccount').start();
76+
const subaccount = `web4.${account}`;
77+
try {
78+
const exists = await checkAccountExists(network, subaccount);
79+
if (exists) {
80+
spinner.succeed(`Web4 subaccount already exists`);
81+
return;
82+
}
83+
84+
spinner.text = 'Creating web4 subaccount';
85+
const command = [
86+
'near',
87+
'account',
88+
'create-account',
89+
'fund-myself',
90+
subaccount,
91+
"'1 NEAR'",
92+
'autogenerate-new-keypair',
93+
'save-to-keychain',
94+
`sign-as`,
95+
account,
96+
'network-config',
97+
network
98+
];
99+
await executeCommand(command);
100+
spinner.succeed('Web4 subaccount created successfully');
101+
} catch (error) {
102+
spinner.fail(`Failed to create web4 subaccount: ${error}`);
103+
throw error;
104+
}
105+
}
106+
107+
async function deployToWeb4(network: string, account: string): Promise<void> {
108+
const spinner = ora('Deploying to web4').start();
109+
try {
110+
const command = [
111+
'npx',
112+
'github:vgrichina/web4-deploy',
113+
'dist',
114+
account,
115+
'--deploy-contract',
116+
'--nearfs',
117+
'--network',
118+
network
119+
];
120+
await executeCommand(command);
121+
spinner.succeed('Deployed to web4 successfully');
122+
} catch (error) {
123+
spinner.fail(`Failed to deploy to web4: ${error}`);
124+
throw error;
125+
}
126+
}
127+
128+
async function main() {
129+
console.log('Starting deployment process...');
130+
131+
const network = await promptUser('Enter the network (mainnet/testnet): ');
132+
if (network !== 'mainnet' && network !== 'testnet') {
133+
throw new Error('Invalid network. Please enter either "mainnet" or "testnet".');
134+
}
135+
136+
const accountSuffix = network === 'mainnet' ? 'near' : 'testnet';
137+
const account = await promptUser(`Enter your account name (e.g root.${accountSuffix}): `);
138+
const fullAccount = `web4.${account}`;
139+
140+
console.log(`\nCreating your web4 account... web4.${account}`);
141+
await createAccount(network, account);
142+
143+
console.log('\nDeploying profile to web4 contract...');
144+
await deployToWeb4(network, fullAccount);
145+
}
146+
147+
main().catch((error) => {
148+
console.error('An error occurred:', error);
149+
cleanupAndExit();
150+
});

0 commit comments

Comments
 (0)