mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 05:11:29 +08:00
[v2] DevServer improvements and fixes (#2664)
* [assetserver, darwin] Fix copying request headers by using strdup * [assetserver, linux] Fake some basic http headers for legacy webkit2 versions to support proxying requests to other servers This fixes the devserver on v2 for newer vite versions that use the custom scheme. * [v2, windows] 304 responses are going to hang the WebView2 so prevent them by removing cache related headers in the request. * [v2, dev] Now uses the custom schemes `wails://` on macOS and Linux for all Vite versions. Prevent missing reload after fast multiple savings on Linux and Windows.
This commit is contained in:
parent
22b53192e6
commit
496461920f
@ -318,9 +318,6 @@ func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process
|
|||||||
os.Setenv("assetdir", f.AssetDir)
|
os.Setenv("assetdir", f.AssetDir)
|
||||||
os.Setenv("devserver", f.DevServer)
|
os.Setenv("devserver", f.DevServer)
|
||||||
os.Setenv("frontenddevserverurl", f.FrontendDevServerURL)
|
os.Setenv("frontenddevserverurl", f.FrontendDevServerURL)
|
||||||
if legacyUseDevServerInsteadofCustomScheme {
|
|
||||||
os.Setenv("legacyusedevsererinsteadofcustomscheme", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start up new binary with correct args
|
// Start up new binary with correct args
|
||||||
newProcess := process.NewProcess(appBinary, args...)
|
newProcess := process.NewProcess(appBinary, args...)
|
||||||
|
@ -106,15 +106,13 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if frontendDevServerURL != "" {
|
if frontendDevServerURL != "" {
|
||||||
if os.Getenv("legacyusedevsererinsteadofcustomscheme") != "" {
|
_, port, err := net.SplitHostPort(devServer)
|
||||||
startURL, err := url.Parse("http://" + devServer)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, fmt.Errorf("unable to determine port of DevServer: %s", err)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, "starturl", startURL)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, "assetserverport", port)
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, "frontenddevserverurl", frontendDevServerURL)
|
ctx = context.WithValue(ctx, "frontenddevserverurl", frontendDevServerURL)
|
||||||
|
|
||||||
externalURL, err := url.Parse(frontendDevServerURL)
|
externalURL, err := url.Parse(frontendDevServerURL)
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
@ -78,6 +79,10 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
|||||||
if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil {
|
if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil {
|
||||||
result.startURL = _starturl
|
result.startURL = _starturl
|
||||||
} else {
|
} else {
|
||||||
|
if port, _ := ctx.Value("assetserverport").(string); port != "" {
|
||||||
|
result.startURL.Host = net.JoinHostPort(result.startURL.Host+".localhost", port)
|
||||||
|
}
|
||||||
|
|
||||||
var bindings string
|
var bindings string
|
||||||
var err error
|
var err error
|
||||||
if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated {
|
if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated {
|
||||||
|
@ -78,6 +78,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -149,6 +150,10 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
|||||||
if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil {
|
if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil {
|
||||||
result.startURL = _starturl
|
result.startURL = _starturl
|
||||||
} else {
|
} else {
|
||||||
|
if port, _ := ctx.Value("assetserverport").(string); port != "" {
|
||||||
|
result.startURL.Host = net.JoinHostPort(result.startURL.Host+".localhost", port)
|
||||||
|
}
|
||||||
|
|
||||||
var bindings string
|
var bindings string
|
||||||
var err error
|
var err error
|
||||||
if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated {
|
if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -92,6 +93,10 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if port, _ := ctx.Value("assetserverport").(string); port != "" {
|
||||||
|
result.startURL.Host = net.JoinHostPort(result.startURL.Host, port)
|
||||||
|
}
|
||||||
|
|
||||||
var bindings string
|
var bindings string
|
||||||
var err error
|
var err error
|
||||||
if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated {
|
if _obfuscated, _ := ctx.Value("obfuscated").(bool); !_obfuscated {
|
||||||
@ -589,8 +594,16 @@ func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, arg
|
|||||||
headers = append(headers, fmt.Sprintf("%s: %s", k, strings.Join(v, ",")))
|
headers = append(headers, fmt.Sprintf("%s: %s", k, strings.Join(v, ",")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code := rw.Code
|
||||||
|
if code == http.StatusNotModified {
|
||||||
|
// WebView2 has problems when a request returns a 304 status code and the WebView2 is going to hang for other
|
||||||
|
// requests including IPC calls.
|
||||||
|
f.logger.Error("%s: AssetServer returned 304 - StatusNotModified which are going to hang WebView2, changed code to 505 - StatusInternalServerError", uri)
|
||||||
|
code = http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
|
||||||
env := f.chromium.Environment()
|
env := f.chromium.Environment()
|
||||||
response, err := env.CreateWebResourceResponse(rw.Body.Bytes(), rw.Code, http.StatusText(rw.Code), strings.Join(headers, "\n"))
|
response, err := env.CreateWebResourceResponse(rw.Body.Bytes(), code, http.StatusText(code), strings.Join(headers, "\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.logger.Error("CreateWebResourceResponse Error: %s", err)
|
f.logger.Error("CreateWebResourceResponse Error: %s", err)
|
||||||
return
|
return
|
||||||
@ -829,6 +842,12 @@ func coreWebview2RequestToHttpRequest(coreReq *edge.ICoreWebView2WebResourceRequ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WebView2 has problems when a request returns a 304 status code and the WebView2 is going to hang for other
|
||||||
|
// requests including IPC calls.
|
||||||
|
// So prevent 304 status codes by removing the headers that are used in combinationwith caching.
|
||||||
|
header.Del("If-Modified-Since")
|
||||||
|
header.Del("If-None-Match")
|
||||||
|
|
||||||
method, err := coreReq.GetMethod()
|
method, err := coreReq.GetMethod()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("GetMethod Error: %s", err)
|
return nil, fmt.Errorf("GetMethod Error: %s", err)
|
||||||
|
@ -97,13 +97,17 @@ func (d *DevWebServer) Run(ctx context.Context) error {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assetServer, err := assetserver.NewDevAssetServer(assetHandler, wsHandler, bindingsJSON, ctx.Value("assetdir") != nil, myLogger, runtime.RuntimeAssetsBundle)
|
assetServer, err := assetserver.NewDevAssetServer(assetHandler, bindingsJSON, ctx.Value("assetdir") != nil, myLogger, runtime.RuntimeAssetsBundle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.server.Any("/*", func(c echo.Context) error {
|
d.server.Any("/*", func(c echo.Context) error {
|
||||||
assetServer.ServeHTTP(c.Response(), c.Request())
|
if c.IsWebSocket() {
|
||||||
|
wsHandler.ServeHTTP(c.Response(), c.Request())
|
||||||
|
} else {
|
||||||
|
assetServer.ServeHTTP(c.Response(), c.Request())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ type RuntimeHandler interface {
|
|||||||
|
|
||||||
type AssetServer struct {
|
type AssetServer struct {
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
wsHandler http.Handler
|
|
||||||
runtimeJS []byte
|
runtimeJS []byte
|
||||||
ipcJS func(*http.Request) []byte
|
ipcJS func(*http.Request) []byte
|
||||||
|
|
||||||
@ -107,12 +106,8 @@ func (d *AssetServer) AddPluginScript(pluginName string, script string) {
|
|||||||
|
|
||||||
func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
if isWebSocket(req) {
|
if isWebSocket(req) {
|
||||||
// Forward WebSockets to the distinct websocket handler if it exists
|
// WebSockets are not supported by the AssetServer
|
||||||
if wsHandler := d.wsHandler; wsHandler != nil {
|
rw.WriteHeader(http.StatusNotImplemented)
|
||||||
wsHandler.ServeHTTP(rw, req)
|
|
||||||
} else {
|
|
||||||
rw.WriteHeader(http.StatusNotImplemented)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +13,12 @@ The assetserver for the dev mode.
|
|||||||
Depending on the UserAgent it injects a websocket based IPC script into `index.html` or the default desktop IPC. The
|
Depending on the UserAgent it injects a websocket based IPC script into `index.html` or the default desktop IPC. The
|
||||||
default desktop IPC is injected when the webview accesses the devserver.
|
default desktop IPC is injected when the webview accesses the devserver.
|
||||||
*/
|
*/
|
||||||
func NewDevAssetServer(handler http.Handler, wsHandler http.Handler, bindingsJSON string, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) {
|
func NewDevAssetServer(handler http.Handler, bindingsJSON string, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) {
|
||||||
result, err := NewAssetServerWithHandler(handler, bindingsJSON, servingFromDisk, logger, runtime)
|
result, err := NewAssetServerWithHandler(handler, bindingsJSON, servingFromDisk, logger, runtime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result.wsHandler = wsHandler
|
|
||||||
result.appendSpinnerToBody = true
|
result.appendSpinnerToBody = true
|
||||||
result.ipcJS = func(req *http.Request) []byte {
|
result.ipcJS = func(req *http.Request) []byte {
|
||||||
if strings.Contains(req.UserAgent(), WailsUserAgentValue) {
|
if strings.Contains(req.UserAgent(), WailsUserAgentValue) {
|
||||||
|
@ -8,6 +8,7 @@ package webview
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <WebKit/WebKit.h>
|
#import <WebKit/WebKit.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static void URLSchemeTaskRetain(void *wkUrlSchemeTask) {
|
static void URLSchemeTaskRetain(void *wkUrlSchemeTask) {
|
||||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||||
@ -44,9 +45,7 @@ static const char * URLSchemeTaskRequestHeadersJSON(void *wkUrlSchemeTask) {
|
|||||||
NSString* headerString = [[[NSString alloc] initWithData:headerData encoding:NSUTF8StringEncoding] autorelease];
|
NSString* headerString = [[[NSString alloc] initWithData:headerData encoding:NSUTF8StringEncoding] autorelease];
|
||||||
const char * headerJSON = [headerString UTF8String];
|
const char * headerJSON = [headerString UTF8String];
|
||||||
|
|
||||||
char * headersOut = malloc(strlen(headerJSON));
|
return strdup(headerJSON);
|
||||||
strcpy(headersOut, headerJSON);
|
|
||||||
return headersOut;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,12 @@ func webkit_uri_scheme_request_get_http_method(_ *C.WebKitURISchemeRequest) stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
func webkit_uri_scheme_request_get_http_headers(_ *C.WebKitURISchemeRequest) http.Header {
|
func webkit_uri_scheme_request_get_http_headers(_ *C.WebKitURISchemeRequest) http.Header {
|
||||||
return http.Header{}
|
// Fake some basic default headers that are needed if e.g. request are being proxied to the an external sever, like
|
||||||
|
// we do in the devserver.
|
||||||
|
h := http.Header{}
|
||||||
|
h.Add("Accept", "*/*")
|
||||||
|
h.Add("User-Agent", "wails.io/605.1.15")
|
||||||
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func webkit_uri_scheme_request_get_http_body(_ *C.WebKitURISchemeRequest) io.ReadCloser {
|
func webkit_uri_scheme_request_get_http_body(_ *C.WebKitURISchemeRequest) io.ReadCloser {
|
||||||
|
@ -17,6 +17,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|
||||||
- The Go WebView2Loader allowed env variable and registry overrides to change the behaviour of WebView2. This is not possible when using the native WebView2Loader with Wails and should not be possible according to [PR](https://github.com/wailsapp/wails/pull/1771). Changed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2668)
|
- The Go WebView2Loader allowed env variable and registry overrides to change the behaviour of WebView2. This is not possible when using the native WebView2Loader with Wails and should not be possible according to [PR](https://github.com/wailsapp/wails/pull/1771). Changed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2668)
|
||||||
|
- `wails dev` now uses the custom schemes `wails://` on macOS and Linux for all Vite versions. This also fixes missing reloads after multiple fast savings on Linux and Windows. Changed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2664)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed segfaults during fast reloads of requests on macOS. Fixed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2664)
|
||||||
|
- Fixed devserver on Linux for older WebKit2GTK versions < 2.36. Fixed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2664)
|
||||||
|
- Fixed devserver on Windows that might have triggered the WebView2 into a hang. Fixed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2664)
|
||||||
|
|
||||||
## v2.5.0 - 2023-05-13
|
## v2.5.0 - 2023-05-13
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user