mirror of
https://github.com/taigrr/wails.git
synced 2026-04-03 21:52:45 -07:00
Compare commits
82 Commits
v2-alpha
...
v2.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
078145c030 | ||
|
|
3765c8fb57 | ||
|
|
10ac38c650 | ||
|
|
a16e41f813 | ||
|
|
1bd3deb39f | ||
|
|
be5f7ceb0e | ||
|
|
6943b657c9 | ||
|
|
a148c67df0 | ||
|
|
69297667c1 | ||
|
|
1ae9469e90 | ||
|
|
d597d8e1c9 | ||
|
|
d32152ed84 | ||
|
|
d28a7e8987 | ||
|
|
ef362a746a | ||
|
|
c16c95673e | ||
|
|
d426fc46b5 | ||
|
|
0efeed4d7f | ||
|
|
a11a75fa12 | ||
|
|
2d551cd019 | ||
|
|
37259b8adb | ||
|
|
d5cfcc80f7 | ||
|
|
25564b7211 | ||
|
|
661b24cfa2 | ||
|
|
75f703465a | ||
|
|
9949420639 | ||
|
|
9e347bf71f | ||
|
|
829fd8616b | ||
|
|
ae980d48fd | ||
|
|
ba9e64f53a | ||
|
|
b15d98b555 | ||
|
|
bdda454f69 | ||
|
|
a59d01ddb9 | ||
|
|
27f8df2b31 | ||
|
|
1b28f69236 | ||
|
|
7572b64bec | ||
|
|
f6b83b0933 | ||
|
|
a51ab25e2c | ||
|
|
aeaaccb942 | ||
|
|
4bf3eb303b | ||
|
|
b5437ed1b5 | ||
|
|
e2e752dd06 | ||
|
|
9dc2caecf0 | ||
|
|
b0da974a7d | ||
|
|
b4dc8c252a | ||
|
|
afb1d12c3b | ||
|
|
7a0cb428f2 | ||
|
|
e6a89790e3 | ||
|
|
daede02c16 | ||
|
|
417895f40b | ||
|
|
6bc26aa669 | ||
|
|
a641deb388 | ||
|
|
e013ce14a1 | ||
|
|
9930ee10da | ||
|
|
de6c57771e | ||
|
|
c8359b0743 | ||
|
|
12b7cf09e6 | ||
|
|
28af34f978 | ||
|
|
49b1acc147 | ||
|
|
0ee3015c7d | ||
|
|
4aa1464b48 | ||
|
|
7b52995c86 | ||
|
|
23c1ebfac9 | ||
|
|
3de31613a1 | ||
|
|
9a54f289c4 | ||
|
|
4a740e6186 | ||
|
|
34e622455f | ||
|
|
b13d8ef9fa | ||
|
|
4898bfdf9c | ||
|
|
28ff364faa | ||
|
|
f254cb086a | ||
|
|
15615eb450 | ||
|
|
37987b3827 | ||
|
|
48cf60ac7c | ||
|
|
368195e5bd | ||
|
|
97765c77e5 | ||
|
|
962ad1ea81 | ||
|
|
eba822da0b | ||
|
|
7b052e7a2d | ||
|
|
481eaa5ade | ||
|
|
cf8e2ee195 | ||
|
|
7311868636 | ||
|
|
ed4b74f01b |
35
.github/workflows/deploy-website-to-wails.top-mirror.yml
vendored
Normal file
35
.github/workflows/deploy-website-to-wails.top-mirror.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Deploy mirror | 部署镜像
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
# pull_request:
|
||||
# branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
name: Automatic deployment | 自动部署
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'misitebao/wails'
|
||||
|
||||
steps:
|
||||
- name: Checkout | 切换到部署分支
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: "master"
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build Site | 构建网站
|
||||
run: |
|
||||
cd website &&
|
||||
npm install && npm run build
|
||||
|
||||
- name: Deploy to Server | 部署到服务器
|
||||
uses: hengkx/ssh-deploy@v1.0.1
|
||||
with:
|
||||
HOST: ${{ secrets.DEPLOY_HOST }}
|
||||
USERNAME: ${{ secrets.DEPLOY_HOST_USER }}
|
||||
PASSWORD: ${{ secrets.DEPLOY_HOST_PASSWORD }}
|
||||
SOURCE: "website/build"
|
||||
TARGET: "/www/wwwroot/wails.top"
|
||||
10
.github/workflows/latest-pre.yml
vendored
10
.github/workflows/latest-pre.yml
vendored
@@ -15,11 +15,11 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
|
||||
12
.github/workflows/pr.yml
vendored
12
.github/workflows/pr.yml
vendored
@@ -13,11 +13,11 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
@@ -29,4 +29,4 @@ jobs:
|
||||
run: go build -v ./cmd/wails
|
||||
|
||||
- name: Test
|
||||
run: ./wails version
|
||||
run: ./wails version
|
||||
|
||||
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -15,11 +15,11 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
@@ -31,4 +31,4 @@ jobs:
|
||||
run: go build -v ./cmd/wails
|
||||
|
||||
- name: Test
|
||||
run: ./wails version
|
||||
run: ./wails version
|
||||
|
||||
12
README.md
12
README.md
@@ -26,6 +26,8 @@ make this easy for you by handling project creation, compilation and bundling. A
|
||||
|
||||
The official docs can be found at [https://wails.app](https://wails.app).
|
||||
|
||||
Click [here](https://wails.io) if you are interested in trying out v2 Beta for Windows.
|
||||
|
||||
<span id="nav-2"></span>
|
||||
|
||||
## Contents
|
||||
@@ -117,6 +119,16 @@ This project is supported by these kind people / companies:
|
||||
<a href="https://github.com/marcus-crane" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/marcus-crane.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
</a>
|
||||
<a href="https://github.com/codydbentley" style="width:65px">
|
||||
<img src="https://github.com/codydbentley.png?size=65" width="65"/>
|
||||
</a>
|
||||
<a href="https://github.com/bbergshaven" style="width:45px">
|
||||
<img src="https://github.com/bbergshaven.png?size=45" width="45"/>
|
||||
</a>
|
||||
<a href="https://github.com/Gilgames000" style="width:45px">
|
||||
<img src="https://github.com/Gilgames000.png?size=45" width="45"/>
|
||||
</a>
|
||||
|
||||
|
||||
<span id="nav-5"></span>
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@@ -5,7 +5,7 @@ require (
|
||||
github.com/abadojack/whatlanggo v1.0.1
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/go-playground/colors v1.2.0
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/jackmordaunt/icns v1.0.0
|
||||
github.com/kennygrant/sanitize v1.2.4
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -11,8 +11,8 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M=
|
||||
github.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=
|
||||
|
||||
6
runtime/js/runtime/package-lock.json
generated
6
runtime/js/runtime/package-lock.json
generated
@@ -260,9 +260,9 @@
|
||||
}
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"path-type": {
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
package dev
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||
"github.com/wailsapp/wails/v2/internal/gomod"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -27,6 +32,8 @@ import (
|
||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||
)
|
||||
|
||||
const defaultDevServerURL = "http://localhost:34115"
|
||||
|
||||
func LogGreen(message string, args ...interface{}) {
|
||||
text := fmt.Sprintf(message, args...)
|
||||
println(colour.Green(text))
|
||||
@@ -50,51 +57,43 @@ func sliceToMap(input []string) map[string]struct{} {
|
||||
return result
|
||||
}
|
||||
|
||||
type devFlags struct {
|
||||
ldflags string
|
||||
compilerCommand string
|
||||
assetDir string
|
||||
extensions string
|
||||
openBrowser bool
|
||||
noReload bool
|
||||
wailsjsdir string
|
||||
tags string
|
||||
verbosity int
|
||||
loglevel string
|
||||
forceBuild bool
|
||||
debounceMS int
|
||||
devServerURL string
|
||||
}
|
||||
|
||||
// AddSubcommand adds the `dev` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("dev", "Development mode")
|
||||
|
||||
// Passthrough ldflags
|
||||
ldflags := ""
|
||||
command.StringFlag("ldflags", "optional ldflags", &ldflags)
|
||||
|
||||
// compiler command
|
||||
compilerCommand := "go"
|
||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
||||
|
||||
assetDir := ""
|
||||
command.StringFlag("assetdir", "Serve assets from the given directory", &assetDir)
|
||||
|
||||
// extensions to trigger rebuilds of application
|
||||
extensions := "go"
|
||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &extensions)
|
||||
|
||||
openBrowser := false
|
||||
command.BoolFlag("browser", "Open application in browser", &openBrowser)
|
||||
|
||||
noreload := false
|
||||
command.BoolFlag("noreload", "Disable reload on asset change", &noreload)
|
||||
|
||||
wailsjsdir := ""
|
||||
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &wailsjsdir)
|
||||
|
||||
// tags to pass to `go`
|
||||
tags := ""
|
||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
|
||||
|
||||
// Verbosity
|
||||
verbosity := 1
|
||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &verbosity)
|
||||
|
||||
loglevel := ""
|
||||
command.StringFlag("loglevel", "Loglevel to use - Trace, Dev, Info, Warning, Error", &loglevel)
|
||||
|
||||
forceBuild := false
|
||||
command.BoolFlag("f", "Force build application", &forceBuild)
|
||||
flags := defaultDevFlags()
|
||||
command.StringFlag("ldflags", "optional ldflags", &flags.ldflags)
|
||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &flags.compilerCommand)
|
||||
command.StringFlag("assetdir", "Serve assets from the given directory", &flags.assetDir)
|
||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &flags.extensions)
|
||||
command.BoolFlag("browser", "Open application in browser", &flags.openBrowser)
|
||||
command.BoolFlag("noreload", "Disable reload on asset change", &flags.noReload)
|
||||
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &flags.wailsjsdir)
|
||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &flags.tags)
|
||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &flags.verbosity)
|
||||
command.StringFlag("loglevel", "Loglevel to use - Trace, Dev, Info, Warning, Error", &flags.loglevel)
|
||||
command.BoolFlag("f", "Force build application", &flags.forceBuild)
|
||||
command.IntFlag("debounce", "The amount of time to wait to trigger a reload on change", &flags.debounceMS)
|
||||
command.StringFlag("devserverurl", "The url of the dev server to use", &flags.devServerURL)
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
app.PrintBanner()
|
||||
@@ -103,90 +102,50 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectConfig, err := project.Load(cwd)
|
||||
|
||||
projectConfig, err := loadAndMergeProjectConfig(cwd, &flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if projectConfig.AssetDirectory == "" && assetDir == "" {
|
||||
return fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.")
|
||||
}
|
||||
|
||||
if assetDir == "" && projectConfig.AssetDirectory != "" {
|
||||
assetDir = projectConfig.AssetDirectory
|
||||
}
|
||||
|
||||
if assetDir != projectConfig.AssetDirectory {
|
||||
projectConfig.AssetDirectory = filepath.ToSlash(assetDir)
|
||||
err := projectConfig.Save()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
assetDir, err := filepath.Abs(assetDir)
|
||||
// Update go.mod to use current wails version
|
||||
err = syncGoModVersion(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wailsjsdir == "" && projectConfig.WailsJSDir != "" {
|
||||
wailsjsdir = projectConfig.WailsJSDir
|
||||
}
|
||||
|
||||
if wailsjsdir == "" {
|
||||
wailsjsdir = "./frontend"
|
||||
}
|
||||
|
||||
if wailsjsdir != projectConfig.WailsJSDir {
|
||||
projectConfig.WailsJSDir = filepath.ToSlash(wailsjsdir)
|
||||
err := projectConfig.Save()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: "dev",
|
||||
Mode: build.Dev,
|
||||
Arch: runtime.GOARCH,
|
||||
Pack: true,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
ForceBuild: forceBuild,
|
||||
IgnoreFrontend: false,
|
||||
Verbosity: verbosity,
|
||||
WailsJSDir: wailsjsdir,
|
||||
}
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
// Run go mod tidy to ensure we're up to date
|
||||
err = runCommand(cwd, false, "go", "mod", "tidy")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}(watcher)
|
||||
|
||||
err = runCommand(cwd, true, "wails", "generate", "module")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// frontend:dev server command
|
||||
if projectConfig.DevCommand != "" {
|
||||
var devCommandWaitGroup sync.WaitGroup
|
||||
closer := runFrontendDevCommand(cwd, projectConfig.DevCommand, &devCommandWaitGroup)
|
||||
defer closer(&devCommandWaitGroup)
|
||||
}
|
||||
|
||||
buildOptions := generateBuildOptions(flags)
|
||||
buildOptions.Logger = logger
|
||||
buildOptions.UserTags = parseUserTags(flags.tags)
|
||||
|
||||
var debugBinaryProcess *process.Process = nil
|
||||
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(extensions, ","))
|
||||
|
||||
// Setup signal handler
|
||||
quitChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||
exitCodeChannel := make(chan int, 1)
|
||||
|
||||
var passthruArgs []string
|
||||
//if len(os.Args) > 2 {
|
||||
// passthruArgs = os.Args[2:]
|
||||
//}
|
||||
|
||||
// Do initial build
|
||||
logger.Println("Building application for development...")
|
||||
newProcess, appBinary, err := restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
|
||||
newProcess, appBinary, err := restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -195,129 +154,32 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
}
|
||||
|
||||
// open browser
|
||||
if openBrowser {
|
||||
err = browser.OpenURL("http://localhost:34115")
|
||||
if flags.openBrowser {
|
||||
url := defaultDevServerURL
|
||||
if flags.devServerURL != "" {
|
||||
url = flags.devServerURL
|
||||
}
|
||||
err = browser.OpenURL(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var newBinaryProcess *process.Process
|
||||
|
||||
// Get project dir
|
||||
projectDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get all subdirectories
|
||||
dirs, err := fs.GetSubdirectories(projectDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
LogGreen("Watching (sub)/directory: %s", projectDir)
|
||||
|
||||
// Setup a watcher for non-node_modules directories
|
||||
dirs.Each(func(dir string) {
|
||||
if strings.Contains(dir, "node_modules") {
|
||||
return
|
||||
}
|
||||
// Ignore build directory
|
||||
if strings.HasPrefix(dir, filepath.Join(projectDir, "build")) {
|
||||
return
|
||||
}
|
||||
// Ignore dot directories
|
||||
if strings.HasPrefix(dir, ".") {
|
||||
return
|
||||
}
|
||||
err = watcher.Add(dir)
|
||||
// create the project files watcher
|
||||
watcher, err := initialiseWatcher(cwd, logger.Fatal)
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
})
|
||||
}(watcher)
|
||||
|
||||
// Main Loop
|
||||
quit := false
|
||||
// Use 100ms debounce
|
||||
interval := 100 * time.Millisecond
|
||||
timer := time.NewTimer(interval)
|
||||
rebuild := false
|
||||
reload := false
|
||||
for quit == false {
|
||||
//reload := false
|
||||
select {
|
||||
case exitCode := <-exitCodeChannel:
|
||||
if exitCode == 0 {
|
||||
quit = true
|
||||
}
|
||||
case item := <-watcher.Events:
|
||||
// Check for file writes
|
||||
if item.Op&fsnotify.Write == fsnotify.Write {
|
||||
// Ignore directories
|
||||
if fs.DirExists(item.Name) {
|
||||
continue
|
||||
}
|
||||
LogGreen("Watching (sub)/directory: %s", cwd)
|
||||
LogGreen("Using Dev Server URL: %s", flags.devServerURL)
|
||||
LogGreen("Using reload debounce setting of %d milliseconds", flags.debounceMS)
|
||||
|
||||
// Iterate all file patterns
|
||||
ext := filepath.Ext(item.Name)
|
||||
if ext != "" {
|
||||
ext = ext[1:]
|
||||
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
|
||||
rebuild = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(item.Name, assetDir) {
|
||||
reload = true
|
||||
}
|
||||
timer.Reset(interval)
|
||||
}
|
||||
// Check for new directories
|
||||
if item.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(item.Name) {
|
||||
//node_modules is BANNED!
|
||||
if !strings.Contains(item.Name, "node_modules") {
|
||||
err := watcher.Add(item.Name)
|
||||
if err != nil {
|
||||
logger.Fatal("%s", err.Error())
|
||||
}
|
||||
LogGreen("Added new directory to watcher: %s", item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-timer.C:
|
||||
if rebuild {
|
||||
rebuild = false
|
||||
LogGreen("[Rebuild triggered] files updated")
|
||||
// Try and build the app
|
||||
newBinaryProcess, _, err = restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
|
||||
if err != nil {
|
||||
LogRed("Error during build: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// If we have a new process, save it
|
||||
if newBinaryProcess != nil {
|
||||
debugBinaryProcess = newBinaryProcess
|
||||
}
|
||||
}
|
||||
if reload {
|
||||
reload = false
|
||||
_, err = http.Get("http://localhost:34115/wails/reload")
|
||||
if err != nil {
|
||||
LogRed("Error during refresh: %s", err.Error())
|
||||
}
|
||||
}
|
||||
case <-quitChannel:
|
||||
LogGreen("\nCaught quit")
|
||||
quit = true
|
||||
}
|
||||
}
|
||||
// Watch for changes and trigger restartApp()
|
||||
doWatcherLoop(buildOptions, debugBinaryProcess, flags, watcher, exitCodeChannel, quitChannel)
|
||||
|
||||
// Kill the current program if running
|
||||
if debugBinaryProcess != nil {
|
||||
@@ -337,18 +199,238 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, assetDir string, firstRun bool, exitCodeChannel chan int) (*process.Process, string, error) {
|
||||
func syncGoModVersion(cwd string) error {
|
||||
gomodFilename := filepath.Join(cwd, "go.mod")
|
||||
gomodData, err := os.ReadFile(gomodFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outOfSync, err := gomod.GoModOutOfSync(gomodData, internal.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !outOfSync {
|
||||
return nil
|
||||
}
|
||||
LogGreen("Updating go.mod to use Wails '%s'", internal.Version)
|
||||
newGoData, err := gomod.UpdateGoModVersion(gomodData, internal.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(gomodFilename, newGoData, 0755)
|
||||
}
|
||||
|
||||
func runCommand(dir string, exitOnError bool, command string, args ...string) error {
|
||||
LogGreen("Executing: " + command + " " + strings.Join(args, " "))
|
||||
cmd := exec.Command(command, args...)
|
||||
cmd.Dir = dir
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
println(string(output))
|
||||
if exitOnError {
|
||||
os.Exit(1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// defaultDevFlags generates devFlags with default options
|
||||
func defaultDevFlags() devFlags {
|
||||
return devFlags{
|
||||
devServerURL: defaultDevServerURL,
|
||||
compilerCommand: "go",
|
||||
verbosity: 1,
|
||||
extensions: "go",
|
||||
debounceMS: 100,
|
||||
}
|
||||
}
|
||||
|
||||
// generateBuildOptions creates a build.Options using the flags
|
||||
func generateBuildOptions(flags devFlags) *build.Options {
|
||||
return &build.Options{
|
||||
OutputType: "dev",
|
||||
Mode: build.Dev,
|
||||
Arch: runtime.GOARCH,
|
||||
Pack: true,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: flags.ldflags,
|
||||
Compiler: flags.compilerCommand,
|
||||
ForceBuild: flags.forceBuild,
|
||||
IgnoreFrontend: false,
|
||||
Verbosity: flags.verbosity,
|
||||
WailsJSDir: flags.wailsjsdir,
|
||||
}
|
||||
}
|
||||
|
||||
// parseUserTags takes the string form of tags and converts to a slice of strings
|
||||
func parseUserTags(tagString string) []string {
|
||||
userTags := make([]string, 0)
|
||||
for _, tag := range strings.Split(tagString, " ") {
|
||||
thisTag := strings.TrimSpace(tag)
|
||||
if thisTag != "" {
|
||||
userTags = append(userTags, thisTag)
|
||||
}
|
||||
}
|
||||
return userTags
|
||||
}
|
||||
|
||||
// loadAndMergeProjectConfig reconciles flags passed to the CLI with project config settings and updates
|
||||
// the project config if necessary
|
||||
func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, error) {
|
||||
projectConfig, err := project.Load(cwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var shouldSaveConfig bool
|
||||
|
||||
if projectConfig.AssetDirectory == "" && flags.assetDir == "" {
|
||||
return nil, fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.")
|
||||
}
|
||||
|
||||
if flags.assetDir == "" && projectConfig.AssetDirectory != "" {
|
||||
flags.assetDir = projectConfig.AssetDirectory
|
||||
}
|
||||
|
||||
if flags.assetDir != projectConfig.AssetDirectory {
|
||||
projectConfig.AssetDirectory = filepath.ToSlash(flags.assetDir)
|
||||
}
|
||||
|
||||
flags.assetDir, err = filepath.Abs(flags.assetDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if flags.devServerURL == defaultDevServerURL && projectConfig.DevServerURL != defaultDevServerURL && projectConfig.DevServerURL != "" {
|
||||
flags.devServerURL = projectConfig.DevServerURL
|
||||
}
|
||||
|
||||
if flags.devServerURL != projectConfig.DevServerURL {
|
||||
projectConfig.DevServerURL = flags.devServerURL
|
||||
shouldSaveConfig = true
|
||||
}
|
||||
|
||||
if flags.wailsjsdir == "" && projectConfig.WailsJSDir != "" {
|
||||
flags.wailsjsdir = projectConfig.WailsJSDir
|
||||
}
|
||||
|
||||
if flags.wailsjsdir == "" {
|
||||
flags.wailsjsdir = "./frontend"
|
||||
}
|
||||
|
||||
if flags.wailsjsdir != projectConfig.WailsJSDir {
|
||||
projectConfig.WailsJSDir = filepath.ToSlash(flags.wailsjsdir)
|
||||
shouldSaveConfig = true
|
||||
}
|
||||
|
||||
if flags.debounceMS == 100 && projectConfig.DebounceMS != 100 {
|
||||
if projectConfig.DebounceMS == 0 {
|
||||
projectConfig.DebounceMS = 100
|
||||
}
|
||||
flags.debounceMS = projectConfig.DebounceMS
|
||||
}
|
||||
|
||||
if flags.debounceMS != projectConfig.DebounceMS {
|
||||
projectConfig.DebounceMS = flags.debounceMS
|
||||
shouldSaveConfig = true
|
||||
}
|
||||
|
||||
if shouldSaveConfig {
|
||||
err = projectConfig.Save()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return projectConfig, nil
|
||||
}
|
||||
|
||||
// runFrontendDevCommand will run the `frontend:dev` command if it was given, ex- `npm run dev`
|
||||
func runFrontendDevCommand(cwd string, devCommand string, wg *sync.WaitGroup) func(group *sync.WaitGroup) {
|
||||
LogGreen("Running frontend dev command: '%s'", devCommand)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
dir := filepath.Join(cwd, "frontend")
|
||||
cmdSlice := strings.Split(devCommand, " ")
|
||||
wg.Add(1)
|
||||
cmd := exec.CommandContext(ctx, cmdSlice[0], cmdSlice[1:]...)
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Dir = dir
|
||||
go func(ctx context.Context, devCommand string, cwd string, wg *sync.WaitGroup) {
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if err.Error() != "exit status 1" {
|
||||
LogRed("Error from '%s': %s", devCommand, err.Error())
|
||||
}
|
||||
}
|
||||
LogGreen("Dev command exited!")
|
||||
wg.Done()
|
||||
}(ctx, devCommand, cwd, wg)
|
||||
|
||||
return func(wg *sync.WaitGroup) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// Credit: https://stackoverflow.com/a/44551450
|
||||
// For whatever reason, killing an npm script on windows just doesn't exit properly with cancel
|
||||
kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid))
|
||||
kill.Stderr = os.Stderr
|
||||
kill.Stdout = os.Stdout
|
||||
err := kill.Run()
|
||||
if err != nil {
|
||||
if err.Error() != "exit status 1" {
|
||||
LogRed("Error from '%s': %s", devCommand, err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cancel()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// initialiseWatcher creates the project directory watcher that will trigger recompile
|
||||
func initialiseWatcher(cwd string, logFatal func(string, ...interface{})) (*fsnotify.Watcher, error) {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get all subdirectories
|
||||
dirs, err := fs.GetSubdirectories(cwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Setup a watcher for non-node_modules directories
|
||||
dirs.Each(func(dir string) {
|
||||
if strings.Contains(dir, "node_modules") {
|
||||
return
|
||||
}
|
||||
// Ignore build directory
|
||||
if strings.HasPrefix(dir, filepath.Join(cwd, "build")) {
|
||||
return
|
||||
}
|
||||
// Ignore dot directories
|
||||
if strings.HasPrefix(dir, ".") {
|
||||
return
|
||||
}
|
||||
err = watcher.Add(dir)
|
||||
if err != nil {
|
||||
logFatal(err.Error())
|
||||
}
|
||||
})
|
||||
return watcher, nil
|
||||
}
|
||||
|
||||
// restartApp does the actual rebuilding of the application when files change
|
||||
func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, exitCodeChannel chan int) (*process.Process, string, error) {
|
||||
|
||||
appBinary, err := build.Build(buildOptions)
|
||||
println()
|
||||
if err != nil {
|
||||
if firstRun {
|
||||
return nil, "", err
|
||||
}
|
||||
LogRed("Build error - continuing to run current version")
|
||||
LogDarkYellow(err.Error())
|
||||
return nil, "", nil
|
||||
@@ -359,7 +441,7 @@ func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugB
|
||||
killError := debugBinaryProcess.Kill()
|
||||
|
||||
if killError != nil {
|
||||
logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
||||
buildOptions.Logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
||||
}
|
||||
|
||||
debugBinaryProcess = nil
|
||||
@@ -367,13 +449,12 @@ func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugB
|
||||
|
||||
// Start up new binary with correct args
|
||||
args := slicer.StringSlicer{}
|
||||
args.Add("-loglevel", loglevel)
|
||||
if assetDir != "" {
|
||||
args.Add("-assetdir", assetDir)
|
||||
args.Add("-loglevel", flags.loglevel)
|
||||
if flags.assetDir != "" {
|
||||
args.Add("-assetdir", flags.assetDir)
|
||||
}
|
||||
|
||||
if len(passthruArgs) > 0 {
|
||||
args.AddSlice(passthruArgs)
|
||||
if flags.devServerURL != "" {
|
||||
args.Add("-devserverurl", flags.devServerURL)
|
||||
}
|
||||
newProcess := process.NewProcess(appBinary, args.AsSlice()...)
|
||||
err = newProcess.Start(exitCodeChannel)
|
||||
@@ -382,11 +463,98 @@ func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugB
|
||||
if fs.FileExists(appBinary) {
|
||||
deleteError := fs.DeleteFile(appBinary)
|
||||
if deleteError != nil {
|
||||
logger.Fatal("Unable to delete app binary: " + appBinary)
|
||||
buildOptions.Logger.Fatal("Unable to delete app binary: " + appBinary)
|
||||
}
|
||||
}
|
||||
logger.Fatal("Unable to start application: %s", err.Error())
|
||||
buildOptions.Logger.Fatal("Unable to start application: %s", err.Error())
|
||||
}
|
||||
|
||||
return newProcess, appBinary, nil
|
||||
}
|
||||
|
||||
// doWatcherLoop is the main watch loop that runs while dev is active
|
||||
func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, watcher *fsnotify.Watcher, exitCodeChannel chan int, quitChannel chan os.Signal) {
|
||||
// Main Loop
|
||||
var (
|
||||
err error
|
||||
newBinaryProcess *process.Process
|
||||
)
|
||||
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(flags.extensions, ","))
|
||||
quit := false
|
||||
interval := time.Duration(flags.debounceMS) * time.Millisecond
|
||||
timer := time.NewTimer(interval)
|
||||
rebuild := false
|
||||
reload := false
|
||||
for quit == false {
|
||||
//reload := false
|
||||
select {
|
||||
case exitCode := <-exitCodeChannel:
|
||||
if exitCode == 0 {
|
||||
quit = true
|
||||
}
|
||||
case item := <-watcher.Events:
|
||||
// Check for file writes
|
||||
if item.Op&fsnotify.Write == fsnotify.Write {
|
||||
// Ignore directories
|
||||
if fs.DirExists(item.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Iterate all file patterns
|
||||
ext := filepath.Ext(item.Name)
|
||||
if ext != "" {
|
||||
ext = ext[1:]
|
||||
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
|
||||
rebuild = true
|
||||
timer.Reset(interval)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(item.Name, flags.assetDir) {
|
||||
reload = true
|
||||
}
|
||||
timer.Reset(interval)
|
||||
}
|
||||
// Check for new directories
|
||||
if item.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(item.Name) {
|
||||
//node_modules is BANNED!
|
||||
if !strings.Contains(item.Name, "node_modules") {
|
||||
err := watcher.Add(item.Name)
|
||||
if err != nil {
|
||||
buildOptions.Logger.Fatal("%s", err.Error())
|
||||
}
|
||||
LogGreen("Added new directory to watcher: %s", item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-timer.C:
|
||||
if rebuild {
|
||||
rebuild = false
|
||||
LogGreen("[Rebuild triggered] files updated")
|
||||
// Try and build the app
|
||||
newBinaryProcess, _, err = restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel)
|
||||
if err != nil {
|
||||
LogRed("Error during build: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// If we have a new process, save it
|
||||
if newBinaryProcess != nil {
|
||||
debugBinaryProcess = newBinaryProcess
|
||||
}
|
||||
}
|
||||
if reload {
|
||||
reload = false
|
||||
_, err = http.Get("http://localhost:34115/wails/reload")
|
||||
if err != nil {
|
||||
LogRed("Error during refresh: %s", err.Error())
|
||||
}
|
||||
}
|
||||
case <-quitChannel:
|
||||
LogGreen("\nCaught quit")
|
||||
quit = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate/template"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||
)
|
||||
|
||||
// AddSubcommand adds the `generate` command for the Wails application
|
||||
@@ -15,34 +13,11 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("generate", "Code Generation Tools")
|
||||
|
||||
//AddModuleCommand(app, command, w)
|
||||
err := AddModuleCommand(app, command, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
template.AddSubCommand(app, command, w)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
|
||||
|
||||
logger.Println("Processed Go package '" + pkg.Gopackage.Name + "' as '" + pkg.Name + "'")
|
||||
for _, strct := range pkg.Structs() {
|
||||
logger.Println("")
|
||||
logger.Println(" Processed struct '" + strct.Name + "'")
|
||||
if strct.IsBound {
|
||||
for _, method := range strct.Methods {
|
||||
logger.Println(" Bound method '" + method.Name + "'")
|
||||
}
|
||||
}
|
||||
if strct.IsUsedAsData {
|
||||
for _, field := range strct.Fields {
|
||||
if !field.Ignored {
|
||||
logger.Print(" Processed ")
|
||||
if field.IsOptional {
|
||||
logger.Print("optional ")
|
||||
}
|
||||
logger.Println("field '" + field.Name + "' as '" + field.JSName() + "'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Println("")
|
||||
}
|
||||
|
||||
@@ -1,58 +1,50 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||
"github.com/wailsapp/wails/v2/internal/shell"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
|
||||
// AddModuleCommand adds the `module` subcommand for the `generate` command
|
||||
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) error {
|
||||
|
||||
// Backend API
|
||||
backendAPI := parent.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
|
||||
command := parent.NewSubCommand("module", "Generate wailsjs modules")
|
||||
|
||||
// Quiet Init
|
||||
quiet := false
|
||||
backendAPI.BoolFlag("q", "Suppress output to console", &quiet)
|
||||
command.Action(func() error {
|
||||
|
||||
backendAPI.Action(func() error {
|
||||
filename := "wailsbindings"
|
||||
if runtime.GOOS == "windows" {
|
||||
filename += ".exe"
|
||||
}
|
||||
// go build -tags bindings -o bindings.exe
|
||||
tempDir := os.TempDir()
|
||||
filename = filepath.Join(tempDir, filename)
|
||||
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
logger.Mute(quiet)
|
||||
|
||||
app.PrintBanner()
|
||||
|
||||
logger.Print("Generating Javascript module for Go code...")
|
||||
|
||||
// Start Time
|
||||
start := time.Now()
|
||||
|
||||
p, err := parser.GenerateWailsFrontendPackage()
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Println("done.")
|
||||
logger.Println("")
|
||||
|
||||
elapsed := time.Since(start)
|
||||
packages := p.Packages
|
||||
|
||||
// Print report
|
||||
for _, pkg := range p.Packages {
|
||||
if pkg.ShouldGenerate() {
|
||||
logPackage(pkg, logger)
|
||||
}
|
||||
|
||||
_, _, err = shell.RunCommand(cwd, "go", "build", "-tags", "bindings", "-o", filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
|
||||
_, _, err = shell.RunCommand(cwd, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.Remove(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ The next steps to complete the template are:
|
||||
|
||||
You can test your template by running this command:
|
||||
|
||||
`wails init -name test -t {{.TemplateDir}}`
|
||||
`wails init -n test -t {{.TemplateDir}}`
|
||||
|
||||
### Checklist
|
||||
|
||||
|
||||
@@ -12,5 +12,5 @@ To generate a platform native package, add the `-package` flag.
|
||||
## Live Development
|
||||
|
||||
To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend`
|
||||
directory and run `npm run dev`. The frontend dev server will run on http://localhost:5000. Connect to this
|
||||
directory and run `npm run dev`. The frontend dev server will run on http://localhost:34115. Connect to this
|
||||
in your browser and connect to your application.
|
||||
|
||||
@@ -2,7 +2,7 @@ module changeme
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.0
|
||||
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
)
|
||||
|
||||
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.0 => {{.WailsDirectory}}
|
||||
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}
|
||||
@@ -81,16 +81,18 @@ func AddSubCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
|
||||
}
|
||||
|
||||
type templateData struct {
|
||||
Name string
|
||||
Description string
|
||||
TemplateDir string
|
||||
Name string
|
||||
Description string
|
||||
TemplateDir string
|
||||
WailsVersion string
|
||||
}
|
||||
|
||||
println("Extracting base template files...")
|
||||
|
||||
err = g.Extract(templateDir, &templateData{
|
||||
Name: name,
|
||||
TemplateDir: templateDir,
|
||||
Name: name,
|
||||
TemplateDir: templateDir,
|
||||
WailsVersion: app.Version(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -2,7 +2,12 @@ package initialise
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/flytam/filenamify"
|
||||
"github.com/leaanthony/slicer"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -46,8 +51,8 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
}
|
||||
|
||||
// VSCode project files
|
||||
vscode := false
|
||||
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
|
||||
ide := ""
|
||||
command.StringFlag("ide", "Generate IDE project files", &ide)
|
||||
|
||||
// List templates
|
||||
list := false
|
||||
@@ -75,6 +80,15 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate IDE option
|
||||
supportedIDEs := slicer.String([]string{"vscode", "goland"})
|
||||
ide = strings.ToLower(ide)
|
||||
if ide != "" {
|
||||
if !supportedIDEs.Contains(ide) {
|
||||
return fmt.Errorf("ide '%s' not supported. Valid values: %s", ide, supportedIDEs.Join(" "))
|
||||
}
|
||||
}
|
||||
|
||||
if !quiet {
|
||||
app.PrintBanner()
|
||||
}
|
||||
@@ -83,27 +97,47 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
logger.Println(task)
|
||||
logger.Println(strings.Repeat("-", len(task)))
|
||||
|
||||
projectFilename, err := filenamify.Filenamify(projectName, filenamify.Options{
|
||||
Replacement: "_",
|
||||
MaxLength: 255,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
goBinary, err := exec.LookPath("go")
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to find Go compiler. Please download and install Go: https://golang.org/dl/")
|
||||
}
|
||||
|
||||
// Get base path and convert to forward slashes
|
||||
goPath := filepath.ToSlash(filepath.Dir(goBinary))
|
||||
// Trim bin directory
|
||||
goSDKPath := strings.TrimSuffix(goPath, "/bin")
|
||||
|
||||
// Create Template Options
|
||||
options := &templates.Options{
|
||||
ProjectName: projectName,
|
||||
TargetDir: projectDirectory,
|
||||
TemplateName: templateName,
|
||||
Logger: logger,
|
||||
GenerateVSCode: vscode,
|
||||
InitGit: initGit,
|
||||
ProjectName: projectName,
|
||||
TargetDir: projectDirectory,
|
||||
TemplateName: templateName,
|
||||
Logger: logger,
|
||||
IDE: ide,
|
||||
InitGit: initGit,
|
||||
ProjectNameFilename: projectFilename,
|
||||
WailsVersion: app.Version(),
|
||||
GoSDKPath: goSDKPath,
|
||||
}
|
||||
|
||||
// Try to discover author details from git config
|
||||
findAuthorDetails(options)
|
||||
|
||||
return initProject(options)
|
||||
return initProject(options, quiet)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initProject is our main init command
|
||||
func initProject(options *templates.Options) error {
|
||||
func initProject(options *templates.Options, quiet bool) error {
|
||||
|
||||
// Start Time
|
||||
start := time.Now()
|
||||
@@ -120,6 +154,19 @@ func initProject(options *templates.Options) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Run `go mod tidy` to ensure `go.sum` is up to date
|
||||
cmd := exec.Command("go", "mod", "tidy")
|
||||
cmd.Dir = options.TargetDir
|
||||
cmd.Stderr = os.Stderr
|
||||
if !quiet {
|
||||
println("")
|
||||
cmd.Stdout = os.Stdout
|
||||
}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.InitGit {
|
||||
err = initGit(options)
|
||||
if err != nil {
|
||||
@@ -127,6 +174,10 @@ func initProject(options *templates.Options) error {
|
||||
}
|
||||
}
|
||||
|
||||
if quiet {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Output stats
|
||||
elapsed := time.Since(start)
|
||||
options.Logger.Println("")
|
||||
@@ -135,9 +186,14 @@ func initProject(options *templates.Options) error {
|
||||
options.Logger.Println("Project Template: " + options.TemplateName)
|
||||
options.Logger.Println("Template Support: " + template.HelpURL)
|
||||
|
||||
if options.GenerateVSCode {
|
||||
// IDE message
|
||||
switch options.IDE {
|
||||
case "vscode":
|
||||
options.Logger.Println("VSCode config files generated.")
|
||||
case "goland":
|
||||
options.Logger.Println("Goland config files generated.")
|
||||
}
|
||||
|
||||
if options.InitGit {
|
||||
options.Logger.Println("Git repository initialised.")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/{{.ProjectNameFilename}}.iml"
|
||||
filepath="$PROJECT_DIR$/.idea/{{.ProjectNameFilename}}.iml"/>
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
{{.ProjectName}}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git"/>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="ALL"/>
|
||||
</component>
|
||||
<component name="GOROOT" url="file://{{.GoSDKPath}}"/>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$"/>
|
||||
</component>
|
||||
<component name="GoLibraries">
|
||||
<option name="indexEntireGoPath" value="false"/>
|
||||
</component>
|
||||
<component name="ProjectId" id="wails-{{.ProjectName}}"/>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true"/>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true"/>
|
||||
<option name="showLibraryContents" value="true"/>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true"/>
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true"/>
|
||||
<property name="WebServerToolWindowFactoryState" value="false"/>
|
||||
<property name="com.intellij.ide.scratch.LRUPopupBuilder$1/New Scratch File" value="TEXT"/>
|
||||
<property name="go.formatter.settings.were.checked" value="true"/>
|
||||
<property name="go.import.settings.migrated" value="true"/>
|
||||
<property name="go.modules.go.list.on.any.changes.was.set" value="true"/>
|
||||
<property name="go.sdk.automatically.set" value="true"/>
|
||||
<property name="go.tried.to.enable.integration.vgo.integrator" value="true"/>
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$"/>
|
||||
<property name="settings.editor.selected.configurable"
|
||||
value="reference.settingsdialog.IDE.editor.colors.Console Font"/>
|
||||
</component>
|
||||
<component name="RunManager" selected="Go Build.{{.ProjectName}} (dev)">>
|
||||
<configuration name="{{.ProjectName}} (dev)" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||
<module name="{{.ProjectName}}"/>
|
||||
<working_directory value="$PROJECT_DIR$"/>
|
||||
<go_parameters value="-gcflags "all=-N -l" -tags dev -o {{.PathToDesktopBinary}}"/>
|
||||
<useCustomBuildTags value="true"/>
|
||||
<parameters value="-assetdir {{.AssetDir}}"/>
|
||||
<envs>
|
||||
<env name="CGO_ENABLED" value=""{{.CGOEnabled}}""/>
|
||||
</envs>
|
||||
<kind value="DIRECTORY"/>
|
||||
<directory value="$PROJECT_DIR$"/>
|
||||
<filePath value="$PROJECT_DIR$"/>
|
||||
<method v="2">
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="{{.ProjectName}} (production)" type="GoApplicationRunConfiguration"
|
||||
factoryName="Go Application">
|
||||
<module name="{{.ProjectName}}"/>
|
||||
<working_directory value="$PROJECT_DIR$"/>
|
||||
<go_parameters
|
||||
value="-ldflags "-w -s{{.WindowsFlags}}" -tags desktop,production -o {{.PathToDesktopBinary}}"/>
|
||||
<useCustomBuildTags value="true"/>
|
||||
<envs>
|
||||
<env name="CGO_ENABLED" value=""{{.CGOEnabled}}""/>
|
||||
</envs>
|
||||
<kind value="DIRECTORY"/>
|
||||
<directory value="$PROJECT_DIR$"/>
|
||||
<filePath value="$PROJECT_DIR$"/>
|
||||
<method v="2">
|
||||
</method>
|
||||
</configuration>
|
||||
|
||||
<list>
|
||||
<item itemvalue="Go Build.{{.ProjectName}} (dev)"/>
|
||||
<item itemvalue="Go Remote.Local"/>
|
||||
</list>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0"
|
||||
DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true"/>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3"/>
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State/>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="oldMeFiltersMigrated" value="true"/>
|
||||
</component>
|
||||
<component name="VgoProject">
|
||||
<integration-enabled>true</integration-enabled>
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
||||
@@ -42,6 +42,11 @@ type Data struct {
|
||||
AuthorEmail string
|
||||
AuthorNameAndEmail string
|
||||
WailsDirectory string
|
||||
GoSDKPath string
|
||||
AssetDir string
|
||||
WindowsFlags string
|
||||
CGOEnabled string
|
||||
OutputFile string
|
||||
}
|
||||
|
||||
// Options for installing a template
|
||||
@@ -51,13 +56,19 @@ type Options struct {
|
||||
BinaryName string
|
||||
TargetDir string
|
||||
Logger *clilogger.CLILogger
|
||||
GenerateVSCode bool
|
||||
PathToDesktopBinary string
|
||||
PathToServerBinary string
|
||||
InitGit bool
|
||||
AuthorName string
|
||||
AuthorEmail string
|
||||
AssetDir string
|
||||
IDE string
|
||||
ProjectNameFilename string // The project name but as a valid filename
|
||||
WailsVersion string
|
||||
GoSDKPath string
|
||||
WindowsFlags string
|
||||
CGOEnabled string
|
||||
OutputFile string
|
||||
}
|
||||
|
||||
// Template holds data relating to a template
|
||||
@@ -241,6 +252,7 @@ func Install(options *Options) (bool, *Template, error) {
|
||||
BinaryName := filepath.Base(options.TargetDir)
|
||||
NPMProjectName := strings.ToLower(strings.ReplaceAll(BinaryName, " ", ""))
|
||||
localWailsDirectory := fs.RelativePath("../../../../../..")
|
||||
|
||||
templateData := &Data{
|
||||
ProjectName: options.ProjectName,
|
||||
BinaryName: filepath.Base(options.TargetDir),
|
||||
@@ -248,6 +260,9 @@ func Install(options *Options) (bool, *Template, error) {
|
||||
WailsDirectory: localWailsDirectory,
|
||||
AuthorEmail: options.AuthorEmail,
|
||||
AuthorName: options.AuthorName,
|
||||
WailsVersion: options.WailsVersion,
|
||||
GoSDKPath: options.GoSDKPath,
|
||||
AssetDir: options.AssetDir,
|
||||
}
|
||||
|
||||
// Create a formatted name and email combo.
|
||||
@@ -259,6 +274,10 @@ func Install(options *Options) (bool, *Template, error) {
|
||||
}
|
||||
templateData.AuthorNameAndEmail = strings.TrimSpace(templateData.AuthorNameAndEmail)
|
||||
|
||||
installer.RenameFiles(map[string]string{
|
||||
"gitignore.txt": ".gitignore",
|
||||
})
|
||||
|
||||
// Extract the template
|
||||
err = installer.Extract(options.TargetDir, templateData)
|
||||
if err != nil {
|
||||
@@ -317,17 +336,58 @@ func OutputList(logger *clilogger.CLILogger) error {
|
||||
|
||||
func generateIDEFiles(options *Options) error {
|
||||
|
||||
if options.GenerateVSCode {
|
||||
switch options.IDE {
|
||||
case "vscode":
|
||||
return generateVSCodeFiles(options)
|
||||
case "goland":
|
||||
return generateGolandFiles(options)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ideOptions struct {
|
||||
name string
|
||||
targetDir string
|
||||
options *Options
|
||||
renameFiles map[string]string
|
||||
ignoredFiles []string
|
||||
}
|
||||
|
||||
func generateGolandFiles(options *Options) error {
|
||||
ideoptions := ideOptions{
|
||||
name: "goland",
|
||||
targetDir: filepath.Join(options.TargetDir, ".idea"),
|
||||
options: options,
|
||||
renameFiles: map[string]string{
|
||||
"projectname.iml": options.ProjectNameFilename + ".iml",
|
||||
"gitignore.txt": ".gitignore",
|
||||
"name": ".name",
|
||||
},
|
||||
}
|
||||
if !options.InitGit {
|
||||
ideoptions.ignoredFiles = []string{"vcs.xml"}
|
||||
}
|
||||
err := installIDEFiles(ideoptions)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "generating Goland IDE files")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateVSCodeFiles(options *Options) error {
|
||||
ideoptions := ideOptions{
|
||||
name: "vscode",
|
||||
targetDir: filepath.Join(options.TargetDir, ".vscode"),
|
||||
options: options,
|
||||
}
|
||||
return installIDEFiles(ideoptions)
|
||||
|
||||
targetDir := filepath.Join(options.TargetDir, ".vscode")
|
||||
source, err := debme.FS(ides, "ides/vscode")
|
||||
}
|
||||
|
||||
func installIDEFiles(o ideOptions) error {
|
||||
source, err := debme.FS(ides, "ides/"+o.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -335,14 +395,22 @@ func generateVSCodeFiles(options *Options) error {
|
||||
// Use gosod to install the template
|
||||
installer := gosod.New(source)
|
||||
|
||||
binaryName := filepath.Base(options.TargetDir)
|
||||
if o.renameFiles != nil {
|
||||
installer.RenameFiles(o.renameFiles)
|
||||
}
|
||||
|
||||
for _, ignoreFile := range o.ignoredFiles {
|
||||
installer.IgnoreFile(ignoreFile)
|
||||
}
|
||||
|
||||
binaryName := filepath.Base(o.options.TargetDir)
|
||||
if runtime.GOOS == "windows" {
|
||||
// yay windows
|
||||
binaryName += ".exe"
|
||||
}
|
||||
|
||||
// Parse wails.json for assetdir
|
||||
wailsJSONBytes, err := os.ReadFile(filepath.Join(options.TargetDir, "wails.json"))
|
||||
wailsJSONBytes, err := os.ReadFile(filepath.Join(o.options.TargetDir, "wails.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -356,10 +424,16 @@ func generateVSCodeFiles(options *Options) error {
|
||||
return fmt.Errorf("Unable to find 'assetdir' in 'wails.json' ")
|
||||
}
|
||||
|
||||
options.AssetDir = assetDir.(string)
|
||||
options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName))
|
||||
o.options.AssetDir = assetDir.(string)
|
||||
o.options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName))
|
||||
|
||||
err = installer.Extract(targetDir, options)
|
||||
o.options.WindowsFlags = ""
|
||||
o.options.CGOEnabled = "1"
|
||||
if runtime.GOOS == "windows" {
|
||||
o.options.WindowsFlags = " -H windowsgui"
|
||||
o.options.CGOEnabled = "0"
|
||||
}
|
||||
err = installer.Extract(o.targetDir, o.options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Wails bin directory
|
||||
build/bin
|
||||
|
||||
# IDEs
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# The black hole that is...
|
||||
node_modules
|
||||
@@ -2,7 +2,7 @@ module changeme
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.0
|
||||
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
)
|
||||
|
||||
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.0 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
||||
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}
|
||||
|
||||
@@ -15,6 +15,7 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642w
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
@@ -58,8 +59,9 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
@@ -75,16 +77,15 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
|
||||
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
@@ -146,6 +147,8 @@ github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfY
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg=
|
||||
github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA=
|
||||
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
@@ -193,8 +196,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -222,4 +225,4 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Wails bin directory
|
||||
build/bin
|
||||
|
||||
# IDEs
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# The black hole that is...
|
||||
node_modules
|
||||
@@ -2,7 +2,7 @@ module changeme
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.0
|
||||
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
)
|
||||
|
||||
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.0 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
||||
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}
|
||||
|
||||
@@ -15,6 +15,7 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642w
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
@@ -58,8 +59,9 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
@@ -75,16 +77,15 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
|
||||
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
@@ -146,6 +147,8 @@ github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfY
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg=
|
||||
github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA=
|
||||
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
@@ -193,8 +196,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
||||
@@ -86,7 +86,7 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
|
||||
|
||||
// Early exit
|
||||
if targetVersionString == currentVersion {
|
||||
logger.Println("Looks like you're up to date!")
|
||||
logger.Println("\nLooks like you're up to date!")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -151,14 +151,16 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
|
||||
log.Fatal("Cannot find home directory! Please file a bug report!")
|
||||
}
|
||||
|
||||
sout, serr, err := shell.RunCommand(homeDir, "go", "get", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion)
|
||||
sout, serr, err := shell.RunCommand(homeDir, "go", "install", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion)
|
||||
if err != nil {
|
||||
logger.Println("Failed.")
|
||||
logger.Println(sout + `\n` + serr)
|
||||
return err
|
||||
}
|
||||
fmt.Println()
|
||||
logger.Println("\n")
|
||||
logger.Println("Wails CLI updated to " + desiredVersion)
|
||||
logger.Println("Make sure you update your project go.mod file to use " + desiredVersion + ":")
|
||||
logger.Println(" require github.com/wailsapp/wails/v2 " + desiredVersion)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
3
v2/cmd/wails/internal/version.go
Normal file
3
v2/cmd/wails/internal/version.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package internal
|
||||
|
||||
var Version = "v2.0.0-beta.5"
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/colour"
|
||||
@@ -24,7 +25,7 @@ func fatal(message string) {
|
||||
func banner(_ *clir.Cli) string {
|
||||
return fmt.Sprintf("%s %s\n",
|
||||
colour.Yellow("Wails CLI"),
|
||||
colour.DarkRed(version))
|
||||
colour.DarkRed(internal.Version))
|
||||
}
|
||||
|
||||
func printFooter() {
|
||||
@@ -35,7 +36,7 @@ func main() {
|
||||
|
||||
var err error
|
||||
|
||||
app := clir.NewCli("Wails", "Go/HTML Appkit", version)
|
||||
app := clir.NewCli("Wails", "Go/HTML Appkit", internal.Version)
|
||||
|
||||
app.SetBannerFunction(banner)
|
||||
defer printFooter()
|
||||
@@ -61,14 +62,14 @@ func main() {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
err = update.AddSubcommand(app, os.Stdout, version)
|
||||
err = update.AddSubcommand(app, os.Stdout, internal.Version)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
command := app.NewSubCommand("version", "The Wails CLI version")
|
||||
command.Action(func() error {
|
||||
println(version)
|
||||
println(internal.Version)
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
package main
|
||||
|
||||
var version = "v2.0.0-beta.0"
|
||||
11
v2/go.mod
11
v2/go.mod
@@ -5,6 +5,7 @@ go 1.17
|
||||
require (
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/fatih/structtag v1.2.0
|
||||
github.com/flytam/filenamify v1.0.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/gabriel-vasile/mimetype v1.3.1
|
||||
github.com/go-git/go-billy/v5 v5.2.0 // indirect
|
||||
@@ -20,8 +21,8 @@ require (
|
||||
github.com/leaanthony/debme v1.2.1
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934
|
||||
github.com/leaanthony/gosod v1.0.2
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd
|
||||
github.com/leaanthony/gosod v1.0.3
|
||||
github.com/leaanthony/idgen v1.0.0
|
||||
github.com/leaanthony/slicer v1.5.0
|
||||
github.com/leaanthony/typescriptify-golang-structs v0.1.7
|
||||
@@ -40,9 +41,9 @@ require (
|
||||
github.com/wzshiming/ctc v1.2.3
|
||||
github.com/xyproto/xpm v1.2.1
|
||||
github.com/ztrue/tracerr v0.3.0
|
||||
golang.org/x/mod v0.4.1 // indirect
|
||||
golang.org/x/mod v0.4.1
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6
|
||||
golang.org/x/tools v0.1.0
|
||||
nhooyr.io/websocket v1.8.6
|
||||
)
|
||||
@@ -56,7 +57,7 @@ require (
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/klauspost/compress v1.12.2 // indirect
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect
|
||||
|
||||
18
v2/go.sum
18
v2/go.sum
@@ -22,6 +22,8 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flytam/filenamify v1.0.0 h1:ewx6BY2dj7U6h2zGPJmt33q/BjkSf/YsY/woQvnUNIs=
|
||||
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
|
||||
@@ -84,8 +86,9 @@ github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmA
|
||||
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@@ -106,17 +109,16 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
|
||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.2 h1:LtjqaIoHuoXiQXbzMPq0isjNfltSyHKhWeiU/JbmP0w=
|
||||
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
|
||||
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
|
||||
github.com/leaanthony/idgen v1.0.0 h1:IZreR+JGEzFV4yeVuBZA25gM0keUoFy+RDUldncQ+Jw=
|
||||
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
@@ -255,8 +257,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
105
v2/internal/appng/app_bindings.go
Normal file
105
v2/internal/appng/app_bindings.go
Normal file
@@ -0,0 +1,105 @@
|
||||
//go:build bindings
|
||||
// +build bindings
|
||||
|
||||
package appng
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/gosod"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/project"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
logger *logger.Logger
|
||||
appoptions *options.App
|
||||
}
|
||||
|
||||
func (a *App) Run() error {
|
||||
|
||||
// Create binding exemptions - Ugly hack. There must be a better way
|
||||
bindingExemptions := []interface{}{a.appoptions.OnStartup, a.appoptions.OnShutdown, a.appoptions.OnDomReady}
|
||||
appBindings := binding.NewBindings(a.logger, a.appoptions.Bind, bindingExemptions)
|
||||
|
||||
err := generateBindings(appBindings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateApp creates the app!
|
||||
func CreateApp(appoptions *options.App) (*App, error) {
|
||||
// Set up logger
|
||||
myLogger := logger.New(appoptions.Logger)
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
result := &App{
|
||||
logger: myLogger,
|
||||
appoptions: appoptions,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
func generateBindings(bindings *binding.Bindings) error {
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectConfig, err := project.Load(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wrapperDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "runtime")
|
||||
_ = os.RemoveAll(wrapperDir)
|
||||
extractor := gosod.New(wrapper.RuntimeWrapper)
|
||||
err = extractor.Extract(wrapperDir, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//ipcdev.js
|
||||
err = os.WriteFile(filepath.Join(wrapperDir, "ipcdev.js"), wailsRuntime.DesktopIPC, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//runtimedev.js
|
||||
err = os.WriteFile(filepath.Join(wrapperDir, "runtimedev.js"), wailsRuntime.RuntimeDesktopJS, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "go")
|
||||
err = os.RemoveAll(targetDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = fs.MkDirs(targetDir)
|
||||
|
||||
modelsFile := filepath.Join(targetDir, "models.ts")
|
||||
err = bindings.WriteTS(modelsFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write backend method wrappers
|
||||
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
||||
err = bindings.GenerateBackendJS(bindingsFilename, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build darwin
|
||||
//go:build darwin && !bindings
|
||||
|
||||
package appng
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !dev && !production && darwin
|
||||
//go:build !dev && !production && !bindings && darwin
|
||||
|
||||
package appng
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !dev && !production && windows
|
||||
//go:build !dev && !production && !bindings && windows
|
||||
|
||||
package appng
|
||||
|
||||
@@ -24,7 +24,7 @@ Please use "wails build" or press "OK" to open the documentation on how to use "
|
||||
"Error",
|
||||
w32.MB_ICONERROR|w32.MB_OKCANCEL)
|
||||
if result == 1 {
|
||||
exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://wails.io").Start()
|
||||
exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://wails.io/docs/guides/manual-builds").Start()
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -61,11 +61,16 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
||||
|
||||
// Check for CLI Flags
|
||||
assetdir := flag.String("assetdir", "", "Directory to serve assets")
|
||||
devServerURL := flag.String("devserverurl", "", "URL of development server")
|
||||
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
||||
flag.Parse()
|
||||
if devServerURL != nil && *devServerURL != "" {
|
||||
ctx = context.WithValue(ctx, "devserverurl", *devServerURL)
|
||||
}
|
||||
if assetdir != nil && *assetdir != "" {
|
||||
ctx = context.WithValue(ctx, "assetdir", *assetdir)
|
||||
}
|
||||
|
||||
if loglevel != nil && *loglevel != "" {
|
||||
level, err := pkglogger.StringToLogLevel(*loglevel)
|
||||
if err != nil {
|
||||
@@ -157,7 +162,7 @@ func generateBindings(bindings *binding.Bindings) error {
|
||||
|
||||
// Write backend method wrappers
|
||||
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
||||
err = bindings.GenerateBackendJS(bindingsFilename)
|
||||
err = bindings.GenerateBackendJS(bindingsFilename, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build windows
|
||||
//go:build windows && !bindings
|
||||
|
||||
package appng
|
||||
|
||||
|
||||
@@ -4,18 +4,19 @@ import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
//go:embed assets/package.json
|
||||
var packageJSON []byte
|
||||
|
||||
func (b *Bindings) GenerateBackendJS(targetfile string) error {
|
||||
func (b *Bindings) GenerateBackendJS(targetfile string, isDevBindings bool) error {
|
||||
|
||||
store := b.db.store
|
||||
var output bytes.Buffer
|
||||
@@ -23,8 +24,18 @@ func (b *Bindings) GenerateBackendJS(targetfile string) error {
|
||||
output.WriteString(`// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
`)
|
||||
|
||||
const go = {`)
|
||||
if isDevBindings {
|
||||
json, err := b.ToJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
output.WriteString("window.wailsbindings = " + json + ";")
|
||||
output.WriteString("\n")
|
||||
}
|
||||
|
||||
output.WriteString(`const go = {`)
|
||||
output.WriteString("\n")
|
||||
|
||||
var sortedPackageNames slicer.StringSlicer
|
||||
@@ -93,7 +104,7 @@ const go = {`)
|
||||
output.WriteString("\n")
|
||||
})
|
||||
|
||||
output.WriteString(fmt.Sprintf(" }\n"))
|
||||
output.WriteString(fmt.Sprintf(" },\n"))
|
||||
output.WriteString("\n")
|
||||
})
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func doInstallationStrategy(installStatus installationStatus) error {
|
||||
confirmed, err := webview2runtime.Confirm("This application requires the WebView2 runtime. Press OK to open the download page. Minimum version required: "+minimumRuntimeVersion, "Missing Requirements")
|
||||
confirmed, err := webview2runtime.Confirm("This application requires the WebView2 runtime. Press OK to open the download page. Minimum version required: "+MinimumRuntimeVersion, "Missing Requirements")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,63 +21,63 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
type AssetServer struct {
|
||||
indexFile []byte
|
||||
type BrowserAssetServer struct {
|
||||
runtimeJS []byte
|
||||
assetdir string
|
||||
appOptions *options.App
|
||||
}
|
||||
|
||||
func NewAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*AssetServer, error) {
|
||||
result := &AssetServer{
|
||||
func NewBrowserAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*BrowserAssetServer, error) {
|
||||
result := &BrowserAssetServer{
|
||||
assetdir: assetdir,
|
||||
appOptions: appOptions,
|
||||
}
|
||||
|
||||
err := result.init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
|
||||
buffer.Write(runtime.RuntimeDesktopJS)
|
||||
result.runtimeJS = buffer.Bytes()
|
||||
err = result.init()
|
||||
return result, err
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (a *AssetServer) loadFileFromDisk(filename string) ([]byte, error) {
|
||||
func (a *BrowserAssetServer) loadFileFromDisk(filename string) ([]byte, error) {
|
||||
return os.ReadFile(filepath.Join(a.assetdir, filename))
|
||||
}
|
||||
|
||||
func (a *AssetServer) init() error {
|
||||
var err error
|
||||
a.indexFile, err = a.loadFileFromDisk("index.html")
|
||||
func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) {
|
||||
indexHTML, err := a.loadFileFromDisk("index.html")
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<div id="wails-spinner"></div>`)
|
||||
indexHTML, err = injectHTML(string(indexHTML), `<div id="wails-spinner"></div>`)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/ipc.js"></script>`)
|
||||
wailsOptions, err := extractOptions(indexHTML)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
if wailsOptions.disableRuntimeInjection == false {
|
||||
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
if wailsOptions.disableIPCInjection == false {
|
||||
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/ipc.js"></script>`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return indexHTML, nil
|
||||
}
|
||||
|
||||
func (a *AssetServer) Load(filename string) ([]byte, string, error) {
|
||||
func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) {
|
||||
var content []byte
|
||||
var err error
|
||||
switch filename {
|
||||
case "/":
|
||||
content = a.indexFile
|
||||
content, err = a.processIndexHTML()
|
||||
case "/wails/runtime.js":
|
||||
content = a.runtimeJS
|
||||
case "/wails/ipc.js":
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"io/fs"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DesktopAssetServer struct {
|
||||
assets debme.Debme
|
||||
indexFile []byte
|
||||
runtimeJS []byte
|
||||
assetdir string
|
||||
logger *logger.Logger
|
||||
@@ -106,27 +106,41 @@ func (a *DesktopAssetServer) init(assets embed.FS) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexHTML, err := a.assets.ReadFile("index.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/ipc.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *DesktopAssetServer) processIndexHTML() ([]byte, error) {
|
||||
indexHTML, err := a.ReadFile("index.html")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wailsOptions, err := extractOptions(indexHTML)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
if wailsOptions.disableRuntimeInjection == false {
|
||||
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if wailsOptions.disableIPCInjection == false {
|
||||
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/ipc.js"></script>`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return indexHTML, nil
|
||||
}
|
||||
|
||||
func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) {
|
||||
var content []byte
|
||||
var err error
|
||||
switch filename {
|
||||
case "/":
|
||||
content = a.indexFile
|
||||
content, err = a.processIndexHTML()
|
||||
case "/wails/runtime.js":
|
||||
content = a.runtimeJS
|
||||
case "/wails/ipc.js":
|
||||
|
||||
@@ -3,19 +3,86 @@ package assetserver
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"golang.org/x/net/html"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type optionType string
|
||||
|
||||
const (
|
||||
noAutoInject optionType = "noautoinject"
|
||||
noAutoInjectRuntime optionType = "noautoinjectruntime"
|
||||
noautoinjectipc optionType = "noautoinjectipc"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
disableRuntimeInjection bool
|
||||
disableIPCInjection bool
|
||||
}
|
||||
|
||||
func newOptions(optionString string) *Options {
|
||||
var result = &Options{}
|
||||
optionString = strings.ToLower(optionString)
|
||||
options := strings.Split(optionString, ",")
|
||||
for _, option := range options {
|
||||
switch optionType(strings.TrimSpace(option)) {
|
||||
case noAutoInject:
|
||||
result.disableRuntimeInjection = true
|
||||
result.disableIPCInjection = true
|
||||
case noautoinjectipc:
|
||||
result.disableIPCInjection = true
|
||||
case noAutoInjectRuntime:
|
||||
result.disableRuntimeInjection = true
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func injectHTML(input string, html string) ([]byte, error) {
|
||||
splits := strings.Split(input, "</body>")
|
||||
splits := strings.Split(input, "</head>")
|
||||
if len(splits) != 2 {
|
||||
return nil, fmt.Errorf("unable to locate a </body> tag in your html")
|
||||
return nil, fmt.Errorf("unable to locate a </head> tag in your html")
|
||||
}
|
||||
|
||||
var result bytes.Buffer
|
||||
result.WriteString(splits[0])
|
||||
result.WriteString(html)
|
||||
result.WriteString("</body>")
|
||||
result.WriteString("</head>")
|
||||
result.WriteString(splits[1])
|
||||
return result.Bytes(), nil
|
||||
}
|
||||
|
||||
func extractOptions(htmldata []byte) (*Options, error) {
|
||||
doc, err := html.Parse(bytes.NewReader(htmldata))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var extractor func(*html.Node) *Options
|
||||
extractor = func(node *html.Node) *Options {
|
||||
if node.Type == html.ElementNode && node.Data == "meta" {
|
||||
isWailsOptionsTag := false
|
||||
wailsOptions := ""
|
||||
for _, attr := range node.Attr {
|
||||
if isWailsOptionsTag && attr.Key == "content" {
|
||||
wailsOptions = attr.Val
|
||||
}
|
||||
if attr.Val == "wails-options" {
|
||||
isWailsOptionsTag = true
|
||||
}
|
||||
}
|
||||
return newOptions(wailsOptions)
|
||||
}
|
||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||
result := extractor(child)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
result := extractor(doc)
|
||||
if result == nil {
|
||||
result = &Options{}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
70
v2/internal/frontend/assetserver/common_test.go
Normal file
70
v2/internal/frontend/assetserver/common_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const realHTML = `<html>
|
||||
|
||||
<head>
|
||||
<title>test3</title>
|
||||
<meta name="wails-options" content="noautoinject">
|
||||
<link rel="stylesheet" href="/main.css">
|
||||
</head>
|
||||
|
||||
<body data-wails-drag>
|
||||
<div class="logo"></div>
|
||||
<div class="result" id="result">Please enter your name below <20></div>
|
||||
<div class="input-box" id="input" data-wails-no-drag>
|
||||
<input class="input" id="name" type="text" autocomplete="off">
|
||||
<button class="btn" onclick="greet()">Greet</button>
|
||||
</div>
|
||||
|
||||
<script src="/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
`
|
||||
|
||||
func genMeta(content string) []byte {
|
||||
return []byte("<html><head><meta name=\"wails-options\" content=\"" + content + "\"></head><body></body></html>")
|
||||
}
|
||||
|
||||
func genOptions(runtime bool, bindings bool) *Options {
|
||||
return &Options{
|
||||
disableRuntimeInjection: runtime,
|
||||
disableIPCInjection: bindings,
|
||||
}
|
||||
}
|
||||
|
||||
func Test_extractOptions(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
htmldata []byte
|
||||
want *Options
|
||||
wantError bool
|
||||
}{
|
||||
{"empty", []byte(""), &Options{}, false},
|
||||
{"bad data", []byte("<"), &Options{}, false},
|
||||
{"bad options", genMeta("noauto"), genOptions(false, false), false},
|
||||
{"realhtml", []byte(realHTML), genOptions(true, true), false},
|
||||
{"noautoinject", genMeta("noautoinject"), genOptions(true, true), false},
|
||||
{"noautoinjectipc", genMeta("noautoinjectipc"), genOptions(false, true), false},
|
||||
{"noautoinjectruntime", genMeta("noautoinjectruntime"), genOptions(true, false), false},
|
||||
{"spaces", genMeta(" noautoinjectruntime "), genOptions(true, false), false},
|
||||
{"multiple", genMeta("noautoinjectruntime,noautoinjectipc"), genOptions(true, true), false},
|
||||
{"multiple spaces", genMeta(" noautoinjectruntime, noautoinjectipc "), genOptions(true, true), false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := extractOptions(tt.htmldata)
|
||||
if !tt.wantError && err != nil {
|
||||
t.Errorf("did not want error but got it")
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("extractOptions() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,9 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
)
|
||||
import "github.com/gabriel-vasile/mimetype"
|
||||
|
||||
var (
|
||||
cache = map[string]string{}
|
||||
@@ -33,6 +34,10 @@ func GetMimetype(filename string, data []byte) string {
|
||||
result = strings.Replace(result, "text/plain", "text/css", 1)
|
||||
}
|
||||
|
||||
if filepath.Ext(filename) == ".js" && strings.HasPrefix(result, "text/plain") {
|
||||
result = strings.Replace(result, "text/plain", "text/javascript", 1)
|
||||
}
|
||||
|
||||
if result == "" {
|
||||
result = "application/octet-stream"
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ func TestGetMimetype(t *testing.T) {
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{"css", args{"test.css", []byte("body{margin:0;padding:0;background-color:#d579b2}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;background-color:#ededed}#nav{padding:30px}#nav a{font-weight:700;color:#2c\n3e50}#nav a.router-link-exact-active{color:#42b983}.hello[data-v-4e26ad49]{margin:10px 0}")}, "text/css; charset=utf-8"},
|
||||
{"js", args{"test.js", []byte("let foo = 'bar'; console.log(foo);")}, "text/javascript; charset=utf-8"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build darwin
|
||||
|
||||
package darwin
|
||||
|
||||
import (
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
package darwin
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ package darwin
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"log"
|
||||
"runtime"
|
||||
|
||||
@@ -310,7 +311,7 @@ func (f *Frontend) Notify(name string, data ...interface{}) {
|
||||
f.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
f.ExecJS(`window.wails.EventsNotify('` + string(payload) + `');`)
|
||||
f.ExecJS(`window.wails.EventsNotify('` + template.JSEscapeString(string(payload)) + `');`)
|
||||
}
|
||||
|
||||
//func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
package windows
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"github.com/leaanthony/go-common-file-dialog/cfd"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
|
||||
@@ -11,8 +11,7 @@ import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"text/template"
|
||||
|
||||
"github.com/leaanthony/go-webview2/pkg/edge"
|
||||
"github.com/leaanthony/winc"
|
||||
@@ -35,7 +34,8 @@ type Frontend struct {
|
||||
debug bool
|
||||
|
||||
// Assets
|
||||
assets *assetserver.DesktopAssetServer
|
||||
assets *assetserver.DesktopAssetServer
|
||||
startURL string
|
||||
|
||||
// main window handle
|
||||
mainWindow *Window
|
||||
@@ -57,21 +57,33 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
||||
minWidth: appoptions.MinWidth,
|
||||
maxHeight: appoptions.MaxHeight,
|
||||
maxWidth: appoptions.MaxWidth,
|
||||
}
|
||||
|
||||
// Check if we have been given a directory to serve assets from.
|
||||
// If so, this means we are in dev mode and are serving assets off disk.
|
||||
// We indicate this through the `servingFromDisk` flag to ensure requests
|
||||
// aren't cached by WebView2 in dev mode
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir != nil {
|
||||
result.servingFromDisk = true
|
||||
startURL: "file://wails/",
|
||||
}
|
||||
|
||||
bindingsJSON, err := appBindings.ToJSON()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
_devServerURL := ctx.Value("devserverurl")
|
||||
if _devServerURL != nil {
|
||||
devServerURL := _devServerURL.(string)
|
||||
if len(devServerURL) > 0 && devServerURL != "http://localhost:34115" {
|
||||
result.startURL = devServerURL
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have been given a directory to serve assets from.
|
||||
// If so, this means we are in dev mode and are serving assets off disk.
|
||||
// We indicate this through the `servingFromDisk` flag to ensure requests
|
||||
// aren't cached by WebView2 in dev mode
|
||||
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir != nil {
|
||||
result.servingFromDisk = true
|
||||
}
|
||||
|
||||
assets, err := assetserver.NewDesktopAssetServer(ctx, appoptions.Assets, bindingsJSON)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -264,16 +276,9 @@ func (f *Frontend) setupChromium() {
|
||||
chromium.MessageCallback = f.processMessage
|
||||
chromium.WebResourceRequestedCallback = f.processRequest
|
||||
chromium.NavigationCompletedCallback = f.navigationCompleted
|
||||
acceleratorsWebviewShouldProcess := slicer.Int([]int{ctrlV, ctrlC, ctrlX, ctrlZ, ctrlA, arrowLeft, arrowRight, arrowUp, arrowDown, keyDel})
|
||||
|
||||
chromium.AcceleratorKeyCallback = func(vkey uint) bool {
|
||||
// We want webview to handle ctrl-C, ctrl-Z, ctrl-v, ctrl-x
|
||||
if acceleratorsWebviewShouldProcess.Contains(int(vkey)) {
|
||||
return false
|
||||
}
|
||||
// Post keypress
|
||||
w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
chromium.Embed(f.mainWindow.Handle())
|
||||
chromium.Resize()
|
||||
@@ -297,7 +302,7 @@ func (f *Frontend) setupChromium() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsStatusBarEnabled(false)
|
||||
err = settings.PutAreBrowserAcceleratorKeysEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -306,7 +311,7 @@ func (f *Frontend) setupChromium() {
|
||||
f.WindowSetRGBA(f.frontendOptions.RGBA)
|
||||
|
||||
chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)
|
||||
chromium.Navigate("file://wails/")
|
||||
chromium.Navigate(f.startURL)
|
||||
}
|
||||
|
||||
type EventNotify struct {
|
||||
@@ -324,7 +329,7 @@ func (f *Frontend) Notify(name string, data ...interface{}) {
|
||||
f.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
f.ExecJS(`window.wails.EventsNotify('` + string(payload) + `');`)
|
||||
f.ExecJS(`window.wails.EventsNotify('` + template.JSEscapeString(string(payload)) + `');`)
|
||||
}
|
||||
|
||||
func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) {
|
||||
|
||||
@@ -33,7 +33,7 @@ type DevWebServer struct {
|
||||
logger *logger.Logger
|
||||
appBindings *binding.Bindings
|
||||
dispatcher frontend.Dispatcher
|
||||
assetServer *assetserver.AssetServer
|
||||
assetServer *assetserver.BrowserAssetServer
|
||||
socketMutex sync.Mutex
|
||||
websocketClients map[*websocket.Conn]struct{}
|
||||
menuManager *menumanager.Manager
|
||||
@@ -93,47 +93,54 @@ func (d *DevWebServer) Run(ctx context.Context) error {
|
||||
}
|
||||
}))
|
||||
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir == nil {
|
||||
return fmt.Errorf("no assetdir provided")
|
||||
_devServerURL := ctx.Value("devserverurl")
|
||||
if _devServerURL == "http://localhost:34115" {
|
||||
// Setup internal dev server
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir == nil {
|
||||
return fmt.Errorf("no assetdir provided")
|
||||
}
|
||||
if _assetdir != nil {
|
||||
assetdir := _assetdir.(string)
|
||||
bindingsJSON, err := d.appBindings.ToJSON()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
d.assetServer, err = assetserver.NewBrowserAssetServer(assetdir, bindingsJSON, d.appoptions)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
absdir, err := filepath.Abs(assetdir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.LogDebug("Serving assets from: %s", absdir)
|
||||
}
|
||||
|
||||
d.server.Get("*", d.loadAsset)
|
||||
|
||||
// Start server
|
||||
go func(server *fiber.App, log *logger.Logger) {
|
||||
err := server.Listen("localhost:34115")
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
d.LogDebug("Shutdown completed")
|
||||
}(d.server, d.logger)
|
||||
|
||||
d.LogDebug("Serving application at http://localhost:34115")
|
||||
|
||||
defer func() {
|
||||
err := d.server.Shutdown()
|
||||
if err != nil {
|
||||
d.logger.Error(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
if _assetdir != nil {
|
||||
assetdir := _assetdir.(string)
|
||||
bindingsJSON, err := d.appBindings.ToJSON()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
d.assetServer, err = assetserver.NewAssetServer(assetdir, bindingsJSON, d.appoptions)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
absdir, err := filepath.Abs(assetdir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.LogDebug("Serving assets from: %s", absdir)
|
||||
}
|
||||
|
||||
d.server.Get("*", d.loadAsset)
|
||||
|
||||
// Start server
|
||||
go func(server *fiber.App, log *logger.Logger) {
|
||||
err := server.Listen(":34115")
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
d.LogDebug("Shutdown completed")
|
||||
}(d.server, d.logger)
|
||||
|
||||
d.LogDebug("Serving application at http://localhost:34115")
|
||||
|
||||
// Launch desktop app
|
||||
err := d.desktopFrontend.Run(ctx)
|
||||
d.LogDebug("Starting shutdown")
|
||||
err2 := d.server.Shutdown()
|
||||
if err2 != nil {
|
||||
d.logger.Error(err.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -358,6 +365,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
||||
appBindings: appBindings,
|
||||
dispatcher: dispatcher,
|
||||
server: fiber.New(fiber.Config{
|
||||
|
||||
ReadTimeout: time.Second * 5,
|
||||
DisableStartupMessage: true,
|
||||
}),
|
||||
|
||||
@@ -10,25 +10,22 @@ The electron alternative for Go
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
/**
|
||||
* SendMessage sends the given message to the backend
|
||||
* WailsInvoke sends the given message to the backend
|
||||
*
|
||||
* @param {string} message
|
||||
*/
|
||||
|
||||
// const windows = 0;
|
||||
// const macos = 1;
|
||||
// const linux = 2;
|
||||
(function () {
|
||||
// Credit: https://stackoverflow.com/a/2631521
|
||||
let _deeptest = function (s) {
|
||||
var obj = window[s.shift()];
|
||||
while (obj && s.length) obj = obj[s.shift()];
|
||||
return obj;
|
||||
};
|
||||
window.WailsInvoke = _deeptest(["chrome", "webview", "postMessage"]) ||
|
||||
_deeptest(["webkit", "messageHandlers", "external", "postMessage"]);
|
||||
|
||||
window.WailsInvoke = function (message) {
|
||||
|
||||
// Call Platform specific invoke method
|
||||
if (PLATFORM === 0) {
|
||||
window.chrome.webview.postMessage(message);
|
||||
} else if (PLATFORM === 1) {
|
||||
window.webkit.messageHandlers.external.postMessage(message);
|
||||
} else if (PLATFORM === 2) {
|
||||
console.error("Unsupported Platform");
|
||||
} else {
|
||||
if (!window.WailsInvoke) {
|
||||
console.error("Unsupported Platform");
|
||||
}
|
||||
};
|
||||
})();
|
||||
@@ -60,21 +60,24 @@ function handleDisconnect() {
|
||||
connect();
|
||||
}
|
||||
|
||||
// Try to connect to the backend every 1s (default value).
|
||||
function _connect() {
|
||||
if (websocket == null) {
|
||||
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/wails/ipc');
|
||||
websocket.onopen = handleConnect;
|
||||
websocket.onerror = function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
websocket = null;
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Try to connect to the backend every .5s
|
||||
function connect() {
|
||||
connectTimer = setInterval(function () {
|
||||
if (websocket == null) {
|
||||
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/wails/ipc');
|
||||
websocket.onopen = handleConnect;
|
||||
websocket.onerror = function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
websocket = null;
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}, 250);
|
||||
_connect();
|
||||
connectTimer = setInterval(_connect, 500);
|
||||
}
|
||||
|
||||
function handleMessage(message) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//go:build windows
|
||||
//go:build darwin || windows
|
||||
|
||||
package runtime
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed ipc_windows.js
|
||||
//go:embed ipc.js
|
||||
var DesktopIPC []byte
|
||||
1
v2/internal/frontend/runtime/ipc.js
Normal file
1
v2/internal/frontend/runtime/ipc.js
Normal file
@@ -0,0 +1 @@
|
||||
(()=>{(function(){let n=function(o){for(var e=window[o.shift()];e&&o.length;)e=e[o.shift()];return e};window.WailsInvoke=n(["chrome","webview","postMessage"])||n(["webkit","messageHandlers","external","postMessage"]),window.WailsInvoke||console.error("Unsupported Platform")})();})();
|
||||
@@ -1,8 +0,0 @@
|
||||
//go:build darwin
|
||||
|
||||
package runtime
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed ipc_darwin.js
|
||||
var DesktopIPC []byte
|
||||
@@ -1 +0,0 @@
|
||||
(()=>{window.WailsInvoke=function(e){window.webkit.messageHandlers.external.postMessage(e)};})();
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
(()=>{window.WailsInvoke=function(e){window.chrome.webview.postMessage(e)};})();
|
||||
@@ -5,8 +5,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "run-p build:*",
|
||||
"build:ipc-windows": "esbuild desktop/ipc.js --bundle --minify --outfile=ipc_windows.js --define:PLATFORM=0",
|
||||
"build:ipc-darwin": "esbuild desktop/ipc.js --bundle --minify --outfile=ipc_darwin.js --define:PLATFORM=1",
|
||||
"build:ipc-desktop": "esbuild desktop/ipc.js --bundle --minify --outfile=ipc.js",
|
||||
"build:ipc-dev": "cd dev && npm run build",
|
||||
"build:runtime-desktop-prod": "esbuild desktop/main.js --bundle --minify --outfile=runtime_prod_desktop.js --define:ENV=1",
|
||||
"build:runtime-desktop-dev": "esbuild desktop/main.js --bundle --sourcemap=inline --outfile=runtime_dev_desktop.js --define:ENV=0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build dev
|
||||
//go:build dev || bindings || (!dev && !production && !bindings)
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
56
v2/internal/gomod/gomod.go
Normal file
56
v2/internal/gomod/gomod.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package gomod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Masterminds/semver"
|
||||
"golang.org/x/mod/modfile"
|
||||
)
|
||||
|
||||
func GetWailsVersionFromModFile(goModText []byte) (*semver.Version, error) {
|
||||
file, err := modfile.Parse("", goModText, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, req := range file.Require {
|
||||
if req.Syntax == nil {
|
||||
continue
|
||||
}
|
||||
if len(req.Syntax.Token) < 3 {
|
||||
continue
|
||||
}
|
||||
if req.Syntax.Token[1] == "github.com/wailsapp/wails/v2" {
|
||||
version := req.Syntax.Token[2]
|
||||
return semver.NewVersion(version)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func GoModOutOfSync(goModData []byte, currentVersion string) (bool, error) {
|
||||
gomodversion, err := GetWailsVersionFromModFile(goModData)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, err := semver.NewVersion(currentVersion)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Unable to parse Wails version: %s", currentVersion)
|
||||
}
|
||||
|
||||
return !gomodversion.Equal(result), nil
|
||||
}
|
||||
|
||||
func UpdateGoModVersion(goModText []byte, currentVersion string) ([]byte, error) {
|
||||
file, err := modfile.Parse("", goModText, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = file.AddRequire("github.com/wailsapp/wails/v2", currentVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return file.Format()
|
||||
}
|
||||
139
v2/internal/gomod/gomod_test.go
Normal file
139
v2/internal/gomod/gomod_test.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package gomod
|
||||
|
||||
import (
|
||||
"github.com/Masterminds/semver"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const basic string = `module changeme
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.4
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/gofiber/fiber/v2 v2.17.0 // indirect
|
||||
github.com/gofiber/websocket/v2 v2.0.8 // indirect
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/klauspost/compress v1.12.2 // indirect
|
||||
github.com/leaanthony/debme v1.2.1 // indirect
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
|
||||
github.com/leaanthony/gosod v1.0.3 // indirect
|
||||
github.com/leaanthony/slicer v1.5.0 // indirect
|
||||
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
|
||||
github.com/leaanthony/webview2runtime v1.1.0 // indirect
|
||||
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
|
||||
github.com/tkrajina/go-reflector v0.5.5 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.28.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||
)
|
||||
|
||||
//replace github.com/wailsapp/wails/v2 v2.0.0-beta.4 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
||||
`
|
||||
|
||||
func TestGetWailsVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
goModText []byte
|
||||
want *semver.Version
|
||||
wantErr bool
|
||||
}{
|
||||
{"basic", []byte(basic), semver.MustParse("v2.0.0-beta.4"), false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GetWailsVersionFromModFile(tt.goModText)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetWailsVersion() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetWailsVersion() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const basicUpdated string = `module changeme
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.5
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/gofiber/fiber/v2 v2.17.0 // indirect
|
||||
github.com/gofiber/websocket/v2 v2.0.8 // indirect
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/klauspost/compress v1.12.2 // indirect
|
||||
github.com/leaanthony/debme v1.2.1 // indirect
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
|
||||
github.com/leaanthony/gosod v1.0.3 // indirect
|
||||
github.com/leaanthony/slicer v1.5.0 // indirect
|
||||
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
|
||||
github.com/leaanthony/webview2runtime v1.1.0 // indirect
|
||||
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
|
||||
github.com/tkrajina/go-reflector v0.5.5 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.28.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||
)
|
||||
|
||||
//replace github.com/wailsapp/wails/v2 v2.0.0-beta.4 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
||||
`
|
||||
|
||||
func TestUpdateGoModVersion(t *testing.T) {
|
||||
type args struct {
|
||||
goModText []byte
|
||||
currentVersion string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []byte
|
||||
wantErr bool
|
||||
}{
|
||||
{"basic", args{[]byte(basic), "v2.0.0-beta.5"}, []byte(basicUpdated), false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := UpdateGoModVersion(tt.args.goModText, tt.args.currentVersion)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("UpdateGoModVersion() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("UpdateGoModVersion() got = %v, want %v", string(got), string(tt.want))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -69,3 +69,7 @@ func (p *Process) Kill() error {
|
||||
func (p *Process) PID() int {
|
||||
return p.cmd.Process.Pid
|
||||
}
|
||||
|
||||
func (p *Process) SetDir(dir string) {
|
||||
p.cmd.Dir = dir
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ type Project struct {
|
||||
|
||||
BuildCommand string `json:"frontend:build"`
|
||||
InstallCommand string `json:"frontend:install"`
|
||||
DevCommand string `json:"frontend:dev"`
|
||||
|
||||
// Directory to generate the API Module
|
||||
WailsJSDir string `json:"wailsjsdir"`
|
||||
@@ -46,6 +47,12 @@ type Project struct {
|
||||
|
||||
// Fully qualified filename
|
||||
filename string
|
||||
|
||||
// The debounce time for hot-reload of the built-in dev server. Default 100
|
||||
DebounceMS int `json:"debounceMS"`
|
||||
|
||||
// The url to use to server assets. Default "https://localhost:34115"
|
||||
DevServerURL string `json:"devserverurl"`
|
||||
}
|
||||
|
||||
func (p *Project) Save() error {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/leaanthony/gosod"
|
||||
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -377,7 +378,22 @@ func generateRuntimeWrapper(options *Options) error {
|
||||
wrapperDir := filepath.Join(options.WailsJSDir, "wailsjs", "runtime")
|
||||
_ = os.RemoveAll(wrapperDir)
|
||||
extractor := gosod.New(wrapper.RuntimeWrapper)
|
||||
return extractor.Extract(wrapperDir, nil)
|
||||
err := extractor.Extract(wrapperDir, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//ipcdev.js
|
||||
err = os.WriteFile(filepath.Join(wrapperDir, "ipcdev.js"), wailsRuntime.DesktopIPC, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//runtimedev.js
|
||||
err = os.WriteFile(filepath.Join(wrapperDir, "runtimedev.js"), wailsRuntime.RuntimeDesktopJS, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NpmInstall runs "npm install" in the given directory
|
||||
|
||||
34
website/.github/deploy-to-wails.top-mirror.yml
vendored
34
website/.github/deploy-to-wails.top-mirror.yml
vendored
@@ -1,34 +0,0 @@
|
||||
name: Deploy mirror | 部署镜像
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
name: Automatic deployment | 自动部署
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'misitebao/wails-docs'
|
||||
|
||||
steps:
|
||||
- name: Checkout | 切换到部署分支
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: "main"
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build Site | 构建网站
|
||||
run: |
|
||||
npm install && npm run build
|
||||
|
||||
# - name: Deploy to Server | 部署到服务器
|
||||
# uses: hengkx/ssh-deploy@v1.0.1
|
||||
# with:
|
||||
# HOST: ${{ secrets.DEPLOY_HOST }}
|
||||
# USERNAME: ${{ secrets.DEPLOY_HOST_USER }}
|
||||
# PASSWORD: ${{ secrets.DEPLOY_HOST_PASSWORD }}
|
||||
# SOURCE: "build"
|
||||
# TARGET: "/www/wwwroot/beta.wails.top"
|
||||
@@ -153,7 +153,7 @@ community can create!
|
||||
|
||||
Wails v2 represents a new foundation for the project.
|
||||
The aim of this release is to get feedback on the new approach, and to iron out any bugs before a full release.
|
||||
Your input would be most welcome. Please direct any feedback to the [v2 Beta](https://github.com/wailsapp/wails/discussions)
|
||||
Your input would be most welcome. Please direct any feedback to the [v2 Beta](https://github.com/wailsapp/wails/discussions/828)
|
||||
discussion board.
|
||||
|
||||
There were many twists and turns, pivots and u-turns to get to this point. This was due partly to early technical decisions
|
||||
|
||||
@@ -12,7 +12,7 @@ to submit links.
|
||||
- [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/)
|
||||
- [Gophers Slack Channel Invite](https://invite.slack.golangbridge.org/)
|
||||
- [Github Issues](https://github.com/wailsapp/wails/issues)
|
||||
- [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions)
|
||||
- [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions/828)
|
||||
|
||||
## Social Media
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# EncryptEasy
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="encrypteasy.jpg"></img><br/>
|
||||
<img src="/img/showcase/encrypteasy.jpg"></img><br/>
|
||||
</p>
|
||||
|
||||
**[EncryptEasy](https://www.encrypteasy.app) is a simple and easy to use PGP encryption tool, managing all your and your contacts keys. Encryption should be simple. Developed with Wails.**
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# FileHound Export Utility
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="filehound.jpg"></img><br/>
|
||||
<img src="/img/showcase/filehound.jpg"></img><br/>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Molley Wallet
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="mollywallet.png"></img><br/>
|
||||
<img src="/img/showcase/mollywallet.png"></img><br/>
|
||||
</p>
|
||||
|
||||
[Molly Wallet](https://github.com/grvlle/constellation_wallet/) the official $DAG wallet of the Constellation Network. It'll let users interact with the Hypergraph Network in various ways, not limited to producing $DAG transactions.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Optimus
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="optimus.png"></img><br/>
|
||||
<img src="/img/showcase/optimus.png"></img><br/>
|
||||
</p>
|
||||
|
||||
[Optimus](https://github.com/splode/optimus) is a desktop image optimization application. It supports conversion and compression between WebP, JPEG, and PNG image formats.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Portfall
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="portfall.gif"></img><br/>
|
||||
<img src="/img/showcase/portfall.gif"></img><br/>
|
||||
</p>
|
||||
|
||||
[Portfall](https://github.com/rekon-oss/portfall) - A desktop k8s port-forwarding portal for easy access to all your cluster UIs
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Surge
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="surge.png"></img><br/>
|
||||
<img src="/img/showcase/surge.png"></img><br/>
|
||||
</p>
|
||||
|
||||
[Surge](https://surge.rule110.io/) is a p2p filesharing app designed to utilize blockchain technologies to enable 100% anonymous file transfers. Surge is end-to-end encrypted, decentralized and open source.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Wally
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="wally.png"></img><br/>
|
||||
<img src="/img/showcase/wally.png"></img><br/>
|
||||
</p>
|
||||
|
||||
[Wally](https://ergodox-ez.com/pages/wally) is the official firmware flasher for [Ergodox](https://ergodox-ez.com/) keyboards. It looks great and is a fantastic example of what you can achieve with Wails: the ability to combine the power of Go and the rich graphical tools of the web development world.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Wombat
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="wombat.png"></img><br/>
|
||||
<img src="/img/showcase/wombat.png"></img><br/>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
@@ -22,4 +22,6 @@ Example: `wails init -n "Your Project Name" -t https://github.com/misitebao/wail
|
||||
## Vue
|
||||
|
||||
- [wails-template-vue](https://github.com/misitebao/wails-template-vue) - A template using vue and vue-router
|
||||
- [wails-vite-vue-ts](https://github.com/codydbentley/wails-vite-vue-ts) - Vue 3 TypeScript with Vite (and instructions to add features)
|
||||
- [wails-vite-vue-the-works](https://github.com/codydbentley/wails-vite-vue-the-works) - Vue 3 TypeScript with Vite, Vuex, Vue Router, Sass, and ESLint + Prettier
|
||||
|
||||
|
||||
@@ -61,6 +61,15 @@ sidebar_position: 99
|
||||
<a href="https://github.com/marcus-crane" style="width:50px">
|
||||
<img src="https://github.com/marcus-crane.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/codydbentley" style="width:65px">
|
||||
<img src="https://github.com/codydbentley.png?size=65" width="65"/>
|
||||
</a>
|
||||
<a href="https://github.com/bbergshaven" style="width:45px">
|
||||
<img src="https://github.com/bbergshaven.png?size=45" width="45"/>
|
||||
</a>
|
||||
<a href="https://github.com/Gilgames000" style="width:45px">
|
||||
<img src="https://github.com/Gilgames000.png?size=45" width="45"/>
|
||||
</a>
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -6,16 +6,16 @@ sidebar_position: 1
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
- Windows 10
|
||||
- MacOS x64 & arm64 (due October '21)
|
||||
- Linux (due December '21)
|
||||
- Windows 10
|
||||
- MacOS x64 & arm64 (due October '21)
|
||||
- Linux (due December '21)
|
||||
|
||||
## Dependencies
|
||||
|
||||
Wails has a number of common dependencies that are required before installation:
|
||||
|
||||
- Go 1.17+
|
||||
- npm (Node 14+)
|
||||
- Go 1.17+
|
||||
- npm (Node 14+)
|
||||
|
||||
### Go
|
||||
|
||||
@@ -23,8 +23,8 @@ Download Go from the [Go Downloads Page](https://golang.org/dl/).
|
||||
|
||||
Ensure that you follow the official [Go installation instructions](https://golang.org/doc/install#install). You will also need to ensure that your `PATH` environment variable also includes the path to your `~/go/bin` directory. Restart your terminal and do the following checks:
|
||||
|
||||
* Check Go is installed correctly: `go version`
|
||||
* Check "~/go/bin" is in your PATH variable: `echo $PATH | grep go/bin`
|
||||
- Check Go is installed correctly: `go version`
|
||||
- Check "~/go/bin" is in your PATH variable: `echo $PATH | grep go/bin`
|
||||
|
||||
### npm
|
||||
|
||||
@@ -36,35 +36,33 @@ Run `npm --version` to verify.
|
||||
|
||||
You will also need to install platform specific dependencies:
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import Tabs from "@theme/Tabs";
|
||||
import TabItem from "@theme/TabItem";
|
||||
|
||||
<Tabs
|
||||
defaultValue="Windows"
|
||||
values={[
|
||||
{label: 'Windows', value: 'Windows'},
|
||||
{label: 'MacOS', value: 'MacOS'},
|
||||
{label: 'Linux', value: 'Linux'},
|
||||
]}>
|
||||
<TabItem value="MacOS">
|
||||
Coming Soon...
|
||||
</TabItem>
|
||||
{ label: "Windows", value: "Windows" },
|
||||
{ label: "MacOS", value: "MacOS" },
|
||||
{ label: "Linux", value: "Linux" },
|
||||
]}
|
||||
>
|
||||
<TabItem value="MacOS">Coming Soon...</TabItem>
|
||||
<TabItem value="Windows">
|
||||
Wails requires that the <a href='https://developer.microsoft.com/en-us/microsoft-edge/webview2/'>WebView2</a> runtime is installed.
|
||||
Some Windows installations will already have this installed. You can check using the `wails doctor` command (see below).
|
||||
</TabItem>
|
||||
<TabItem value="Linux">
|
||||
Coming Soon...
|
||||
Wails requires that the <a href="https://developer.microsoft.com/en-us/microsoft-edge/webview2/">WebView2</a>{" "}
|
||||
runtime is installed. Some Windows installations will already have this installed. You can check using the{" "}
|
||||
<code>wails doctor</code> command (see below).
|
||||
</TabItem>
|
||||
<TabItem value="Linux">Coming Soon...</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Optional Dependencies
|
||||
|
||||
- [UPX](https://upx.github.io/) for compressing your applications.
|
||||
- [UPX](https://upx.github.io/) for compressing your applications.
|
||||
|
||||
## Installing Wails
|
||||
|
||||
Run `go get github.com/wailsapp/wails/v2/cmd/wails` to install the Wails CLI.
|
||||
Run `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.4` to install the Wails CLI.
|
||||
|
||||
## System Check
|
||||
|
||||
|
||||
@@ -161,11 +161,20 @@ The second, if given, will be executed in the `frontend` directory to build the
|
||||
|
||||
If these 2 keys aren't given, then Wails does absolutely nothing with the frontend. It is only expecting that `embed.FS`.
|
||||
|
||||
## Live Reloading
|
||||
## Built in Dev Server
|
||||
|
||||
Running `wails dev` will start a file watcher in your project directory. By default, if any file changes, wails checks
|
||||
if it was an application file (default: `.go`, configurable with `-e` flag). If it was, then it will rebuild your
|
||||
application and relaunch it. If the changed file was in the `assetdir` directory, it will issue a reload.
|
||||
Running `wails dev` will start the built in dev server which will start a file watcher in your project directory. By
|
||||
default, if any file changes, wails checks if it was an application file (default: `.go`, configurable with `-e` flag).
|
||||
If it was, then it will rebuild your application and relaunch it. If the changed file was in the `assetdir` directory,
|
||||
it will issue a reload after a short amount of time.
|
||||
|
||||
The dev server uses a technique called "debouncing" which means it doesn't reload straight away,
|
||||
as there may be multiple files changed in a short amount of time. When a trigger occurs, it waits for a set amount of time
|
||||
before issuing a reload. If another trigger happens, it resets to the wait time again. By default this value is `100ms`.
|
||||
If this value doesn't work for your project, it can be configured using the `-debounce` flag. If used, this value will
|
||||
be saved to your project config and become the default.
|
||||
|
||||
## External Dev Server
|
||||
|
||||
Some frameworks come with their own live-reloading server, however they will not be able to take advantage of the Wails
|
||||
Go bindings. In this scenario, it is best to run a watcher script that rebuilds the project into the build directory, which
|
||||
|
||||
77
website/docs/guides/frontend.mdx
Normal file
77
website/docs/guides/frontend.mdx
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
# Frontend
|
||||
|
||||
## Script Injection
|
||||
|
||||
When Wails serves your `index.html`, by default, it will inject 2 script entries into the `<body>` tag to load `/wails/bindings.js`
|
||||
and `/wails/runtime.js`. These files install the bindings and runtime respectively.
|
||||
|
||||
The code below shows where these are injected by default:
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<title>injection example</title>
|
||||
<link rel="stylesheet" href="/main.css">
|
||||
<!-- <script src="/wails/ipc.js"></script> -->
|
||||
<!-- <script src="/wails/runtime.js"></script> -->
|
||||
</head>
|
||||
|
||||
<body data-wails-drag>
|
||||
<div class="logo"></div>
|
||||
<div class="result" id="result">Please enter your name below 👇</div>
|
||||
<div class="input-box" id="input" data-wails-no-drag>
|
||||
<input class="input" id="name" type="text" autocomplete="off">
|
||||
<button class="btn" onclick="greet()">Greet</button>
|
||||
</div>
|
||||
|
||||
<script src="/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
### Overriding Default Script Injection
|
||||
|
||||
To provide more flexibility to developers, there is a meta tag that may be used to customise this behaviour:
|
||||
|
||||
```html
|
||||
<meta name="wails-options" content="[options]">
|
||||
```
|
||||
|
||||
The options are as follows:
|
||||
|
||||
| Value | Description |
|
||||
| -------------------- | ------------------------------------------------- |
|
||||
| noautoinjectruntime | Disable the autoinjection of `/wails/runtime.js` |
|
||||
| noautoinjectipc | Disable the autoinjection of `/wails/ipc.js` |
|
||||
| noautoinject | Disable all autoinjection of scripts |
|
||||
|
||||
Multiple options may be used provided they are comma seperated.
|
||||
|
||||
This code is perfectly valid and operates the same as the autoinjection version:
|
||||
|
||||
```html
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>injection example</title>
|
||||
<meta name="wails-options" content="noautoinject">
|
||||
<link rel="stylesheet" href="/main.css">
|
||||
</head>
|
||||
|
||||
<body data-wails-drag>
|
||||
<div class="logo"></div>
|
||||
<div class="result" id="result">Please enter your name below 👇</div>
|
||||
<div class="input-box" id="input" data-wails-no-drag>
|
||||
<input class="input" id="name" type="text" autocomplete="off">
|
||||
<button class="btn" onclick="greet()">Greet</button>
|
||||
</div>
|
||||
|
||||
<script src="/wails/ipc.js"></script>
|
||||
<script src="/wails/runtime.js"></script>
|
||||
<script src="/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
@@ -12,7 +12,7 @@ Currently, we support [Visual Studio Code](https://code.visualstudio.com/) but a
|
||||
<img src="/img/vscode.png" style={{"width": "75%"}}></img>
|
||||
</p>
|
||||
|
||||
When generating a project using the `-vscode` flag, IDE files will be created alongside the other project files.
|
||||
When generating a project using the `-ide vscode` flags, IDE files will be created alongside the other project files.
|
||||
These files are placed into the `.vscode` directory and provide the correct configuration for debugging your application.
|
||||
|
||||
The 2 files generated are `tasks.json` and `launch.json`. Below are the files generated for the default vanilla project:
|
||||
|
||||
@@ -11,12 +11,13 @@ version of the runtime library. Finally, it is possible to bind Go methods to th
|
||||
Javascript methods that can be called, just as if they were local Javascript methods.
|
||||
|
||||
<div className="text--center">
|
||||
<img src="/img/architecture.svg" width='75%'/>
|
||||
<img src="/img/architecture.svg" width="75%" />
|
||||
</div>
|
||||
|
||||
## The Main Application
|
||||
|
||||
### Overview
|
||||
|
||||
The main application consists of a single call to `wails.Run()`. It accepts the
|
||||
application configuration which describes the size of the application window, the window title,
|
||||
what assets to use, etc. A basic application might look like this:
|
||||
@@ -75,12 +76,12 @@ func (b *App) Greet(name string) string {
|
||||
|
||||
This example has the following options set:
|
||||
|
||||
- `Title` - The text that should appear in the window's title bar
|
||||
- `Width` & `Height` - The dimensions of the window
|
||||
- `Assets` - The application's frontend assets
|
||||
- `OnStartup` - A callback for when the window is created and is about to start loading the frontend assets
|
||||
- `OnShutdown` - A callback for when the application is about to quit
|
||||
- `Bind` - A slice of struct instances that we wish to expose to the frontend
|
||||
- `Title` - The text that should appear in the window's title bar
|
||||
- `Width` & `Height` - The dimensions of the window
|
||||
- `Assets` - The application's frontend assets
|
||||
- `OnStartup` - A callback for when the window is created and is about to start loading the frontend assets
|
||||
- `OnShutdown` - A callback for when the application is about to quit
|
||||
- `Bind` - A slice of struct instances that we wish to expose to the frontend
|
||||
|
||||
A full list of application options can be found in the [Options Reference](/docs/reference/options).
|
||||
|
||||
@@ -94,7 +95,7 @@ there is no requirement on where in the `embed.FS` the files live. It is likely
|
||||
directory relative to your main application code, such as `frontend/dist`:
|
||||
|
||||
```go title="main.go"
|
||||
// go:embed frontend/dist
|
||||
//go:embed frontend/dist
|
||||
var assets embed.FS
|
||||
```
|
||||
|
||||
@@ -117,7 +118,7 @@ Just before the frontend is about to load `index.html`, a callback is made to th
|
||||
A standard Go context is passed to this method. This context is required when calling the runtime so a standard pattern is to save
|
||||
a reference to in this method. Just before the application shuts down, the [OnShutdown](/docs/reference/options#OnShutdown) callback is called in the same way,
|
||||
again with the context. There is also an [OnDomReady](/docs/reference/options#OnDomReady) callback for when the frontend
|
||||
has completed loading all assets in `index.html` and is equivalent of the [`body onload`](https://www.w3schools.com/jsref/event_onload.asp) event in Javascript.
|
||||
has completed loading all assets in `index.html` and is equivalent of the [`body onload`](https://www.w3schools.com/jsref/event_onload.asp) event in Javascript.
|
||||
|
||||
#### Method Binding
|
||||
|
||||
@@ -133,7 +134,7 @@ These methods return a promise. A successful call will result in the first retur
|
||||
to the resolve handler. An unsuccessful call is when a Go method that has an error type as it's second return value,
|
||||
passes an error instance back to the caller. This is passed back via the reject handler.
|
||||
In the example above, `Greet` only returns a `string` so the Javascript call will never reject - unless invalid data
|
||||
is passed to it.
|
||||
is passed to it.
|
||||
|
||||
All data types are correctly translated between Go and Javascript. Even structs. If you return a struct from a Go call,
|
||||
it will be returned to your frontend as a Javascript map. Note: If you wish to use structs, you **must** define `json` struct
|
||||
@@ -148,14 +149,17 @@ section of the [Application Development Guide](/docs/guides/application-developm
|
||||
## The Frontend
|
||||
|
||||
### Overview
|
||||
|
||||
The frontend is a collection of files rendered by webkit. It's like a browser and webserver in one.
|
||||
There is virtually[^1] no limit to which frameworks or libraries you can use. The main points of interaction between
|
||||
the frontend and your Go code are:
|
||||
- Calling bound Go methods
|
||||
- Calling runtime methods
|
||||
|
||||
[^1]: There is a very small subset of libraries that use features unsupported in WebViews. There are often alternatives and
|
||||
workarounds for such cases.
|
||||
- Calling bound Go methods
|
||||
- Calling runtime methods
|
||||
|
||||
[^1]:
|
||||
There is a very small subset of libraries that use features unsupported in WebViews. There are often alternatives and
|
||||
workarounds for such cases.
|
||||
|
||||
### Calling bound Go methods
|
||||
|
||||
@@ -163,11 +167,11 @@ All bound Go methods are available at `window.go.<package>.<struct>.<method>`. A
|
||||
the previous section, these return a Promise where a successful call returns a value to the
|
||||
resolve handler and an error returns a value to the reject handler.
|
||||
|
||||
```go title="mycode.js"
|
||||
window.go.main.App.Greet("Bill").then((result) => {
|
||||
console.log("The greeting is: " + result);
|
||||
})
|
||||
```
|
||||
```go title="mycode.js"
|
||||
window.go.main.App.Greet("Bill").then((result) => {
|
||||
console.log("The greeting is: " + result);
|
||||
})
|
||||
```
|
||||
|
||||
When running the application in `dev` mode, a javascript module is generated that wraps these
|
||||
methods with JSDoc annotations. This really help with development, especially as most
|
||||
@@ -178,19 +182,18 @@ following code:
|
||||
|
||||
```js title="bindings.js"
|
||||
const go = {
|
||||
"main": {
|
||||
"App": {
|
||||
main: {
|
||||
App: {
|
||||
/**
|
||||
* Greet
|
||||
* @param {Person} arg1 - Go Type: string
|
||||
* @returns {Promise<string>} - Go Type: string
|
||||
*/
|
||||
"Greet": (arg1) => {
|
||||
Greet: (arg1) => {
|
||||
return window.go.main.App.Greet(arg1);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
};
|
||||
export default go;
|
||||
```
|
||||
@@ -221,93 +224,97 @@ func (a *App) Greet(p Person) string {
|
||||
return fmt.Sprintf("Hello %s (Age: %d)!", p.Name, p.Age)
|
||||
}
|
||||
```
|
||||
|
||||
Our `bindings.js` file has now been updated to reflect the change:
|
||||
|
||||
```js title="bindings.js"
|
||||
const go = {
|
||||
"main": {
|
||||
"App": {
|
||||
main: {
|
||||
App: {
|
||||
/**
|
||||
* Greet
|
||||
* @param {Person} arg1 - Go Type: main.Person
|
||||
* @returns {Promise<string>} - Go Type: string
|
||||
*/
|
||||
"Greet": (arg1) => {
|
||||
Greet: (arg1) => {
|
||||
return window.go.main.App.Greet(arg1);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
};
|
||||
export default go;
|
||||
```
|
||||
|
||||
Alongside `bindings.js`, there is a file called `models.ts`. This contains our Go structs in TypeScript form:
|
||||
|
||||
```ts title="models.ts"
|
||||
export class Address {
|
||||
street: string;
|
||||
postcode: string;
|
||||
street: string;
|
||||
postcode: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Address(source);
|
||||
}
|
||||
static createFrom(source: any = {}) {
|
||||
return new Address(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.street = source["street"];
|
||||
this.postcode = source["postcode"];
|
||||
}
|
||||
constructor(source: any = {}) {
|
||||
if ("string" === typeof source) source = JSON.parse(source);
|
||||
this.street = source["street"];
|
||||
this.postcode = source["postcode"];
|
||||
}
|
||||
}
|
||||
export class Person {
|
||||
name: string;
|
||||
age: number;
|
||||
address?: Address;
|
||||
name: string;
|
||||
age: number;
|
||||
address?: Address;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Person(source);
|
||||
static createFrom(source: any = {}) {
|
||||
return new Person(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ("string" === typeof source) source = JSON.parse(source);
|
||||
this.name = source["name"];
|
||||
this.age = source["age"];
|
||||
this.address = this.convertValues(source["address"], Address);
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.name = source["name"];
|
||||
this.age = source["age"];
|
||||
this.address = this.convertValues(source["address"], Address);
|
||||
if (a.slice) {
|
||||
return (a as any[]).map((elem) => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
So long as you have TypeScript as part of your frontend build configuration, you can use these models in
|
||||
the following way:
|
||||
|
||||
```js title="mycode.js"
|
||||
import go from "./wailsjs/go/bindings";
|
||||
import {Person} from "./wailsjs/go/models";
|
||||
import go from "./wailsjs/go/bindings";
|
||||
import { Person } from "./wailsjs/go/models";
|
||||
|
||||
let name = "";
|
||||
let name = "";
|
||||
|
||||
function greet(name) {
|
||||
let p = new Person();
|
||||
p.name = name;
|
||||
p.age = 42;
|
||||
go.main.App.Greet(p).then((result) => {
|
||||
console.log(result);
|
||||
});
|
||||
}
|
||||
function greet(name) {
|
||||
let p = new Person();
|
||||
p.name = name;
|
||||
p.age = 42;
|
||||
go.main.App.Greet(p).then((result) => {
|
||||
console.log(result);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The combination of JSDoc and TypeScript generated models makes for a powerful development environment.
|
||||
|
||||
@@ -20,11 +20,11 @@ The Wails CLI has a number of commands that are used for managing your projects.
|
||||
| -l | List available project templates | |
|
||||
| -q | Suppress output to console | |
|
||||
| -t "template name" | The project template to use. This can be the name of a default template or a URL to a remote template hosted on github. | vanilla |
|
||||
| -vscode | Generate VSCode project files | |
|
||||
| -ide | Generate IDE project files | |
|
||||
| -f | Force build application | false |
|
||||
|
||||
Example:
|
||||
`wails init -n test -d mytestproject -g -vscode -q`
|
||||
`wails init -n test -d mytestproject -g -ide vscode -q`
|
||||
|
||||
This will generate a a project called "test" in the "mytestproject" directory, initialise git,
|
||||
generate vscode project files and do so silently.
|
||||
@@ -131,7 +131,8 @@ Your system is ready for Wails development!
|
||||
| -loglevel "loglevel"| Loglevel to use - Trace, Debug, Info, Warning, Error | Debug |
|
||||
| -noreload | Disable automatic reload when assets change | |
|
||||
| -v | Verbosity level (0 - silent, 1 - standard, 2 - verbose) | 1 |
|
||||
| -wailsjsdir | The directory to generate the generated Wails JS modules | Value store in `wails.json` |
|
||||
| -wailsjsdir | The directory to generate the generated Wails JS modules | Value in `wails.json` |
|
||||
| -debounce | The time to wait for reload after an asset change is detected | 100 (milliseconds) |
|
||||
|
||||
If the `-assetdir` or `-wailsjsdir` flags are provided on the command line, they are saved in `wails.json`, and become
|
||||
the defaults for subsequent invocations.
|
||||
|
||||
@@ -14,7 +14,8 @@ The project config resides in the `wails.json` file in the project directory. Th
|
||||
"frontend:build": "[The command to build the assets, run in the frontend directory - often `npm run build`]",
|
||||
"wailsjsdir": "[Relative path to the directory that the auto-generated JS modules will be created]",
|
||||
"version": "[Project config version]",
|
||||
"outputfilename": "[The name of the binary]"
|
||||
"outputfilename": "[The name of the binary]",
|
||||
"debounceMS": 100, // The default time the dev server waits to reload when it detects a vhange in assets
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ If you have any concerns or suggestions, please raise them in the projects githu
|
||||
|
||||
export const NewComponent = () => (
|
||||
<div>
|
||||
<iframe plausible-embed="true" src="https://plausible.io/share/beta.wails.io?auth=wJa_HtqinG_eosqMjP-T1&embed=true&theme=system" scrolling="no" frameBorder={0} loading="lazy" style={{width: '1px', minWidth: '100%', height: '1600px'}} />
|
||||
<iframe plausible-embed="true" src="https://plausible.io/share/wails.io?auth=Ll6cPlScOwOi_wgwZwMBn&embed=true&theme=system" scrolling="no" frameBorder={0} loading="lazy" style={{width: '1px', minWidth: '100%', height: '1600px'}} />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -9,42 +9,151 @@ authors:
|
||||
tags: [wails, v2]
|
||||
---
|
||||
|
||||
两年多前,在悉尼的火车上,当我第一次在 Reddit 宣布 Wails 时,我没想到它会引起太多关注。几天后,一位多产的科技视频博主发布了一个教程视频,并给予了正面评价,从那时起,人们对这个项目的兴趣直线上升。
|
||||
<div class="text--center">
|
||||
<img
|
||||
src="/img/wails.png"
|
||||
width="40%"
|
||||
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
人们对在他们的 Go 项目中添加 web 前端感到兴奋,几乎立即在这个项目推送并超出了我创建这个项目的设想。当时,Wails 使用 [webview](https://github.com/webview/webview) 项目来处理前端,
|
||||
两年多前,在悉尼的火车上,当我第一次在 Reddit 宣布 Wails 时,我没想到它会引起太多关注。几天后,一位多产的科技视频博主发布了一个教程视频,并给予了正面评价,从那时起,人们对该项目的兴趣猛增。
|
||||
|
||||
很明显,人们对将 Web 前端添加到他们的 Go 项目感到兴奋,几乎立即将项目推动到超出我创建这个项目的设想。当时,Wails 使用 [webview](https://github.com/webview/webview) 项目来处理前端,
|
||||
Windows 的唯一选择是 IE11 渲染器。许多错误报告都因为受到它的限制:糟糕的 JavaScript/CSS 支持并且没有开发工具来调试它。这是一段令人沮丧的开发经历,但我们也没有采取什么措施去纠正它。
|
||||
|
||||
很长一段时间以来,我一直坚信微软最终会解决他们的浏览器问题。世界在不断进步,前端开发正在蓬勃发展,而 IE 并没有做到这一点。当微软宣布将 Chromium 作为其新浏览器方向的基础时,
|
||||
我知道 Wails 能够使用它并将 Windows 开发者的体验提升到下一个水平只是时间问题。
|
||||
|
||||
今天,我很高兴地宣布:**适用于 Windows 的 Wails v2 公测啦**!
|
||||
今天,我很高兴地宣布:**适用于 Windows 的 Wails v2 公测啦**!此版本中有大量内容需要展开来说,所以,请倒一杯茶,咱们坐下来慢慢讲......
|
||||
|
||||
- 没有 CGO 依赖!不,我不是在开玩笑:_没有依赖 CGO_ 🤯!
|
||||
- WebView2 (chromium) 渲染引擎! 终于!
|
||||
- 不需要在应用程序中附带任何 dll,包括`WebView2Loader.dll`。单个二进制文件的构想继续存在。
|
||||
- 不需要打包资源(只需要提供一个 embed.FS,就像一个 web 服务器)
|
||||
- 应用程序菜单支持
|
||||
- 具有热重载和自动重新构建功能的新开发方式
|
||||
- 用于控制应用程序窗口的运行时方法
|
||||
- 现代化的原生对话框
|
||||
### 没有 CGO 依赖
|
||||
|
||||
Wails v2 代表了该项目的新基础。此版本的目的是获得有关新方式的反馈,并在完整版本发布之前解决所有错误。欢迎提出您的意见。请直接反馈到 [v2 测试版](https://github.com/wailsapp/wails/discussions)讨论板。
|
||||
不,我不是在开玩笑:*没有 CGO 依赖*🤯!Windows 的问题在于,与 MacOS 和 Linux 不同,它没有默认编译器。
|
||||
此外,CGO 需要一个 mingw 编译器,并且有大量不同的安装选项。删除 CGO 的要求大大简化了设置,并使调试变得非常容易。
|
||||
虽然我已经付出了相当多的努力来完成这项工作,但大部分功劳应该归功于[John Chadwick](https://github.com/jchv),他不仅启动了几个项目使这成为可能,
|
||||
而且还对接受这些项目并以此为基础的人持开放态度. 还要归功于[Tad Vizbaras](https://github.com/tadvi),他的[winc](https://github.com/tadvi/winc)项目让我走上了这条道路。
|
||||
|
||||
为了达到这一点,经历了许多曲折和坎坷。部分原因是早期的技术决策需要改变,另一部分原因是我们花时间构建的一些核心问题的变通方式已经在上游得到了解决:Go 的 embed 特性就是一个很好的例子。幸运的是,一切都刚刚好,今天我们有了我们所能拥有的最好的解决方案。我相信等待是值得的 - 这在两个月前是完全不可能的。
|
||||
### WebView2 Chromium 渲染引擎
|
||||
|
||||
<div class="text--center">
|
||||
<img
|
||||
src="/img/devtools.png"
|
||||
width="75%"
|
||||
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
最终,Windows 开发人员为他们的应用程序获得了一流的渲染引擎!扭曲前端代码以在 Windows 上工作的日子已经一去不复返了。最重要的是,您将获得一流的开发者工具体验!
|
||||
|
||||
但是,WebView2 组件确实需要将其放置`WebView2Loader.dll`在二进制文件旁边。这使得分发比我们 gophers 习惯的更痛苦。所有使用 WebView2 的解决方案和库(我知道的)都具有这种依赖性。
|
||||
|
||||
然而,我真的很高兴地宣布,Wails 应用程序*没有这样的要求*!感谢[John Chadwick](https://github.com/jchv)的魔法,我们能够将这个 dll 打包在二进制文件中,并让 Windows 加载它,就像它存在于磁盘上一样。
|
||||
|
||||
Gophers 欢呼吧!单个二进制文件的设想依然存在!
|
||||
|
||||
### 新功能
|
||||
|
||||
<div class="text--center">
|
||||
<img
|
||||
src="/img/wails-menus.png"
|
||||
width="60%"
|
||||
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
有很多对原生菜单支持的请求。Wails 终于让您满意了。应用程序菜单现已可用,并且包括对大多数原生菜单功能的支持。这包括标准菜单项、复选框、单选组、子菜单和分隔符。
|
||||
|
||||
在 v1 中有大量的请求,要求能够更好地控制窗口本身。我很高兴地宣布,有专门用于此的新运行时 API。它功能丰富,支持多显示器配置。
|
||||
还有一个改进的对话框 API:现在,您可以拥有具有丰富配置的现代原生对话框,以满足您的所有对话框需求。
|
||||
|
||||
现在可以选择随项目生成 IDE 配置。这意味着如果您在受支持的 IDE 中打开您的项目,它已经被配置为构建和调试您的应用程序。目前支持 VSCode,但我们希望尽快支持其他 IDE,例如 Goland。
|
||||
|
||||
<div class="text--center">
|
||||
<img
|
||||
src="/img/vscode.png"
|
||||
width="100%"
|
||||
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
### 无需打包资源
|
||||
|
||||
v1 的一个巨大痛点是需要将整个应用程序压缩为单个 JS 和 CSS 文件。我很高兴地宣布,对于 v2,不需要以任何形式打包资源。
|
||||
想要加载本地图片?使用带有本地`src`路径的`<img>`标签。想使用很酷的字体吗?复制它并在你的 CSS 中添加它的路径。
|
||||
|
||||
> 哇,这听起来像一个网络服务器......
|
||||
|
||||
是的,它就像一个网络服务器一样工作,但它不是。
|
||||
|
||||
> 那么我如何包含我的资源?
|
||||
|
||||
您只需将`embed.FS`包含所有资产的单个文件传递到您的应用程序配置中。他们甚至不需要在顶级目录中——Wails 会为你解决这个问题。
|
||||
|
||||
### 全新的开发体验
|
||||
|
||||
<div class="text--center">
|
||||
<img
|
||||
src="/img/browser.png"
|
||||
width="60%"
|
||||
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
现在不需要打包资源,它启用了全新的开发体验。新`wails dev`命令将构建并运行您的应用程序,但它不使用`embed.FS`中的资源,而是直接从磁盘加载它们。
|
||||
|
||||
它还提供了附加功能:
|
||||
|
||||
- 热重载 - 对前端资产的任何更改都将触发并自动重载应用程序前端
|
||||
- 自动重新构建 - 对 Go 代码的任何更改都将重新构建并重新启动您的应用程序
|
||||
|
||||
除此之外,网络服务器将在端口 34115 上启动。这将为您的应用程序提供连接到它的任何浏览器。所有连接的 Web 浏览器都会响应系统事件,例如资产更改时的热重载。
|
||||
|
||||
在 Go 中,我们习惯于在应用程序中处理结构。将结构发送到我们的前端并将它们用作我们应用程序中的状态通常很有用。在 v1 中,这是一个非常手动的过程,对开发人员来说有点负担。
|
||||
我很高兴地宣布,在 v2 中,任何在开发模式下运行的应用程序都将自动为所有结构生成 Typescript 模型,这些结构是绑定方法的输入或输出参数。这实现了两个世界之间数据模型的无缝交换。
|
||||
除此之外,还会动态生成另一个 JS 模块来包装您的所有绑定方法。这为您的方法提供了 JSDoc,在您的 IDE 中提供代码完成和提示。当您在自动生成的包含 Go 代码的模块中点击 Tab 时自动导入数据模型,这真的很酷!
|
||||
|
||||
### 远程模板
|
||||
|
||||
<div class="text--center">
|
||||
<img
|
||||
src="/img/remote.png"
|
||||
width="60%"
|
||||
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
让应用程序快速启动并运行一直是 Wails 项目的一个关键目标。当我们推出时,我们试图涵盖当时的很多现代框架:react、vue 和 angular。前端开发的世界非常自以为是,快速发展且难以掌握!
|
||||
结果,我们发现我们的基本模板很快就过时了,这导致了维护问题。这也意味着我们没有用于最新和最伟大技术堆栈的酷炫现代模板。
|
||||
|
||||
在 v2 中,我希望通过让您能够自己创建和托管模板来增强社区的能力,而不是依赖于 Wails 项目。所以现在您可以使用社区支持的模板创建项目!
|
||||
我希望这将激励开发人员创建一个充满活力的项目模板生态系统。我对我们的开发者社区可以创造的东西感到非常兴奋!
|
||||
|
||||
### 结语
|
||||
|
||||
Wails v2 代表了该项目的新基础。此版本的目的是获得有关新方式的反馈,并在完整版本发布之前解决所有错误。欢迎提出您的意见。请直接反馈到 [v2 测试版](https://github.com/wailsapp/wails/discussions/828)讨论板。
|
||||
|
||||
为了达到这一点,经历了许多曲折和坎坷。部分原因是早期的技术决策需要改变,另一部分原因是我们花时间构建的一些核心问题的变通方式已经在上游得到了解决:Go 的 embed 特性就是一个很好的例子。幸运的是,一切都刚刚好,今天我们有了我们所能拥有的最好的解决方案。我相信等待是值得的 - 这在两个月前是完全不可能的。
|
||||
|
||||
我还需要特别感谢 :pray: 以下人员,因为没有他们,这个版本就不会存在:
|
||||
|
||||
- [Misitebao](https://github.com/misitebao) - 中文翻译的绝对主力和和令人难以置信的漏洞发现者。
|
||||
- [Misitebao](https://github.com/misitebao) - 中文翻译的主要人员和和令人难以置信的漏洞发现者。
|
||||
- [John Chadwick](https://github.com/jchv) - 他在 [go-webview2](https://github.com/jchv/go-webview2) 和 [go-winloader](https://github.com/jchv/go-winloader) 方面的出色工作使 Windows 版本成为可能。
|
||||
- [Tad Vizbaras](https://github.com/tadvi) - 他的 winc 项目是走向纯粹的 Go Wails 的第一步。
|
||||
- [Tad Vizbaras](https://github.com/tadvi) - 他的[winc](https://github.com/tadvi/winc)项目是走向纯粹的 Go Wails 的第一步。
|
||||
- [Mat Ryer](https://github.com/matryer) - 他的支持、鼓励和反馈确实推动了项目向前发展。
|
||||
|
||||
最后,我还要特别感谢包括[JetBrains](https://www.jetbrains.com?from=Wails)在内的所有项目[赞助商](/docs/credits#sponsors),他们的幕后支持以多种方式推动了该项目。
|
||||
|
||||
我期待看到在项目的下一个激动人心的阶段人们用 Wails 构建什么!
|
||||
|
||||
对了,最后一件事:如果您或您的公司发现 Wails 有用,可以考虑[赞助该项目](https://github.com/sponsors/leaanthony)。谢谢!
|
||||
|
||||
Lea.
|
||||
|
||||
PS:MacOS 和 Linux 用户不必感到被冷落了——移植到这个新基础上的工作正在积极进行中,大部分复杂的工作已经完成。坚持下去。。。
|
||||
PS:MacOS 和 Linux 用户不必感到被忽略了——移植到这个新基础上的工作正在积极进行中,大部分复杂的工作已经完成。坚持下去...
|
||||
|
||||
PPS:如果您或您的公司发现 Wails 有用,可以考虑[赞助该项目](https://github.com/sponsors/leaanthony)。谢谢!
|
||||
|
||||
@@ -26,5 +26,9 @@
|
||||
"sidebar.tutorialSidebar.category.Community": {
|
||||
"message": "社区交流",
|
||||
"description": "The label for category Community in sidebar tutorialSidebar"
|
||||
},
|
||||
"sidebar.tutorialSidebar.category.Showcase": {
|
||||
"message": "项目展示",
|
||||
"description": "The label for category Showcase in sidebar tutorialSidebar"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
---
|
||||
title: 关于 sidebar_position: 1
|
||||
title: 关于
|
||||
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# 关于
|
||||
|
||||
## 概述
|
||||
|
||||
Wails 是一个可让你使用 Go 和 Web 技术编写桌面应用的项目。
|
||||
Wails 是一个可让您使用 Go 和 Web 技术编写桌面应用的项目。
|
||||
|
||||
将它看作为轻量快速的 “Electron for Go”。 你可以结合了丰富、现代的前端技术轻松地构建具有灵活性和强大功能的 Go 应用程序。
|
||||
将它看作为轻量快速的 “Electron for Go”。 您可以使用 Go 的灵活性和强大功能,结合丰富的现代前端,轻松的构建应用程序。
|
||||
|
||||
Wails 一点也不弱!这是 [xbar](https://xbarapp.com) - 一个使用 Wails 编写的 MacOS 桌面应用。它使用 Mac 的系统原生菜单,支持浅色和深色桌面主题,主窗口使用半透明,使其具有原生应用的
|
||||
“冰霜” 效果。
|
||||
@@ -19,12 +21,13 @@ Wails 一点也不弱!这是 [xbar](https://xbarapp.com) - 一个使用 Wails
|
||||
|
||||
## 原生元素
|
||||
|
||||
Wails 使用专门的库来处理原生元素,例如窗口、菜单、对话框等,因此你可以构建美观、功能丰富的桌面应用程序。 它不嵌入浏览器,因此性能高。相反,它使用平台的原生渲染引擎。在 Windows 上,是基于 Chromium 构建的新
|
||||
Microsoft Webview2 库。
|
||||
Wails 使用专门的库来处理原生元素,例如窗口、菜单、对话框等,因此您可以构建美观、功能丰富的桌面应用程序。
|
||||
|
||||
**它不嵌入浏览器**,因此性能高。相反,它使用平台的原生渲染引擎。在 Windows 上,是基于 Chromium 构建的新 Microsoft Webview2 库。
|
||||
|
||||
## Go 和 Javascript 互操作
|
||||
|
||||
Wails 自动使你的 Go 方法可用于 Javascript,因此你可以从前端按名称调用它们!它甚至会生成 Go 方法使用的结构的 Typescript 版本,因此你可以在 Go 和 Javascript 之间传递相同的数据结构。
|
||||
Wails 自动使您的 Go 方法可用于 Javascript,因此您可以从前端按名称调用它们!它甚至会生成 Go 方法使用的结构体的 Typescript 版本,因此您可以在 Go 和 Javascript 之间传递相同的数据结构。
|
||||
|
||||
## 运行时库
|
||||
|
||||
@@ -34,21 +37,21 @@ Wails 为 Go 和 Javascript 提供了一个运行时库,可以处理现代应
|
||||
|
||||
### 自动重新构建
|
||||
|
||||
当你在“dev”模式下运行你的应用程序时,Wails 会将你的应用程序构建为原生桌面应用程序,但会从磁盘读取你的资源。它将检测你的 Go 代码的任何更改,并自动重新构建和重新启动你的应用程序。
|
||||
当您在“dev”模式下运行您的应用程序时,Wails 会将您的应用程序构建为原生桌面应用程序,但会从磁盘读取您的资源。它将检测您的 Go 代码的任何更改,并自动重新构建和重新启动您的应用程序。
|
||||
|
||||
### 自动重新加载
|
||||
|
||||
当检测到你的应用程序资源发生更改时,你正在运行的应用程序将“重新加载”,几乎立即反馈你的更改。
|
||||
当检测到您的应用程序资源发生更改时,您正在运行的应用程序将“重新加载”,几乎立即反馈您的更改。
|
||||
|
||||
### 在浏览器中开发你的应用程序
|
||||
### 在浏览器中开发您的应用程序
|
||||
|
||||
如果你更喜欢在浏览器中调试和开发,那么我们可以满足你的需求。正在运行的应用程序还有一个网络服务器,它将在连接到它的任何浏览器中运行你的应用程序。当你的资源在磁盘上发生变化时,它会刷新。
|
||||
如果您更喜欢在浏览器中调试和开发,那么 Wails 可以满足您的需求。正在运行的应用程序还有一个网络服务器,它将在连接到它的任何浏览器中运行您的应用程序。当您的资源在磁盘上发生变化时,它会刷新。
|
||||
|
||||
## 生成原生二进制文件
|
||||
|
||||
当你准备好完成应用程序的最终构建时,CLI 会将其编译为单个可执行文件,并将所有资源打包到其中。在 Windows 和 MacOS
|
||||
上,可以创建用于分发的原生包。使用打包器后生成的资源(图标、info.plist、清单文件等)是你项目的一部分,可以自定义,让你完全控制应用程序的构建方式。
|
||||
当您准备好完成应用程序的最终构建时,CLI 会将其编译为单个可执行文件,并将所有资源打包到其中。在 Windows 和 MacOS
|
||||
上,可以创建用于分发的原生包。使用打包工具后生成的资源(图标、info.plist、清单文件等)是您项目的一部分,可以自定义,让您完全控制应用程序的构建方式。
|
||||
|
||||
## 工具
|
||||
|
||||
Wails CLI 提供了一种简单的方法来生成、构建和打包你的应用程序。可以从许多入门模板中进行选择,以快速启动和运行!
|
||||
Wails CLI 提供了一种简单的方法来生成、构建和打包您的应用程序。它将完成创建图标的繁重工作,使用最佳设置编译您的应用程序,并提供可分发的、可用于生产的二进制文件。可以从许多入门模板中进行选择,以快速启动和运行!
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
sidebar_position: 50
|
||||
---
|
||||
|
||||
# 社区模板
|
||||
|
||||
此页面用作社区支持的模板列表。请提交一个包含您的模板的 PR(点击页面底部的`编辑此页`)。要构建您自己的模板,请参考[模板](/docs/guides/templates)指南。
|
||||
|
||||
要使用这些模板,请运行 `wails init -n "你的项目名" -t [下面的链接]`
|
||||
|
||||
示例:`wails init -n "Your Project Name" -t https://github.com/misitebao/wails-template-vue`
|
||||
|
||||
:::warning 注意
|
||||
|
||||
仅安装你信任的远程模板。 如果你不确定某个模板,请检查 `package.json` 中运行的脚本和安装的模块。 **Wails 项目对第 3 方模板不承担任何责任!**
|
||||
|
||||
:::
|
||||
|
||||
## Vue
|
||||
|
||||
- [wails-template-vue](https://github.com/misitebao/wails-template-vue) - 基于 Vue 和 Vue-Router 的 Wails 模板
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Community",
|
||||
"position": 5
|
||||
"position": 50
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ sidebar_position: 2
|
||||
- [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/)
|
||||
- [Gophers Slack Channel Invite](https://invite.slack.golangbridge.org/)
|
||||
- [Github Issues](https://github.com/wailsapp/wails/issues)
|
||||
- [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions)
|
||||
- [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions/828)
|
||||
|
||||
## 社交媒体
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
# EncryptEasy
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="/img/showcase/encrypteasy.jpg"></img><br/>
|
||||
</p>
|
||||
|
||||
**[EncryptEasy](https://www.encrypteasy.app) is a simple and easy to use PGP encryption tool, managing all your and your contacts keys. Encryption should be simple. Developed with Wails.**
|
||||
|
||||
Encrypting messages using PGP is the industry standard. Everyone has a private and a public key. Your private key, well, needs to be kept private so only you can read messages. Your public key is distributed to anyone who wants to send you secret, encrypted messages. Managing keys, encrypting messages and decrypting messages should be a smooth experience. EncryptEasy is all about making it easy.
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
# FileHound Export Utility
|
||||
|
||||
<p style={{"text-align": "center"}}>
|
||||
<img src="/img/showcase/filehound.jpg"></img><br/>
|
||||
</p>
|
||||
|
||||
|
||||
[FileHound Export Utility](https://www.filehound.co.uk/) FileHound is a cloud document management platform made for secure file retention, business process automation and SmartCapture capabilities.
|
||||
|
||||
The FileHound Export Utility allows FileHound Administrators the ability to run a secure document and data extraction tasks for alternative back-up and recovery purposes. This application will download all documents and/or meta data saved in FileHound based on the filters you choose. The metadata will be exported in both JSON and XML formats.
|
||||
|
||||
Backend built with:
|
||||
Go 1.15
|
||||
Wails 1.11.0
|
||||
go-sqlite3 1.14.6
|
||||
go-linq 3.2
|
||||
|
||||
Frontend with:
|
||||
Vue 2.6.11
|
||||
Vuex 3.4.0
|
||||
Typescript
|
||||
Tailwind 1.9.6
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user