github.com/vugu/vugu@v0.3.6-0.20240430171613-3f6f402e014b/devutil/static.go (about) 1 package devutil 2 3 import ( 4 "net/http" 5 "os" 6 "strings" 7 "time" 8 ) 9 10 // DefaultIndex is the default index.html content for a development Vugu app. 11 // The exact text `<title>Vugu App</title>`, `<!-- styles -->` and `<!-- scripts -->` 12 // are meant to be replaced as needed if you quickly need to hack in CSS or 13 // JS references for a development Vugu application. If you need more control 14 // than that, just copy it into your application. 15 var DefaultIndex = StaticContent(`<!doctype html> 16 <html> 17 <head> 18 <title>Vugu App</title> 19 <meta charset="utf-8"/> 20 <!-- styles --> 21 </head> 22 <body> 23 <div id="vugu_mount_point"> 24 <img style="position: absolute; top: 50%; left: 50%;" src="https://cdnjs.cloudflare.com/ajax/libs/galleriffic/2.0.1/css/loader.gif"> 25 </div> 26 <script src="https://cdn.jsdelivr.net/npm/text-encoding@0.7.0/lib/encoding.min.js"></script> <!-- MS Edge polyfill --> 27 <script src="/wasm_exec.js"></script> 28 <!-- scripts --> 29 <script> 30 var wasmSupported = (typeof WebAssembly === "object"); 31 if (wasmSupported) { 32 if (!WebAssembly.instantiateStreaming) { // polyfill 33 WebAssembly.instantiateStreaming = async (resp, importObject) => { 34 const source = await (await resp).arrayBuffer(); 35 return await WebAssembly.instantiate(source, importObject); 36 }; 37 } 38 var mainWasmReq = fetch("/main.wasm").then(function(res) { 39 if (res.ok) { 40 const go = new Go(); 41 WebAssembly.instantiateStreaming(res, go.importObject).then((result) => { 42 go.run(result.instance); 43 }); 44 } else { 45 res.text().then(function(txt) { 46 var el = document.getElementById("vugu_mount_point"); 47 el.style = 'font-family: monospace; background: black; color: red; padding: 10px'; 48 el.innerText = txt; 49 }) 50 } 51 }) 52 } else { 53 document.getElementById("vugu_mount_point").innerHTML = 'This application requires WebAssembly support. Please upgrade your browser.'; 54 } 55 </script> 56 </body> 57 </html> 58 `) 59 60 // DefaultAutoReloadIndex is like DefaultIndex but also includes a script tag to load 61 // auto-reload.js from the default URL. 62 var DefaultAutoReloadIndex = DefaultIndex.Replace( 63 "<!-- scripts -->", 64 "<script src=\"http://localhost:8324/auto-reload.js\"></script>\n<!-- scripts -->") 65 66 var startupTime = time.Now() 67 68 // StaticContent implements http.Handler and serves the HTML content in this string. 69 type StaticContent string 70 71 // ServeHTTP implements http.Handler 72 func (sc StaticContent) ServeHTTP(w http.ResponseWriter, r *http.Request) { 73 http.ServeContent(w, r, r.URL.Path, startupTime, strings.NewReader(string(sc))) 74 } 75 76 // Replace performs a single string replacement on this StaticContent and returns the new value. 77 func (sc StaticContent) Replace(old, new string) StaticContent { 78 return StaticContent(strings.Replace(string(sc), old, new, 1)) 79 } 80 81 // StaticFilePath implements http.Handler and serves the file at this path. 82 type StaticFilePath string 83 84 // ServeHTTP implements http.Handler 85 func (sfp StaticFilePath) ServeHTTP(w http.ResponseWriter, r *http.Request) { 86 f, err := os.Open(string(sfp)) 87 if err != nil { 88 msg, code := toHTTPError(err) 89 http.Error(w, msg, code) 90 return 91 } 92 defer f.Close() 93 st, err := f.Stat() 94 if err != nil { 95 msg, code := toHTTPError(err) 96 http.Error(w, msg, code) 97 return 98 } 99 http.ServeContent(w, r, r.URL.Path, st.ModTime(), f) 100 }