diff --git a/v2/cmd/wails/internal/commands/dev/dev.go b/v2/cmd/wails/internal/commands/dev/dev.go index b17b7d433..0095273ed 100644 --- a/v2/cmd/wails/internal/commands/dev/dev.go +++ b/v2/cmd/wails/internal/commands/dev/dev.go @@ -16,10 +16,10 @@ import ( "runtime" "strings" "sync" + "sync/atomic" "syscall" "time" - "github.com/bitfield/script" "github.com/google/shlex" "github.com/wailsapp/wails/v2/cmd/wails/internal" "github.com/wailsapp/wails/v2/internal/gomod" @@ -186,23 +186,15 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM) exitCodeChannel := make(chan int, 1) - // Install if needed - if installCommand := projectConfig.GetDevInstallerCommand(); installCommand != "" { - // Install initial frontend dev dependencies - err = os.Chdir(filepath.Join(cwd, "frontend")) - if err != nil { - return err - } - LogGreen("Installing frontend dependencies...") - pipe := script.Exec(installCommand) - pipe.Wait() - if pipe.Error() != nil { - return pipe.Error() - } - err = os.Chdir(cwd) - if err != nil { + // Build the frontend if requested, but ignore building the application itself. + ignoreFrontend := buildOptions.IgnoreFrontend + if !ignoreFrontend { + logger.Println("Building frontend for development...") + buildOptions.IgnoreApplication = true + if _, err := build.Build(buildOptions); err != nil { return err } + buildOptions.IgnoreApplication = false } // frontend:dev:watcher command. @@ -218,9 +210,11 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { defer closer() } - // Do initial build + // Do initial build but only for the application. logger.Println("Building application for development...") + buildOptions.IgnoreFrontend = true debugBinaryProcess, appBinary, err := restartApp(buildOptions, nil, flags, exitCodeChannel) + buildOptions.IgnoreFrontend = ignoreFrontend || flags.frontendDevServerURL != "" if err != nil { return err } @@ -473,19 +467,30 @@ func runFrontendDevWatcherCommand(cwd string, devCommand string, discoverViteSer LogGreen("Running frontend DevWatcher command: '%s'", devCommand) var wg sync.WaitGroup wg.Add(1) + + const ( + stateRunning int32 = 0 + stateCanceling = 1 + stateStopped = 2 + ) + state := stateRunning go func() { if err := cmd.Wait(); err != nil { - if err.Error() != "exit status 1" { + wasRunning := atomic.CompareAndSwapInt32(&state, stateRunning, stateStopped) + if err.Error() != "exit status 1" && wasRunning { LogRed("Error from DevWatcher '%s': %s", devCommand, err.Error()) } } + atomic.StoreInt32(&state, stateStopped) LogGreen("DevWatcher command exited!") wg.Done() }() return func() { - killProc(cmd, devCommand) - LogGreen("DevWatcher command killed!") + if atomic.CompareAndSwapInt32(&state, stateRunning, stateCanceling) { + LogGreen("Killing DevWatcher command...") + killProc(cmd, devCommand) + } cancel() wg.Wait() }, viteServerURL, nil @@ -674,7 +679,6 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc rebuild = false LogGreen("[Rebuild triggered] files updated") // Try and build the app - buildOptions.IgnoreFrontend = flags.skipFrontend || flags.frontendDevServerURL != "" newBinaryProcess, _, err := restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel) if err != nil { LogRed("Error during build: %s", err.Error()) diff --git a/v2/pkg/commands/build/build.go b/v2/pkg/commands/build/build.go index 8762481bb..c618e28a7 100644 --- a/v2/pkg/commands/build/build.go +++ b/v2/pkg/commands/build/build.go @@ -42,6 +42,7 @@ type Options struct { Compiler string // The compiler command to use SkipModTidy bool // Skip mod tidy before compile IgnoreFrontend bool // Indicates if the frontend does not need building + IgnoreApplication bool // Indicates if the application does not need building OutputFile string // Override the output filename BuildDirectory string // Directory to use for building the application CleanBuildDirectory bool // Indicates if the build directory should be cleaned before building @@ -125,13 +126,35 @@ func Build(options *Options) (string, error) { } } - if !options.IgnoreFrontend || options.ForceBuild { + if !options.IgnoreFrontend { err = builder.BuildFrontend(outputLogger) if err != nil { return "", err } } + compileBinary := "" + if !options.IgnoreApplication { + compileBinary, err = execBuildApplication(builder, options) + if err != nil { + return "", err + } + } + + hookArgs["${bin}"] = compileBinary + for _, hook := range []string{options.Platform + "/" + options.Arch, options.Platform + "/*", "*/*"} { + if err := execPostBuildHook(outputLogger, options, hook, hookArgs); err != nil { + return "", err + } + } + + return compileBinary, nil +} + +func execBuildApplication(builder Builder, options *Options) (string, error) { + // Extract logger + outputLogger := options.Logger + // If we are building for windows, we will need to generate the asset bundle before // compilation. This will be a .syso file in the project root if options.Pack && options.Platform == "windows" { @@ -166,8 +189,7 @@ func Build(options *Options) (string, error) { if options.Verbosity == VERBOSE { outputLogger.Println("\nBuilding AMD64 Target: %s", filepath.Join(options.BuildDirectory, options.OutputFile)) } - err = builder.CompileProject(options) - + err := builder.CompileProject(options) if err != nil { return "", err } @@ -200,10 +222,10 @@ func Build(options *Options) (string, error) { if err != nil { return "", err } - projectData.OutputFilename = outputFile + options.ProjectData.OutputFilename = outputFile options.CompiledBinary = filepath.Join(options.BuildDirectory, outputFile) } else { - err = builder.CompileProject(options) + err := builder.CompileProject(options) if err != nil { return "", err } @@ -217,23 +239,14 @@ func Build(options *Options) (string, error) { outputLogger.Print(" - Packaging application: ") // TODO: Allow cross platform build - err = packageProject(options, runtime.GOOS) + err := packageProject(options, runtime.GOOS) if err != nil { return "", err } outputLogger.Println("Done.") } - compileBinary := options.CompiledBinary - hookArgs["${bin}"] = compileBinary - - for _, hook := range []string{options.Platform + "/" + options.Arch, options.Platform + "/*", "*/*"} { - if err := execPostBuildHook(outputLogger, options, hook, hookArgs); err != nil { - return "", err - } - } - - return compileBinary, nil + return options.CompiledBinary, nil } func execPreBuildHook(outputLogger *clilogger.CLILogger, options *Options, hookIdentifier string, argReplacements map[string]string) error {