Skip to content

Commit 59a8ecc

Browse files
committed
Support template generation
1 parent 773dca7 commit 59a8ecc

File tree

35 files changed

+667
-80
lines changed

35 files changed

+667
-80
lines changed

docs/src/content/docs/changelog.mdx

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3434
- Added `init()` method in runtime to allow manual initialisation of the runtime by [@leaanthony](https://github.com/leaanthony)
3535
- Added `WindowDidMoveDebounceMS` option to Window's WindowOptions by [@leaanthony](https://github.com/leaanthony)
3636
- Added Single Instance feature by [@leaanthony](https://github.com/leaanthony). Based on the [v2 PR](https://github.com/wailsapp/wails/pull/2951) by @APshenkin.
37+
- Added template generation using `wails3 generate template` command by [@leaanthony](https://github.com/leaanthony)
3738

3839
### Fixed
3940

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
---
2+
title: Creating Custom Templates
3+
description: Learn how to create and customise your own Wails v3 templates
4+
sidebar:
5+
order: 50
6+
---
7+
8+
This guide will walk you through the process of creating a custom template for Wails v3.
9+
10+
## Why would I make a custom template?
11+
12+
Wails comes with a number of pre-configured templates that allow you to get your application up and running quickly. But if you need a more customised setup, you can create your own template to suit your needs. This can then be shared with the Wails community for others to use.
13+
14+
### 1. Generating a Template
15+
16+
To create a custom template, you can use the `wails generate template` command:
17+
18+
```bash
19+
wails3 generate template -name mytemplate
20+
```
21+
22+
This will create a new directory called "mytemplate" in your current directory.
23+
24+
The `wails3 generate template` command supports the following options:
25+
26+
| Option | Description | Default |
27+
|----------------|---------------------------------------------------|-------------------|
28+
| `-name` | The name of your template (required) | - |
29+
| `-frontend` | Path to an existing frontend directory to include | - |
30+
| `-author` | The author of the template | - |
31+
| `-description` | A description of the template | - |
32+
| `-helpurl` | URL for template documentation | - |
33+
| `-dir` | Directory to generate the template in | Current directory |
34+
| `-version` | Template version | v0.0.1 |
35+
36+
For example, to create a template with all options:
37+
38+
```bash
39+
wails3 generate template \
40+
-name "My Custom Template" \
41+
-frontend ./my-existing-frontend \
42+
-author "Your Name" \
43+
-description "A template with my preferred setup" \
44+
-helpurl "https://github.com/yourusername/template-docs" \
45+
-dir ./templates \
46+
-version "v1.0.0"
47+
```
48+
49+
:::tip
50+
Using the `-frontend` option will copy an existing web frontend project into the template.
51+
:::
52+
53+
### 2. Configure Template Metadata
54+
55+
If you didn't specify the template configuration when generating the template, you can update the `template.json` file in the template directory:
56+
57+
```json5
58+
{
59+
"name": "Your Template Name", // Display name of your template
60+
"shortname": "template-shortname", // Used when referencing your template
61+
"author": "Your Name", // Template author
62+
"description": "Template description", // Template description
63+
"helpurl": "https://your-docs.com", // Documentation URL
64+
"version": "v0.0.1", // Template version
65+
"schema": 3 // Must be kept as 3 for Wails v3
66+
}
67+
```
68+
:::caution
69+
The `schema` field must remain set to `3` for compatibility with Wails v3.
70+
:::
71+
72+
### 3. Set Up Build Tasks
73+
74+
In the `build` directory is `Taskfile.yml` where you can define your template's build process.
75+
This file uses [Task](https://taskfile.dev) for build automation. The key steps are:
76+
77+
```yaml
78+
tasks:
79+
install:frontend:deps:
80+
summary: Install frontend dependencies
81+
dir: frontend
82+
sources:
83+
- package.json
84+
- package-lock.json
85+
generates:
86+
- node_modules/*
87+
preconditions:
88+
- sh: npm version
89+
msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/"
90+
cmds:
91+
- npm install
92+
93+
build:frontend:
94+
summary: Build the frontend project
95+
dir: frontend
96+
sources:
97+
- "**/*"
98+
generates:
99+
- dist/*
100+
deps:
101+
- task: install:frontend:deps
102+
- task: generate:bindings
103+
cmds:
104+
- npm run build -q
105+
106+
107+
```
108+
109+
### 4. Frontend Setup
110+
111+
If you did not use `-frontend` when generating the template, you need to add frontend files to your template.
112+
113+
There are a number of ways to set up your frontend: starting from scratch or using an existing framework.
114+
115+
import { Tabs, TabItem } from '@astrojs/starlight/components';
116+
117+
<Tabs>
118+
<TabItem label="Start from Scratch">
119+
If you want to start from scratch, you can create your frontend project just like you would for any web application.
120+
The `frontend` directory in your template is just a regular directory where you can set up your preferred
121+
development environment. You might want to use build tools like Vite, webpack, or even just plain HTML, CSS, and
122+
JavaScript - it's entirely up to you!
123+
124+
For example, if you're using Vite, you could navigate to the `frontend` directory and run:
125+
126+
```bash
127+
npm create vite@latest .
128+
```
129+
130+
Then follow the prompts to set up your project exactly how you want it. The key thing to remember is that this is just a regular frontend project - you can use any tools, frameworks, or libraries you're familiar with.
131+
</TabItem>
132+
<TabItem label="Use Existing Framework">
133+
For this example, we'll use [Vite](https://vitejs.dev/) to set up a React frontend project:
134+
135+
```bash
136+
npm create vite@latest frontend -- --template react
137+
cd frontend
138+
npm install
139+
```
140+
141+
</TabItem>
142+
</Tabs>
143+
144+
145+
Now you have the frontend files in place, update `common/Taskfile.yml` with the appropriate commands:
146+
```yaml
147+
tasks:
148+
install:frontend:deps:
149+
summary: Install frontend dependencies
150+
dir: frontend
151+
sources:
152+
- package.json
153+
- package-lock.json
154+
generates:
155+
- node_modules/*
156+
preconditions:
157+
- sh: npm version
158+
msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/"
159+
cmds:
160+
- npm install
161+
162+
build:frontend:
163+
summary: Build the frontend project
164+
dir: frontend
165+
sources:
166+
- "**/*"
167+
generates:
168+
- dist/*
169+
deps:
170+
- task: install:frontend:deps
171+
- task: generate:bindings
172+
cmds:
173+
- npm run build -q
174+
```
175+
176+
:::note
177+
For this example, the default Tasks do not need updating as they use the standard `npm install` and `npm run build` commands.
178+
:::
179+
180+
### 5. Configure the Go Application
181+
182+
The default files in the template directory are sufficient to get users started. However, you may want to provide some additional functionality to demonstrate your template's capabilities. The best way to do this is to rename `main.go.tmpl` to `main.go` and edit it like any other Go file. Once finished, ensure you rename it back to `main.go.tmpl` before committing your changes. If you do not care about having a templated `main.go` file (the default template injests the project name into the `Name` field of the application), you can skip this step.
183+
184+
#### Template Variables
185+
186+
Wails uses Go's templating engine to process files with the `.tmpl` extension. During template generation, several variables are available for use in your template files:
187+
188+
| Variable | Description | Example |
189+
|----------------------|----------------------------------|-----------------------------------|
190+
| `Name` | The name of the project | `"MyApp"` |
191+
| `BinaryName` | The name of the generated binary | `"myapp"` |
192+
| `ProductName` | The product name | `"My Application"` |
193+
| `ProductDescription` | Description of the product | `"An awesome application"` |
194+
| `ProductVersion` | Version of the product | `"1.0.0"` |
195+
| `ProductCompany` | Company name | `"My Company Ltd"` |
196+
| `ProductCopyright` | Copyright information | `"Copyright 2024 My Company Ltd"` |
197+
| `ProductComments` | Additional product comments | `"Built with Wails"` |
198+
| `ProductIdentifier` | Unique product identifier | `"com.mycompany.myapp"` |
199+
| `Typescript` | Whether TypeScript is being used | `true` or `false` |
200+
| `WailsVersion` | The version of Wails being used | `"3.0.0"` |
201+
202+
You can use these variables in your template files using Go's template syntax:
203+
204+
```go
205+
// main.go.tmpl
206+
package main
207+
208+
import (
209+
"github.com/wailsapp/wails/v3/pkg/application"
210+
)
211+
212+
func main() {
213+
app := application.New(application.Options{
214+
Name: "{{.ProductName}}",
215+
Description: "{{.ProductDescription}}",
216+
})
217+
// ...
218+
}
219+
```
220+
221+
:::tip
222+
Templating can be applied to any file in your template, even html files, so long as the filename has `.tmpl` in its name.
223+
:::
224+
225+
### 6. Testing Your Template
226+
227+
To test your template:
228+
229+
1. Generate a project using your template: `wails3 init -n testproject -t path/to/your/template`
230+
2. Run `wails3 build` to generate the production build and make sure the binary in `bin` runs correctly
231+
3. Run `wails3 dev` to start the development server.
232+
4. Test that changes to the frontend code are reflected in the application.
233+
5. Test that changes to the Go code rebuild and relaunch the application
234+
235+
### 7. Sharing Your Template
236+
237+
Once your template is ready, you can share it with the community by hosting it on GitHub. Here's how:
238+
239+
1. Create a new GitHub repository for your template
240+
2. Push your template code to the repository
241+
3. Tag your releases using semantic versioning (e.g., v1.0.0)
242+
243+
Users can then use your template directly from GitHub using the HTTPS URL:
244+
245+
```bash
246+
wails3 init -n myapp -t https://github.com/yourusername/your-template
247+
```
248+
249+
You can also specify a particular version using the URL format:
250+
251+
```bash
252+
# Use a specific version tag
253+
wails3 init -n myapp -t https://github.com/yourusername/your-template/releases/tag/v1.0.0
254+
255+
# Use a specific branch
256+
wails3 init -n myapp -t https://github.com/yourusername/your-template/tree/main
257+
```
258+
259+
To test your template before sharing:
260+
261+
1. Push your changes to GitHub
262+
2. Create a new test project using the HTTPS URL:
263+
```bash
264+
wails3 init -n testapp -t https://github.com/yourusername/your-template
265+
```
266+
3. Verify that all files are correctly generated
267+
4. Test the build and development workflow as described in the testing section
268+
269+
:::note
270+
Make sure your repository is public if you want others to use your template.
271+
:::
272+
273+
For more information, visit the [Wails documentation](https://wails.io)
274+
275+
276+
## Best Practices
277+
278+
Let's talk about some key practices that will help make your template more useful and maintainable. Here are the main areas to focus on:
279+
280+
1. **Make Your Template Easy to Understand**
281+
- Write a clear, helpful README.md that gets users started quickly
282+
- Add comments in your config files to explain the "why" behind your choices
283+
- Show examples of common customisations - users love to see real-world use cases!
284+
285+
2. **Keep Dependencies Happy**
286+
- Stay on top of your frontend package updates
287+
- Lock down specific versions in package.json to avoid surprises
288+
- Let users know upfront what they'll need to have installed
289+
290+
3. **Love Your Template**
291+
- Keep it fresh with regular updates
292+
- Give it a thorough test drive before sharing
293+
- Share it with the Wails community - we'd love to see what you create!

v3/cmd/wails3/main.go

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func main() {
5252
generate.NewSubCommandFunction("syso", "Generate Windows .syso file", commands.GenerateSyso)
5353
generate.NewSubCommandFunction("runtime", "Generate the pre-built version of the runtime", commands.GenerateRuntime)
5454
generate.NewSubCommandFunction("webview2bootstrapper", "Generate WebView2 bootstrapper", commands.GenerateWebView2Bootstrapper)
55+
generate.NewSubCommandFunction("template", "Generate a new template", commands.GenerateTemplate)
5556

5657
update := app.NewSubCommand("update", "Update tools")
5758
update.NewSubCommandFunction("build-assets", "Updates the build assets using the given config file", commands.UpdateBuildAssets)

v3/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ require (
8989
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
9090
github.com/klauspost/pgzip v1.2.6 // indirect
9191
github.com/lithammer/fuzzysearch v1.1.5 // indirect
92-
github.com/mattn/go-runewidth v0.0.15 // indirect
92+
github.com/mattn/go-runewidth v0.0.16 // indirect
9393
github.com/mattn/go-zglob v0.0.6 // indirect
9494
github.com/mitchellh/copystructure v1.2.0 // indirect
9595
github.com/mitchellh/go-homedir v1.1.0 // indirect

v3/go.sum

+2-4
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
212212
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
213213
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
214214
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
215-
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
216-
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
215+
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
216+
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
217217
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
218218
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
219219
github.com/mattn/go-zglob v0.0.6 h1:mP8RnmCgho4oaUYDIDn6GNxYk+qJGUs8fJLn+twYj2A=
@@ -303,8 +303,6 @@ github.com/tc-hib/winres v0.3.1 h1:CwRjEGrKdbi5CvZ4ID+iyVhgyfatxFoizjPhzez9Io4=
303303
github.com/tc-hib/winres v0.3.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=
304304
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
305305
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
306-
github.com/wailsapp/go-webview2 v1.0.18 h1:SSSCoLA+MYikSp1U0WmvELF/4c3x5kH8Vi31TKyZ4yk=
307-
github.com/wailsapp/go-webview2 v1.0.18/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
308306
github.com/wailsapp/go-webview2 v1.0.19-0.20241227010006-11c6e567b916 h1:W0UQJWILiXJOOCg7ec5xJNqxkg4Ced5KCGO4tFAf13w=
309307
github.com/wailsapp/go-webview2 v1.0.19-0.20241227010006-11c6e567b916/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
310308
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package commands
2+
3+
import (
4+
"github.com/wailsapp/wails/v3/internal/templates"
5+
)
6+
7+
func GenerateTemplate(options *templates.BaseTemplate) error {
8+
return templates.GenerateTemplate(options)
9+
}

v3/internal/commands/init.go

-4
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,6 @@ func Init(options *flags.Init) error {
122122

123123
options.ProjectName = sanitizeFileName(options.ProjectName)
124124

125-
if !templates.ValidTemplateName(options.TemplateName) {
126-
return fmt.Errorf("invalid template name: %s. Use -l flag to list valid templates", options.TemplateName)
127-
}
128-
129125
err := templates.Install(options)
130126
if err != nil {
131127
return err

v3/internal/flags/init.go

+1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ type Init struct {
1717
ProductCopyright string `description:"The copyright notice" default:"\u00a9 now, My Company"`
1818
ProductComments string `description:"Comments to add to the generated files" default:"This is a comment"`
1919
ProductIdentifier string `description:"The product identifier, e.g com.mycompany.myproduct"`
20+
SkipWarning bool `name:"s" description:"Skips the warning message when using remote templates"`
2021
}

0 commit comments

Comments
 (0)