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', () => { ...@@ -6,7 +6,7 @@ describe('processUrlTemplate', () => {
let fakeDocument; let fakeDocument;
beforeEach(() => { beforeEach(() => {
fakeDocument = { currentScript: null }; fakeDocument = { currentScript: null, querySelectorAll: sinon.stub() };
}); });
context('when `document.currentScript` is set', () => { context('when `document.currentScript` is set', () => {
...@@ -34,12 +34,27 @@ describe('processUrlTemplate', () => { ...@@ -34,12 +34,27 @@ describe('processUrlTemplate', () => {
}); });
context('when `document.currentScript` is not set', () => { 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( const url = processUrlTemplate(
'{current_scheme}://{current_host}:2000/style.css', '{current_scheme}://{current_host}:2000/style.css',
fakeDocument 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'; '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 { try {
const scriptEl = document_.currentScript; let scriptEl = document_.currentScript;
return new URL(scriptEl.src);
if (!scriptEl) {
// Fallback for IE 11.
const scripts = document_.querySelectorAll('script');
scriptEl = scripts[scripts.length - 1];
}
return extractOrigin(scriptEl.src);
} catch (err) { } catch (err) {
return null; return null;
} }
...@@ -19,11 +41,18 @@ function currentScriptUrl(document_ = document) { ...@@ -19,11 +41,18 @@ function currentScriptUrl(document_ = document) {
* with the IP/hostname of the dev server. * with the IP/hostname of the dev server.
*/ */
function processUrlTemplate(url, document_ = document) { function processUrlTemplate(url, document_ = document) {
const scriptUrl = currentScriptUrl(document_); if (url.indexOf('{') === -1) {
if (scriptUrl) { // Not a template. This should always be the case in production.
url = url.replace('{current_host}', scriptUrl.hostname); return url;
url = url.replace('{current_scheme}', scriptUrl.protocol.slice(0, -1));
} }
const origin = currentScriptOrigin(document_);
if (origin) {
url = url.replace('{current_host}', origin.hostname);
url = url.replace('{current_scheme}', origin.protocol);
}
return url; 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