Skip to content

Commit

Permalink
feat: vue-run supports compressed exports
Browse files Browse the repository at this point in the history
  • Loading branch information
sohaha committed Sep 23, 2020
1 parent 6029e63 commit 64eb188
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 38 deletions.
3 changes: 1 addition & 2 deletions app/build/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"regexp"
"strings"

"github.com/sohaha/zlsgo/zenv"
"github.com/sohaha/zlsgo/zshell"
"github.com/sohaha/zlsgo/zutil"

Expand Down Expand Up @@ -92,7 +91,7 @@ func CommadString(os []OSData, isVendor, isCGO bool, packageName, outDir string)
commad = []string{cmd}
if outDir != "" {
name := packageName
commad = []string{cmd + " -o=" + outDir + zutil.IfVal(zenv.IsWin(), name+".exe", name).(string)}
commad = []string{cmd + " -o=" + outDir + zutil.IfVal(zutil.IsWin(), name+".exe", name).(string)}
}
}
return
Expand Down
4 changes: 2 additions & 2 deletions app/more/install.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package more

import (
"github.com/sohaha/zlsgo/zenv"
"github.com/sohaha/zlsgo/zfile"
"github.com/sohaha/zlsgo/zutil"
"github.com/sohaha/zzz/util"
"io"
"os"
Expand Down Expand Up @@ -36,7 +36,7 @@ func (m *Methods) Install(vars []string) {
}

func copyMain(src, dest string) (data string, err error) {
if zenv.IsWin() {
if zutil.IsWin() {
data, err = util.ExecCommand("cmd", "/C", "copy", src, dest)
} else {
data, err = util.ExecCommand("cp", src, dest)
Expand Down
4 changes: 2 additions & 2 deletions app/root/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"time"

"github.com/sohaha/zlsgo/zenv"
"github.com/sohaha/zlsgo/zutil"
)

var ExampleConfig = `# zzz 主配置
Expand Down Expand Up @@ -127,7 +127,7 @@ func GetExampleConfig(version string) string {

func GetExampleWatchConfig(version string) string {
name := "tmpApp"
if zenv.IsWin() {
if zutil.IsWin() {
name = "tmpApp.exe"
}
return fmt.Sprintf(ExampleWatchConfig, version, name, name)
Expand Down
10 changes: 5 additions & 5 deletions app/stress/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ func CreateTextStressSummary(reqStatSummary RequestStatSummary) string {
summary += fmt.Sprintf("Total time: %d ms\n", reqStatSummary.endTime.Sub(reqStatSummary.startTime).Nanoseconds()/1000000)

summary += "\nData Transferred\n"
summary += fmt.Sprintf("Mean query: %s\n", zfile.FileSizeFormat(uint64(reqStatSummary.avgDataTransferred)))
summary += fmt.Sprintf("Largest query: %s\n", zfile.FileSizeFormat(uint64(reqStatSummary.maxDataTransferred)))
summary += fmt.Sprintf("Smallest query: %s\n", zfile.FileSizeFormat(uint64(reqStatSummary.minDataTransferred)))
summary += fmt.Sprintf("Total: %s\n", zfile.FileSizeFormat(uint64(reqStatSummary.totalDataTransferred)))
summary += fmt.Sprintf("Mean query: %s\n", zfile.SizeFormat(uint64(reqStatSummary.avgDataTransferred)))
summary += fmt.Sprintf("Largest query: %s\n", zfile.SizeFormat(uint64(reqStatSummary.maxDataTransferred)))
summary += fmt.Sprintf("Smallest query: %s\n", zfile.SizeFormat(uint64(reqStatSummary.minDataTransferred)))
summary += fmt.Sprintf("Total: %s\n", zfile.SizeFormat(uint64(reqStatSummary.totalDataTransferred)))

summary = summary + "\nResponse Codes\n"
//sort the status codes
Expand Down Expand Up @@ -88,7 +88,7 @@ func (p *printer) printStat(stat RequestStat) {
fmt.Fprintf(p.output, "%s %d\t%s \t%d ms\t-> %s %s\n",
stat.Proto,
stat.StatusCode,
zfile.FileSizeFormat(uint64(stat.DataTransferred)),
zfile.SizeFormat(uint64(stat.DataTransferred)),
stat.Duration.Nanoseconds()/1000000,
stat.Method,
stat.URL)
Expand Down
13 changes: 10 additions & 3 deletions app/watch/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import (
"github.com/sohaha/zlsgo/znet"
"github.com/sohaha/zlsgo/zstring"
"github.com/sohaha/zlsgo/ztype"
"github.com/sohaha/zzz/util"
"gopkg.in/olahol/melody.v1"

"github.com/sohaha/zzz/util"
)

var (
Expand Down Expand Up @@ -63,6 +64,7 @@ func httpRun() {

ws = melody.New()
service := znet.New()
// service.SetMode(znet.DebugMode)
service.Log.ResetFlags(0)
service.Log.SetPrefix("")
service.NotFoundHandler(func(c *znet.Context) {
Expand All @@ -77,6 +79,8 @@ func httpRun() {
}
})

service.POST("/___VueRunMinifyApi___/", util.MinifyHandle)

ws.HandleMessage(func(s *melody.Session, data []byte) {
// msg := string(data[:])
// zlog.Println(msg)
Expand Down Expand Up @@ -138,6 +142,8 @@ func httpEntrance(c *znet.Context) {
}
if err = proxy(pullPath, c.Writer, c.Request); err != nil {
c.String(404, "file not found")
} else {
c.Abort(200)
}
}

Expand Down Expand Up @@ -172,14 +178,15 @@ func injectingCode(file string) (data string) {
html.WriteString(vueSpaJs)
} else if httpType == "vue-run" {
html.WriteString(vueHotReload)
// html.WriteString(vueRunExport)
}
html.WriteString("</script>")
data = html.String()
return
}

func proxy(_ string, w http.ResponseWriter, r *http.Request) (err error) {
host, scheme := urlParse()
host, scheme := urlParse(httpProxy)
if host == "" {
err = errors.New("404")
} else {
Expand All @@ -196,7 +203,7 @@ func proxy(_ string, w http.ResponseWriter, r *http.Request) (err error) {
return
}

func urlParse() (string, string) {
func urlParse(httpProxy string) (string, string) {
var host, scheme string
p, err := url.Parse(httpProxy)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion app/watch/httpUtil.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ a=function(n){for(var o in e)if(e.hasOwnProperty(o)&&e[o]===n)return void locati
n){!0===n?n=SpaResource.mod[e]||[]:SpaResource.mod[e]=n,r.mod[e]=n;var o=r.sta,a={},i=!0,c=!1,f=void 0;try{for(var u,l=n[Symbol.iterator]();!(i=(u=l.next()).done);i=!0){var s=u.value;s=t(s);var d=o[s]||[];d.indexOf(e)>=0||(d.push(e),a[s]=d)}}catch(e){c=!0,f=e}finally{try{!i&&l.return&&l.return()}finally{if(c)throw f}}Object.assign(o,a),Object.assign(SpaResource.sta,a)},f=function(){(_SpaForChildren=function(e,n){for(var o=e.length,a=0;a<o;a++){var r=e[a];r&&n&&setTimeout(function(){r.$vnode.context.$forceUpdate()}),_SpaForChildren(r.$children,n)}})(Spa.vue.$children,1)};window._SpaModGet=function(e,n){!1===n?i(e):c(e,n)},window.Spa?function e(){try{var n=location.host;zwatchWs=new WebSocket("ws://"+n+"/"),zwatchWs.onopen=function(e){},zwatchWs.onmessage=function(e){var n=JSON.parse(e.data);if(console.log("update: ",n.Name),n.Name){0!==n.Name.indexOf("/")&&(n.Name="/"+n.Name);var r=Spa.baseUrl;0!==r.indexOf("/")&&(r="/"+r);var t=new RegExp(r+"(.*)"+Spa.suffix,"g").exec(n.Name);if(t)Spa.loadMod(t[1],!0).then(function(){f()});else{var i=SpaResource.sta[n.Name];i?(i=i.map(function(e){return e.replace(/_/g,"/")}),Spa.loadMod(i,!0).then(function(){f()})):(a(n.Name),o(n.Name))}}},zwatchWs.onclose=function(n){console.warn("Disconnect from zwatch."),setTimeout(function(){e()},300)}}catch(e){}}():function(){` + webJs + `}()}();
`

const vueHotReload = `!function(){var n=function(){function n(n){return n?(h.href=n,h.pathname):""}function e(n){var e=n.lastIndexOf(".");return-1!=e?n.substring(e+1,n.length).toLowerCase():""}function o(n,e){if(e.functional){var o=e.render;e.render=function(e,t){var r=l[n].instances;return t&&r.indexOf(t.parent)<0&&r.push(t.parent),o(e,t)}}else t(e,p,function(){var e=l[n];e.Ctor||(e.Ctor=this.constructor),e.instances.push(this)}),t(e,"beforeDestroy",function(){var e=l[n].instances;e.splice(e.indexOf(this),1)})}function t(n,e,o){var t=n[e];n[e]=t?Array.isArray(t)?t.concat(o):[t,o]:[o]}function r(n){return function(e,o){try{n(e,o)}catch(n){console.error(n),console.warn("Something went wrong during Vue component hot-reload. Full reload required.")}}}function i(n,e){for(var o in n)o in e||delete n[o];for(var t in e)n[t]=e[t]}function c(n){if(n._u){var e=n._u;return n._u=function(n){try{return e(n,!0)}catch(o){return e(n,null,!0)}},function(){n._u=e}}}var a,s,u={},l=Object.create(null);window.__VUE_HOT_MAP__=l;var f=!1,d=!1,p="beforeCreate";window.VueRun.debug=u;var v={},h=document.createElement("a"),w=function(){try{var o=location.host;zwatchWs=new WebSocket("ws://"+o+"/"),zwatchWs.onopen=function(n){},zwatchWs.onmessage=function(o){var t=JSON.parse(o.data),r="/"+t.Name,i=e(r);switch(console.log("update:",r),i){case"vue":VueRun.hotReload(r),console.log("hotReload:",r);break;case"html":var c=location.pathname;"/"==c&&(c="/index.html"),r===c&&location.reload();break;case"css":if(v[r])return void(v[r].href=r+"?v="+ +new Date);document.querySelectorAll("link").forEach(function(n){var e=n.href;e&&(e=e.replace(location.origin,""))===r&&(n.href=e+"?v="+ +new Date,v[r]=n)});break;case"es6":case"js":for(var a in VueRun.staticState){n(VueRun.staticState[a])===r&&location.reload()}document.querySelectorAll("script").forEach(function(n){var e=n.src;if(e)return e=e.replace(location.origin,""),e===r?void location.reload():void 0})}},zwatchWs.onclose=function(n){console.warn("Disconnect from zwatch."),setTimeout(function(){w()},300)}}catch(n){}};if(w(),!window.Vue||!window.Vue.use)return void console.warn("[HMR] Vue not found");u.install=function(n,e){if(!f)return f=!0,a=n.__esModule?n.default:n,s=a.version.split(".").map(Number),d=e,a.config._lifecycleHooks.indexOf("init")>-1&&(p="init"),u.compatible=s[0]>=2,u.compatible?void 0:void console.warn("[HMR] You are using a version of vue-hot-reload-api that is only compatible with Vue.js core ^2.0.0.")},u.install(window.Vue),u.createRecord=function(n,e){if(!l[n]){var t=null;"function"==typeof e&&(t=e,e=t.options),o(n,e),l[n]={Ctor:t,options:e,instances:[]}}},u.isRecorded=function(n){return void 0!==l[n]},u.rerender=r(function(n,e){var o=l[n];if(!e)return void o.instances.slice().forEach(function(n){n.$forceUpdate()});if("function"==typeof e&&(e=e.options),o.Ctor)o.Ctor.options.render=e.render,o.Ctor.options.staticRenderFns=e.staticRenderFns,o.instances.slice().forEach(function(n){n.$options.render=e.render,n.$options.staticRenderFns=e.staticRenderFns,n._staticTrees&&(n._staticTrees=[]),Array.isArray(o.Ctor.options.cached)&&(o.Ctor.options.cached=[]),Array.isArray(n.$options.cached)&&(n.$options.cached=[]);var t=c(n);n.$forceUpdate(),n.$nextTick(t)});else if(o.options.render=e.render,o.options.staticRenderFns=e.staticRenderFns,o.options.functional){if(Object.keys(e).length>2)i(o.options,e);else{var t=o.options._injectStyles;if(t){var r=e.render;o.options.render=function(n,e){return t.call(e),r(n,e)}}}o.options._Ctor=null,Array.isArray(o.options.cached)&&(o.options.cached=[]),o.instances.slice().forEach(function(n){n.$forceUpdate()})}}),u.reload=r(function(n,e){var t=l[n];if(e)if("function"==typeof e&&(e=e.options),o(n,e),t.Ctor){s[1]<2&&(t.Ctor.extendOptions=e);var r=t.Ctor.super.extend(e);r.options._Ctor=t.options._Ctor,t.Ctor.options=r.options,t.Ctor.cid=r.cid,t.Ctor.prototype=r.prototype,r.release&&r.release()}else i(t.options,e);t.instances.slice().forEach(function(n){n.$vnode&&n.$vnode.context?n.$vnode.context.$forceUpdate():console.warn("Root or manually mounted instance modified. Full reload required.")})})},e=setInterval(function(){window.Vue&&window.VueRun&&(clearInterval(e),n())},1e3)}();`
const vueHotReload = `!function(){var e=function(){function e(e){return e?(v.href=e,v.pathname):""}function n(e){var n=e.lastIndexOf(".");return-1!=n?e.substring(n+1,e.length).toLowerCase():""}function t(e,n){if(n.functional){var t=n.render;n.render=function(n,o){var r=l[e].instances;return o&&r.indexOf(o.parent)<0&&r.push(o.parent),t(n,o)}}else o(n,p,function(){var n=l[e];n.Ctor||(n.Ctor=this.constructor),n.instances.push(this)}),o(n,"beforeDestroy",function(){var n=l[e].instances;n.splice(n.indexOf(this),1)})}function o(e,n,t){var o=e[n];e[n]=o?Array.isArray(o)?o.concat(t):[o,t]:[t]}function r(e){return function(n,t){try{e(n,t)}catch(e){console.error(e),console.warn("Something went wrong during Vue component hot-reload. Full reload required.")}}}function i(e,n){for(var t in e)t in n||delete e[t];for(var o in n)e[o]=n[o]}function c(e){if(e._u){var n=e._u;return e._u=function(e){try{return n(e,!0)}catch(t){return n(e,null,!0)}},function(){e._u=n}}}var a,s,u={},l=Object.create(null);window.__VUE_HOT_MAP__=l;var d=!1,f=!1,p="beforeCreate";window.VueRun.debug=u;var h={},v=document.createElement("a"),y=function(){try{var t=location.host;zwatchWs=new WebSocket("ws://"+t+"/"),zwatchWs.onopen=function(e){},zwatchWs.onmessage=function(t){var o=JSON.parse(t.data);console.log(o);var r="/"+o.Name,i=n(r);switch(console.log("update:",r),i){case"vue":VueRun.hotReload(r),console.log("hotReload:",r);break;case"html":var c=location.pathname;"/"==c&&(c="/index.html"),r===c&&location.reload();break;case"css":if(h[r])return void(h[r].href=r+"?v="+ +new Date);document.querySelectorAll("link").forEach(function(e){var n=e.href;n&&(n=n.replace(location.origin,""))===r&&(e.href=n+"?v="+ +new Date,h[r]=e)});break;case"es6":case"js":for(var a in VueRun.staticState){e(VueRun.staticState[a])===r&&location.reload()}document.querySelectorAll("script").forEach(function(e){var n=e.src;if(n)return n=n.replace(location.origin,""),n===r?void location.reload():void 0})}},zwatchWs.onclose=function(e){console.warn("Disconnect from zwatch."),setTimeout(function(){y()},300)}}catch(e){}};if(y(),!window.Vue||!window.Vue.use)return void console.warn("[HMR] Vue not found");u.install=function(e,n){if(!d)return d=!0,a=e.__esModule?e.default:e,s=a.version.split(".").map(Number),f=n,a.config._lifecycleHooks.indexOf("init")>-1&&(p="init"),u.compatible=s[0]>=2,u.compatible?void 0:void console.warn("[HMR] You are using a version of vue-hot-reload-api that is only compatible with Vue.js core ^2.0.0.")},u.install(window.Vue),u.createRecord=function(e,n){if(!l[e]){var o=null;"function"==typeof n&&(o=n,n=o.options),t(e,n),l[e]={Ctor:o,options:n,instances:[]}}},u.isRecorded=function(e){return void 0!==l[e]},u.rerender=r(function(e,n){var t=l[e];if(!n)return void t.instances.slice().forEach(function(e){e.$forceUpdate()});if("function"==typeof n&&(n=n.options),t.Ctor)t.Ctor.options.render=n.render,t.Ctor.options.staticRenderFns=n.staticRenderFns,t.instances.slice().forEach(function(e){e.$options.render=n.render,e.$options.staticRenderFns=n.staticRenderFns,e._staticTrees&&(e._staticTrees=[]),Array.isArray(t.Ctor.options.cached)&&(t.Ctor.options.cached=[]),Array.isArray(e.$options.cached)&&(e.$options.cached=[]);var o=c(e);e.$forceUpdate(),e.$nextTick(o)});else if(t.options.render=n.render,t.options.staticRenderFns=n.staticRenderFns,t.options.functional){if(Object.keys(n).length>2)i(t.options,n);else{var o=t.options._injectStyles;if(o){var r=n.render;t.options.render=function(e,n){return o.call(n),r(e,n)}}}t.options._Ctor=null,Array.isArray(t.options.cached)&&(t.options.cached=[]),t.instances.slice().forEach(function(e){e.$forceUpdate()})}}),u.reload=r(function(e,n){var o=l[e];if(n)if("function"==typeof n&&(n=n.options),t(e,n),o.Ctor){s[1]<2&&(o.Ctor.extendOptions=n);var r=o.Ctor.super.extend(n);r.options._Ctor=o.options._Ctor,o.Ctor.options=r.options,o.Ctor.cid=r.cid,o.Ctor.prototype=r.prototype,r.release&&r.release()}else i(o.options,n);o.instances.slice().forEach(function(e){e.$vnode&&e.$vnode.context?e.$vnode.context.$forceUpdate():console.warn("Root or manually mounted instance modified. Full reload required.")})})},n=setInterval(function(){window.Vue&&window.VueRun&&(clearInterval(n),e())},1e3);!function(){function e(e){return 0===e?"h":1===e?"j":"c"}function n(n,t,o,r){var i="";switch(e(o)){case"h":t+="<template>"+n+"</template>";break;case"c":i=r.styles[0].elt.hasAttribute("data-scopeid")?"scoped":"",t+="<style "+i+">"+n+"</style>";break;case"j":t+="<script>"+n+"<\/script>"}return t}function t(e,n){var t=document.createElement("a");t.download=n,t.style.display="none";var o=new Blob([e]);t.href=URL.createObjectURL(o),document.body.appendChild(t),t.click(),document.body.removeChild(t)}function o(e){return fetch(window.VueRunMinifyApi||r||"https://api.73zls.com/minify/",{method:"POST",mode:"cors",body:JSON.stringify(e)}).then(function(e){return e.json()})}if(window.VueRunExportSave){var r="//"+location.host+"/___VueRunMinifyApi___/",i={},c=document.createElement("button");c.innerHTML="导出",c.style.position="fixed",c.style.bottom="10px",c.style.right="10px",c.style.opacity="0.5",c.style.fontSize="12px",c.style.border="0",c.style.cursor="pointer",c.style.color="#009688",c.style.borderRadius="100px",c.style.transform="scale(0.8)",c.style.boxShadow="1px 1px 14px #009688",c.addEventListener("click",function(e){window.VueRunSave()}),window.addEventListener("load",function(e){document.body.appendChild(c)}),window.VueRunSave=function(){setTimeout(function(){t("var VueRunPreliminaryData="+JSON.stringify(i)+";VueRun.preLoad(VueRunPreliminaryData);","all.js")},1e3)},window.VueRunExport=function(e,t,r){"object"==typeof t&&o(t).then(function(t){if(200!==t.code)return alert(t.msg),null;var o="";t.data.forEach(function(e,t){o=n(e,o,t,r)}),i[e]=o})}}}()}();`
4 changes: 2 additions & 2 deletions app/watch/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package watch
import (
"bufio"
"fmt"
"github.com/sohaha/zlsgo/zenv"
"github.com/sohaha/zlsgo/zlog"
"github.com/sohaha/zlsgo/zstring"
"github.com/sohaha/zlsgo/ztype"
"github.com/sohaha/zlsgo/zutil"
"github.com/sohaha/zzz/util"
"io"
"os"
Expand Down Expand Up @@ -233,7 +233,7 @@ func (t *taskType) runBackground(cf *changedFile, commands []string) []*exec.Cmd

func cloes(cmd *exec.Cmd) {
if cmd != nil && cmd.Process != nil {
if !zenv.IsWin() {
if !zutil.IsWin() {
p, e := os.FindProcess(-cmd.Process.Pid)
if e == nil {
_ = p.Signal(syscall.SIGINT)
Expand Down
Empty file modified build.sh
100644 → 100755
Empty file.
5 changes: 3 additions & 2 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import (
"path/filepath"
"strings"

"github.com/sohaha/zlsgo/zenv"
"github.com/sohaha/zlsgo/zfile"
"github.com/sohaha/zlsgo/zshell"
"github.com/sohaha/zlsgo/zstring"
"github.com/sohaha/zlsgo/zutil"

"github.com/spf13/cobra"

zbuild "github.com/sohaha/zstatic/build"
Expand Down Expand Up @@ -63,7 +64,7 @@ var buildCmd = &cobra.Command{
}
defer func() {
for _, filename := range targetFiles {
if zenv.Getenv("NODELETETMP") == "" {
if zutil.Getenv("NODELETETMP") == "" {
_ = os.Remove(filename)
}
}
Expand Down
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ require (
github.com/dustin/go-humanize v1.0.0
github.com/fatih/color v1.9.0
github.com/fsnotify/fsnotify v1.4.9
github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77
github.com/lucasjones/reggen v0.0.0-20200904144131-37ba4fa293bb
github.com/manifoldco/promptui v0.7.0
github.com/mitchellh/go-homedir v1.1.0
github.com/sohaha/zlsgo v0.1.46
github.com/sohaha/zlsgo v0.1.61
github.com/sohaha/zstatic v0.0.2
github.com/spf13/cobra v1.0.0
github.com/spf13/viper v1.7.0
golang.org/x/net v0.0.0-20200625001655-4c5254603344
github.com/spf13/viper v1.7.1
github.com/tdewolff/minify/v2 v2.9.4
golang.org/x/net v0.0.0-20200904194848-62affa334b73
gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376
)
Loading

0 comments on commit 64eb188

Please sign in to comment.