兼容wkwebview的defer不生效,延迟js加载
Showing
3 changed files
with
182 additions
and
10 deletions
@@ -14,7 +14,6 @@ const watcher = { | @@ -14,7 +14,6 @@ const watcher = { | ||
14 | 14 | ||
15 | let renderer; | 15 | let renderer; |
16 | let realyPromise; | 16 | let realyPromise; |
17 | -let template = fs.readFileSync(path.join(__dirname, './apps/index.html'), 'utf-8'); | ||
18 | 17 | ||
19 | if (cluster.isMaster) { | 18 | if (cluster.isMaster) { |
20 | const masterApp = express(); | 19 | const masterApp = express(); |
@@ -22,7 +21,7 @@ if (cluster.isMaster) { | @@ -22,7 +21,7 @@ if (cluster.isMaster) { | ||
22 | realyPromise = devServer(masterApp, params => { | 21 | realyPromise = devServer(masterApp, params => { |
23 | renderer = createBundleRenderer(params.bundle, Object.assign(params.options, { | 22 | renderer = createBundleRenderer(params.bundle, Object.assign(params.options, { |
24 | runInNewContext: false, | 23 | runInNewContext: false, |
25 | - template | 24 | + inject: false |
26 | })); | 25 | })); |
27 | }); | 26 | }); |
28 | let childWorker = cluster.fork(); | 27 | let childWorker = cluster.fork(); |
@@ -34,7 +33,12 @@ if (cluster.isMaster) { | @@ -34,7 +33,12 @@ if (cluster.isMaster) { | ||
34 | if (err) { | 33 | if (err) { |
35 | console.error(err); | 34 | console.error(err); |
36 | } | 35 | } |
37 | - worker.send({action: 'ssr_request', html, err: err && JSON.stringify(err)}); | 36 | + const styles = msg.context.renderStyles(); |
37 | + const scripts = msg.context.renderScripts(); | ||
38 | + const resources = msg.context.renderResourceHints(); | ||
39 | + const states = msg.context.renderState(); | ||
40 | + | ||
41 | + worker.send({action: 'ssr_request', html, styles, scripts, resources, states, err: err && JSON.stringify(err)}); | ||
38 | }); | 42 | }); |
39 | }); | 43 | }); |
40 | } | 44 | } |
@@ -9,6 +9,7 @@ const routes = require('../../config/ssr-routes'); | @@ -9,6 +9,7 @@ const routes = require('../../config/ssr-routes'); | ||
9 | const redis = require('../../utils/redis'); | 9 | const redis = require('../../utils/redis'); |
10 | const routeEncode = require('../../utils/route-encode'); | 10 | const routeEncode = require('../../utils/route-encode'); |
11 | const {createBundleRenderer} = require('vue-server-renderer'); | 11 | const {createBundleRenderer} = require('vue-server-renderer'); |
12 | +const Handlebars = require('handlebars'); | ||
12 | const logger = global.yoho.logger; | 13 | const logger = global.yoho.logger; |
13 | const config = global.yoho.config; | 14 | const config = global.yoho.config; |
14 | 15 | ||
@@ -18,8 +19,11 @@ let renderer; | @@ -18,8 +19,11 @@ let renderer; | ||
18 | let serverBundle; | 19 | let serverBundle; |
19 | let degradeHtml; | 20 | let degradeHtml; |
20 | 21 | ||
22 | +const hbs = fs.readFileSync(path.join(__dirname, '../views/index.hbs'), 'utf-8'); | ||
23 | + | ||
24 | +const template = Handlebars.compile(hbs); | ||
25 | + | ||
21 | if (!isDev) { | 26 | if (!isDev) { |
22 | - const template = fs.readFileSync(path.join(__dirname, '../../index.html'), 'utf-8'); | ||
23 | 27 | ||
24 | degradeHtml = fs.readFileSync(path.join(__dirname, '../../degrade.html'), 'utf-8'); | 28 | degradeHtml = fs.readFileSync(path.join(__dirname, '../../degrade.html'), 'utf-8'); |
25 | 29 | ||
@@ -28,11 +32,28 @@ if (!isDev) { | @@ -28,11 +32,28 @@ if (!isDev) { | ||
28 | 32 | ||
29 | renderer = createBundleRenderer(serverBundle, { | 33 | renderer = createBundleRenderer(serverBundle, { |
30 | runInNewContext: false, | 34 | runInNewContext: false, |
31 | - template, | ||
32 | - clientManifest | 35 | + clientManifest, |
36 | + inject: false | ||
33 | }); | 37 | }); |
34 | } | 38 | } |
35 | 39 | ||
40 | +const REG_SCRIPT = /src="([^"]+)"/g; | ||
41 | + | ||
42 | +const asyncLoadScripts = (renderScripts) => { | ||
43 | + let match; | ||
44 | + const scripts = []; | ||
45 | + | ||
46 | + while ((match = REG_SCRIPT.exec(renderScripts))) { | ||
47 | + scripts.push({ | ||
48 | + src: match[1], | ||
49 | + index: scripts.length | ||
50 | + }); | ||
51 | + } | ||
52 | + | ||
53 | + return scripts; | ||
54 | +}; | ||
55 | + | ||
56 | + | ||
36 | const getContext = (req) => { | 57 | const getContext = (req) => { |
37 | return { | 58 | return { |
38 | url: req.url, | 59 | url: req.url, |
@@ -103,13 +124,33 @@ const render = (route) => { | @@ -103,13 +124,33 @@ const render = (route) => { | ||
103 | let context = getContext(req); | 124 | let context = getContext(req); |
104 | 125 | ||
105 | renderer.renderToString(context, (err, html) => { | 126 | renderer.renderToString(context, (err, html) => { |
127 | + | ||
106 | if (err) { | 128 | if (err) { |
107 | return handlerError(err, req, res, next); | 129 | return handlerError(err, req, res, next); |
108 | } | 130 | } |
131 | + const styles = context.renderStyles(); | ||
132 | + let scripts = context.renderScripts(); | ||
133 | + const resources = context.renderResourceHints(); | ||
134 | + const states = context.renderState(); | ||
135 | + let asyncScripts; | ||
136 | + | ||
137 | + if (req.yoho.isiOS) { | ||
138 | + asyncScripts = asyncLoadScripts(scripts); | ||
139 | + } | ||
140 | + | ||
141 | + const result = template({ | ||
142 | + html, | ||
143 | + styles, | ||
144 | + scripts, | ||
145 | + asyncScripts, | ||
146 | + resources, | ||
147 | + states | ||
148 | + }); | ||
149 | + | ||
109 | if (config.useCache && route.cache && ck) { | 150 | if (config.useCache && route.cache && ck) { |
110 | - redis.setex(ck, route.cacheTime || 60, html); | 151 | + redis.setex(ck, route.cacheTime || 60, result); |
111 | } | 152 | } |
112 | - return res.send(html); | 153 | + return res.send(result); |
113 | }); | 154 | }); |
114 | } catch (error) { | 155 | } catch (error) { |
115 | return next(error); | 156 | return next(error); |
@@ -158,10 +199,21 @@ const devRender = (route) => { | @@ -158,10 +199,21 @@ const devRender = (route) => { | ||
158 | } catch (error) {} // eslint-disable-line | 199 | } catch (error) {} // eslint-disable-line |
159 | return handlerError(err, req, res, next); | 200 | return handlerError(err, req, res, next); |
160 | } | 201 | } |
202 | + let {styles, scripts, resources, states, html} = msg; | ||
203 | + | ||
204 | + const result = template({ | ||
205 | + html, | ||
206 | + styles, | ||
207 | + scripts, | ||
208 | + resources, | ||
209 | + states | ||
210 | + }); | ||
211 | + | ||
212 | + | ||
161 | if (config.useCache && route.cache && ck) { | 213 | if (config.useCache && route.cache && ck) { |
162 | - redis.setex(ck, route.cacheTime || 60, msg.html); | 214 | + redis.setex(ck, route.cacheTime || 60, result); |
163 | } | 215 | } |
164 | - return res.end(msg.html); | 216 | + return res.end(result); |
165 | } | 217 | } |
166 | }; | 218 | }; |
167 | 219 |
doraemon/views/index.hbs
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html lang="en"> | ||
3 | +<head> | ||
4 | + <meta charset="utf-8"> | ||
5 | + <title>{{title}}</title> | ||
6 | + <meta name="keywords" content=""> | ||
7 | + <meta name="description" content=""> | ||
8 | + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover"> | ||
9 | + <meta name="apple-mobile-web-app-status-bar-style" content="black"> | ||
10 | + <meta content="yes" name="apple-mobile-web-app-capable"> | ||
11 | + <meta content="telephone=no" name="format-detection"> | ||
12 | + <meta content="email=no" name="format-detection"> | ||
13 | + {{{resources}}} | ||
14 | + {{{styles}}} | ||
15 | + <script type="text/javascript"> | ||
16 | + (function(d,c){var e=d.documentElement,a="orientationchange" in window?"orientationchange":"resize",b=function(){var f=e.clientWidth;if(!f){return}if(f>=750){e.style.fontSize="40px"}else{e.style.fontSize=40*(f/750)+"px"}};if(!d.addEventListener){return}b();c.addEventListener(a,b,false);d.addEventListener("DOMContentLoaded",b,false)})(document,window); | ||
17 | + </script> | ||
18 | +</head> | ||
19 | +<body> | ||
20 | + {{{html}}} | ||
21 | + <div id="degrade-app"></div> | ||
22 | + <div id="main-wrap"> | ||
23 | + <div id="no-download"></div> | ||
24 | + </div> | ||
25 | + {{{states}}} | ||
26 | + {{#if asyncScripts}} | ||
27 | + <script> | ||
28 | + document.addEventListener('DOMContentLoaded', function() { | ||
29 | + console.log('DOMContentLoaded') | ||
30 | + setTimeout(function() { | ||
31 | + var s = document.getElementsByTagName("script")[0]; | ||
32 | + {{# asyncScripts}} | ||
33 | + var hm{{index}} = document.createElement("script"); | ||
34 | + hm{{index}}.async = true; | ||
35 | + hm{{index}}.src = "{{src}}"; | ||
36 | + s.parentNode.insertBefore(hm{{index}}, s); | ||
37 | + {{/ asyncScripts}} | ||
38 | + }, 200) | ||
39 | + }) | ||
40 | + </script> | ||
41 | + {{^}} | ||
42 | + {{{scripts}}} | ||
43 | + {{/if}} | ||
44 | + <script> | ||
45 | + setTimeout(function() { | ||
46 | + (function(w, d, s, j, f) { | ||
47 | + var a = d.createElement(s); | ||
48 | + var m = d.getElementsByTagName(s)[0]; | ||
49 | + | ||
50 | + w.YohoAcquisitionObject = f; | ||
51 | + | ||
52 | + w[f] = function() { | ||
53 | + w[f].p = arguments; | ||
54 | + }; | ||
55 | + | ||
56 | + a.async = 1; | ||
57 | + a.src = j; | ||
58 | + m.parentNode.insertBefore(a, m); | ||
59 | + }(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.4.18/yas.js', '_yas')); | ||
60 | + | ||
61 | + var _hmt = _hmt || []; | ||
62 | + | ||
63 | + (function() { | ||
64 | + function getUid() { | ||
65 | + var uid, | ||
66 | + name = 'app_uid', | ||
67 | + cookies = (document.cookie && document.cookie.split(';')) || []; | ||
68 | + | ||
69 | + for (var i = 0; i < cookies.length; i++) { | ||
70 | + if (cookies[i].indexOf(name) > -1) { | ||
71 | + uid = decodeURIComponent(cookies[i].replace(name + '=', '').trim()); | ||
72 | + break; | ||
73 | + } | ||
74 | + } | ||
75 | + | ||
76 | + if (!uid) return 0; | ||
77 | + | ||
78 | + uid = uid.split('::'); | ||
79 | + if (!uid || uid.length < 4) { | ||
80 | + return 0; | ||
81 | + } | ||
82 | + return uid[1]; | ||
83 | + } | ||
84 | + | ||
85 | + function queryString() { | ||
86 | + var vars = {}, | ||
87 | + hash, | ||
88 | + i; | ||
89 | + var hashes = window.location.search.slice(1).split('&'); | ||
90 | + | ||
91 | + for (i = 0; i < hashes.length; i++) { | ||
92 | + hash = hashes[i].split('='); | ||
93 | + vars[hash[0]] = hash[1]; | ||
94 | + } | ||
95 | + return vars; | ||
96 | + } | ||
97 | + | ||
98 | + var uid = getUid() || queryString().uid; | ||
99 | + | ||
100 | + uid = uid === 0 ? '' : uid; | ||
101 | + window._ozuid = uid; // 暴露ozuid | ||
102 | + if (window._yas) { | ||
103 | + window._yas(1 * new Date(), '2.4.16', 'yohoappweb', uid, '', ''); | ||
104 | + } | ||
105 | + | ||
106 | + (function() { | ||
107 | + var hm = document.createElement("script"); | ||
108 | + hm.src = "https://hm.baidu.com/hm.js?65dd99e0435a55177ffda862198ce841"; | ||
109 | + var s = document.getElementsByTagName("script")[0]; | ||
110 | + s.parentNode.insertBefore(hm, s); | ||
111 | + })(); | ||
112 | + }()); | ||
113 | + }, 500); | ||
114 | + </script> | ||
115 | +</body> | ||
116 | +</html> |
-
Please register or login to post a comment