Skip to content

Commit 5eaed7a

Browse files
committed
Add Vite server integration and GH actions workflow to simplify deployment
1 parent e320e0e commit 5eaed7a

File tree

8 files changed

+1635
-49
lines changed

8 files changed

+1635
-49
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Build and Release
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
7+
permissions:
8+
contents: write
9+
10+
jobs:
11+
build-and-release:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout repository
16+
uses: actions/checkout@v4
17+
18+
- name: Setup Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: '22'
22+
cache: 'npm'
23+
24+
- name: Install all dependencies
25+
run: npm ci
26+
27+
- name: Build project
28+
run: npm run build
29+
30+
- name: Install production dependencies only
31+
run: |
32+
npm ci --production
33+
34+
- name: Create release tarball
35+
run: |
36+
tar -czf release.tar.gz dist/ package.json server.js node_modules/
37+
38+
- name: Upload build artifact (for workflow logs)
39+
uses: actions/upload-artifact@v4
40+
with:
41+
name: dist
42+
path: dist
43+
44+
- name: Create GitHub Release and upload asset
45+
uses: ncipollo/release-action@v1
46+
with:
47+
token: ${{ secrets.GITHUB_TOKEN }}
48+
tag: v${{ github.run_number }}
49+
name: Release ${{ github.run_number }}
50+
body: |
51+
Latest build from main branch.
52+
artifacts: release.tar.gz
53+
allowUpdates: false
54+
draft: false
55+
prerelease: false
56+
makeLatest: true

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
node_modules
2-
2+
dist/
3+
.DS_Store

README.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,12 @@ This template includes a local development server (`server.js`) that provides:
108108
### Starting the Server
109109

110110
```bash
111-
node server.js
111+
npm run start:dev # Vite + API for local development
112+
npm run build # Create production build in dist/
113+
npm run start:prod # Serve built assets from dist/
112114
```
113115

114-
The server will start on `http://localhost:3000` by default.
116+
The server will start on `http://localhost:3000` by default. `start:prod` expects `dist/` to exist (created via `npm run build`).
115117

116118
### WebSocket Messaging API
117119

@@ -138,3 +140,31 @@ curl -X POST http://localhost:3000/message \
138140
-H "Content-Type: application/json" \
139141
-d '{"message": "Hello from the server!"}'
140142
```
143+
144+
## CI/CD and Automated Releases
145+
146+
This template includes a GitHub Actions workflow (`.github/workflows/build-release.yml`) that automatically builds and releases your application when you push to the `main` branch.
147+
148+
### How It Works
149+
150+
When you push to `main`, the workflow will:
151+
152+
1. **Build the project** - Runs `npm run build` to create production assets in `dist/`
153+
2. **Create a release tarball** - Packages `dist/`, `package.json`, `server.js`, and production `node_modules/` into `release.tar.gz`
154+
3. **Create a GitHub Release** - Automatically creates a new release tagged as `v{run_number}` with the tarball attached
155+
156+
### Release Contents
157+
158+
The release tarball (`release.tar.gz`) contains everything needed to deploy the application:
159+
- `dist/` - Built production assets
160+
- `package.json` - Project dependencies and scripts
161+
- `server.js` - Production server
162+
- `node_modules/` - Production dependencies only
163+
164+
### Using Releases
165+
166+
To deploy a release:
167+
168+
1. Download `release.tar.gz` from the latest GitHub Release (e.g. with `wget`)
169+
2. Extract (and remove) the tarball: `tar -xzf release.tar.gz && rm release.tar.gz`
170+
3. Start the production server: `npm run start:prod`

client/app.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@
1111
function initializeWebSocket() {
1212
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
1313
const host = window.location.host;
14-
const wsUrl = `${protocol}//${host}`;
15-
14+
const wsUrl = `${protocol}//${host}/ws`;
15+
1616
try {
1717
websocket = new WebSocket(wsUrl);
18-
18+
1919
websocket.onopen = function(event) {
2020
console.log('WebSocket connected');
2121
setStatus('Ready (WebSocket connected)');
2222
};
23-
23+
2424
websocket.onmessage = function(event) {
2525
try {
2626
const data = JSON.parse(event.data);
@@ -31,23 +31,23 @@
3131
console.error('Error parsing WebSocket message:', error);
3232
}
3333
};
34-
34+
3535
websocket.onclose = function(event) {
3636
console.log('WebSocket disconnected');
3737
setStatus('Ready (WebSocket disconnected)');
38-
38+
3939
// Attempt to reconnect after 3 seconds
4040
setTimeout(() => {
4141
console.log('Attempting to reconnect WebSocket...');
4242
initializeWebSocket();
4343
}, 3000);
4444
};
45-
45+
4646
websocket.onerror = function(error) {
4747
console.error('WebSocket error:', error);
4848
setStatus('Ready (WebSocket error)');
4949
};
50-
50+
5151
} catch (error) {
5252
console.error('Failed to create WebSocket connection:', error);
5353
setStatus('Ready (WebSocket unavailable)');

0 commit comments

Comments
 (0)