diff --git a/v2/cmd/wails/internal/commands/dev/dev.go b/v2/cmd/wails/internal/commands/dev/dev.go index df452d1f..169c6168 100644 --- a/v2/cmd/wails/internal/commands/dev/dev.go +++ b/v2/cmd/wails/internal/commands/dev/dev.go @@ -63,6 +63,7 @@ type devFlags struct { compilerCommand string assetDir string extensions string + reloadDirs string openBrowser bool noReload bool wailsjsdir string @@ -83,8 +84,9 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { 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("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("reloaddirs", "Additional directories to trigger reloads (comma separated)", &flags.reloadDirs) 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) @@ -301,10 +303,6 @@ func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, e 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 } @@ -313,9 +311,19 @@ func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, e projectConfig.AssetDirectory = filepath.ToSlash(flags.assetDir) } - flags.assetDir, err = filepath.Abs(flags.assetDir) - if err != nil { - return nil, err + if flags.assetDir != "" { + flags.assetDir, err = filepath.Abs(flags.assetDir) + 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) } if flags.devServerURL == defaultDevServerURL && projectConfig.DevServerURL != defaultDevServerURL && projectConfig.DevServerURL != "" { @@ -503,11 +511,26 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc newBinaryProcess *process.Process ) 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 interval := time.Duration(flags.debounceMS) * time.Millisecond timer := time.NewTimer(interval) rebuild := false reload := false + assetDir := "" + changedPaths := map[string]struct{}{} for quit == false { //reload := false select { @@ -519,12 +542,13 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc // Check for file writes if item.Op&fsnotify.Write == fsnotify.Write { // Ignore directories - if fs.DirExists(item.Name) { + itemName := item.Name + if fs.DirExists(itemName) { continue } // Iterate all file patterns - ext := filepath.Ext(item.Name) + ext := filepath.Ext(itemName) if ext != "" { ext = ext[1:] if _, exists := extensionsThatTriggerARebuild[ext]; exists { @@ -534,9 +558,17 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc } } - if strings.HasPrefix(item.Name, flags.assetDir) { - reload = true + for _, reloadDir := range dirsThatTriggerAReload { + if strings.HasPrefix(itemName, reloadDir) { + reload = true + break + } } + + if !reload { + changedPaths[filepath.Dir(itemName)] = struct{}{} + } + timer.Reset(interval) } // Check for new directories @@ -568,6 +600,35 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc 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 { reload = false _, err = http.Get("http://localhost:34115/wails/reload") diff --git a/v2/cmd/wails/internal/commands/generate/template/base/NEXTSTEPS.md.template b/v2/cmd/wails/internal/commands/generate/template/base/NEXTSTEPS.md.template index a357acd8..5363d10f 100644 --- a/v2/cmd/wails/internal/commands/generate/template/base/NEXTSTEPS.md.template +++ b/v2/cmd/wails/internal/commands/generate/template/base/NEXTSTEPS.md.template @@ -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. 2. Update `README.md`. 3. Edit `wails.json` and ensure all fields are correct, especially: - - `assetdir` - path to your assets - `wailsjsdir` - path to generate wailsjs modules - `frontend:install` - The command to install your frontend dependencies - `frontend:build` - The command to build your frontend diff --git a/v2/cmd/wails/internal/commands/generate/template/base/wails.tmpl.json b/v2/cmd/wails/internal/commands/generate/template/base/wails.tmpl.json index b8d08108..63c4e6fe 100644 --- a/v2/cmd/wails/internal/commands/generate/template/base/wails.tmpl.json +++ b/v2/cmd/wails/internal/commands/generate/template/base/wails.tmpl.json @@ -1,7 +1,6 @@ { "name": "{{.ProjectName}}", "outputfilename": "{{.BinaryName}}", - "assetdir": "frontend/dist", "frontend:install": "npm install", "frontend:build": "npm run build", "author": { diff --git a/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/workspace.tmpl.xml b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/workspace.tmpl.xml index 42f98045..9727844b 100644 --- a/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/workspace.tmpl.xml +++ b/v2/cmd/wails/internal/commands/initialise/templates/ides/goland/workspace.tmpl.xml @@ -36,7 +36,6 @@ - diff --git a/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/launch.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/launch.tmpl.json index d03d5ccd..005f9bc4 100644 --- a/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/launch.tmpl.json +++ b/v2/cmd/wails/internal/commands/initialise/templates/ides/vscode/launch.tmpl.json @@ -9,11 +9,7 @@ "program": "${workspaceFolder}/{{.PathToDesktopBinary}}", "preLaunchTask": "build", "cwd": "${workspaceFolder}", - "env": {}, - "args": [ - "-assetdir", - "{{.AssetDir}}" - ] + "env": {} } ] } \ No newline at end of file diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates.go b/v2/cmd/wails/internal/commands/initialise/templates/templates.go index 64191678..2c81e05b 100644 --- a/v2/cmd/wails/internal/commands/initialise/templates/templates.go +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates.go @@ -42,7 +42,6 @@ type Data struct { AuthorNameAndEmail string WailsDirectory string GoSDKPath string - AssetDir string WindowsFlags string CGOEnabled string OutputFile string @@ -60,7 +59,6 @@ type Options struct { InitGit bool AuthorName string AuthorEmail string - AssetDir string IDE string ProjectNameFilename string // The project name but as a valid filename WailsVersion string @@ -261,7 +259,6 @@ func Install(options *Options) (bool, *Template, error) { AuthorName: options.AuthorName, WailsVersion: options.WailsVersion, GoSDKPath: options.GoSDKPath, - AssetDir: options.AssetDir, } // Create a formatted name and email combo. @@ -408,22 +405,6 @@ func installIDEFiles(o ideOptions) error { 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.WindowsFlags = "" diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/wails.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/wails.tmpl.json index 5bf6b2a9..eb4c38f7 100644 --- a/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/wails.tmpl.json +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/svelte/wails.tmpl.json @@ -1,7 +1,6 @@ { "name": "{{.ProjectName}}", "outputfilename": "{{.BinaryName}}", - "assetdir": "frontend/dist", "frontend:install": "npm install", "frontend:build": "npm run build", "wailsjsdir": "./frontend", diff --git a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/wails.tmpl.json b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/wails.tmpl.json index a4f2bc2d..b010f320 100644 --- a/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/wails.tmpl.json +++ b/v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/wails.tmpl.json @@ -1,7 +1,6 @@ { "name": "{{.ProjectName}}", "outputfilename": "{{.BinaryName}}", - "assetdir": "frontend/src", "wailsjsdir": "./frontend", "author": { "name": "{{.AuthorName}}", diff --git a/v2/internal/appng/app_dev.go b/v2/internal/appng/app_dev.go index b232e21d..cf1bcdef 100644 --- a/v2/internal/appng/app_dev.go +++ b/v2/internal/appng/app_dev.go @@ -5,7 +5,10 @@ package appng import ( "context" + "embed" "flag" + "fmt" + iofs "io/fs" "os" "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 != "" { ctx = context.WithValue(ctx, "devserverurl", devServerURL) } - if assetdir != "" { - ctx = context.WithValue(ctx, "assetdir", assetdir) - } if loglevel != "" { level, err := pkglogger.StringToLogLevel(loglevel) @@ -203,3 +224,32 @@ func generateBindings(bindings *binding.Bindings) error { 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 +} diff --git a/v2/internal/frontend/assetserver/assetserver_browser_dev.go b/v2/internal/frontend/assetserver/assetserver_browser_dev.go index 296f98a7..93de7607 100644 --- a/v2/internal/frontend/assetserver/assetserver_browser_dev.go +++ b/v2/internal/frontend/assetserver/assetserver_browser_dev.go @@ -5,10 +5,13 @@ package assetserver import ( "bytes" + "context" + "io/fs" + "strings" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" - "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/internal/logger" "golang.org/x/net/html" - "path/filepath" ) /* @@ -18,35 +21,41 @@ It injects a websocket based IPC script into `index.html`. */ -import ( - "os" -) - type BrowserAssetServer struct { - runtimeJS []byte - assetdir string - appOptions *options.App + assets fs.FS + runtimeJS []byte + logger *logger.Logger } -func NewBrowserAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*BrowserAssetServer, error) { - result := &BrowserAssetServer{ - assetdir: assetdir, - appOptions: appOptions, +func NewBrowserAssetServer(ctx context.Context, assets fs.FS, bindingsJSON string) (*BrowserAssetServer, error) { + result := &BrowserAssetServer{} + _logger := ctx.Value("logger") + 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 buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n") buffer.Write(runtime.RuntimeDesktopJS) result.runtimeJS = buffer.Bytes() + return result, nil } -func (a *BrowserAssetServer) loadFileFromDisk(filename string) ([]byte, error) { - return os.ReadFile(filepath.Join(a.assetdir, filename)) +func (d *BrowserAssetServer) LogDebug(message string, args ...interface{}) { + if d.logger != nil { + d.logger.Debug("[BrowserAssetServer] "+message, args...) + } } func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) { - indexHTML, err := a.loadFileFromDisk("index.html") + indexHTML, err := fs.ReadFile(a.assets, "index.html") if err != nil { return nil, err } @@ -96,7 +105,9 @@ func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) { case "/wails/ipc.js": content = runtime.WebsocketIPC default: - content, err = a.loadFileFromDisk(filename) + filename = strings.TrimPrefix(filename, "/") + a.LogDebug("Loading file: %s", filename) + content, err = fs.ReadFile(a.assets, filename) } if err != nil { return nil, "", err diff --git a/v2/internal/frontend/assetserver/assetserver_common.go b/v2/internal/frontend/assetserver/assetserver_common.go new file mode 100644 index 00000000..d8ab4c9c --- /dev/null +++ b/v2/internal/frontend/assetserver/assetserver_common.go @@ -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 +} diff --git a/v2/internal/frontend/assetserver/assetserver_desktop.go b/v2/internal/frontend/assetserver/assetserver_desktop.go index 1ec4a753..6d4c15b2 100644 --- a/v2/internal/frontend/assetserver/assetserver_desktop.go +++ b/v2/internal/frontend/assetserver/assetserver_desktop.go @@ -3,26 +3,21 @@ package assetserver import ( "bytes" "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" "log" - "path/filepath" "strings" + + "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/wailsapp/wails/v2/internal/logger" ) type DesktopAssetServer struct { - assets debme.Debme + assets fs.FS runtimeJS []byte - assetdir string 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{} _logger := ctx.Value("logger") @@ -30,22 +25,18 @@ func NewDesktopAssetServer(ctx context.Context, assets embed.FS, bindingsJSON st result.logger = _logger.(*logger.Logger) } - _assetdir := ctx.Value("assetdir") - if _assetdir != nil { - result.assetdir = _assetdir.(string) - absdir, err := filepath.Abs(result.assetdir) - if err != nil { - return nil, err - } - result.LogDebug("Loading assets from: %s", absdir) + var err error + result.assets, err = prepareAssetsForServing(assets) + 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(assets) - return result, err + + return result, nil } 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) { - indexHTML, err := a.ReadFile("index.html") + indexHTML, err := fs.ReadFile(a.assets, "index.html") if err != nil { return nil, err } @@ -146,7 +82,9 @@ func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) { case "/wails/ipc.js": content = runtime.DesktopIPC 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 { return nil, "", err diff --git a/v2/internal/frontend/assetserver/assetserver_desktop_dev.go b/v2/internal/frontend/assetserver/assetserver_desktop_dev.go deleted file mode 100644 index 42726ae3..00000000 --- a/v2/internal/frontend/assetserver/assetserver_desktop_dev.go +++ /dev/null @@ -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)) -} diff --git a/v2/internal/frontend/assetserver/assetserver_desktop_production.go b/v2/internal/frontend/assetserver/assetserver_desktop_production.go deleted file mode 100644 index fb09ee1a..00000000 --- a/v2/internal/frontend/assetserver/assetserver_desktop_production.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build production - -package assetserver - -func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) { - return a.assets.ReadFile(filename) -} diff --git a/v2/internal/frontend/devserver/devserver.go b/v2/internal/frontend/devserver/devserver.go index e73828c5..3dcb84c5 100644 --- a/v2/internal/frontend/devserver/devserver.go +++ b/v2/internal/frontend/devserver/devserver.go @@ -10,7 +10,6 @@ import ( "fmt" "io/fs" "log" - "path/filepath" "strings" "sync" "time" @@ -50,6 +49,11 @@ func (d *DevWebServer) WindowReload() { func (d *DevWebServer) Run(ctx context.Context) error { 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.WindowReload() d.desktopFrontend.WindowReload() @@ -100,25 +104,14 @@ func (d *DevWebServer) Run(ctx context.Context) error { _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") + bindingsJSON, err := d.appBindings.ToJSON() + if err != nil { + log.Fatal(err) } - 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.assetServer, err = assetserver.NewBrowserAssetServer(ctx, d.appoptions.Assets, bindingsJSON) + if err != nil { + log.Fatal(err) } d.server.Get("*", d.loadAsset) diff --git a/v2/internal/fs/fs.go b/v2/internal/fs/fs.go index 862e003c..0f6fbb7e 100644 --- a/v2/internal/fs/fs.go +++ b/v2/internal/fs/fs.go @@ -4,9 +4,11 @@ import ( "crypto/md5" "fmt" "io" + "io/fs" "os" "path/filepath" "runtime" + "strings" "unsafe" "github.com/leaanthony/slicer" @@ -394,3 +396,30 @@ func MoveDirExtended(src string, dst string, ignore []string) (err error) { 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 +} diff --git a/v2/internal/project/project.go b/v2/internal/project/project.go index 192f26e7..96d43358 100644 --- a/v2/internal/project/project.go +++ b/v2/internal/project/project.go @@ -15,6 +15,8 @@ type Project struct { Name string `json:"name"` AssetDirectory string `json:"assetdir"` + ReloadDirectories string `json:"reloaddirs"` + BuildCommand string `json:"frontend:build"` InstallCommand string `json:"frontend:install"` DevCommand string `json:"frontend:dev"` diff --git a/v2/pkg/options/options.go b/v2/pkg/options/options.go index 717fd93d..db224a5a 100644 --- a/v2/pkg/options/options.go +++ b/v2/pkg/options/options.go @@ -2,11 +2,11 @@ package options import ( "context" - "embed" - "github.com/wailsapp/wails/v2/pkg/options/linux" + "io/fs" "log" "runtime" + "github.com/wailsapp/wails/v2/pkg/options/linux" "github.com/wailsapp/wails/v2/pkg/options/mac" "github.com/wailsapp/wails/v2/pkg/options/windows" @@ -41,7 +41,7 @@ type App struct { HideWindowOnClose bool AlwaysOnTop bool RGBA *RGBA - Assets embed.FS + Assets fs.FS Menu *menu.Menu Logger logger.Logger `json:"-"` LogLevel logger.LogLevel