mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
Browser Live Reload with the upcoming Iris CLI :)
Former-commit-id: dd061ca2977d0d5456f72ac05b6a42d9bb0c2697
This commit is contained in:
parent
5ff2ed016d
commit
4cfd3c7a05
|
@ -706,7 +706,7 @@ func (api *APIBuilder) Use(handlers ...context.Handler) {
|
|||
// It doesn't care about call order, it will prepend the handlers to all
|
||||
// existing routes and the future routes that may being registered.
|
||||
//
|
||||
// The difference from `.DoneGLobal` is that this/or these Handler(s) are being always running first.
|
||||
// The difference from `.DoneGlobal` is that this/or these Handler(s) are being always running first.
|
||||
// Use of `ctx.Next()` of those handler(s) is necessary to call the main handler or the next middleware.
|
||||
// It's always a good practise to call it right before the `Application#Run` function.
|
||||
func (api *APIBuilder) UseGlobal(handlers ...context.Handler) {
|
||||
|
|
113
iris.go
113
iris.go
|
@ -2,7 +2,7 @@ package iris
|
|||
|
||||
import (
|
||||
// std packages
|
||||
|
||||
"bytes"
|
||||
stdContext "context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -11,12 +11,11 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/golog"
|
||||
|
||||
// context for the handlers
|
||||
"github.com/kataras/iris/v12/context"
|
||||
// core packages, required to build the application
|
||||
|
@ -36,6 +35,9 @@ import (
|
|||
// handlers used in `Default` function
|
||||
requestLogger "github.com/kataras/iris/v12/middleware/logger"
|
||||
"github.com/kataras/iris/v12/middleware/recover"
|
||||
|
||||
"github.com/kataras/golog"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Version is the current version number of the Iris Web Framework.
|
||||
|
@ -875,6 +877,11 @@ func (app *Application) Build() error {
|
|||
|
||||
if !app.Router.Downgraded() {
|
||||
// router
|
||||
|
||||
if err := app.tryInjectLiveReload(); err != nil {
|
||||
rp.Errf("LiveReload: init: failed: %v", err)
|
||||
}
|
||||
|
||||
// create the request handler, the default routing handler
|
||||
routerHandler := router.NewDefaultHandler()
|
||||
err := app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder, false)
|
||||
|
@ -943,6 +950,106 @@ func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// tryInjectLiveReload tries to check if this application
|
||||
// runs under https://github.com/kataras/iris-cli and if so
|
||||
// then it checks if the livereload is enabled and then injects
|
||||
// the watch listener (js script) on every HTML response.
|
||||
// It has a slight performance cost but
|
||||
// this (iris-cli with watch and livereload enabled)
|
||||
// is meant to be used only in development mode.
|
||||
// It does a full reload at the moment and if the port changed
|
||||
// at runtime it will fire 404 instead of redirecting to the correct port (that's a TODO).
|
||||
//
|
||||
// tryInjectLiveReload runs right before Build -> BuildRouter.
|
||||
func (app *Application) tryInjectLiveReload() error {
|
||||
conf := struct {
|
||||
Running bool `yaml:"Running,omitempty"`
|
||||
LiveReload struct {
|
||||
Disable bool `yaml:"Disable"`
|
||||
Port int `yaml:"Port"`
|
||||
} `yaml:"LiveReload"`
|
||||
}{}
|
||||
// defaults to disabled here.
|
||||
conf.LiveReload.Disable = true
|
||||
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, path := range []string{".iris.yml" /*, "../.iris.yml", "../../.iris.yml" */} {
|
||||
path = filepath.Join(wd, path)
|
||||
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
inFile, err := os.OpenFile(path, os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dec := yaml.NewDecoder(inFile)
|
||||
err = dec.Decode(&conf)
|
||||
inFile.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !conf.Running || conf.LiveReload.Disable {
|
||||
return nil
|
||||
}
|
||||
|
||||
scriptReloadJS := []byte(fmt.Sprintf(`<script>(function () {
|
||||
const scheme = document.location.protocol == "https:" ? "wss" : "ws";
|
||||
const endpoint = scheme + "://" + document.location.hostname + ":%d/livereload";
|
||||
|
||||
w = new WebSocket(endpoint);
|
||||
w.onopen = function () {
|
||||
console.info("LiveReload: initialization");
|
||||
};
|
||||
w.onclose = function () {
|
||||
console.info("LiveReload: terminated");
|
||||
};
|
||||
w.onmessage = function (message) {
|
||||
// NOTE: full-reload, at least for the moment. Also if backend changed its port then we will get 404 here.
|
||||
window.location.reload();
|
||||
};
|
||||
}());</script>`, conf.LiveReload.Port))
|
||||
|
||||
bodyCloseTag := []byte("</body>")
|
||||
|
||||
app.WrapRouter(func(w http.ResponseWriter, r *http.Request, _ http.HandlerFunc) {
|
||||
ctx := app.ContextPool.Acquire(w, r)
|
||||
rec := ctx.Recorder() // Record everything and write all in once at the Context release.
|
||||
app.ServeHTTPC(ctx) // We directly call request handler with Context.
|
||||
|
||||
if strings.HasPrefix(ctx.GetContentType(), "text/html") {
|
||||
// delete(rec.Header(), context.ContentLengthHeaderKey)
|
||||
|
||||
body := rec.Body()
|
||||
|
||||
if idx := bytes.LastIndex(body, bodyCloseTag); idx > 0 {
|
||||
// add the script right before last </body>.
|
||||
body = append(body[:idx], bytes.Replace(body[idx:], bodyCloseTag, append(scriptReloadJS, bodyCloseTag...), 1)...)
|
||||
rec.SetBody(body)
|
||||
} else {
|
||||
// Just append it.
|
||||
rec.Write(scriptReloadJS)
|
||||
}
|
||||
|
||||
if _, has := rec.Header()[context.ContentLengthHeaderKey]; has {
|
||||
rec.Header().Set(context.ContentLengthHeaderKey, fmt.Sprintf("%d", len(rec.Body())))
|
||||
}
|
||||
}
|
||||
|
||||
app.ContextPool.Release(ctx)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://ngrok.com/docs
|
||||
func (app *Application) tryStartTunneling() {
|
||||
if !app.config.Tunneling.isEnabled() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user