-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1800d63
commit edfd80d
Showing
2 changed files
with
198 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
const url = require('url'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const mime = require('mime'); | ||
const _ = require('lodash'); | ||
const normalizeUrl = require('normalize-url'); | ||
const { stripSlashes, ensureTrailingSlash } = require('../utils.js'); | ||
const PageNotFoundError = require('../error-types/PageNotFoundError.js'); | ||
|
||
const serverErrorTemplatePath = path.join(__dirname, '../', 'templates', 'server-error.html'); | ||
const serverErrorTemplate = fs.readFileSync(serverErrorTemplatePath, 'utf8'); | ||
const serverErrorPage = function serverErrorPage (error) { | ||
return { | ||
src: '', | ||
dest: '__acetate/server-error/index.html', | ||
error: error, | ||
template: serverErrorTemplate | ||
}; | ||
}; | ||
|
||
function normalizeRequestUrl (baseUrl) { | ||
// perform basic URL normalization | ||
baseUrl = normalizeUrl(baseUrl); | ||
|
||
// ensure we have leading `/` and no trailing `/` | ||
baseUrl = '/' + stripSlashes(url.parse(baseUrl).pathname || ''); | ||
|
||
// ensure there is a trailing slash unless there is a extension | ||
baseUrl = ensureTrailingSlash(baseUrl); | ||
|
||
// normalize index pages | ||
baseUrl = baseUrl.replace(/index.html?$/, ''); | ||
|
||
return baseUrl; | ||
} | ||
|
||
module.exports = function (acetate) { | ||
var pagesCache = {}; | ||
|
||
function findPage (requestUrl) { | ||
return acetate.loader.getPages() | ||
.then((pages) => acetate.transformer.transformPages(pages)) | ||
.then((pages) => { | ||
pagesCache = _.keyBy(pages, 'url'); | ||
return pages; | ||
}) | ||
.then((pages) => _.filter(pages, (page) => page.url === requestUrl)) | ||
.then((pages) => { | ||
if (pages.length > 1) { | ||
acetate.warn(`found ${pages.length} pages matching ${requestUrl} (${pages.map(page => page.src).join(',')})`); | ||
return pages[0]; | ||
} | ||
return pages[0]; | ||
}); | ||
} | ||
|
||
function renderPage (page, status = 200) { | ||
if (page.ignore) { | ||
acetate.warn(`Page ${page.src} is ignored but server will still process and serve it`); | ||
} | ||
|
||
return Promise.all([ | ||
Promise.resolve(page), | ||
acetate.renderer.renderPage(page) | ||
]) | ||
.then(([page, output]) => { | ||
pagesCache[page.url] = page; | ||
return Promise.all([ | ||
Promise.resolve(page), | ||
Promise.resolve(status), | ||
Promise.resolve(output) | ||
]); | ||
}) | ||
.catch((error) => { | ||
return Promise.all([ | ||
Promise.resolve(page), | ||
Promise.resolve(500), | ||
acetate.renderer.renderPage(serverErrorPage(error)) | ||
]); | ||
}); | ||
} | ||
|
||
const acetateMiddleware = function acetateMiddleware (request, response, next) { | ||
if (request.method !== 'GET') { | ||
next(); | ||
return; | ||
} | ||
|
||
const normalizedUrl = normalizeRequestUrl(request.url); | ||
acetate.debug(`Looking up ${normalizedUrl}`); | ||
findPage(normalizedUrl) | ||
.then(page => { | ||
if (!page) { | ||
return Promise.reject(new PageNotFoundError(normalizedUrl)); | ||
} | ||
return renderPage(page); | ||
}) | ||
.catch(error => { | ||
if (error.name === 'PageNotFoundError') { | ||
acetate.debug(`No page matching ${normalizedUrl} found`); | ||
next(); | ||
return Promise.reject(error); | ||
} else { | ||
return renderPage(serverErrorPage(error), 500); | ||
} | ||
}) | ||
.then(([page, status, html]) => { | ||
response.writeHead(status, {'Content-Type': mime.lookup(page.dest)}); | ||
response.end(html); | ||
}).catch((error) => { | ||
if (error.name !== 'PageNotFoundError') { | ||
acetate.error(`Uncaught error in middleware ${error}`); | ||
} | ||
}); | ||
}; | ||
|
||
acetateMiddleware.getPageCache = function () { | ||
return pagesCache; | ||
}; | ||
|
||
return acetateMiddleware; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
(function (socket) { | ||
var acetateRoot = document.createElement('div'); | ||
acetateRoot.style.position = 'fixed'; | ||
acetateRoot.style.top = '0'; | ||
acetateRoot.style.left = '0'; | ||
acetateRoot.style.right = '0'; | ||
acetateRoot.style.bottom = '0'; | ||
acetateRoot.style.width = '100%'; | ||
acetateRoot.style.height = '100%'; | ||
acetateRoot.style.background = '#7C8D9B'; | ||
acetateRoot.style.color = 'white'; | ||
acetateRoot.style.fontFamily = '"Lucida Grande","Lucida Sans Unicode","Lucida Sans","Trebuchet MS",Tahoma,sans-serif'; | ||
acetateRoot.style.textAlign = 'left'; | ||
acetateRoot.style.padding = '1rem'; | ||
acetateRoot.style.zIndex = '100000'; | ||
acetateRoot.style.overflow = 'scroll'; | ||
acetateRoot.style.boxSizing = 'border-box'; | ||
|
||
var acetateTitle = document.createElement('h1'); | ||
acetateTitle.style.fontSize = '3rem'; | ||
acetateTitle.innerText = 'Acetate Error'; | ||
acetateRoot.appendChild(acetateTitle); | ||
|
||
var acetateMessage = document.createElement('code'); | ||
acetateMessage.style.fontSize = '2.5rem'; | ||
acetateRoot.appendChild(acetateMessage); | ||
|
||
var acetateStack = document.createElement('pre'); | ||
acetateStack.style.fontSize = '1.5rem'; | ||
acetateStack.style.border = '3px dashed #8A9BAB'; | ||
acetateStack.style.margin = '1rem 0'; | ||
acetateStack.style.padding = '1rem'; | ||
acetateStack.style.overflow = 'auto'; | ||
acetateRoot.appendChild(acetateStack); | ||
|
||
socket.on('acetate:init', function () { | ||
socket.emit('acetate:client-info', { | ||
url: window.location.pathname | ||
}); | ||
}); | ||
|
||
socket.on('acetate:connected', function () { | ||
log('[Acetate]', 'connected', []); | ||
}); | ||
|
||
socket.on('acetate:log', function (e) { | ||
log(e.prefix || '[Acetate]', e.message, e.extras || []); | ||
}); | ||
|
||
socket.on('acetate:fullscreen-message', function (e) { | ||
showFullScreenMessage(e.title, e.message, e.extra, e.timeout); | ||
}); | ||
|
||
socket.on('acetate:clear-fullscreen', function () { | ||
document.body.removeChild(acetateRoot); | ||
}); | ||
|
||
function log (prefix, message, extras) { | ||
var args = [prefix, message].concat(extras); | ||
console.log.apply(console, args); // eslint-disable-line no-console | ||
} | ||
|
||
function showFullScreenMessage (title, message, extra, timeout) { | ||
acetateTitle.innerText = title; | ||
acetateMessage.innerText = message; | ||
acetateStack.innerText = extra; | ||
|
||
document.body.appendChild(acetateRoot); | ||
|
||
if (timeout) { | ||
setTimeout(function () { | ||
document.body.removeChild(acetateRoot); | ||
}, timeout); | ||
} | ||
} | ||
})(window.___browserSync___.socket); |