Skip to content

Commit 647be7e

Browse files
droguscloutiertylerjdetter
authored
spacetime init rewrite (#3366)
This is a draft of the new functionality for `spacetime init`. In order to run it with built-in templates you have to set the path to the config file: ``` export SPACETIMEDB_CLI_TEMPLATES_FILE=crates/cli/.init-templates.json ``` In the future it will fetch the list from GH. A few notes: * the previous functionality of `spacetime init` does not work at the moment * the code needs a bit more cleanup and tests before merging * there is a bit of a mix in how we generate empty server and client projects. For Rust we use the existing way of generating. For TypeScript we clone an empty project from the repo. I wanted to play with both ways of doing things, and I'm still not sure which is better. Generation in Rust means that the generated code will match the CLI version and not necessarily whatever is in Git. On the other hand, for the builtin templates we will be fetching the newest version from GH, which I guess might also not what we want, ie. we probably want only stable templates. More discussion is needed here * we use `spacetimedb` directory for the server files * I don't particularly like the inability to disable interactive mode easily. We discussed disabling it by default if all of the required arguments are passed, but I don't think it's feature proof. For example, if someone relies on a non-interactive mode, and we add a new required argument, instead of printing a message `missing --foo`, we will automatically launch interactive mode, which is harder to debug. That's why I think I'd prefer to implement `--non-interactive` argument * it's kind of hard to keep the legacy behaviour. If you don't pass any arguments, we go into interactive mode. In the legacy version, we would print required arguments. If someone passes `--lang` or `--project-path` explicitly, I guess we could run the legacy workflow, but not sure if it's worth it, as the command was marked as unstable anyway * the project path defaults to the project name, but I think we should probably replace change whitespaces to dashes, or at least ask for the project path with the project name being the default (or both) --------- Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com> Signed-off-by: John Detter <4099508+jdetter@users.noreply.github.com> Co-authored-by: = <cloutiertyler@gmail.com> Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com> Co-authored-by: Tyler Cloutier <cloutiertyler@aol.com> Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
1 parent 32dad5d commit 647be7e

81 files changed

Lines changed: 2784 additions & 320 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,5 +221,8 @@ new.json
221221
# Test data
222222
!crates/core/testdata/
223223

224+
# Temporary templates dir for CLI's init command
225+
/crates/cli/.templates
226+
224227
# Symlinked output from `nix build`
225228
result

Cargo.lock

Lines changed: 74 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ futures = "0.3"
181181
futures-channel = "0.3"
182182
futures-util = "0.3"
183183
getrandom02 = { package = "getrandom", version = "0.2" }
184+
git2 = "0.19"
184185
glob = "0.3.1"
185186
hashbrown = { version = "0.15", default-features = false, features = ["equivalent", "inline-more"] }
186187
headers = "0.4"
@@ -223,6 +224,7 @@ prometheus = "0.13.0"
223224
proptest = "1.4"
224225
proptest-derive = "0.5"
225226
quick-junit = { version = "0.3.2" }
227+
quick-xml = "0.31"
226228
quote = "1.0.8"
227229
rand08 = { package = "rand", version = "0.8" }
228230
rand = "0.9"
@@ -298,6 +300,7 @@ wasmbin = "0.6"
298300
webbrowser = "1.0.2"
299301
windows-sys = "0.59"
300302
xdg = "2.5"
303+
xmltree = "0.11"
301304
tikv-jemallocator = { version = "0.6.0", features = ["profiling", "stats"] }
302305
tikv-jemalloc-ctl = { version = "0.6.0", features = ["stats"] }
303306
jemalloc_pprof = { version = "0.8", features = ["symbolize", "flamegraph"] }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>SpacetimeDB React App</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@clockworklabs/basic-react",
3+
"private": true,
4+
"version": "0.0.1",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"preview": "vite preview",
10+
"local": "spacetime publish --project-path spacetimedb --server local && spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb",
11+
"deploy": "spacetime publish --project-path spacetimedb && spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb"
12+
},
13+
"dependencies": {
14+
"spacetimedb": "workspace:*",
15+
"react": "^18.3.1",
16+
"react-dom": "^18.3.1"
17+
},
18+
"devDependencies": {
19+
"@types/react": "^18.3.18",
20+
"@types/react-dom": "^18.3.5",
21+
"@vitejs/plugin-react": "^5.0.2",
22+
"typescript": "~5.6.2",
23+
"vite": "^7.1.5"
24+
}
25+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { useState } from 'react';
2+
import { DbConnection, Person } from './module_bindings';
3+
import { useSpacetimeDB, useTable } from 'spacetimedb/react';
4+
5+
function App() {
6+
const [name, setName] = useState('');
7+
8+
const conn = useSpacetimeDB<DbConnection>();
9+
const { isActive: connected } = conn;
10+
11+
// Subscribe to all people in the database
12+
const { rows: people } = useTable<DbConnection, Person>('person');
13+
14+
const addPerson = (e: React.FormEvent) => {
15+
e.preventDefault();
16+
if (!name.trim() || !connected) return;
17+
18+
// Call the add reducer
19+
conn.reducers.add(name);
20+
setName('');
21+
};
22+
23+
return (
24+
<div style={{ padding: '2rem' }}>
25+
<h1>SpacetimeDB React App</h1>
26+
27+
<div style={{ marginBottom: '1rem' }}>
28+
Status:{' '}
29+
<strong style={{ color: connected ? 'green' : 'red' }}>
30+
{connected ? 'Connected' : 'Disconnected'}
31+
</strong>
32+
</div>
33+
34+
<form onSubmit={addPerson} style={{ marginBottom: '2rem' }}>
35+
<input
36+
type="text"
37+
placeholder="Enter name"
38+
value={name}
39+
onChange={e => setName(e.target.value)}
40+
style={{ padding: '0.5rem', marginRight: '0.5rem' }}
41+
disabled={!connected}
42+
/>
43+
<button
44+
type="submit"
45+
style={{ padding: '0.5rem 1rem' }}
46+
disabled={!connected}
47+
>
48+
Add Person
49+
</button>
50+
</form>
51+
52+
<div>
53+
<h2>People ({people.length})</h2>
54+
{people.length === 0 ? (
55+
<p>No people yet. Add someone above!</p>
56+
) : (
57+
<ul>
58+
{people.map((person, index) => (
59+
<li key={index}>{person.name}</li>
60+
))}
61+
</ul>
62+
)}
63+
</div>
64+
</div>
65+
);
66+
}
67+
68+
export default App;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { StrictMode } from 'react';
2+
import { createRoot } from 'react-dom/client';
3+
import App from './App.tsx';
4+
import { Identity } from 'spacetimedb';
5+
import { SpacetimeDBProvider } from 'spacetimedb/react';
6+
import { DbConnection, ErrorContext } from './module_bindings/index.ts';
7+
8+
const HOST = import.meta.env.VITE_SPACETIMEDB_HOST ?? 'ws://localhost:3000';
9+
const DB_NAME = import.meta.env.VITE_SPACETIMEDB_DB_NAME ?? 'my-db';
10+
11+
const onConnect = (conn: DbConnection, identity: Identity, token: string) => {
12+
localStorage.setItem('auth_token', token);
13+
console.log(
14+
'Connected to SpacetimeDB with identity:',
15+
identity.toHexString()
16+
);
17+
};
18+
19+
const onDisconnect = () => {
20+
console.log('Disconnected from SpacetimeDB');
21+
};
22+
23+
const onConnectError = (_ctx: ErrorContext, err: Error) => {
24+
console.log('Error connecting to SpacetimeDB:', err);
25+
};
26+
27+
const connectionBuilder = DbConnection.builder()
28+
.withUri(HOST)
29+
.withModuleName(DB_NAME)
30+
.withToken(localStorage.getItem('auth_token') || undefined)
31+
.onConnect(onConnect)
32+
.onDisconnect(onDisconnect)
33+
.onConnectError(onConnectError);
34+
35+
createRoot(document.getElementById('root')!).render(
36+
<StrictMode>
37+
<SpacetimeDBProvider connectionBuilder={connectionBuilder}>
38+
<App />
39+
</SpacetimeDBProvider>
40+
</StrictMode>
41+
);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"useDefineForClassFields": true,
5+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
6+
"module": "ESNext",
7+
"skipLibCheck": true,
8+
9+
"moduleResolution": "bundler",
10+
"allowImportingTsExtensions": true,
11+
"isolatedModules": true,
12+
"moduleDetection": "force",
13+
"noEmit": true,
14+
"jsx": "react-jsx",
15+
16+
"strict": true,
17+
"noUnusedLocals": true,
18+
"noUnusedParameters": true,
19+
"noFallthroughCasesInSwitch": true,
20+
"noUncheckedSideEffectImports": true
21+
},
22+
"include": ["src", "vite.config.ts"]
23+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { defineConfig } from 'vite';
2+
import react from '@vitejs/plugin-react';
3+
4+
export default defineConfig({
5+
plugins: [react()],
6+
});

0 commit comments

Comments
 (0)