Commit 863dc558 authored by Robert Knight's avatar Robert Knight

Make boot URL templating work in IE 11 / early Edge

Make the boot URL templating used during development work in IE 11 and
Edge. In IE 11 `document.currentScript` is not available and in IE 11 /
early Edge, the `URL` constructor is not available before polyfills have
been loaded.

The `document.currentScript` fallback here assumes that the boot script
has been loaded synchronously so that the boot script is the last
`<script>` element on the page at the point when it runs.

Also add a fast path for production builds where URLs do not contain
template params.

This is a follow up to #1441
parent 1c80ed66
......@@ -6,7 +6,7 @@ describe('processUrlTemplate', () => {
let fakeDocument;
beforeEach(() => {
fakeDocument = { currentScript: null };
fakeDocument = { currentScript: null, querySelectorAll: sinon.stub() };
});
context('when `document.currentScript` is set', () => {
......@@ -34,12 +34,27 @@ describe('processUrlTemplate', () => {
});
context('when `document.currentScript` is not set', () => {
it('does not replace parameters', () => {
beforeEach(() => {
fakeDocument.querySelectorAll
.withArgs('script')
.returns([{ src: 'http://test-host:3001/script.js' }]);
});
it('falls back to using origin info from the last <script> tag in the document', () => {
const url = processUrlTemplate(
'{current_scheme}://{current_host}:2000/style.css',
fakeDocument
);
assert.equal(url, '{current_scheme}://{current_host}:2000/style.css');
assert.equal(url, 'http://test-host:2000/style.css');
});
it('does not try to determine the origin if there are no URL template params', () => {
const url = processUrlTemplate(
'https://hypothes.is/embed.js',
fakeDocument
);
assert.equal(url, 'https://hypothes.is/embed.js');
assert.notCalled(fakeDocument.querySelectorAll);
});
});
});
'use strict';
function currentScriptUrl(document_ = document) {
/**
* Extract the protocol and hostname (ie. host without port) from the URL.
*
* We don't use the URL constructor here because IE and early versions of Edge
* do not support it and this code runs early in the life of the app before any
* polyfills can be loaded.
*/
function extractOrigin(url) {
const match = url.match(/(https?):\/\/([^:/]+)/);
if (!match) {
return null;
}
return { protocol: match[1], hostname: match[2] };
}
function currentScriptOrigin(document_ = document) {
try {
const scriptEl = document_.currentScript;
return new URL(scriptEl.src);
let scriptEl = document_.currentScript;
if (!scriptEl) {
// Fallback for IE 11.
const scripts = document_.querySelectorAll('script');
scriptEl = scripts[scripts.length - 1];
}
return extractOrigin(scriptEl.src);
} catch (err) {
return null;
}
......@@ -19,11 +41,18 @@ function currentScriptUrl(document_ = document) {
* with the IP/hostname of the dev server.
*/
function processUrlTemplate(url, document_ = document) {
const scriptUrl = currentScriptUrl(document_);
if (scriptUrl) {
url = url.replace('{current_host}', scriptUrl.hostname);
url = url.replace('{current_scheme}', scriptUrl.protocol.slice(0, -1));
if (url.indexOf('{') === -1) {
// Not a template. This should always be the case in production.
return url;
}
const origin = currentScriptOrigin(document_);
if (origin) {
url = url.replace('{current_host}', origin.hostname);
url = url.replace('{current_scheme}', origin.protocol);
}
return url;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment