Fixes
This commit is contained in:
1 parent
f041daeda3
commit
9407c26d2d
6 files changed
+301
-33
No files matched your search
+70
-7
@@ -24,6 +24,26 @@
|
||||
// template that extends or includes another names only the file.
|
||||
var TEMPLATES = './templates/';
|
||||
|
||||
// All of them. Named here rather than in either caller because this file is
|
||||
// the one that knows what a template is: sw.js precaches them from this list
|
||||
// and both renderers load them from it, so there is one place to add the
|
||||
// next one. A template missing from here is a template nunjucks would have
|
||||
// to fetch mid-render, which is the one thing loadAll() exists to prevent.
|
||||
var NAMES = [
|
||||
'base.njk',
|
||||
'page.njk',
|
||||
'book.njk',
|
||||
'index.njk',
|
||||
'bookmark.njk',
|
||||
'reference.njk',
|
||||
'verses.njk',
|
||||
'version.njk',
|
||||
'status.njk',
|
||||
'notice.njk'
|
||||
];
|
||||
|
||||
scope.TEMPLATE_URLS = NAMES.map(function (name) { return TEMPLATES + name; });
|
||||
|
||||
// readText(path) -> Promise<string> is the only thing the two callers do
|
||||
// differently: the worker reads through its cache, the page over the network.
|
||||
scope.createRenderer = function (readText) {
|
||||
@@ -42,10 +62,50 @@
|
||||
// worker, so they never go stale.
|
||||
var env = new nunjucks.Environment(new Loader(), { autoescape: true });
|
||||
|
||||
// Every template, in nunjucks' hands before the first render, because an
|
||||
// include that has to wait for one does not come out whole.
|
||||
//
|
||||
// getTemplate answers from the loader's cache by calling straight back,
|
||||
// and only reaches this loader -- and this loader's promise -- for a
|
||||
// template it has never seen. Nunjucks compiles {% include %} into a
|
||||
// waterfall, and the rest of the block it sits in is the waterfall's
|
||||
// callback while the code after that block runs on regardless. Answered
|
||||
// in the same tick the two happen in order and the output is whole;
|
||||
// answered a tick later the render is finished and handed back first,
|
||||
// and what comes back is missing the include and everything between it
|
||||
// and the end of its block. The verse list, and then the </select> after
|
||||
// it -- a picker with a chapter and no verses, on whichever navigation
|
||||
// happened to be the first to need the template.
|
||||
//
|
||||
// Which is why it is all of them and not just the ones that get included:
|
||||
// whether a template has been reached yet depends on which pages have
|
||||
// been rendered, and in the worker on whether it has been restarted since.
|
||||
// That is the whole shape of the bug -- intermittent, and never twice in a
|
||||
// row. One pass over a few kilobytes already in the cache buys the
|
||||
// question being settled.
|
||||
//
|
||||
// Failures resolve rather than reject: a template that cannot be read now
|
||||
// will fail again in the render that actually needs it, where the error
|
||||
// belongs to a request and can be answered with the bare fragment.
|
||||
var loaded = null;
|
||||
|
||||
function loadAll() {
|
||||
if (!loaded) {
|
||||
loaded = Promise.all(NAMES.map(function (name) {
|
||||
return new Promise(function (resolve) {
|
||||
env.getTemplate(name, true, null, false, function () { resolve(); });
|
||||
});
|
||||
}));
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
function render(name, context) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
env.render(name, context, function (err, out) {
|
||||
return err ? reject(err) : resolve(out);
|
||||
return loadAll().then(function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
env.render(name, context, function (err, out) {
|
||||
return err ? reject(err) : resolve(out);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -61,9 +121,11 @@
|
||||
// base.njk is for.
|
||||
//
|
||||
// chrome is what the shell needs and the fragment cannot carry: the
|
||||
// bookmark, and the navbar picker's model. Both are null from boot.html,
|
||||
// which has no worker to ask for either, and both render as a hidden
|
||||
// slot that fills itself if one ever appears.
|
||||
// bookmark, the navbar picker's model, and the two versions the worker
|
||||
// was built with. All three are null from boot.html, which has no worker
|
||||
// to ask for any of them; the first two render as a hidden slot that
|
||||
// fills itself if one ever appears, and the third renders as nothing,
|
||||
// because no worker is the whole of what there is to report.
|
||||
compose: function (fragment, chrome) {
|
||||
var title = (TITLE_RE.exec(fragment) || ['', ''])[1].trim();
|
||||
var content = fragment.replace(TITLE_RE, '');
|
||||
@@ -72,7 +134,8 @@
|
||||
title: title,
|
||||
content: content,
|
||||
mark: (chrome && chrome.mark) || null,
|
||||
reference: (chrome && chrome.reference) || null
|
||||
reference: (chrome && chrome.reference) || null,
|
||||
version: (chrome && chrome.version) || null
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
Reference in new issue
Block a user