Compare commits

...

34 Commits

Author SHA1 Message Date
Lea\Anthony
11c9c34958 Revert "v2.0.0-beta.23"
This reverts commit fa380105f4.
2021-12-15 19:33:03 +11:00
Lea\Anthony
fa380105f4 v2.0.0-beta.23 2021-12-15 19:27:58 +11:00
Lea\Anthony
24eaef1604 [mac] fix dynamically linking UTIFramework during cgo build 2021-12-11 19:43:21 +11:00
Lea\Anthony
62adcab722 [mac] try dynamically linking UTIFramework during cgo build 2021-12-11 19:36:17 +11:00
Lea Anthony
e12b630dfb [mac] Attempt to fix 10.14 compilation issue 2021-12-11 07:29:47 +11:00
Lea\Anthony
81b3ecb056 v1.16.9 2021-12-10 19:04:22 +11:00
Lea\Anthony
b4d14644ee Only generate ico if not there 2021-12-10 19:04:10 +11:00
Lea\Anthony
69fd584c32 Update sponsors 2021-12-10 19:00:26 +11:00
Lea Anthony
3444ec50a7 Merge pull request #1017 from stffabi/feature/add-upx-info-windows
[docs] Add info about upx and antivirus vendors
2021-12-09 21:55:52 +11:00
stffabi
02d4c65e01 [docs] Add info about upx and antivirus vendors 2021-12-09 11:03:53 +01:00
Lea Anthony
efdcfe9985 [v2] Remove AllowFiles & AllowDirectories 2021-12-09 08:16:45 +11:00
Lea Anthony
5884b7a87c Update supported platforms 2021-12-08 19:50:11 +11:00
Lea\Anthony
7229446ce7 v2.0.0-beta.22 2021-12-08 19:17:45 +11:00
Lea Anthony
c355d63768 Update bug_report.md 2021-12-08 18:44:36 +11:00
Lea Anthony
eb0030adeb Merge pull request #1012 from meatherly/fix_for_950
Fix for #950
2021-12-08 07:36:10 +11:00
Lea Anthony
fe224d9ecd Merge pull request #1013 from stffabi/feature/fsfs-docs-improvements
[v2] Update docs with new assetdir management and add reloaddirs
2021-12-07 17:08:45 +11:00
stffabi
a98d55db58 [v2] Update wails.json with updated reloaddirs from wails dev 2021-12-07 03:34:51 +01:00
stffabi
f034163da5 [v2] Update wails.json with updated assetdir from wails dev
Makes the code consistent with the docs
2021-12-07 03:34:51 +01:00
stffabi
d8fe011509 [v2] Update docs with new assetdir management and add reloaddirs 2021-12-07 03:34:19 +01:00
stffabi
e7bb3b3e83 [v2] Omit empty assetdir and reloaddirs in wails.json 2021-12-07 03:26:55 +01:00
meatherly
3201206d4f locking the event manager before mutating it. this should resolve issue #950 2021-12-06 16:21:35 -06:00
Lea Anthony
69c14d2a5d Merge pull request #1001 from stffabi/feature/fsfs-assets
proposal: [v2] Support fs.FS for assets
2021-12-07 06:03:59 +11:00
stffabi
778cbe04d9 [v2] Add reloaddirs flag to add additional reload directories
This is interesting if someone uses an asset FS which is not an embed.FS,
but still has some special handling to include loading data from disk in
dev mode. E.g. one might conditionally use an embed.FS or os.DirFS
depending on the build mode.
2021-12-06 13:47:16 +01:00
stffabi
131a8f421d [v2] Infer assetDir from embed.FS
AssetDir is now inferred from the assets, if the assets is an
embed.FS, by taking the relativ path to the index.html joined with
the project root.

The assetDir flag still exists and can be used if the inferring doesn't
work, because the provided embed.FS wasn't defined in the main
package.
2021-12-06 13:47:16 +01:00
stffabi
6fcd4b7bd4 [v2] Support fs.FS for assets
Reloading changed asset files in dev mode will only work
if an embed.FS has been provided for the assets.
2021-12-06 08:50:39 +01:00
Lea Anthony
f3b2f6ab76 Merge pull request #1011 from misitebao/optimize-documentation
docs: synchronize and optimize documents
2021-12-06 17:37:44 +11:00
misitebao
b556e860c4 docs: fix document translation 2021-12-06 11:10:36 +08:00
misitebao
eb01a005dc docs: fix document translation 2021-12-06 11:09:22 +08:00
misitebao
6dcee51940 docs: optimize english documents 2021-12-06 11:06:08 +08:00
misitebao
4c7a53b72b docs: synchronize chinese documents 2021-12-06 11:05:37 +08:00
Lea\Anthony
73c9fba731 [website] Added Angular router guide 2021-12-05 22:23:02 +11:00
Lea\Anthony
0726ae9e83 [website] Added router guide 2021-12-05 22:18:52 +11:00
Lea\Anthony
9ba4ca10ca [website] Link to Awesome Wails 2021-12-05 19:31:42 +11:00
Lea\Anthony
38caa645e5 [v2] A better approach to delayed IPC 2021-12-05 14:23:48 +11:00
54 changed files with 501 additions and 1070 deletions

View File

@@ -8,7 +8,7 @@ assignees: ''
--- ---
##################################################### #####################################################
**If you have a technical issue, please do not open a bug this way!** **V1 users: If you have a technical issue, please do not open a bug this way!**
Please use the `wails issue` command! Please use the `wails issue` command!
If you do not do this then the issue may be closed automatically. If you do not do this then the issue may be closed automatically.
@@ -33,7 +33,7 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**System Details** **System Details**
Please provide your platform, GO version and variables, etc V2 users: Please add the output of `wails doctor`.
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

View File

@@ -106,6 +106,13 @@ Click [here](https://wails.io) if you are interested in trying out v2 Beta for W
This project is supported by these kind people / companies: This project is supported by these kind people / companies:
<p align="center">
<a href="https://www.easywebadv.it/" style="width:100px;">
<img src="website/static/img/easyweb.png" width="100"/>
</a>
</p>
<br/>
<br/>
<a href="https://github.com/sponsors/leaanthony" style="width:100px;"> <a href="https://github.com/sponsors/leaanthony" style="width:100px;">
<img src="sponsors/silver%20sponsor.png" width="100"/> <img src="sponsors/silver%20sponsor.png" width="100"/>
</a> </a>

View File

@@ -109,6 +109,13 @@
这个项目由以下这些人或者公司支持: 这个项目由以下这些人或者公司支持:
<p align="center">
<a href="https://www.easywebadv.it/" style="width:100px;">
<img src="website/static/img/easyweb.png" width="100"/>
</a>
</p>
<br/>
<br/>
<a href="https://github.com/sponsors/leaanthony" style="width:100px;"> <a href="https://github.com/sponsors/leaanthony" style="width:100px;">
<img src="sponsors/silver%20sponsor.png" width="100"/> <img src="sponsors/silver%20sponsor.png" width="100"/>
</a> </a>

View File

@@ -313,10 +313,12 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
return err return err
} }
// Generate icon from PNG // Generate icon from PNG if it doesn't exist
err = generateWindowsIcon(icon, basename+".ico") if !fs.FileExists(basename + ".ico") {
if err != nil { err = generateWindowsIcon(icon, basename+".ico")
return err if err != nil {
return err
}
} }
// Copy manifest // Copy manifest

View File

@@ -1,4 +1,4 @@
package cmd package cmd
// Version - Wails version // Version - Wails version
const Version = "v1.16.8" const Version = "v1.16.9"

View File

@@ -55,20 +55,20 @@ func (e *Manager) addEventListener(eventName string, callback func(...interface{
return fmt.Errorf("nil callback bassed to addEventListener") return fmt.Errorf("nil callback bassed to addEventListener")
} }
// Check event has been registered before
if e.listeners[eventName] == nil {
e.listeners[eventName] = []*eventListener{}
}
// Create the callback // Create the callback
listener := &eventListener{ listener := &eventListener{
callback: callback, callback: callback,
counter: counter, counter: counter,
} }
e.mu.Lock()
// Check event has been registered before
if e.listeners[eventName] == nil {
e.listeners[eventName] = []*eventListener{}
}
// Register listener // Register listener
e.listeners[eventName] = append(e.listeners[eventName], listener) e.listeners[eventName] = append(e.listeners[eventName], listener)
e.mu.Unlock()
// All good mate // All good mate
return nil return nil
} }

View File

@@ -63,6 +63,7 @@ type devFlags struct {
compilerCommand string compilerCommand string
assetDir string assetDir string
extensions string extensions string
reloadDirs string
openBrowser bool openBrowser bool
noReload bool noReload bool
wailsjsdir string wailsjsdir string
@@ -83,8 +84,9 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
flags := defaultDevFlags() flags := defaultDevFlags()
command.StringFlag("ldflags", "optional ldflags", &flags.ldflags) command.StringFlag("ldflags", "optional ldflags", &flags.ldflags)
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &flags.compilerCommand) 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("assetdir", "Serve assets from the given directory instead of using the provided asset FS", &flags.assetDir)
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &flags.extensions) command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &flags.extensions)
command.StringFlag("reloaddirs", "Additional directories to trigger reloads (comma separated)", &flags.reloadDirs)
command.BoolFlag("browser", "Open application in browser", &flags.openBrowser) command.BoolFlag("browser", "Open application in browser", &flags.openBrowser)
command.BoolFlag("noreload", "Disable reload on asset change", &flags.noReload) command.BoolFlag("noreload", "Disable reload on asset change", &flags.noReload)
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &flags.wailsjsdir) command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &flags.wailsjsdir)
@@ -301,21 +303,29 @@ func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, e
var shouldSaveConfig bool 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 != "" { if flags.assetDir == "" && projectConfig.AssetDirectory != "" {
flags.assetDir = projectConfig.AssetDirectory flags.assetDir = projectConfig.AssetDirectory
} }
if flags.assetDir != projectConfig.AssetDirectory { if flags.assetDir != projectConfig.AssetDirectory {
projectConfig.AssetDirectory = filepath.ToSlash(flags.assetDir) projectConfig.AssetDirectory = filepath.ToSlash(flags.assetDir)
shouldSaveConfig = true
} }
flags.assetDir, err = filepath.Abs(flags.assetDir) if flags.assetDir != "" {
if err != nil { flags.assetDir, err = filepath.Abs(flags.assetDir)
return nil, err if err != nil {
return nil, err
}
}
if flags.reloadDirs == "" && projectConfig.ReloadDirectories != "" {
flags.reloadDirs = projectConfig.ReloadDirectories
}
if flags.reloadDirs != projectConfig.ReloadDirectories {
projectConfig.ReloadDirectories = filepath.ToSlash(flags.reloadDirs)
shouldSaveConfig = true
} }
if flags.devServerURL == defaultDevServerURL && projectConfig.DevServerURL != defaultDevServerURL && projectConfig.DevServerURL != "" { if flags.devServerURL == defaultDevServerURL && projectConfig.DevServerURL != defaultDevServerURL && projectConfig.DevServerURL != "" {
@@ -503,11 +513,26 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc
newBinaryProcess *process.Process newBinaryProcess *process.Process
) )
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(flags.extensions, ",")) var extensionsThatTriggerARebuild = sliceToMap(strings.Split(flags.extensions, ","))
var dirsThatTriggerAReload []string
for _, dir := range strings.Split(flags.reloadDirs, ",") {
if dir == "" {
continue
}
path, err := filepath.Abs(dir)
if err != nil {
LogRed("Unable to expand reloadDir '%s': %s", dir, err)
continue
}
dirsThatTriggerAReload = append(dirsThatTriggerAReload, path)
}
quit := false quit := false
interval := time.Duration(flags.debounceMS) * time.Millisecond interval := time.Duration(flags.debounceMS) * time.Millisecond
timer := time.NewTimer(interval) timer := time.NewTimer(interval)
rebuild := false rebuild := false
reload := false reload := false
assetDir := ""
changedPaths := map[string]struct{}{}
for quit == false { for quit == false {
//reload := false //reload := false
select { select {
@@ -519,12 +544,13 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc
// Check for file writes // Check for file writes
if item.Op&fsnotify.Write == fsnotify.Write { if item.Op&fsnotify.Write == fsnotify.Write {
// Ignore directories // Ignore directories
if fs.DirExists(item.Name) { itemName := item.Name
if fs.DirExists(itemName) {
continue continue
} }
// Iterate all file patterns // Iterate all file patterns
ext := filepath.Ext(item.Name) ext := filepath.Ext(itemName)
if ext != "" { if ext != "" {
ext = ext[1:] ext = ext[1:]
if _, exists := extensionsThatTriggerARebuild[ext]; exists { if _, exists := extensionsThatTriggerARebuild[ext]; exists {
@@ -534,9 +560,17 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc
} }
} }
if strings.HasPrefix(item.Name, flags.assetDir) { for _, reloadDir := range dirsThatTriggerAReload {
reload = true if strings.HasPrefix(itemName, reloadDir) {
reload = true
break
}
} }
if !reload {
changedPaths[filepath.Dir(itemName)] = struct{}{}
}
timer.Reset(interval) timer.Reset(interval)
} }
// Check for new directories // Check for new directories
@@ -568,6 +602,35 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc
debugBinaryProcess = newBinaryProcess debugBinaryProcess = newBinaryProcess
} }
} }
if len(changedPaths) != 0 {
if assetDir == "" {
resp, err := http.Get("http://localhost:34115/wails/assetdir")
if err != nil {
LogRed("Error during retrieving assetdir: %s", err.Error())
} else {
content, err := io.ReadAll(resp.Body)
if err != nil {
LogRed("Error reading assetdir from devserver: %s", err.Error())
} else {
assetDir = string(content)
}
resp.Body.Close()
}
}
if assetDir != "" {
for path := range changedPaths {
if strings.HasPrefix(path, assetDir) {
reload = true
break
}
}
} else if len(dirsThatTriggerAReload) == 0 {
LogRed("Reloading couldn't be triggered: Please specify -assetdir or -reloaddirs")
}
changedPaths = map[string]struct{}{}
}
if reload { if reload {
reload = false reload = false
_, err = http.Get("http://localhost:34115/wails/reload") _, err = http.Get("http://localhost:34115/wails/reload")

View File

@@ -10,7 +10,6 @@ The next steps to complete the template are:
- It is really important to ensure `helpurl` is valid as this is where users of the template will be directed for help. - It is really important to ensure `helpurl` is valid as this is where users of the template will be directed for help.
2. Update `README.md`. 2. Update `README.md`.
3. Edit `wails.json` and ensure all fields are correct, especially: 3. Edit `wails.json` and ensure all fields are correct, especially:
- `assetdir` - path to your assets
- `wailsjsdir` - path to generate wailsjs modules - `wailsjsdir` - path to generate wailsjs modules
- `frontend:install` - The command to install your frontend dependencies - `frontend:install` - The command to install your frontend dependencies
- `frontend:build` - The command to build your frontend - `frontend:build` - The command to build your frontend

View File

@@ -1,7 +1,6 @@
{ {
"name": "{{.ProjectName}}", "name": "{{.ProjectName}}",
"outputfilename": "{{.BinaryName}}", "outputfilename": "{{.BinaryName}}",
"assetdir": "frontend/dist",
"frontend:install": "npm install", "frontend:install": "npm install",
"frontend:build": "npm run build", "frontend:build": "npm run build",
"author": { "author": {

View File

@@ -36,7 +36,6 @@
<working_directory value="$PROJECT_DIR$"/> <working_directory value="$PROJECT_DIR$"/>
<go_parameters value="-gcflags &quot;all=-N -l&quot; -tags dev -o {{.PathToDesktopBinary}}"/> <go_parameters value="-gcflags &quot;all=-N -l&quot; -tags dev -o {{.PathToDesktopBinary}}"/>
<useCustomBuildTags value="true"/> <useCustomBuildTags value="true"/>
<parameters value="-assetdir {{.AssetDir}}"/>
<envs> <envs>
<env name="CGO_ENABLED" value="&quot;{{.CGOEnabled}}&quot;"/> <env name="CGO_ENABLED" value="&quot;{{.CGOEnabled}}&quot;"/>
</envs> </envs>

View File

@@ -9,11 +9,7 @@
"program": "${workspaceFolder}/{{.PathToDesktopBinary}}", "program": "${workspaceFolder}/{{.PathToDesktopBinary}}",
"preLaunchTask": "build", "preLaunchTask": "build",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"env": {}, "env": {}
"args": [
"-assetdir",
"{{.AssetDir}}"
]
} }
] ]
} }

View File

@@ -42,7 +42,6 @@ type Data struct {
AuthorNameAndEmail string AuthorNameAndEmail string
WailsDirectory string WailsDirectory string
GoSDKPath string GoSDKPath string
AssetDir string
WindowsFlags string WindowsFlags string
CGOEnabled string CGOEnabled string
OutputFile string OutputFile string
@@ -60,7 +59,6 @@ type Options struct {
InitGit bool InitGit bool
AuthorName string AuthorName string
AuthorEmail string AuthorEmail string
AssetDir string
IDE string IDE string
ProjectNameFilename string // The project name but as a valid filename ProjectNameFilename string // The project name but as a valid filename
WailsVersion string WailsVersion string
@@ -261,7 +259,6 @@ func Install(options *Options) (bool, *Template, error) {
AuthorName: options.AuthorName, AuthorName: options.AuthorName,
WailsVersion: options.WailsVersion, WailsVersion: options.WailsVersion,
GoSDKPath: options.GoSDKPath, GoSDKPath: options.GoSDKPath,
AssetDir: options.AssetDir,
} }
// Create a formatted name and email combo. // Create a formatted name and email combo.
@@ -408,22 +405,6 @@ func installIDEFiles(o ideOptions) error {
binaryName += ".exe" binaryName += ".exe"
} }
// Parse wails.json for assetdir
wailsJSONBytes, err := os.ReadFile(filepath.Join(o.options.TargetDir, "wails.json"))
if err != nil {
return err
}
var wailsJSON map[string]interface{}
err = json.Unmarshal(wailsJSONBytes, &wailsJSON)
if err != nil {
return err
}
assetDir := wailsJSON["assetdir"]
if assetDir == "" {
return fmt.Errorf("Unable to find 'assetdir' in 'wails.json' ")
}
o.options.AssetDir = assetDir.(string)
o.options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName)) o.options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName))
o.options.WindowsFlags = "" o.options.WindowsFlags = ""

View File

@@ -1,7 +1,6 @@
{ {
"name": "{{.ProjectName}}", "name": "{{.ProjectName}}",
"outputfilename": "{{.BinaryName}}", "outputfilename": "{{.BinaryName}}",
"assetdir": "frontend/dist",
"frontend:install": "npm install", "frontend:install": "npm install",
"frontend:build": "npm run build", "frontend:build": "npm run build",
"wailsjsdir": "./frontend", "wailsjsdir": "./frontend",

View File

@@ -1,7 +1,6 @@
{ {
"name": "{{.ProjectName}}", "name": "{{.ProjectName}}",
"outputfilename": "{{.BinaryName}}", "outputfilename": "{{.BinaryName}}",
"assetdir": "frontend/src",
"wailsjsdir": "./frontend", "wailsjsdir": "./frontend",
"author": { "author": {
"name": "{{.AuthorName}}", "name": "{{.AuthorName}}",

View File

@@ -1,3 +1,3 @@
package internal package internal
var Version = "v2.0.0-beta.21" var Version = "v2.0.0-beta.22"

View File

@@ -5,7 +5,10 @@ package appng
import ( import (
"context" "context"
"embed"
"flag" "flag"
"fmt"
iofs "io/fs"
"os" "os"
"path/filepath" "path/filepath"
@@ -91,12 +94,30 @@ func CreateApp(appoptions *options.App) (*App, error) {
} }
} }
if assetdir == "" {
// If no assetdir has been defined, let's try to infer it from the project root and the asset FS.
assetdir, err = tryInferAssetDirFromFS(appoptions.Assets)
if err != nil {
return nil, err
}
}
if assetdir != "" {
// Let's override the assets to serve from on disk, if needed
absdir, err := filepath.Abs(assetdir)
if err != nil {
return nil, err
}
myLogger.Info("Serving assets from disk: %s", absdir)
appoptions.Assets = os.DirFS(absdir)
ctx = context.WithValue(ctx, "assetdir", assetdir)
}
if devServerURL != "" { if devServerURL != "" {
ctx = context.WithValue(ctx, "devserverurl", devServerURL) ctx = context.WithValue(ctx, "devserverurl", devServerURL)
} }
if assetdir != "" {
ctx = context.WithValue(ctx, "assetdir", assetdir)
}
if loglevel != "" { if loglevel != "" {
level, err := pkglogger.StringToLogLevel(loglevel) level, err := pkglogger.StringToLogLevel(loglevel)
@@ -203,3 +224,32 @@ func generateBindings(bindings *binding.Bindings) error {
return nil return nil
} }
func tryInferAssetDirFromFS(assets iofs.FS) (string, error) {
if _, isEmbedFs := assets.(embed.FS); !isEmbedFs {
// We only infer the assetdir for embed.FS assets
return "", nil
}
path, err := fs.FindPathToFile(assets, "index.html")
if err != nil {
return "", err
}
path, err = filepath.Abs(path)
if err != nil {
return "", err
}
if _, err := os.Stat(filepath.Join(path, "index.html")); err != nil {
if os.IsNotExist(err) {
err = fmt.Errorf(
"inferred assetdir '%s' does not exist or does not contain an 'index.html' file, "+
"please specify it with -assetdir or set it in wails.json",
path)
}
return "", err
}
return path, nil
}

View File

@@ -5,11 +5,13 @@ package assetserver
import ( import (
"bytes" "bytes"
"github.com/wailsapp/wails/v2/internal/frontend/runtime" "context"
"github.com/wailsapp/wails/v2/pkg/options" "io/fs"
"golang.org/x/net/html"
"path/filepath"
"strings" "strings"
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/logger"
"golang.org/x/net/html"
) )
/* /*
@@ -19,35 +21,41 @@ It injects a websocket based IPC script into `index.html`.
*/ */
import (
"os"
)
type BrowserAssetServer struct { type BrowserAssetServer struct {
runtimeJS []byte assets fs.FS
assetdir string runtimeJS []byte
appOptions *options.App logger *logger.Logger
} }
func NewBrowserAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*BrowserAssetServer, error) { func NewBrowserAssetServer(ctx context.Context, assets fs.FS, bindingsJSON string) (*BrowserAssetServer, error) {
result := &BrowserAssetServer{ result := &BrowserAssetServer{}
assetdir: assetdir, _logger := ctx.Value("logger")
appOptions: appOptions, if _logger != nil {
result.logger = _logger.(*logger.Logger)
}
var err error
result.assets, err = prepareAssetsForServing(assets)
if err != nil {
return nil, err
} }
var buffer bytes.Buffer var buffer bytes.Buffer
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n") buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
buffer.Write(runtime.RuntimeDesktopJS) buffer.Write(runtime.RuntimeDesktopJS)
result.runtimeJS = buffer.Bytes() result.runtimeJS = buffer.Bytes()
return result, nil return result, nil
} }
func (a *BrowserAssetServer) loadFileFromDisk(filename string) ([]byte, error) { func (d *BrowserAssetServer) LogDebug(message string, args ...interface{}) {
return os.ReadFile(filepath.Join(a.assetdir, filename)) if d.logger != nil {
d.logger.Debug("[BrowserAssetServer] "+message, args...)
}
} }
func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) { func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) {
indexHTML, err := a.loadFileFromDisk("index.html") indexHTML, err := fs.ReadFile(a.assets, "index.html")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -97,15 +105,9 @@ func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) {
case "/wails/ipc.js": case "/wails/ipc.js":
content = runtime.WebsocketIPC content = runtime.WebsocketIPC
default: default:
content, err = a.loadFileFromDisk(filename) filename = strings.TrimPrefix(filename, "/")
if strings.HasSuffix(filename, ".js") { a.LogDebug("Loading file: %s", filename)
var buffer bytes.Buffer content, err = fs.ReadFile(a.assets, filename)
buffer.WriteString("window.awaitIPC('" + filename + "', ()=>{")
buffer.Write(content)
buffer.WriteString(`
});`)
content = buffer.Bytes()
}
} }
if err != nil { if err != nil {
return nil, "", err return nil, "", err

View File

@@ -0,0 +1,25 @@
package assetserver
import (
iofs "io/fs"
"path"
"github.com/wailsapp/wails/v2/internal/fs"
)
func prepareAssetsForServing(assets iofs.FS) (iofs.FS, error) {
if _, err := assets.Open("."); err != nil {
return nil, err
}
subDir, err := fs.FindPathToFile(assets, "index.html")
if err != nil {
return nil, err
}
assets, err = iofs.Sub(assets, path.Clean(subDir))
if err != nil {
return nil, err
}
return assets, nil
}

View File

@@ -3,26 +3,21 @@ package assetserver
import ( import (
"bytes" "bytes"
"context" "context"
"embed"
"fmt"
"github.com/leaanthony/debme"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/logger"
"io/fs" "io/fs"
"log" "log"
"path/filepath"
"strings" "strings"
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/logger"
) )
type DesktopAssetServer struct { type DesktopAssetServer struct {
assets debme.Debme assets fs.FS
runtimeJS []byte runtimeJS []byte
assetdir string
logger *logger.Logger logger *logger.Logger
} }
func NewDesktopAssetServer(ctx context.Context, assets embed.FS, bindingsJSON string) (*DesktopAssetServer, error) { func NewDesktopAssetServer(ctx context.Context, assets fs.FS, bindingsJSON string) (*DesktopAssetServer, error) {
result := &DesktopAssetServer{} result := &DesktopAssetServer{}
_logger := ctx.Value("logger") _logger := ctx.Value("logger")
@@ -30,22 +25,18 @@ func NewDesktopAssetServer(ctx context.Context, assets embed.FS, bindingsJSON st
result.logger = _logger.(*logger.Logger) result.logger = _logger.(*logger.Logger)
} }
_assetdir := ctx.Value("assetdir") var err error
if _assetdir != nil { result.assets, err = prepareAssetsForServing(assets)
result.assetdir = _assetdir.(string) if err != nil {
absdir, err := filepath.Abs(result.assetdir) return nil, err
if err != nil {
return nil, err
}
result.LogDebug("Loading assets from: %s", absdir)
} }
var buffer bytes.Buffer var buffer bytes.Buffer
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n") buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
buffer.Write(runtime.RuntimeDesktopJS) buffer.Write(runtime.RuntimeDesktopJS)
result.runtimeJS = buffer.Bytes() result.runtimeJS = buffer.Bytes()
err := result.init(assets)
return result, err return result, nil
} }
func (d *DesktopAssetServer) LogDebug(message string, args ...interface{}) { func (d *DesktopAssetServer) LogDebug(message string, args ...interface{}) {
@@ -54,63 +45,8 @@ func (d *DesktopAssetServer) LogDebug(message string, args ...interface{}) {
} }
} }
func (d *DesktopAssetServer) SetAssetDir(assetdir string) {
d.assetdir = assetdir
}
func PathToIndexHTML(assets embed.FS) (string, error) {
stat, err := fs.Stat(assets, "index.html")
if stat != nil {
return ".", nil
}
var indexFiles slicer.StringSlicer
err = fs.WalkDir(assets, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if strings.HasSuffix(path, "index.html") {
indexFiles.Add(path)
}
return nil
})
if err != nil {
return "", err
}
if indexFiles.Length() > 1 {
return "", fmt.Errorf("multiple 'index.html' files found in assets")
}
path, _ := filepath.Split(indexFiles.AsSlice()[0])
return path, nil
}
func processAssets(assets embed.FS) (debme.Debme, error) {
result, err := debme.FS(assets, ".")
if err != nil {
return result, err
}
// Find index.html
path, err := PathToIndexHTML(assets)
if err != nil {
return debme.Debme{}, err
}
return debme.FS(assets, path)
}
func (a *DesktopAssetServer) init(assets embed.FS) error {
var err error
a.assets, err = processAssets(assets)
if err != nil {
return err
}
return nil
}
func (a *DesktopAssetServer) processIndexHTML() ([]byte, error) { func (a *DesktopAssetServer) processIndexHTML() ([]byte, error) {
indexHTML, err := a.ReadFile("index.html") indexHTML, err := fs.ReadFile(a.assets, "index.html")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -146,7 +82,9 @@ func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) {
case "/wails/ipc.js": case "/wails/ipc.js":
content = runtime.DesktopIPC content = runtime.DesktopIPC
default: default:
content, err = a.ReadFile(filename) filename = strings.TrimPrefix(filename, "/")
a.LogDebug("Loading file: %s", filename)
content, err = fs.ReadFile(a.assets, filename)
} }
if err != nil { if err != nil {
return nil, "", err return nil, "", err

View File

@@ -1,13 +0,0 @@
//go:build dev
package assetserver
import (
"os"
"path/filepath"
)
func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) {
a.LogDebug("Loading file from disk: %s", filename)
return os.ReadFile(filepath.Join(a.assetdir, filename))
}

View File

@@ -1,7 +0,0 @@
//go:build production
package assetserver
func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) {
return a.assets.ReadFile(filename)
}

View File

@@ -497,16 +497,16 @@
filters = [filters stringByReplacingOccurrencesOfString:@"*." withString:@""]; filters = [filters stringByReplacingOccurrencesOfString:@"*." withString:@""];
filters = [filters stringByReplacingOccurrencesOfString:@" " withString:@""]; filters = [filters stringByReplacingOccurrencesOfString:@" " withString:@""];
NSArray *filterList = [filters componentsSeparatedByString:@";"]; NSArray *filterList = [filters componentsSeparatedByString:@";"];
if (@available(macOS 10.16, *)) { #ifdef USE_NEW_FILTERS
NSMutableArray *contentTypes = [[NSMutableArray new] autorelease]; NSMutableArray *contentTypes = [[NSMutableArray new] autorelease];
for (NSString *filter in filterList) { for (NSString *filter in filterList) {
UTType *t = [UTType typeWithFilenameExtension:filter]; UTType *t = [UTType typeWithFilenameExtension:filter];
[contentTypes addObject:t]; [contentTypes addObject:t];
} }
[dialog setAllowedContentTypes:contentTypes]; [dialog setAllowedContentTypes:contentTypes];
} else { #else
[dialog setAllowedFileTypes:filterList]; [dialog setAllowedFileTypes:filterList];
} #endif
} else { } else {
[dialog setAllowsOtherFileTypes:true]; [dialog setAllowsOtherFileTypes:true];
} }

View File

@@ -84,7 +84,7 @@ func (f *Frontend) openDialog(options *frontend.OpenDialogOptions, multiple bool
// OpenFileDialog prompts the user to select a file // OpenFileDialog prompts the user to select a file
func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) { func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) {
results, err := f.openDialog(&options, false, options.AllowFiles, options.AllowDirectories) results, err := f.openDialog(&options, false, true, false)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -97,7 +97,7 @@ func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, e
// OpenMultipleFilesDialog prompts the user to select a file // OpenMultipleFilesDialog prompts the user to select a file
func (f *Frontend) OpenMultipleFilesDialog(options frontend.OpenDialogOptions) ([]string, error) { func (f *Frontend) OpenMultipleFilesDialog(options frontend.OpenDialogOptions) ([]string, error) {
return f.openDialog(&options, true, options.AllowFiles, options.AllowDirectories) return f.openDialog(&options, true, true, false)
} }
// SaveFileDialog prompts the user to select a file // SaveFileDialog prompts the user to select a file

View File

@@ -5,7 +5,7 @@ package darwin
/* /*
#cgo CFLAGS: -x objective-c #cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit -framework UniformTypeIdentifiers #cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Application.h" #import "Application.h"
#import "WailsContext.h" #import "WailsContext.h"

View File

@@ -10,7 +10,6 @@ import (
"fmt" "fmt"
"io/fs" "io/fs"
"log" "log"
"path/filepath"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -50,6 +49,11 @@ func (d *DevWebServer) WindowReload() {
func (d *DevWebServer) Run(ctx context.Context) error { func (d *DevWebServer) Run(ctx context.Context) error {
d.ctx = ctx d.ctx = ctx
assetdir, _ := ctx.Value("assetdir").(string)
d.server.Get("/wails/assetdir", func(fctx *fiber.Ctx) error {
return fctx.SendString(assetdir)
})
d.server.Get("/wails/reload", func(fctx *fiber.Ctx) error { d.server.Get("/wails/reload", func(fctx *fiber.Ctx) error {
d.WindowReload() d.WindowReload()
d.desktopFrontend.WindowReload() d.desktopFrontend.WindowReload()
@@ -100,25 +104,14 @@ func (d *DevWebServer) Run(ctx context.Context) error {
_devServerURL := ctx.Value("devserverurl") _devServerURL := ctx.Value("devserverurl")
if _devServerURL == "http://localhost:34115" { if _devServerURL == "http://localhost:34115" {
// Setup internal dev server // Setup internal dev server
_assetdir := ctx.Value("assetdir") bindingsJSON, err := d.appBindings.ToJSON()
if _assetdir == nil { if err != nil {
return fmt.Errorf("no assetdir provided") log.Fatal(err)
} }
if _assetdir != nil {
assetdir := _assetdir.(string) d.assetServer, err = assetserver.NewBrowserAssetServer(ctx, d.appoptions.Assets, bindingsJSON)
bindingsJSON, err := d.appBindings.ToJSON() if err != nil {
if err != nil { log.Fatal(err)
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) d.server.Get("*", d.loadAsset)

View File

@@ -19,8 +19,6 @@ type OpenDialogOptions struct {
DefaultFilename string DefaultFilename string
Title string Title string
Filters []FileFilter Filters []FileFilter
AllowFiles bool
AllowDirectories bool
ShowHiddenFiles bool ShowHiddenFiles bool
CanCreateDirectories bool CanCreateDirectories bool
ResolvesAliases bool ResolvesAliases bool

View File

@@ -14,14 +14,17 @@ import Overlay from "./Overlay.svelte";
import {hideOverlay, showOverlay} from "./store"; import {hideOverlay, showOverlay} from "./store";
let components = {}; let components = {};
window.ipcCallbacks = [];
window.ipcCallbackNames = [];
window.awaitIPC = (name, callback) => { let wailsInvokeInternal = null;
if (!window.ipcCallbacks) return callback; let messageQueue = [];
log("Queuing '" + name + "' for execution once ipc ready.");
window.ipcCallbackNames.push(name); window.WailsInvoke = (message) => {
window.ipcCallbacks.push(callback); if (!wailsInvokeInternal) {
console.log("Queueing: " + message);
messageQueue.push(message);
return;
}
wailsInvokeInternal(message);
}; };
window.addEventListener('DOMContentLoaded', () => { window.addEventListener('DOMContentLoaded', () => {
@@ -47,15 +50,14 @@ window.onbeforeunload = function () {
connect(); connect();
function setupIPCBridge() { function setupIPCBridge() {
window.WailsInvoke = (message) => { wailsInvokeInternal = (message) => {
websocket.send(message); websocket.send(message);
}; };
for (let i = 0; i < window.ipcCallbacks.length; i++) { for (let i = 0; i < messageQueue.length; i++) {
log("Executing JS: " + window.ipcCallbackNames[i]); console.log("sending queued message: " + messageQueue[i]);
window.ipcCallbacks[i](); window.WailsInvoke(messageQueue[i]);
} }
delete window.ipcCallbacks; messageQueue = [];
delete window.ipcCallbackNames;
} }
// Handles incoming websocket connections // Handles incoming websocket connections

View File

@@ -1,812 +1,8 @@
{ {
"name": "dev", "name": "dev",
"version": "2.0.0", "version": "2.0.0",
"lockfileVersion": 2, "lockfileVersion": 1,
"requires": true, "requires": true,
"packages": {
"": {
"version": "2.0.0",
"license": "ISC",
"devDependencies": {
"esbuild": "^0.12.17",
"esbuild-svelte": "^0.5.6",
"npm-run-all": "^4.1.5",
"svelte": "^3.42.2"
}
},
"node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"node_modules/cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"dependencies": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
},
"engines": {
"node": ">=4.8"
}
},
"node_modules/define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"dev": true,
"dependencies": {
"object-keys": "^1.0.12"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"dependencies": {
"is-arrayish": "^0.2.1"
}
},
"node_modules/es-abstract": {
"version": "1.18.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz",
"integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"get-intrinsic": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.2",
"internal-slot": "^1.0.3",
"is-callable": "^1.2.3",
"is-negative-zero": "^2.0.1",
"is-regex": "^1.1.3",
"is-string": "^1.0.6",
"object-inspect": "^1.11.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.2",
"string.prototype.trimend": "^1.0.4",
"string.prototype.trimstart": "^1.0.4",
"unbox-primitive": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"dev": true,
"dependencies": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": {
"version": "0.12.21",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.21.tgz",
"integrity": "sha512-7hyXbU3g94aREufI/5nls7Xcc+RGQeZWZApm6hoBaFvt2BPtpT4TjFMQ9Tb1jU8XyBGz00ShmiyflCogphMHFQ==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
}
},
"node_modules/esbuild-svelte": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.5.6.tgz",
"integrity": "sha512-Bz8nU45FrT6sP/Tf3M2rQUuBGxnDSNSPZNIoYwSNt5H+wjSyo/t+zm94tgnOZsR6GgpDMbNQgo4jGbK0NLvEfw==",
"dev": true,
"dependencies": {
"svelte": "^3.42.6"
}
},
"node_modules/esbuild-svelte/node_modules/svelte": {
"version": "3.43.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.43.1.tgz",
"integrity": "sha512-nvPIaKx4HLzYlSdquISZpgG1Kqr2VAWQjZOt3Iwm3UhbqmA0LnSx4k1YpRMEhjQYW3ZCqQoK8Egto9tv4YewMA==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"node_modules/get-intrinsic": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
}
},
"node_modules/graceful-fs": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
"integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==",
"dev": true
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/has-bigints": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
"integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==",
"dev": true
},
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/has-symbols": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
"dev": true,
"dependencies": {
"has-symbols": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
"node_modules/internal-slot": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
"integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
"dev": true,
"dependencies": {
"get-intrinsic": "^1.1.0",
"has": "^1.0.3",
"side-channel": "^1.0.4"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"node_modules/is-bigint": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
"integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
"dev": true,
"dependencies": {
"has-bigints": "^1.0.1"
}
},
"node_modules/is-boolean-object": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
"integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-callable": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
"integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-core-module": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz",
"integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==",
"dev": true,
"dependencies": {
"has": "^1.0.3"
}
},
"node_modules/is-date-object": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
"dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-negative-zero": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
"integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-number-object": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
"integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==",
"dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-string": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
"integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
"dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-symbol": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
"integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
"dev": true,
"dependencies": {
"has-symbols": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"node_modules/json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
"node_modules/load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
"dev": true,
"dependencies": {
"graceful-fs": "^4.1.2",
"parse-json": "^4.0.0",
"pify": "^3.0.0",
"strip-bom": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
"dev": true,
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"node_modules/normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"dependencies": {
"hosted-git-info": "^2.1.4",
"resolve": "^1.10.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
},
"node_modules/npm-run-all": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
"integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"chalk": "^2.4.1",
"cross-spawn": "^6.0.5",
"memorystream": "^0.3.1",
"minimatch": "^3.0.4",
"pidtree": "^0.3.0",
"read-pkg": "^3.0.0",
"shell-quote": "^1.6.1",
"string.prototype.padend": "^3.0.0"
},
"bin": {
"npm-run-all": "bin/npm-run-all/index.js",
"run-p": "bin/run-p/index.js",
"run-s": "bin/run-s/index.js"
},
"engines": {
"node": ">= 4"
}
},
"node_modules/object-inspect": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
"dev": true
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object.assign": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
"integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3",
"has-symbols": "^1.0.1",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"dependencies": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
},
"engines": {
"node": ">=4"
}
},
"node_modules/path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/path-parse": {
"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
},
"node_modules/path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"dependencies": {
"pify": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pidtree": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
"integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==",
"dev": true,
"bin": {
"pidtree": "bin/pidtree.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
"dev": true,
"dependencies": {
"load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/resolve": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
"dev": true,
"dependencies": {
"is-core-module": "^2.2.0",
"path-parse": "^1.0.6"
}
},
"node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true,
"dependencies": {
"shebang-regex": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/shell-quote": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
"dev": true
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
}
},
"node_modules/spdx-correct": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
"dev": true,
"dependencies": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
}
},
"node_modules/spdx-exceptions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
"dev": true
},
"node_modules/spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
"dependencies": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"node_modules/spdx-license-ids": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz",
"integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==",
"dev": true
},
"node_modules/string.prototype.padend": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz",
"integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
"es-abstract": "^1.18.0-next.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/string.prototype.trimend": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
"integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
}
},
"node_modules/string.prototype.trimstart": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
"integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
}
},
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/svelte": {
"version": "3.42.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.42.2.tgz",
"integrity": "sha512-FOyNYKXb8wdE0Ot+Ctt2/OyDLsNBP8+V6PUE9ag6ZKeLslIou0LnMu1fhtWUA+HjzKTbAM1yj+4PFLtg/3pMJA==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/unbox-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
"integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"has-bigints": "^1.0.1",
"has-symbols": "^1.0.2",
"which-boxed-primitive": "^1.0.2"
}
},
"node_modules/validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
"dependencies": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
}
},
"node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"which": "bin/which"
}
},
"node_modules/which-boxed-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
"dev": true,
"dependencies": {
"is-bigint": "^1.0.1",
"is-boolean-object": "^1.1.0",
"is-number-object": "^1.0.4",
"is-string": "^1.0.5",
"is-symbol": "^1.0.3"
}
}
},
"dependencies": { "dependencies": {
"ansi-styles": { "ansi-styles": {
"version": "3.2.1", "version": "3.2.1",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,9 +4,11 @@ import (
"crypto/md5" "crypto/md5"
"fmt" "fmt"
"io" "io"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings"
"unsafe" "unsafe"
"github.com/leaanthony/slicer" "github.com/leaanthony/slicer"
@@ -394,3 +396,30 @@ func MoveDirExtended(src string, dst string, ignore []string) (err error) {
return return
} }
func FindPathToFile(fsys fs.FS, file string) (string, error) {
stat, _ := fs.Stat(fsys, file)
if stat != nil {
return ".", nil
}
var indexFiles slicer.StringSlicer
err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if strings.HasSuffix(path, file) {
indexFiles.Add(path)
}
return nil
})
if err != nil {
return "", err
}
if indexFiles.Length() > 1 {
return "", fmt.Errorf("multiple '%s' files found in assets", file)
}
path, _ := filepath.Split(indexFiles.AsSlice()[0])
return path, nil
}

View File

@@ -13,7 +13,9 @@ type Project struct {
/*** Application Data ***/ /*** Application Data ***/
Name string `json:"name"` Name string `json:"name"`
AssetDirectory string `json:"assetdir"` AssetDirectory string `json:"assetdir,omitempty"`
ReloadDirectories string `json:"reloaddirs,omitempty"`
BuildCommand string `json:"frontend:build"` BuildCommand string `json:"frontend:build"`
InstallCommand string `json:"frontend:install"` InstallCommand string `json:"frontend:install"`

View File

@@ -3,6 +3,7 @@ package build
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/wailsapp/wails/v2/internal/system"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@@ -319,11 +320,21 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
return "1" return "1"
}) })
if options.Platform == "darwin" { if options.Platform == "darwin" {
// Determine verison
info, err := system.GetInfo()
if err != nil {
return err
}
versionSplit := strings.Split(info.OS.Version, ".")
addUTIFramework := versionSplit[0] == "11"
// Set the minimum Mac SDK to 10.13 // Set the minimum Mac SDK to 10.13
cmd.Env = upsertEnv(cmd.Env, "CGO_LDFLAGS", func(v string) string { cmd.Env = upsertEnv(cmd.Env, "CGO_LDFLAGS", func(v string) string {
if v != "" { if v != "" {
v += " " v += " "
} }
if addUTIFramework {
v += "-framework UniformTypeIdentifiers "
}
v += "-mmacosx-version-min=10.13" v += "-mmacosx-version-min=10.13"
return v return v

View File

@@ -2,11 +2,11 @@ package options
import ( import (
"context" "context"
"embed" "io/fs"
"github.com/wailsapp/wails/v2/pkg/options/linux"
"log" "log"
"runtime" "runtime"
"github.com/wailsapp/wails/v2/pkg/options/linux"
"github.com/wailsapp/wails/v2/pkg/options/mac" "github.com/wailsapp/wails/v2/pkg/options/mac"
"github.com/wailsapp/wails/v2/pkg/options/windows" "github.com/wailsapp/wails/v2/pkg/options/windows"
@@ -41,7 +41,7 @@ type App struct {
HideWindowOnClose bool HideWindowOnClose bool
AlwaysOnTop bool AlwaysOnTop bool
RGBA *RGBA RGBA *RGBA
Assets embed.FS Assets fs.FS
Menu *menu.Menu Menu *menu.Menu
Logger logger.Logger `json:"-"` Logger logger.Logger `json:"-"`
LogLevel logger.LogLevel LogLevel logger.LogLevel

View File

@@ -7,13 +7,18 @@ sidebar_position: 2
This page serves as a list for community related links. Please submit a PR (click `Edit this page` at the bottom) This page serves as a list for community related links. Please submit a PR (click `Edit this page` at the bottom)
to submit links. to submit links.
## Awesome Wails
The [definitive list](https://github.com/wailsapp/awesome-wails) of links related to Wails.
## Support Channels ## Support Channels
- [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/) - [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/)
- [Gophers Slack Channel Invite](https://invite.slack.golangbridge.org/) - [Gophers Slack Channel Invite](https://invite.slack.golangbridge.org/)
- [Github Issues](https://github.com/wailsapp/wails/issues) - [Github Issues](https://github.com/wailsapp/wails/issues)
- [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions/828) - [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions/828)
## Social Media ## Social Media
- [Twitter](https://twitter.com/wailsapp) - [Twitter](https://twitter.com/wailsapp)
- [Wails Chinese Community QQ Group](https://qm.qq.com/cgi-bin/qm/qr?k=PmIURne5hFGNd7QWzW5qd6FV-INEjNJv&jump_from=webapi) - Group number: 1067173054

View File

@@ -14,6 +14,13 @@ sidebar_position: 99
<div <div
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: ` __html: `
<p align="center">
<a href="https://www.easywebadv.it/" style="width:100px;">
<img src="/img/easyweb.png" width="100"/>
</a>
</p>
<br/>
<br/>
<a href="https://github.com/sponsors/leaanthony" style="width:100px;"> <a href="https://github.com/sponsors/leaanthony" style="width:100px;">
<img src="/img/silver%20sponsor.png" width="100"/> <img src="/img/silver%20sponsor.png" width="100"/>
</a> </a>

View File

@@ -6,9 +6,9 @@ sidebar_position: 1
## Supported Platforms ## Supported Platforms
- Windows 10 - Windows 10 AMD64/ARM64
- MacOS 10.13+ (amd64) - MacOS 10.13+ AMD64
- MacOS 11.0+ (arm64) - MacOS 11.0+ ARM64
- Linux (due Jan '22) - Linux (due Jan '22)
## Dependencies ## Dependencies

View File

@@ -165,7 +165,7 @@ If these 2 keys aren't given, then Wails does absolutely nothing with the fronte
Running `wails dev` will start the built in dev server which will start a file watcher in your project directory. By 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). 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, If it was, then it will rebuild your application and relaunch it. If the changed file was in the assets,
it will issue a reload after a short amount of time. 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, The dev server uses a technique called "debouncing" which means it doesn't reload straight away,

View File

@@ -46,8 +46,7 @@ The 2 files generated are `tasks.json` and `launch.json`. Below are the files ge
"program": "${workspaceFolder}/build/bin/myproject.exe", "program": "${workspaceFolder}/build/bin/myproject.exe",
"preLaunchTask": "build", "preLaunchTask": "build",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"env": {}, "env": {}
"args": ["-assetdir", "frontend/src"]
}, },
] ]
} }

View File

@@ -199,7 +199,8 @@ The format of the file is slightly different. Here is a comparison:
| frontend / serve | | Removed | | frontend / serve | | Removed |
| tags | | Removed | | tags | | Removed |
| | wailsjsdir | The directory to generate wailsjs modules | | | wailsjsdir | The directory to generate wailsjs modules |
| | assetdir | The directory of the compiled frontend assets for `dev` mode | | | assetdir | The directory of the compiled frontend assets for `dev` mode. This is normally inferred and could be left empty. |
| | reloaddirs | Comma separated list of additional directories to watch for changes and to trigger reloads in `dev` mode. This is only needed for some more advanced asset configurations. |
</p> </p>

View File

@@ -0,0 +1,27 @@
# Routing
Routing is a popular way to switch views in an application. This page offers some guidance around how to do that.
## Vue
The recommended approach for routing in Vue is [Hash Mode](https://next.router.vuejs.org/guide/essentials/history-mode.html#hash-mode):
```js
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes: [
//...
],
})
```
## Angular
The recommended approach for routing in Angular is [HashLocationStrategy](https://codecraft.tv/courses/angular/routing/routing-strategies/#_hashlocationstrategy):
```ts
RouterModule.forRoot(routes, {useHash: true})
```

View File

@@ -106,9 +106,7 @@ As production binaries use the files contained in `embed.FS`, there are no exter
the application. the application.
When running in development mode using the `wails dev` command, the assets are loaded off disk, and any changes result When running in development mode using the `wails dev` command, the assets are loaded off disk, and any changes result
in a "live reload". The location of the assets needs to be passed to the `wails dev` command using the `-assetdir` flag in a "live reload". The location of the assets will be inferred from the `embed.FS`.
and is likely to be the same as the embed path. It is hoped that in the future we can calculate this from the `embed.FS`
itself.
More details can be found in the [Application Development Guide](/docs/guides/application-development). More details can be found in the [Application Development Guide](/docs/guides/application-development).

View File

@@ -82,6 +82,12 @@ Example:
::: :::
:::info UPX on Windows
Some Antivirus vendors false positively mark `upx` compressed binaries as virus, see [issue](https://github.com/upx/upx/issues/437).
:::
## doctor ## doctor
`wails doctor` will run diagnostics to ensure that your system is ready for development. `wails doctor` will run diagnostics to ensure that your system is ready for development.
@@ -130,10 +136,11 @@ Your system is ready for Wails development!
| Flag | Description | Default | | Flag | Description | Default |
| :------------------- | :-------------------------------------- | :------------------------- | | :------------------- | :-------------------------------------- | :------------------------- |
| -assetdir "./path/to/assets" | The path to your compiled assets | Value in `wails.json` | | -assetdir "./path/to/assets" | Serve assets from the given directory instead of using the provided asset FS | Value in `wails.json` |
| -browser | Opens a browser to `http://localhost:34115` on startup | | | -browser | Opens a browser to `http://localhost:34115` on startup | |
| -compiler "compiler"| Use a different go compiler to build, eg go1.15beta1 | go | | -compiler "compiler"| Use a different go compiler to build, eg go1.15beta1 | go |
| -e | Extensions to trigger rebuilds (comma separated) | go | | -e | Extensions to trigger rebuilds (comma separated) | go |
| -reloaddirs | Additional directories to trigger reloads (comma separated) | Value in `wails.json` |
| -ldflags "flags" | Additional ldflags to pass to the compiler | | | -ldflags "flags" | Additional ldflags to pass to the compiler | |
| -tags "extra tags" | Build tags to pass to compiler (quoted and space separated) | | | -tags "extra tags" | Build tags to pass to compiler (quoted and space separated) | |
| -loglevel "loglevel"| Loglevel to use - Trace, Debug, Info, Warning, Error | Debug | | -loglevel "loglevel"| Loglevel to use - Trace, Debug, Info, Warning, Error | Debug |
@@ -145,7 +152,7 @@ Your system is ready for Wails development!
| -appargs "args" | Arguments passed to the application in shell style | | | -appargs "args" | Arguments passed to the application in shell style | |
| -platform "platform" | Platform/Arch to target | `runtime.GOOS` | | -platform "platform" | Platform/Arch to target | `runtime.GOOS` |
If the `assetdir`, `wailsjsdir`, `debounce` or `devserverurl` flags are provided on the command line, they are saved in If the `assetdir`, `reloaddirs`, `wailsjsdir`, `debounce` or `devserverurl` flags are provided on the command line, they are saved in
`wails.json`, and become the defaults for subsequent invocations. `wails.json`, and become the defaults for subsequent invocations.
Example: Example:

View File

@@ -36,6 +36,7 @@ func main() {
OnStartup: app.startup, OnStartup: app.startup,
OnDomReady: app.domready, OnDomReady: app.domready,
OnShutdown: app.shutdown, OnShutdown: app.shutdown,
OnBeforeClose: app.beforeClose,
WindowStartState: options.Maximised, WindowStartState: options.Maximised,
Bind: []interface{}{ Bind: []interface{}{
app, app,
@@ -315,6 +316,14 @@ Type: \*windows.Options
This defines [Windows specific options](#windows-specific-options). This defines [Windows specific options](#windows-specific-options).
### Mac
Name: Mac
Type: \*mac.Options
This defines [Mac specific options](#mac-specific-options).
## Windows Specific Options ## Windows Specific Options
### WebviewIsTransparent ### WebviewIsTransparent

View File

@@ -9,7 +9,8 @@ The project config resides in the `wails.json` file in the project directory. Th
```json ```json
{ {
"name": "[The project name]", "name": "[The project name]",
"assetdir": "[Relative path to the directory containing the compiled assets]", "assetdir": "[Relative path to the directory containing the compiled assets, this is normally inferred and could be left empty]",
"reloaddirs": "[Additional directories to trigger reloads (comma separated), this is only used for some advanced asset configurations]",
"frontend:install": "[The command to install node dependencies, run in the frontend directory - often `npm install`]", "frontend:install": "[The command to install node dependencies, run in the frontend directory - often `npm install`]",
"frontend:build": "[The command to build the assets, run in the frontend directory - often `npm run build`]", "frontend:build": "[The command to build the assets, run in the frontend directory - often `npm run build`]",
"frontend:dev": "[This command is run in a separate process on `wails dev`. Useful for 3rd party watchers]", "frontend:dev": "[This command is run in a separate process on `wails dev`. Useful for 3rd party watchers]",
@@ -25,5 +26,5 @@ The project config resides in the `wails.json` file in the project directory. Th
This file is read by the Wails CLI when running `wails build` or `wails dev`. This file is read by the Wails CLI when running `wails build` or `wails dev`.
The `assetdir`, `wailsjsdir`, `debounceMS` and `devserverurl` flags in `wails build/dev` will update the project config The `assetdir`, `reloaddirs`, `wailsjsdir`, `debounceMS` and `devserverurl` flags in `wails build/dev` will update the project config
and thus become defaults for subsequent runs. and thus become defaults for subsequent runs.

View File

@@ -69,8 +69,6 @@ type OpenDialogOptions struct {
DefaultFilename string DefaultFilename string
Title string Title string
Filters []FileFilter Filters []FileFilter
AllowFiles bool
AllowDirectories bool
ShowHiddenFiles bool ShowHiddenFiles bool
CanCreateDirectories bool CanCreateDirectories bool
ResolvesAliases bool ResolvesAliases bool
@@ -83,8 +81,6 @@ type OpenDialogOptions struct {
| DefaultFilename | The default filename | ✅ | ✅ | | DefaultFilename | The default filename | ✅ | ✅ |
| Title | Title for the dialog | ✅ | ✅ | | Title | Title for the dialog | ✅ | ✅ |
| [Filters](#filefilter) | A list of file filters | ✅ | ✅ | | [Filters](#filefilter) | A list of file filters | ✅ | ✅ |
| AllowFiles | Allow files to be selected | | ✅ |
| AllowDirectories | Allow directories to be selected | | ✅ |
| ShowHiddenFiles | Show files hidden by the system | | ✅ | | ShowHiddenFiles | Show files hidden by the system | | ✅ |
| CanCreateDirectories | Allow user to create directories | | ✅ | | CanCreateDirectories | Allow user to create directories | | ✅ |
| ResolvesAliases | If true, returns the file not the alias | | ✅ | | ResolvesAliases | If true, returns the file not the alias | | ✅ |

View File

@@ -6,6 +6,10 @@ sidebar_position: 2
此页面用于列出社区相关的链接。请提交 PR点击页面底部的`编辑此页`)增加链接。 此页面用于列出社区相关的链接。请提交 PR点击页面底部的`编辑此页`)增加链接。
## 了不起的 Wails
Wails 相关的[优秀列表](https://github.com/wailsapp/awesome-wails)。
## 支持的通道 ## 支持的通道
- [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/) - [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/)

View File

@@ -0,0 +1,10 @@
# Ytd
<p>
<img src="/img/showcase/ytd.png"></img><br/>
</p>
[Ytd](https://github.com/marcio199226/ytd/tree/v2-wails) is an app for downloading tracks from youtube, creating offline playlists and share them with your friends, your friends will be able to playback your playlists or download them for offline listening, has an built-in player.

View File

@@ -0,0 +1,27 @@
# 前沿风险技术
## 概述
Wails 一直在开发中,新版本会定期“标记”。这通常发生在`master`分支上所有较新的代码都经过测试并确认有效时。如果您需要尚未发布的错误修复或功能,可以通过以下步骤使用最新的“前沿风险”版本:
- `git clone https://github.com/wailsapp/wails`
- `cd wails/v2/cmd/wails`
- `go install`
注意您将项目克隆到的目录现在将被称为“clonedir”。
Wails CLI 现在将是最新版本。要更新项目以使用最新版本,请更新项目并确保以下行位于`go.mod`文件底部:
`replace github.com/wailsapp/wails/v2 => <clonedir>`
示例:
在 Windows 上:
`replace github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2`
在'nix 上:
`replace github.com/wailsapp/wails/v2 => /home/me/projects/wails/v2`
要恢复到稳定版本,请运行:
`go install github.com/wailsapp/wails/v2/cmd/wails@latest`

View File

@@ -0,0 +1,26 @@
# 路由
路由是一种在应用程序中切换视图的流行方式。此页面提供了有关如何执行此操作的一些指导。
## Vue
在 Vue 中推荐的路由方法是[Hash 模式](https://next.router.vuejs.org/guide/essentials/history-mode.html#hash-mode):
```js
import { createRouter, createWebHashHistory } from "vue-router";
const router = createRouter({
history: createWebHashHistory(),
routes: [
//...
],
});
```
## Angular
在 Angular 中推荐的路由方法是[HashLocationStrategy](https://codecraft.tv/courses/angular/routing/routing-strategies/#_hashlocationstrategy):
```ts
RouterModule.forRoot(routes, { useHash: true });
```

View File

@@ -106,7 +106,7 @@ var assets embed.FS
在即将加载前端`index.html`之前,对 [应用启动回调](/docs/reference/options#应用启动回调) 中提供的函数进行回调。一个标准的 Go 上下文被传递给这个方法。 在即将加载前端`index.html`之前,对 [应用启动回调](/docs/reference/options#应用启动回调) 中提供的函数进行回调。一个标准的 Go 上下文被传递给这个方法。
调用运行时需要此上下文,因此标准模式是保存此时对它的引用。在应用程序关闭之前,以同样的方式调用 [应用退出回调](/docs/reference/options#应用退出回调) 回调, 调用运行时需要此上下文,因此标准模式是保存此时对它的引用。在应用程序关闭之前,以同样的方式调用 [应用退出回调](/docs/reference/options#应用退出回调) 回调,
再次使用上下文。当前端完成加载`index.html`中所有资源时,还有一个 [前端 Dom 加载完成回调](/docs/reference/options#前端-dom-加载完成回调) 回调,相当于 Javascript 中的`body onload`事件。 再次使用上下文。当前端完成加载`index.html`中所有资源时,还有一个 [前端 Dom 加载完成回调](/docs/reference/options#前端-dom-加载完成回调) 回调,相当于 Javascript 中的`body onload`事件。还可以通过设置[关闭应用程序之前回调](/docs/reference/options#关闭应用程序之前回调)选项来控制窗口关闭(或应用程序退出)事件。
#### 方法绑定 #### 方法绑定

View File

@@ -34,7 +34,8 @@ func main() {
LogLevel: logger.DEBUG, LogLevel: logger.DEBUG,
OnStartup: app.startup, OnStartup: app.startup,
OnDomReady: app.domready, OnDomReady: app.domready,
OnShutdown: app.shutdown,, OnShutdown: app.shutdown,
OnBeforeClose: app.beforeClose,
WindowStartState: options.Maximised, WindowStartState: options.Maximised,
Bind: []interface{}{ Bind: []interface{}{
app, app,
@@ -245,6 +246,30 @@ func main() {
在前端被销毁之后,就在应用程序终止之前,调用此回调。它给出了应用程序上下文。 在前端被销毁之后,就在应用程序终止之前,调用此回调。它给出了应用程序上下文。
### 关闭应用程序之前回调
名称OnBeforeClose
类型func(ctx context.Context) bool
如果设置了此回调,它将在通过单击窗口关闭按钮或调用`runtime.Quit`即将退出应用程序时被调用. 返回 `true` 将导致应用程序继续,`false` 将继续正常关闭。这有助于与用户确认他们希望退出程序。
示例:
```go title=windowsapp.go
func (b *App) beforeClose(ctx context.Context) (prevent bool) {
dialog, err := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{
Type: runtime.QuestionDialog,
Title: "Quit?",
Message: "Are you sure you want to quit?",
})
if err != nil {
return false
}
return dialog != "Yes"
```
### 窗口启动状态 ### 窗口启动状态
名称WindowStartState 名称WindowStartState
@@ -273,7 +298,15 @@ func main() {
类型:\*windows.Options 类型:\*windows.Options
这定义了[Windows 特定的选项](#windows-特定选项). 这定义了[Windows 特定的选项](#windows-特定选项)。
### Mac
名称Mac
类型:\*mac.Options
这定义了[Mac 特定的选项](#mac-特定选项)。
## Windows 特定选项 ## Windows 特定选项
@@ -301,6 +334,14 @@ func main() {
将此设置为 `true` 将删除标题栏左上角的图标。 将此设置为 `true` 将删除标题栏左上角的图标。
### 启用无边框模式的外边框
名称EnableFramelessBorder
类型bool
如果已激活[无边框](#无边框),则将此设置为`true`将在窗口周围添加边框。这允许隐藏标题栏但仍然在窗口周围有边框。
## Mac 特定选项 ## Mac 特定选项
### 标题栏 ### 标题栏

View File

@@ -63,8 +63,6 @@ type OpenDialogOptions struct {
DefaultFilename string DefaultFilename string
Title string Title string
Filters []FileFilter Filters []FileFilter
AllowFiles bool
AllowDirectories bool
ShowHiddenFiles bool ShowHiddenFiles bool
CanCreateDirectories bool CanCreateDirectories bool
ResolvesAliases bool ResolvesAliases bool
@@ -78,8 +76,6 @@ type OpenDialogOptions struct {
| DefaultFilename | 默认文件名 | ✅ | ✅ | | DefaultFilename | 默认文件名 | ✅ | ✅ |
| Title | 对话框的标题 | ✅ | ✅ | | Title | 对话框的标题 | ✅ | ✅ |
| [Filters](#文件过滤) | 文件过滤器列表 | ✅ | ✅ | | [Filters](#文件过滤) | 文件过滤器列表 | ✅ | ✅ |
| AllowFiles | 允许选择文件 | | ✅ |
| AllowDirectories | 允许选择目录 | | ✅ |
| ShowHiddenFiles | 显示系统隐藏的文件 | | ✅ | | ShowHiddenFiles | 显示系统隐藏的文件 | | ✅ |
| CanCreateDirectories | 允许用户创建目录 | | ✅ | | CanCreateDirectories | 允许用户创建目录 | | ✅ |
| ResolvesAliases | 如果为 true则返回文件而不是别名 | | ✅ | | ResolvesAliases | 如果为 true则返回文件而不是别名 | | ✅ |

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB