Browse Source

fix

tags/v0.9.2
郑荣升 5 years ago
parent
commit
b5afb504df
  1. 3
      .gitignore
  2. 47
      govue/bindata.go
  3. 2
      govue/cmd/main.go
  4. 30
      govue/govue-js-src/build.js
  5. 123370
      govue/govue-js-src/dist/index.js
  6. 14
      govue/govue-js-src/package.json
  7. 12
      govue/govue-js-src/predo.js
  8. 9
      govue/govue-js-src/replace.tp
  9. 1
      govue/govue-js-src/replace2.tp
  10. 74
      govue/govue-js-src/src/browser.js
  11. 104
      govue/govue-js-src/src/goruntime.js
  12. 120
      govue/govue-js-src/src/index.js
  13. 54852
      govue/govue-runtime/govue.js
  14. 109
      govue/govue-runtime/header.js
  15. 7203
      govue/govue-runtime/polyfill.js
  16. 79
      govue/govue-runtime/runtime.js
  17. 8959
      govue/govue-runtime/vuessr.js
  18. 110
      govue/govue.go
  19. 122
      jsruntime/runtime.go
  20. 36
      jsruntime/timeout.go
  21. 10
      pool/pool.go
  22. 49
      static/index.html
  23. 23
      static/use.js

3
.gitignore

@ -12,4 +12,5 @@
# Output of the go coverage tool, specifically when used with LiteIDE # Output of the go coverage tool, specifically when used with LiteIDE
*.out *.out
.idea .idea
build
build
*.json

47
govue/bindata.go
File diff suppressed because it is too large
View File

2
govue/cmd/main.go

@ -69,7 +69,7 @@ func main() {
govue.SetPoolConfig(config.Pool) govue.SetPoolConfig(config.Pool)
gv, err := govue.NewGoVue(config.UseJsFile, config.StaticDir)
gv, err := govue.NewGoVue(config.UseJsFile, config.StaticDir, mode == "debug")
if errorPage404 != "" { if errorPage404 != "" {
config.ErrorPage404 = errorPage404 config.ErrorPage404 = errorPage404

30
govue/govue-js-src/build.js

@ -2,22 +2,20 @@ var fs = require("fs");
var envify = require('envify/custom') var envify = require('envify/custom')
var browserify = require("browserify"); var browserify = require("browserify");
browserify("./src/index.js") browserify("./src/index.js")
.transform("babelify", {
plugins: [
'@babel/preset-env',
"@babel/preset-es2015"
],
plugins: [
'@babel/plugin-transform-modules-commonjs',
'@babel/plugin-transform-object-assign',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread'
]
}).transform(
// 用来处理 `node_modules` 文件
{ global: true },
envify({ NODE_ENV: 'production' })
)
// .transform("babelify", {
// plugins: [
// '@babel/plugin-transform-modules-commonjs',
// '@babel/plugin-transform-object-assign',
// '@babel/plugin-proposal-class-properties',
// '@babel/plugin-transform-property-mutators',
// "transform-remove-strict-mode"
// ]
// })
// .transform(
// // 用来处理 `node_modules` 文件
// { global: true },
// envify({ NODE_ENV: 'production' })
// )
.bundle() .bundle()
.pipe(fs.createWriteStream("./dist/index.js")); .pipe(fs.createWriteStream("./dist/index.js"));

123370
govue/govue-js-src/dist/index.js
File diff suppressed because it is too large
View File

14
govue/govue-js-src/package.json

@ -1,19 +1,24 @@
{ {
"name": "govue-template", "name": "govue-template",
"dependencies": { "dependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-transform-modules-commonjs": "^7.9.6",
"@babel/plugin-transform-object-assign": "^7.8.3",
"@babel/preset-env": "^7.9.6",
"@babel/preset-es2015": "^7.0.0-beta.53",
"axios": "^0.19.2", "axios": "^0.19.2",
"domino": "^2.1.5",
"babel-plugin-transform-remove-strict-mode": "^0.0.2",
"envify": "^4.1.0", "envify": "^4.1.0",
"es6-promise": "^4.2.8", "es6-promise": "^4.2.8",
"esprima": "^4.0.1", "esprima": "^4.0.1",
"jquery-bbq": "^1.0.0", "jquery-bbq": "^1.0.0",
"qs": "^6.9.4",
"through": "^2.3.8", "through": "^2.3.8",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-axios": "^2.1.5",
"vue-router": "^3.1.6"
"vue-router": "^3.2.0"
}, },
"scripts": { "scripts": {
"build": "node build.js && node predo.js"
"build": "node build.js && node predo.js && cp ./dist/index.js ../govue-runtime/govue.js"
}, },
"browser": { "browser": {
"vue": "vue/dist/vue.common.js" "vue": "vue/dist/vue.common.js"
@ -31,6 +36,7 @@
"@babel/preset-es2015": "^7.0.0-beta.53", "@babel/preset-es2015": "^7.0.0-beta.53",
"@babel/preset-react": "^7.9.4", "@babel/preset-react": "^7.9.4",
"babel-cli": "^6.26.0", "babel-cli": "^6.26.0",
"babel-plugin-transform-remove-strict-mode": "^0.0.2",
"babelify": "^10.0.0", "babelify": "^10.0.0",
"browserify": "^16.5.1" "browserify": "^16.5.1"
} }

12
govue/govue-js-src/predo.js

@ -1,15 +1,9 @@
var fs = require("fs"); var fs = require("fs");
var retemp = fs.readFileSync("./replace.tp")
var retemp2 = fs.readFileSync("./replace2.tp")
var content = fs.readFileSync("./dist/index.js") var content = fs.readFileSync("./dist/index.js")
retemp = retemp.toString().replace(/\r\n/g,"\n")
var test = content.toString().indexOf(retemp)
console.log(test)
// content = content.toString().replace(`_m("`, `this._m("`).replace(`var isHTMLTag = `, `var isHTMLTag = makeMap('html,body,base,head,link,meta,style,title');var _isHTMLTag = `)
// fs.writeFileSync("./dist/index.js", content)
content = content.toString().replace(retemp, `NodeList`).replace(retemp2, ``)
fs.writeFileSync("./dist/index.js", content)

9
govue/govue-js-src/replace.tp

@ -1,9 +0,0 @@
class NodeList extends Array {
constructor(a) {
super((a && a.length) || 0);
if (a) {
for (var idx in a) { this[idx] = a[idx]; }
}
}
item(i) { return this[i] || null; }
}

1
govue/govue-js-src/replace2.tp

@ -1 +0,0 @@
throw new Error("NotYetImplemented");

74
govue/govue-js-src/src/browser.js

@ -1,74 +0,0 @@
console.log("浏览器端")
Promise = require('es6-promise').Promise;
window.Vue = require('vue');
window.VueRouter = require('vue-router');
Vue.use(VueRouter)
window.$ = window.jQuery = require('jquery');
require('jquery-bbq');
window.axios = require('axios');
import VueAxios from 'vue-axios'
window.Vue.use(VueAxios, window.axios)
window.GoQuery = location.search;
window.GoParam = jQuery.deparam(GoQuery);
window.GoUse = function (cb) {
var path = location.pathname
if (path.indexOf(".html") < 0) {
if (path[path.length - 1] == "/" && path.length > 1) {
path = path + "index.html"
} else {
path = path + ".html"
}
}
if (cb) cb(path, location.search)
}
window.GoUseRegistered = function (id, cb) {
var govueId = "";
if (document.getElementsByTagName("html").length > 0) {
govueId = document.getElementsByTagName("html")[0].getAttribute("govue-id")
}
var path = location.pathname
if (path.indexOf(".html") < 0) {
if (path[path.length - 1] == "/" && path.length > 1) {
path = path + "index.html"
} else {
path = path + ".html"
}
}
if (govueId == id || path == id) {
if (cb) cb(location.search)
}
};
window.GoUseCall = function (e) {
// console.log("GoUseCall", 2)
var id = e["id"];
var path = e["path"];
var query = e["query"];
if (useRoute[id]) {
console.log(useRoute[id])
useRoute[id](query);
return
}
// console.log("GoUseCall", 3)
if (useRoute[path]) {
useRoute[path](query);
return
}
console.log("路由未找到:", id, "-", path)
}

104
govue/govue-js-src/src/goruntime.js

@ -1,104 +0,0 @@
domino = require('domino');
window = domino.createWindow("", "http://127.0.0.1/");
document = window.document;
location = window.location;
Promise = require('es6-promise').Promise;
Vue = require('vue');
$ = jQuery = require('jquery');
require('jquery-bbq');
qs = require('qs');
axios = require('axios');
var buildURL = require('axios/lib/helpers/buildURL');
var buildFullPath = require('axios/lib/core/buildFullPath');
var settle = require('axios/lib/core/settle');
var createError = require('axios/lib/core/createError');
function transformResponse(mpResponse, config, mpRequestOption) {
var headers = mpResponse.header || mpResponse.headers;
var status = mpResponse.statusCode || mpResponse.status;
var statusText = '';
if (status === 200) {
statusText = 'OK';
}
else if (status === 400) {
statusText = 'Bad Request';
}
var response = {
data: mpResponse.data,
status: status,
statusText: statusText,
headers: headers,
config: config,
request: mpRequestOption
};
return response;
}
axios.defaults.adapter = function (config) {
return new Promise(function (resolve, reject) {
// console.log("resolve", JSON.stringify(resolve));
// console.log("reject", JSON.stringify(reject));
// console.log("config", JSON.stringify(config));
// console.log("axios.defaults.headers", JSON.stringify(axios.defaults.headers));
var mpRequestOption = {
url: buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer),
method: config["method"].toUpperCase(),
data: config["data"],
header: config["headers"],
timeout: config["timeout"],
success: function (mpResponse) {
// console.log("success");
// console.log(JSON.stringify(mpResponse));
var response = transformResponse(mpResponse, config, mpRequestOption);
settle(resolve, reject, response);
},
fail: function (error) {
reject(createError(error.data));
},
};
net.request(mpRequestOption)
})
};
useRoute = {};
GoUseRegistered = function (id, cb) {
useRoute[id] = cb
};
goUseCallCache
GoUseCall = function (e) {
// console.log("GoUseCall", 1)
if (goUseCallCache) {
goUseCallCache(e)
}
// console.log("GoUseCall", 2)
var id = e["id"];
var path = e["path"];
var query = e["query"];
if (useRoute[id]) {
// console.log(useRoute[id])
useRoute[id](query);
return
}
// console.log("GoUseCall", 3)
if (useRoute[path]) {
useRoute[path](query);
return
}
// console.log("路由未找到:", id, "-", path)
}
GoUse = function (cb) {
goUseCallCache = cb
}

120
govue/govue-js-src/src/index.js

@ -1,8 +1,118 @@
domino = require('../domino/lib/index');
window = domino.createWindow("", "http://127.0.0.1/");
document = window.document;
location = window.location;
if (window) {
require("./browser")
} else {
require("./goruntime")
Intl = require('./Intl');
Vue = require('vue');
VueRouter = require('vue-router');
Vue.use(VueRouter)
vuessr = require('vue-server-renderer')
$ = jQuery = require('jquery');
require('jquery-bbq');
qs = require('qs');
Promise = require('es6-promise').Promise;
axios = require('axios');
var buildURL = require('axios/lib/helpers/buildURL');
var buildFullPath = require('axios/lib/core/buildFullPath');
var settle = require('axios/lib/core/settle');
var createError = require('axios/lib/core/createError');
function transformResponse(mpResponse, config, mpRequestOption) {
var headers = mpResponse.header || mpResponse.headers;
var status = mpResponse.statusCode || mpResponse.status;
var statusText = '';
if (status === 200) {
statusText = 'OK';
}
else if (status === 400) {
statusText = 'Bad Request';
}
var response = {
data: mpResponse.data,
status: status,
statusText: statusText,
headers: headers,
config: config,
request: mpRequestOption
};
return response;
}
axios.defaults.adapter = function (config) {
return new Promise(function (resolve, reject) {
// console.log("resolve", JSON.stringify(resolve));
// console.log("reject", JSON.stringify(reject));
// console.log("config", JSON.stringify(config));
// console.log("axios.defaults.headers", JSON.stringify(axios.defaults.headers));
var mpRequestOption = {
url: buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer),
method: config["method"].toUpperCase(),
data: config["data"],
header: config["headers"],
timeout: config["timeout"],
success: function (mpResponse) {
// console.log("success");
// console.log(JSON.stringify(mpResponse));
var response = transformResponse(mpResponse, config, mpRequestOption);
settle(resolve, reject, response);
},
fail: function (error) {
reject(createError(error.data));
},
};
net.request(mpRequestOption)
})
};
useRoute = {};
GoUseRegistered = function (id, cb) {
useRoute[id] = cb
};
goUseCallCache
GoUseCall = function (e) {
// console.log("GoUseCall", 1)
if (goUseCallCache) {
goUseCallCache(e)
}
// console.log("GoUseCall", 2)
var id = e["id"];
var path = e["path"];
var query = e["query"];
if (useRoute[id]) {
// console.log(useRoute[id])
useRoute[id](query);
return
}
// console.log("GoUseCall", 3)
if (useRoute[path]) {
useRoute[path](query);
return
}
// console.log("路由未找到:", id, "-", path)
}
GoUse = function (cb) {
goUseCallCache = cb
}
for (var i in global) {
window[i] = global[i]
} }

54852
govue/govue-runtime/govue.js
File diff suppressed because it is too large
View File

109
govue/govue-runtime/header.js

@ -1,9 +1,17 @@
var domino, window, document, location, Vue, VueRouter, navigator, axios, Promise, GoUseCall, GoUse, GoUseRegistered,
govueId, useRoute, goUseCallCache, $, jQuery, GoParam, qs;
var domino, window, document, location, Vue, VueRouter, vuessr, navigator, axios, Promise, GoUseCall, GoUse,
GoUseRegistered,
govueId, useRoute, goUseCallCache, $, jQuery, GoParam, qs, Intl;
var global = this;
global.Vue = Vue;
global.VueRouter = VueRouter;
global.Intl = Intl;
navigator = { navigator = {
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 a/537.36 "
}; };
var net = { var net = {
request: function (c) { request: function (c) {
var url = c["url"]; var url = c["url"];
@ -37,10 +45,6 @@ var net = {
url = $.param.querystring(url, data); url = $.param.querystring(url, data);
data = "" data = ""
} else { } else {
// console.log("data:");
// console.log(JSON.stringify(header["Content-Type"]));
// console.log(JSON.stringify(data));
if (typeof (data) == "object") { if (typeof (data) == "object") {
if (header["Content-Type"].indexOf("application/json") > -1 || header["content-type"].indexOf("application/json") > -1) { if (header["Content-Type"].indexOf("application/json") > -1 || header["content-type"].indexOf("application/json") > -1) {
data = JSON.stringify(data); data = JSON.stringify(data);
@ -70,20 +74,52 @@ var net = {
} }
if (statusCode == 200) { if (statusCode == 200) {
success({
success && success({
data: result, data: result,
statusCode: statusCode, statusCode: statusCode,
}); });
} else { } else {
fail({
fail && fail({
data: result, data: result,
statusCode: statusCode, statusCode: statusCode,
}) })
} }
complete && complete({
data: result,
statusCode: statusCode,
})
} }
}; };
function GoVueRender(template, app, context) {
var raw = GoReadFile(template);
var renderer = vuessr.createRenderer({
template: raw
});
// 第 3 步:将 Vue 实例渲染为 HTML
renderer.renderToString(app, context, function (err, html) {
if (err) throw err;
GoReturn(html);
// => <div data-server-rendered="true">Hello World</div>
})
}
function LoadPage(src, href) {
window = domino.createWindow(src, href);
document = window.document;
location = window.location;
for (var i in global) {
window[i] = global[i]
}
}
/** /**
* 获取页面Id * 获取页面Id
@ -129,10 +165,11 @@ function RunInlineCode() {
} }
for (var i in jsInlineFiles) { for (var i in jsInlineFiles) {
if (jsInlineFiles[i]["file"]) { if (jsInlineFiles[i]["file"]) {
console.log("load file", jsInlineFiles[i]["file"]);
GoRunCodeByFile(jsInlineFiles[i]["file"]); GoRunCodeByFile(jsInlineFiles[i]["file"]);
} }
if (jsInlineFiles[i]["src"]) { if (jsInlineFiles[i]["src"]) {
eval(jsInlineFiles[i]["src"]);
GoRunCode(jsInlineFiles[i]["src"]);
} }
} }
} }
@ -167,20 +204,24 @@ var GoVueIgnore = function () {
gv_ignore_tag_map[i] = gv_ignore[i].innerHTML; gv_ignore_tag_map[i] = gv_ignore[i].innerHTML;
gv_ignore[i].outerHTML = "<gv-ignore-" + i + "></gv-ignore-" + i + ">"; gv_ignore[i].outerHTML = "<gv-ignore-" + i + "></gv-ignore-" + i + ">";
} }
var gv_ignore_class = document.getElementsByClassName("gv-ignore");
var gv_ignore_class = document.querySelectorAll("[gv-ignore]");
gv_ignore_class_len = gv_ignore_class.length; gv_ignore_class_len = gv_ignore_class.length;
// console.log("gv_ignore_class_len",gv_ignore_class_len)
for (var i = 0; i < gv_ignore_class_len; i++) { for (var i = 0; i < gv_ignore_class_len; i++) {
if (!gv_ignore_class_map[i]) { if (!gv_ignore_class_map[i]) {
gv_ignore_class_map[i] = {}; gv_ignore_class_map[i] = {};
} }
var a = gv_ignore_class[i].attributes; var a = gv_ignore_class[i].attributes;
var len = gv_ignore_class[i].attributes.length; var len = gv_ignore_class[i].attributes.length;
var ignoreVal = gv_ignore_class[i].getAttribute("gv-ignore");
for (var k = len - 1; k >= 0; k--) { for (var k = len - 1; k >= 0; k--) {
gv_ignore_class_map[i][a.item(k).name] = a.item(k).value;
gv_ignore_class[i].removeAttribute(a.item(k).name);
if (!ignoreVal || ignoreVal == "" || ignoreVal.split("|").includes(a.item(k).name)) {
gv_ignore_class_map[i][a.item(k).name] = a.item(k).value;
gv_ignore_class[i].removeAttribute(a.item(k).name);
}
} }
gv_ignore_class[i].setAttribute("class", "gv-ignore-" + i)
gv_ignore_class[i].removeAttribute("gv-ignore");
gv_ignore_class[i].setAttribute("gv-ignore-val", "gv-ignore-" + i)
} }
}; };
@ -192,18 +233,52 @@ var GoVueIgnore = function () {
for (i = 0; i < gv_ignore_len; i++) { for (i = 0; i < gv_ignore_len; i++) {
gv_restore = document.getElementsByTagName("gv-ignore-" + i); gv_restore = document.getElementsByTagName("gv-ignore-" + i);
for (k = 0; k < gv_restore.length; k++) { for (k = 0; k < gv_restore.length; k++) {
gv_restore[k].innerHTML = gv_ignore_tag_map[i];
gv_restore[k].outerHTML = gv_ignore_tag_map[i];
} }
} }
for (i = 0; i < gv_ignore_class_len; i++) { for (i = 0; i < gv_ignore_class_len; i++) {
gv_restore = document.getElementsByClassName("gv-ignore-" + i);
gv_restore = document.querySelectorAll("[gv-ignore-val='gv-ignore-" + i + "']");
for (k = 0; k < gv_restore.length; k++) { for (k = 0; k < gv_restore.length; k++) {
for (j in gv_ignore_class_map[i]) { for (j in gv_ignore_class_map[i]) {
gv_restore[k].setAttribute(j, gv_ignore_class_map[i][j]); gv_restore[k].setAttribute(j, gv_ignore_class_map[i][j]);
} }
gv_restore[k].removeAttribute("gv-ignore-val");
} }
} }
} }
};
//自动替换事件属性,不成熟实用性不足,不启用
var GoVueIgnoreOnEvent = function () {
var all = document.querySelectorAll('*');
all.forEach(function (el) {
var len = el.attributes.length;
var arr = [];
var arr2 = [];
for (var i = 0; i < len; i++) {
var name = el.attributes.item(i).name;
if (name[0] == "@" || name.indexOf("v-on:") == 0) {
arr.push({
name: name.replace("v-on:", "gv-on:").replace("@", "gv-on:"),
value: el.attributes.item(i).value,
});
arr2.push({
name: ":data-" + name.replace("v-on:", "gv-on:").replace("@", "gv-on:"),
value: el.attributes.item(i).value.match(/\((.+?)\)/g),
});
// el.setAttribute("gv-on:" + name, el.attributes.item(i).value);
// el.setAttribute(":gv-on-data:" + name, el.attributes.item(i).value.match(/\((.+?)\)/g));
}
}
for (var i in arr) {
console.log(JSON.stringify(arr[i]));
el.setAttribute(arr[i].name, arr[i].value);
el.setAttribute(arr2[i].name, arr2[i].value);
}
})
}; };

7203
govue/govue-runtime/polyfill.js
File diff suppressed because it is too large
View File

79
govue/govue-runtime/runtime.js

@ -1,34 +1,69 @@
window = domino.createWindow(GoHtmlSrc, GoHref);
if (!IS_VUE_SSR) {
document = window.document;
try {
LoadPage(GoHtmlSrc, GoHref);
} catch (e) {
console.log("LoadPage:" + e);
}
location = window.location;
try {
var govueId = GetGoVueId();
} catch (e) {
console.log("GetGoVueId:" + e);
}
try {
var govueId = GetGoVueId();
LoadGoParam(); LoadGoParam();
var goVueIgnore = new GoVueIgnore();
goVueIgnore.ignore();
try {
var goVueIgnore = new GoVueIgnore();
goVueIgnore.ignore();
} catch (e) {
console.log("goVueIgnore.ignore:" + e);
}
GoUseCall({
id: govueId,
path: GoPath,
query: jQuery.deparam(GoQuery)
});
try {
GoUseCall({
id: govueId,
path: GoPath,
query: jQuery.deparam(GoQuery)
});
} catch (e) {
console.log("GoUseCall:" + e);
}
RunInlineCode();
try {
RunInlineCode();
} catch (e) {
console.log("RunInlineCode:" + e);
}
goVueIgnore.restore()
try {
goVueIgnore.restore();
} catch (e) {
console.log("goVueIgnore.restore:" + e);
}
} catch (e) {
console.log("VM Uncaught:", e);
}
// console.log(document.innerHTML);
GoReturn(document.innerHTML);
try {
GoReturn(document.innerHTML);
} catch (e) {
console.log("GoReturn:" + e)
}
} else {
try {
LoadPage(GoHtmlSrc, GoHref);
} catch (e) {
console.log("LoadPage:" + e);
}
try {
GoUseCall({
path: GoPath,
query: jQuery.deparam(GoQuery)
});
} catch (e) {
console.log("GoUseCall:" + e);
}
}

8959
govue/govue-runtime/vuessr.js
File diff suppressed because it is too large
View File

110
govue/govue.go

@ -12,6 +12,7 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"time" "time"
) )
@ -23,22 +24,22 @@ type GoVue struct {
jsRuntimePool *pool.JsRuntimePool jsRuntimePool *pool.JsRuntimePool
} }
func NewGoVueDefaultConfig() (gv *GoVue, err error) {
func NewGoVueDefaultConfig(debug bool) (gv *GoVue, err error) {
gv = &GoVue{ gv = &GoVue{
Resources: assetFS(), Resources: assetFS(),
} }
err = gv.initRender()
err = gv.initRender(debug)
return return
} }
func NewGoVue(useJsPath string, staticPath string) (gv *GoVue, err error) {
func NewGoVue(useJsPath string, staticPath string, debug bool) (gv *GoVue, err error) {
gv = &GoVue{ gv = &GoVue{
StaticPath: staticPath, StaticPath: staticPath,
UseJsPath: useJsPath, UseJsPath: useJsPath,
Resources: assetFS(), Resources: assetFS(),
} }
err = gv.initRender()
err = gv.initRender(debug)
return return
} }
@ -50,7 +51,7 @@ func SetPoolConfig(config pool.Config) {
pool.DefaultConfig = config pool.DefaultConfig = config
} }
func (gv *GoVue) initRender() (err error) {
func (gv *GoVue) initRender(debug bool) (err error) {
if gv.StaticPath == "" { if gv.StaticPath == "" {
gv.StaticPath = filepath.Join(getSelfFilePath(), "static") gv.StaticPath = filepath.Join(getSelfFilePath(), "static")
} }
@ -59,42 +60,63 @@ func (gv *GoVue) initRender() (err error) {
gv.UseJsPath = filepath.Join(gv.StaticPath, "use.js") gv.UseJsPath = filepath.Join(gv.StaticPath, "use.js")
} }
//mainScript, err := ioutil.ReadFile(filepath.Join("govue", "govue-runtime", "runtime.js"))
//if err != nil {
// return
//}
//headerScript, err := ioutil.ReadFile(filepath.Join("govue", "govue-runtime", "header.js"))
//if err != nil {
// return
//}
//govueScript, err := ioutil.ReadFile(filepath.Join("govue", "govue-js-src", "dist", "index.js"))
//if err != nil {
// return
//}
vuessr, err := ioutil.ReadFile(filepath.Join("govue", "govue-runtime", "vuessr.js"))
if err != nil {
return
}
polyfill, err := ioutil.ReadFile(filepath.Join("govue", "govue-runtime", "polyfill.js"))
if err != nil {
return
}
mainScript, err := gv.Resources.Asset(filepath.Join("govue-runtime", "runtime.js"))
mainScript, err := ioutil.ReadFile(filepath.Join("govue", "govue-runtime", "runtime.js"))
if err != nil { if err != nil {
return return
} }
headerScript, err := gv.Resources.Asset(filepath.Join("govue-runtime", "header.js"))
headerScript, err := ioutil.ReadFile(filepath.Join("govue", "govue-runtime", "header.js"))
if err != nil { if err != nil {
return return
} }
govueScript, err := gv.Resources.Asset(filepath.Join("govue-runtime", "govue.js"))
govueScript, err := ioutil.ReadFile(filepath.Join("govue", "govue-js-src", "dist", "index.js"))
if err != nil { if err != nil {
return return
} }
//mainScript, err := gv.Resources.Asset(filepath.Join("govue-runtime", "runtime.js"))
//if err != nil {
// return
//}
//govueScript, err := gv.Resources.Asset(filepath.Join("govue-runtime", "govue.js"))
//if err != nil {
// return
//}
//headerScript, err := gv.Resources.Asset(filepath.Join("govue-runtime", "header.js"))
//if err != nil {
// return
//}
//vueScript, err := ioutil.ReadFile(filepath.Join("static", "js", "vue.js"))
//if err != nil {
// return
//}
gv.jsRuntimePool = pool.NewJsRuntimePool(string(mainScript), gv.UseJsPath, gv.StaticPath, jsruntime.Relys{ gv.jsRuntimePool = pool.NewJsRuntimePool(string(mainScript), gv.UseJsPath, gv.StaticPath, jsruntime.Relys{
jsruntime.Rely{ jsruntime.Rely{
Src: string(polyfill),
},
jsruntime.Rely{
Src: string(headerScript), Src: string(headerScript),
}, },
jsruntime.Rely{ jsruntime.Rely{
Src: string(vuessr),
},
jsruntime.Rely{
Src: string(govueScript), Src: string(govueScript),
}, },
}, jsruntime.ModeSync)
}, jsruntime.ModeSync, debug)
return return
} }
@ -123,7 +145,7 @@ func (gv *GoVue) StartPoolLog() {
} }
func (gv *GoVue) LoadStaticResources(request *http.Request, goExtDataS ...interface{}) (result []byte, err error) { func (gv *GoVue) LoadStaticResources(request *http.Request, goExtDataS ...interface{}) (result []byte, err error) {
var path string
var staticDir string var staticDir string
var filePath = request.URL.Path var filePath = request.URL.Path
if gv.StaticPath == "" { if gv.StaticPath == "" {
@ -132,21 +154,38 @@ func (gv *GoVue) LoadStaticResources(request *http.Request, goExtDataS ...interf
staticDir = gv.StaticPath staticDir = gv.StaticPath
} }
path = filepath.Join(staticDir, filePath)
fi, err := os.Stat(path)
if err != nil {
return gv.renderErrPage(404, request, goExtDataS...)
} else if fi.IsDir() {
filePath = filepath.Join(filePath, "index.html")
path = filepath.Join(staticDir, filePath)
filePath = filepath.Join(staticDir, filePath)
fi, err := os.Stat(filePath)
if err == nil {
if fi.IsDir() {
defaultPath := []string{"index.vue", "index.html"}
for e := range defaultPath {
path := filepath.Join(filePath, defaultPath[e])
_, err := os.Stat(path)
if err == nil {
filePath = path
break
}
}
}
} else {
if filepath.Ext(filePath) == ".html" {
split := strings.Split(filePath, ".")
split[len(split)-1] = "vue"
vuePath := strings.Join(split, ".")
_, err := os.Stat(vuePath)
if err == nil {
filePath = vuePath
}
}
} }
result, err = ioutil.ReadFile(path)
if !pathExists(path) || err != nil {
result, err = ioutil.ReadFile(filePath)
if err != nil {
return gv.renderErrPage(404, request, goExtDataS...) return gv.renderErrPage(404, request, goExtDataS...)
} }
if filepath.Ext(path) != ".html" {
if filepath.Ext(filePath) != ".html" && filepath.Ext(filePath) != ".vue" {
return return
} }
@ -155,6 +194,11 @@ func (gv *GoVue) LoadStaticResources(request *http.Request, goExtDataS ...interf
goExtData = goExtDataS[0] goExtData = goExtDataS[0]
} }
err = gv.jsRuntimePool.JsRuntimeCall(func(jr *jsruntime.JsRuntime) { err = gv.jsRuntimePool.JsRuntimeCall(func(jr *jsruntime.JsRuntime) {
if filepath.Ext(filePath) == ".vue" {
jr.SetVariable("IS_VUE_SSR", true)
} else {
jr.SetVariable("IS_VUE_SSR", false)
}
err = jr.Render(filePath, fmt.Sprintf("http://%s%s", request.Host, request.RequestURI), string(result), goExtData, func(data string) { err = jr.Render(filePath, fmt.Sprintf("http://%s%s", request.Host, request.RequestURI), string(result), goExtData, func(data string) {
result = []byte(data) result = []byte(data)
}) })

122
jsruntime/runtime.go

@ -4,23 +4,27 @@ import (
"crypto/md5" "crypto/md5"
"fmt" "fmt"
"github.com/dop251/goja" "github.com/dop251/goja"
"github.com/go-errors/errors"
"html"
"io/ioutil" "io/ioutil"
"log" "log"
"net/url" "net/url"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"sync" "sync"
"time"
) )
type JsRuntime struct { type JsRuntime struct {
MainSrc string
UseSrcFun func() string
ExtFileDir string
Relys Relys
TimeoutSec int64
runtime *goja.Runtime
mutex sync.Mutex
MainSrc string
UseSrcFun func() string
ExtFileDir string
Relys Relys
TimeoutSec int64
runtime *goja.Runtime
mutex sync.Mutex
RenderCallBackFun func(string)
IsDebugModel bool
} }
type Rely struct { type Rely struct {
@ -55,14 +59,29 @@ func NewJsRuntime(mainScript string, extFileDir string, rels Relys, mode RunMode
jr.EnableConsoleFun() jr.EnableConsoleFun()
jr.SetVariable("GoReadFile", func(filePath string) string {
code, err := ioutil.ReadFile(filepath.Join(jr.ExtFileDir, filePath))
if err != nil {
jr.PrintError(fmt.Sprintln("GoRunCodeByFile Read Error:", err.Error()), string(code))
}
return string(code)
})
jr.SetVariable("GoRunCode", func(code string) {
err = jr.RunCode(string(code))
if err != nil {
jr.PrintError(fmt.Sprintln("GoRunCode Run Error:", err.Error()), code)
}
})
jr.SetVariable("GoRunCodeByFile", func(filePath string) { jr.SetVariable("GoRunCodeByFile", func(filePath string) {
code, err := ioutil.ReadFile(filepath.Join(jr.ExtFileDir, filePath)) code, err := ioutil.ReadFile(filepath.Join(jr.ExtFileDir, filePath))
if err != nil { if err != nil {
log.Println("GoRunCodeByFile Read Error:", err)
jr.PrintError(fmt.Sprintln("GoRunCodeByFile Read Error:", err.Error()), string(code))
} }
err = jr.RunCode(string(code)) err = jr.RunCode(string(code))
if err != nil { if err != nil {
log.Println("GoRunCodeByFile Run Error:", err)
jr.PrintError(fmt.Sprintln("GoRunCodeByFile Run Error:", err.Error()), string(code))
} }
}) })
err = jr.InitJsCode() err = jr.InitJsCode()
@ -73,6 +92,67 @@ func NewJsRuntime(mainScript string, extFileDir string, rels Relys, mode RunMode
return jr, nil return jr, nil
} }
func (jr *JsRuntime) PrintError(msg string, code string) {
if !jr.IsDebugModel {
log.Println(msg)
}
var errLine string
var line = -1
evalErr := strings.Split(msg, "<eval>")
if len(evalErr) > 1 {
evalErr = strings.Split(evalErr[1], ":")
if len(evalErr) > 1 {
line, _ = strconv.Atoi(evalErr[1])
}
}
if line == -1 {
evalErr = strings.Split(msg, ": Line ")
if len(evalErr) > 1 {
evalErr = strings.Split(evalErr[1], ":")
if len(evalErr) > 0 {
line, _ = strconv.Atoi(evalErr[0])
}
}
}
//log.Println("error line", line,evalErr)
if line > -1 {
lines := strings.Split(string(code), "\n")
linesStart := line - 15
linesEnd := line + 15
if linesStart < 0 {
linesStart = 0
}
if len(lines)-1 < linesEnd {
linesEnd = len(lines)
}
log.Println("error line linesEnd", linesEnd)
//linesEnd = linesStart + linesEnd
for e := range lines[linesStart:linesEnd] {
if e+linesStart+1 == line {
lines[linesStart:linesEnd][e] = fmt.Sprintf(`%2d: >>>>>> %s`, e+linesStart, lines[linesStart:linesEnd][e])
} else {
lines[linesStart:linesEnd][e] = fmt.Sprintf(`%2d: %s`, e+linesStart, lines[linesStart:linesEnd][e])
}
}
errLine = strings.Join(lines[linesStart:linesEnd], "\n")
}
if jr.RenderCallBackFun != nil {
jr.RenderCallBackFun(fmt.Sprintf(`
<body style="background: #eeeeee;padding: 5%%;width:85%%;">
<h3 style="color: red;">%s</h3>
<div style="background: #fff;">
<pre style="width:95%%;font-size: 14px; padding: 2%%; ">%s<pre>
</div>
</body>
`, html.EscapeString(msg), html.EscapeString(errLine)))
jr.RenderCallBackFun = func(s string) {
}
}
}
func (jr *JsRuntime) InitJsCode() error { func (jr *JsRuntime) InitJsCode() error {
for e := range jr.Relys { for e := range jr.Relys {
@ -82,7 +162,6 @@ func (jr *JsRuntime) InitJsCode() error {
//log.Println(e, "加载时间:", end-start) //log.Println(e, "加载时间:", end-start)
if err != nil { if err != nil {
log.Println("initjscode", err)
return err return err
} }
} }
@ -108,6 +187,7 @@ func (jr *JsRuntime) RunCode(code string) error {
if !ok { if !ok {
pro, err := goja.Compile("", code, false) pro, err := goja.Compile("", code, false)
if err != nil { if err != nil {
log.Println("Compile Error")
return err return err
} }
codeMap.Store(id, pro) codeMap.Store(id, pro)
@ -116,10 +196,12 @@ func (jr *JsRuntime) RunCode(code string) error {
program := p.(*goja.Program) program := p.(*goja.Program)
_, err := jr.runtime.RunProgram(program) _, err := jr.runtime.RunProgram(program)
//log.Println("RunCode result", result)
return err return err
} }
func (jr *JsRuntime) Render(filePath, href, tplSrc string, GoExtData interface{}, cb func(data string)) (err error) { func (jr *JsRuntime) Render(filePath, href, tplSrc string, GoExtData interface{}, cb func(data string)) (err error) {
jr.RenderCallBackFun = cb
jr.mutex.Lock() jr.mutex.Lock()
defer jr.mutex.Unlock() defer jr.mutex.Unlock()
@ -140,18 +222,18 @@ func (jr *JsRuntime) Render(filePath, href, tplSrc string, GoExtData interface{}
if useSrc != "" { if useSrc != "" {
err = jr.RunCode(useSrc) err = jr.RunCode(useSrc)
if err != nil { if err != nil {
return errors.New(err.Error() + "1")
return err
} }
} }
url, err := url.Parse(href) url, err := url.Parse(href)
if err != nil { if err != nil {
return errors.New(err.Error() + "2")
return err
} }
url2, err := url.Parse(strings.Replace(filePath, `\`, "/", -1)) url2, err := url.Parse(strings.Replace(filePath, `\`, "/", -1))
if err != nil { if err != nil {
return errors.New(err.Error() + "3")
return err
} }
runtime.Set("GoExtData", GoExtData) runtime.Set("GoExtData", GoExtData)
@ -165,11 +247,19 @@ func (jr *JsRuntime) Render(filePath, href, tplSrc string, GoExtData interface{}
runtime.Set("GoPath", url2.Path) runtime.Set("GoPath", url2.Path)
runtime.Set("GoReturn", func(data string) { runtime.Set("GoReturn", func(data string) {
cb(data)
jr.RenderCallBackFun(data)
})
t := time.AfterFunc(time.Duration(jr.TimeoutSec), func() {
jr.runtime.Interrupt("time out")
jr.runtime.ClearInterrupt()
}) })
defer t.Stop()
err = jr.RunCode(mainSrc) err = jr.RunCode(mainSrc)
if err != nil { if err != nil {
return errors.New(err.Error() + "4")
return err
} }
return return

36
jsruntime/timeout.go

@ -2,29 +2,13 @@ package jsruntime
import ( import (
"github.com/dop251/goja" "github.com/dop251/goja"
"log"
) )
func (jr *JsRuntime) EnableTimeoutFunc() { func (jr *JsRuntime) EnableTimeoutFunc() {
//
//var funs []func()
//var task func()
//task = func() {
// recover()
// go task()
// for ; ; {
// l := len(funs)
// if len(funs) > 0 {
// fun := funs[l-1]
// funs = funs[:l-1]
// fun()
// }
// time.Sleep(time.Second / 100)
// }
//}
//go task()
jr.runtime.Set("setTimeout", func(call goja.FunctionCall) goja.Value { jr.runtime.Set("setTimeout", func(call goja.FunctionCall) goja.Value {
//log.Println("setTimeout")
//log.Println(call.Argument(0))
if fn, ok := goja.AssertFunction(call.Argument(0)); ok { if fn, ok := goja.AssertFunction(call.Argument(0)); ok {
//delay := call.Argument(1).ToInteger() //delay := call.Argument(1).ToInteger()
var args []goja.Value var args []goja.Value
@ -33,22 +17,12 @@ func (jr *JsRuntime) EnableTimeoutFunc() {
} }
//time.Sleep(time.Duration(delay) * time.Millisecond) //time.Sleep(time.Duration(delay) * time.Millisecond)
fn(nil, args...)
//
//time.AfterFunc(time.Duration(delay) * time.Millisecond, func(){
// fn(nil, args...)
//})
//funs = append(funs, func() {
// time.Sleep(time.Duration(delay) * time.Millisecond)
// fn(nil, args...)
//})
//log.Println("setTimeout ok")
fn(nil, args...)
} }
return jr.runtime.ToValue(123124512) return jr.runtime.ToValue(123124512)
}) })
jr.runtime.Set("clearTimeout", func(i int64) { jr.runtime.Set("clearTimeout", func(i int64) {
//log.Println("clearTimeout")
log.Println("clearTimeout暂未支持")
}) })
} }

10
pool/pool.go

@ -24,15 +24,17 @@ var DefaultConfig Config
var useSrc string var useSrc string
func NewJsRuntimePool(mainScript string, useFileName string, staticPath string, relys jsruntime.Relys, mode jsruntime.RunMode) (jrp *JsRuntimePool) {
func NewJsRuntimePool(mainScript string, useFileName string, staticPath string, relys jsruntime.Relys, mode jsruntime.RunMode, debug bool) (jrp *JsRuntimePool) {
jrp = &JsRuntimePool{} jrp = &JsRuntimePool{}
factory := pool.NewPooledObjectFactorySimple( factory := pool.NewPooledObjectFactorySimple(
func(context.Context) (interface{}, error) { func(context.Context) (interface{}, error) {
render, err := jsruntime.NewJsRuntime(mainScript, staticPath, relys, mode) render, err := jsruntime.NewJsRuntime(mainScript, staticPath, relys, mode)
render.UseSrcFun = func() string {
return useSrc
if err == nil {
render.IsDebugModel = debug
render.UseSrcFun = func() string {
return useSrc
}
} }
return render, err return render, err
}) })

49
static/index.html

@ -4,26 +4,50 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="keywords" content=""> <meta name="keywords" content="">
<link rel="stylesheet" href="css/main.css"> <link rel="stylesheet" href="css/main.css">
<script src="js/vue.min.js"></script>
<script src="js/vue.js" gv-src></script>
</head> </head>
<body> <body>
<div id="app" class="content">
<my-title></my-title>
<a>{{desc}}</a>
</div>
<div id="demo" class="content">
<h3>{{title}}</h3>
<a v-on:click="click" class="gv-ignore" >触发事件</a>
<div id="demo">
<div>searchShops</div>
</div> </div>
</body> </body>
<script src="index.js" gv-src></script>
<script gv-src gv-common>
new Vue({
<script gv-src>
a = function () {
this.m5 = function () {
this.m(this.c)
};
this.m2 = (new Function("with(this){m(c)}"))
this.m3 = (new Function("with(this){m4('hello')}"))
};
a.prototype.c = "hello";
a.prototype.m = function () {
console.log("c:", this.c)
};
a.prototype.m4 = function (a) {
console.log(this);
console.log("c:", a)
};
b = new a();
b.m5();
b.m3();
b.m2();
</script>
<script gv-src>
var a = new Vue({
el: "#demo", el: "#demo",
data: { data: {
title: "两端通用加载"
title: "两端通用加载",
categoryList: [],
swiperList: [],
searchShops: "123",
}, },
methods: { methods: {
click: function () { click: function () {
@ -34,5 +58,4 @@
</script> </script>
</html> </html>

23
static/use.js

@ -1,21 +1,5 @@
//公用 //公用
GoUse(function () { GoUse(function () {
if (GoExtData){
console.log("GoExtData",JSON.stringify(GoExtData))
}
// 定义一个名为 button-counter 的新组件
document.title = "govue";
document
.getElementsByName("keywords")[0]
.setAttribute("content", "govue,服务端渲染,ssr");
Vue.component('my-title', {
template: '<h1 id="title">govue</h1>'
});
}); });
@ -26,11 +10,4 @@ GoUse(function () {
//分页面 //分页面
GoUseRegistered("index", function (query) { GoUseRegistered("index", function (query) {
new Vue({
el: "#app",
data: {
"desc": "基础golang开发的一套vue服务端渲染方案"
},
});
}); });
Loading…
Cancel
Save