Skip to content

Commit 9858eee

Browse files
committed
Implement client commands for JS/TS with Parcel
1 parent 4de269b commit 9858eee

File tree

8 files changed

+122
-57
lines changed

8 files changed

+122
-57
lines changed

new_client.go

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var clientTSIndexTemplate string
3232
//go:embed templates/new/client/ts/game.ts.tmpl
3333
var clientTSGameTemplate string
3434

35-
//go:embed templates/new/client/js/index.html.tmpl
35+
//go:embed templates/new/client/index.html.tmpl
3636
var clientIndexHTMLTemplate string
3737

3838
func CreateNewClient(projectName string) error {
@@ -52,7 +52,13 @@ func CreateNewClient(projectName string) error {
5252
return err
5353
}
5454

55-
runtime, err := cli.SelectString("Runtime:", []string{"Browser", "Node.js"}, []string{"browser", "node"})
55+
var runtime string
56+
57+
if typescript {
58+
runtime, err = cli.SelectString("Runtime:", []string{"Node.js", "Browser (with Parcel)"}, []string{"node", "bundler"})
59+
} else {
60+
runtime, err = cli.SelectString("Runtime:", []string{"Node.js", "Browser", "Browser (with Parcel)"}, []string{"node", "browser", "bundler"})
61+
}
5662
if err != nil {
5763
return err
5864
}
@@ -67,12 +73,6 @@ func CreateNewClient(projectName string) error {
6773
return err
6874
}
6975

70-
node := runtime == "node"
71-
72-
if !node && typescript {
73-
panic("not implemented")
74-
}
75-
7676
cge, err := api.GetCGEFile()
7777
if err != nil {
7878
return err
@@ -87,7 +87,7 @@ func CreateNewClient(projectName string) error {
8787
return err
8888
}
8989

90-
err = createClientTemplate(projectName, info, eventNames, commandNames, node, typescript)
90+
err = createClientTemplate(projectName, info, eventNames, commandNames, runtime, typescript)
9191
if err != nil {
9292
return err
9393
}
@@ -110,32 +110,42 @@ func CreateNewClient(projectName string) error {
110110
return err
111111
}
112112
} else {
113-
if !node {
113+
if runtime == "browser" {
114114
_, err = exec.Execute(true, "npm", "install", "--save-dev", "serve")
115-
if err != nil {
116-
return err
117-
}
115+
}
116+
if err != nil {
117+
return err
118+
}
119+
}
120+
if runtime == "bundler" {
121+
_, err = exec.Execute(true, "npm", "install", "--save-dev", "parcel")
122+
if err != nil {
123+
return err
118124
}
119125
}
120126
cli.FinishLoading()
121127

122128
return nil
123129
}
124130

125-
func createClientTemplate(projectName string, info server.GameInfo, eventNames, commandNames []string, node, typescript bool) error {
126-
return execClientTemplate(projectName, info, eventNames, commandNames, node, typescript, false)
131+
func createClientTemplate(projectName string, info server.GameInfo, eventNames, commandNames []string, runtime string, typescript bool) error {
132+
return execClientTemplate(projectName, info, eventNames, commandNames, runtime, typescript, false)
127133
}
128134

129-
func execClientTemplate(projectName string, info server.GameInfo, eventNames, commandNames []string, node, typescript, update bool) error {
135+
func execClientTemplate(projectName string, info server.GameInfo, eventNames, commandNames []string, runtime string, typescript, update bool) error {
136+
wrapperDir := info.Name
137+
if runtime != "browser" {
138+
wrapperDir = filepath.Join("src", wrapperDir)
139+
}
130140
if update {
131-
cli.Warn("This action will ERASE and regenerate ALL files in '%s/'.\nYou will have to manually update your code to work with the new version.", info.Name)
141+
cli.Warn("This action will ERASE and regenerate ALL files in '%s/'.\nYou will have to manually update your code to work with the new version.", wrapperDir)
132142
ok, err := cli.YesNo("Continue?", false)
133143
if err != nil || !ok {
134144
return cli.ErrCanceled
135145
}
136-
os.RemoveAll(info.Name)
146+
os.RemoveAll(wrapperDir)
137147
} else {
138-
cli.Warn("DO NOT EDIT the `%s/` directory inside of the project. ALL CHANGES WILL BE LOST when running `codegame update`.", info.Name)
148+
cli.Warn("DO NOT EDIT the `%s/` directory inside of the project. ALL CHANGES WILL BE LOST when running `codegame update`.", wrapperDir)
139149
}
140150

141151
type event struct {
@@ -170,22 +180,32 @@ func execClientTemplate(projectName string, info server.GameInfo, eventNames, co
170180
GameName string
171181
Version string
172182
Node bool
183+
Bundler bool
173184
TypeScript bool
174185
Events []event
175186
Commands []event
176187
}{
177188
ProjectName: projectName,
178189
GameName: info.Name,
179190
Version: info.Version,
180-
Node: node,
191+
Node: runtime == "node",
192+
Bundler: runtime == "bundler",
181193
TypeScript: typescript,
182194
Events: events,
183195
Commands: commands,
184196
}
185197

186198
if typescript {
187199
if !update {
188-
err := ExecTemplate(clientTSIndexTemplate, "src/index.ts", data)
200+
indexName := "src/index.ts"
201+
if runtime == "bundler" {
202+
indexName = "src/app.ts"
203+
err := ExecTemplate(clientIndexHTMLTemplate, "src/index.html", data)
204+
if err != nil {
205+
return err
206+
}
207+
}
208+
err := ExecTemplate(clientTSIndexTemplate, indexName, data)
189209
if err != nil {
190210
return err
191211
}
@@ -194,32 +214,38 @@ func execClientTemplate(projectName string, info server.GameInfo, eventNames, co
194214
return err
195215
}
196216
}
197-
err := ExecTemplate(clientTSGameTemplate, filepath.Join("src", info.Name, "game.ts"), data)
217+
err := ExecTemplate(clientTSGameTemplate, filepath.Join(wrapperDir, "game.ts"), data)
198218
if err != nil {
199219
return err
200220
}
201221
} else {
202222
if !update {
203-
indexName := "index.js"
204-
if !node {
223+
indexName := "src/index.js"
224+
if runtime == "browser" {
205225
indexName = "app.js"
206226
err := ExecTemplate(clientIndexHTMLTemplate, "index.html", data)
207227
if err != nil {
208228
return err
209229
}
230+
} else if runtime == "bundler" {
231+
indexName = "src/app.js"
232+
err := ExecTemplate(clientIndexHTMLTemplate, "src/index.html", data)
233+
if err != nil {
234+
return err
235+
}
210236
}
211237
err := ExecTemplate(clientJSIndexTemplate, indexName, data)
212238
if err != nil {
213239
return err
214240
}
215241
}
216-
err := ExecTemplate(clientJSGameTemplate, filepath.Join(info.Name, "game.js"), data)
242+
err := ExecTemplate(clientJSGameTemplate, filepath.Join(wrapperDir, "game.js"), data)
217243
if err != nil {
218244
return err
219245
}
220246
}
221247

222-
if !update && node {
248+
if !update {
223249
err := ExecTemplate(clientPackageJSONTemplate, "package.json", data)
224250
if err != nil {
225251
return err

run.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,33 @@ func Run() error {
2626
if err != nil {
2727
return err
2828
}
29-
runtime := config.LangConfig["runtime"]
30-
node := runtime == "node"
29+
runtime, _ := config.LangConfig["runtime"].(string)
30+
if runtime != "node" && runtime != "bundler" && (typescript || runtime != "browser") {
31+
return fmt.Errorf("Invalid runtime: '%s'", runtime)
32+
}
3133

3234
url := external.TrimURL(config.URL)
3335

3436
switch config.Type {
3537
case "client":
36-
return runClient(url, data.Args, typescript, node)
38+
return runClient(url, data.Args, runtime, typescript)
3739
case "server":
38-
return runServer(data.Args, typescript, node)
40+
return runServer(data.Args, typescript)
3941
default:
4042
return fmt.Errorf("Unknown project type: %s", config.Type)
4143
}
4244
}
4345

44-
func runClient(url string, args []string, typescript, node bool) error {
45-
if typescript {
46+
func runClient(url string, args []string, runtime string, typescript bool) error {
47+
if typescript && runtime != "bundler" {
4648
_, err := cgExec.Execute(true, "npx", "tsc")
4749
if err != nil {
4850
return err
4951
}
5052
}
5153

52-
if node {
53-
path := "index.js"
54+
if runtime == "node" {
55+
path := "src/index.js"
5456
if typescript {
5557
path = "dist/index.js"
5658
}
@@ -79,15 +81,20 @@ func runClient(url string, args []string, typescript, node bool) error {
7981
if _, err := exec.LookPath("npx"); err != nil {
8082
return fmt.Errorf("'npx' ist not installed!")
8183
}
82-
83-
cmd := exec.Command("npx", "serve", "-n", "--no-port-switching", "-l", "5000", ".")
84+
var cmdArgs []string
85+
if runtime == "bundler" {
86+
cmdArgs = []string{"parcel", "--watch-for-stdin", "-p", "5000", "src/index.html"}
87+
} else {
88+
cmdArgs = []string{"serve", "-n", "--no-port-switching", "-p", "5000", "."}
89+
}
90+
cmd := exec.Command("npx", cmdArgs...)
8491
cmd.Stdin = os.Stdin
8592
cmd.Stdout = os.Stdout
8693
cmd.Stderr = os.Stderr
8794

8895
err := cmd.Start()
8996
if err != nil {
90-
return fmt.Errorf("Failed to start 'npx serve': %s", err)
97+
return fmt.Errorf("Failed to start '%s': %s", strings.Join(cmdArgs, " "), err)
9198
}
9299

93100
pflag.Usage = func() {
@@ -146,14 +153,14 @@ func runClient(url string, args []string, typescript, node bool) error {
146153
cgExec.OpenBrowser(fmt.Sprintf("http://localhost:5000?game_url=%s&op=%s%s", url, op, queryParams))
147154
err = cmd.Wait()
148155
if err != nil {
149-
return fmt.Errorf("Failed to run 'npx serve -n --no-port-switching -l 5000 .': %s", err)
156+
return fmt.Errorf("Failed to run '%s': %s", strings.Join(cmdArgs, " "), err)
150157
}
151158
}
152159

153160
return nil
154161
}
155162

156-
func runServer(args []string, typescript, node bool) error {
163+
func runServer(args []string, typescript bool) error {
157164
panic("not implemented")
158165
return nil
159166
}

templates/new/client/js/index.html.tmpl renamed to templates/new/client/index.html.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<meta http-equiv="X-UA-Compatible" content="IE=edge">
77
<meta name="viewport" content="width=device-width, initial-scale=1.0">
88
<title>CodeGame Web</title>
9-
<script type="module" src="app.js" defer></script>
9+
<script type="module" src="app.{{if.TypeScript}}ts{{else}}js{{end}}" defer></script>
1010
</head>
1111

1212
<body>

templates/new/client/js/app.js.tmpl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
import { Game, Verbosity } from './{{.GameName}}/game.js';
2-
3-
{{ if .Node }}
1+
{{ if .Bundler }}import { Game, Verbosity } from './{{.GameName}}/game';
2+
{{ else }}import { Game, Verbosity } from './{{.GameName}}/game.js';
3+
{{end}}{{ if .Node }}
44
const { game } = await Game.fromArgv({}, Verbosity.DEBUG);
5+
{{ else if .Bundler }}
6+
let game;
7+
8+
(async () => {
9+
({ game } = await Game.fromQuery({}, Verbosity.DEBUG));
10+
})();
511
{{ else }}
612
const { game } = await Game.fromQuery({}, Verbosity.DEBUG);
713
{{ end }}

templates/new/client/js/game.js.tmpl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ function getURL() {
1515
else return env.CG_GAME_URL;
1616
}
1717
{{ else }}
18-
import { createSocket, GameSocket, Verbosity } from '../node_modules/@code-game-project/client/dist/browser.js';
19-
18+
{{ if .Bundler }}import { createSocket, GameSocket, Verbosity } from '@code-game-project/client';
19+
{{ else }}import { createSocket, GameSocket, Verbosity } from '../node_modules/@code-game-project/client/dist/browser.js'
20+
{{end}}
2021
function getURL() {
2122
const CG_GAME_URL = new URLSearchParams(window.location.search).get('game_url');
2223
if (!CG_GAME_URL) throw 'Query parameter "game_url" must be set.';

templates/new/client/ts/game.ts.tmpl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ function getURL(): string {
1818
else return env.CG_GAME_URL;
1919
}
2020
{{ else }}
21-
import { createSocket, GameSocket, Verbosity } from '@code-game-project/client/dist/browser';
22-
import type { EventListenerCallback, Session } from '@code-game-project/client/dist/browser';
23-
import type { Events, Commands{{range .Commands}}, {{.PascalName}}Cmd{{end}}{{range .Events}}, {{.PascalName}}Event{{end}} } from './event_definitions';
21+
import { createSocket, GameSocket, Verbosity } from '@code-game-project/client';
22+
import type { EventListenerCallback, Session } from '@code-game-project/client';
23+
import type { Events, Commands{{range .Commands}}, {{.PascalName}}Cmd{{end}}{{range .Events}}, {{.PascalName}}Event{{end}}, GameConfig } from './event_definitions';
2424

2525
function getURL(): string {
2626
const CG_GAME_URL = new URLSearchParams(window.location.search).get('game_url');
@@ -45,7 +45,7 @@ function logGameCreds(gameId: string, joinSecret?: string) {
4545

4646
/** Wrapper for {{ .GameName }}{{if .Version}} v{{ .Version }}{{end}}. */
4747
export class Game {
48-
private socket: GameSocket<Events>;
48+
private socket: GameSocket<Commands, Events>;
4949
private spectating: boolean;
5050

5151
/**

templates/new/client/ts/index.ts.tmpl

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { GameConfig } from './{{.GameName}}/event_definitions.js';
2-
import { Game, Verbosity } from './{{.GameName}}/game.js';
3-
4-
{{ if .Node }}
1+
{{ if .Node }}import { Game, Verbosity } from './{{.GameName}}/game.js';
2+
{{ else }}import { Game, Verbosity } from './{{.GameName}}/game';
3+
{{end}}{{ if .Node }}
54
const { game } = await Game.fromArgv({}, Verbosity.DEBUG);
65
{{ else }}
7-
const { game } = await Game.fromQuery({}, Verbosity.DEBUG);
6+
let game: Game;
7+
8+
(async () => {
9+
({ game } = await Game.fromQuery({}, Verbosity.DEBUG));
10+
})();
811
{{ end }}

update.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,14 @@ func updateClient(projectName, libraryVersion string, config *cgfile.CodeGameFil
5555
return err
5656
}
5757

58-
err = updateClientTemplate(projectName, info, eventNames, commandNames, config.LangConfig["runtime"] == "node", config.Lang == "ts")
58+
typescript := config.Lang == "ts"
59+
60+
runtime, _ := config.LangConfig["runtime"].(string)
61+
if runtime != "node" && runtime != "bundler" && (typescript || runtime != "browser") {
62+
return fmt.Errorf("Invalid runtime: '%s'", runtime)
63+
}
64+
65+
err = updateClientTemplate(projectName, info, eventNames, commandNames, runtime, typescript)
5966
if err != nil {
6067
return err
6168
}
@@ -65,6 +72,21 @@ func updateClient(projectName, libraryVersion string, config *cgfile.CodeGameFil
6572
if err != nil {
6673
return err
6774
}
75+
switch runtime {
76+
case "browser":
77+
_, err = exec.Execute(true, "npm", "install", "--save-dev", "serve@latest")
78+
case "bundler":
79+
_, err = exec.Execute(true, "npm", "install", "--save-dev", "parcel@latest")
80+
}
81+
if err != nil {
82+
return err
83+
}
84+
if typescript {
85+
_, err = exec.Execute(true, "npm", "install", "--save-dev", "typescript@latest", "@types/node@latest")
86+
if err != nil {
87+
return err
88+
}
89+
}
6890
_, err = exec.Execute(true, "npm", "update")
6991
if err != nil {
7092
return err
@@ -73,8 +95,8 @@ func updateClient(projectName, libraryVersion string, config *cgfile.CodeGameFil
7395
return nil
7496
}
7597

76-
func updateClientTemplate(projectName string, info server.GameInfo, eventNames, commandNames []string, node, typescript bool) error {
77-
return execClientTemplate(projectName, info, eventNames, commandNames, node, typescript, true)
98+
func updateClientTemplate(projectName string, info server.GameInfo, eventNames, commandNames []string, runtime string, typescript bool) error {
99+
return execClientTemplate(projectName, info, eventNames, commandNames, runtime, typescript, true)
78100
}
79101

80102
func updateServer(libraryVersion string) error {

0 commit comments

Comments
 (0)