Skip to content

Commit

Permalink
Merge pull request #372 from xg-wang/host
Browse files Browse the repository at this point in the history
fix: throwing w/ fresh ember-cli-fastboot serve
  • Loading branch information
xg-wang authored Nov 3, 2019
2 parents c94a71d + 8fdf660 commit b5a867e
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 30 deletions.
9 changes: 3 additions & 6 deletions fastboot/instance-initializers/setup-fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import { setupFastboot } from 'fetch';

/**
* To allow relative URLs for Fastboot mode, we need the per request information
* from the fastboot service. Then we set the protocol and host to fetch module.
* from the fastboot service. Then we save the request from fastboot info.
* On each fetch with relative url we get host and protocol from it.
*/
function patchFetchForRelativeURLs(instance) {
const fastboot = instance.lookup('service:fastboot');
const request = fastboot.get('request');
// Prember is not sending protocol
const protocol = request.protocol === 'undefined:' ? 'http:' : request.protocol;
// host is cp
setupFastboot(protocol, request.get('host'));
setupFastboot(fastboot.get('request'));
}

export default {
Expand Down
38 changes: 20 additions & 18 deletions public/fetch-fastboot.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,42 @@ define('fetch', ['exports'], function(exports) {
);
var nodeFetch = FastBoot.require('node-fetch');

function parseRequest(request) {
if (request === null) {
throw new Error('Trying to fetch with relative url but ember-fetch hasn\'t finished loading FastBootInfo, see details at https://github.com/ember-cli/ember-fetch#relative-url');
}
// Old Prember version is not sending protocol
const protocol = request.protocol === 'undefined:' ? 'http:' : request.protocol;
return [request.get('host'), protocol];
}

/**
* Build the absolute url if it's not, can handle:
* - protocol-relative URL (//can-be-http-or-https.com/)
* - path-relative URL (/file/under/root)
*
* @param {string} url
* @param {string} protocol
* @param {string} host
* @returns {string}
*/
function buildAbsoluteUrl(url, protocol, host) {
function buildAbsoluteUrl(url) {
if (protocolRelativeRegex.test(url)) {
let [host,] = parseRequest(REQUEST);
url = host + url;
} else if (!httpRegex.test(url)) {
if (!host) {
throw new Error(
'You are using using fetch with a path-relative URL, but host is missing from Fastboot request. Please set the hostWhitelist property in your environment.js.'
);
}
let [host, protocol] = parseRequest(REQUEST);
url = protocol + '//' + host + url;
}
return url;
}

var FastbootHost, FastbootProtocol;
var REQUEST = null;

class FastBootRequest extends nodeFetch.Request {
constructor(input, init) {
if (typeof input === 'string') {
input = buildAbsoluteUrl(input, FastbootProtocol, FastbootHost);
input = buildAbsoluteUrl(input);
} else if (input && input.href) {
// WHATWG URL or Node.js Url Object
input = buildAbsoluteUrl(input.href, FastbootProtocol, FastbootHost);
input = buildAbsoluteUrl(input.href);
}
super(input, init);
}
Expand All @@ -60,19 +63,18 @@ define('fetch', ['exports'], function(exports) {
*/
exports.default = function fetch(input, options) {
if (input && input.href) {
input.url = buildAbsoluteUrl(input.href, FastbootProtocol, FastbootHost);
input.url = buildAbsoluteUrl(input.href);
} else if (typeof input === 'string') {
input = buildAbsoluteUrl(input, FastbootProtocol, FastbootHost);
input = buildAbsoluteUrl(input);
}
return nodeFetch(input, options);
};
/**
* Assign the local protocol and host being used for building absolute URLs
* Assign the local REQUEST object for building absolute URLs
* @private
*/
exports.setupFastboot = function setupFastboot(protocol, host) {
FastbootProtocol = protocol;
FastbootHost = host;
exports.setupFastboot = function setupFastboot(fastBootRequest) {
REQUEST = fastBootRequest;
}
exports.Request = FastBootRequest;
exports.Headers = nodeFetch.Headers;
Expand Down
55 changes: 55 additions & 0 deletions test/fastboot-fetch-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict';
const request = require('request');
const get = require('rsvp').denodeify(request);
const chai = require('chai');
const expect = chai.expect;
chai.use(require('chai-fs'));

const AddonTestApp = require('ember-cli-addon-tests').AddonTestApp;

describe('renders in fastboot build', function() {
this.timeout(300000);

let app;

beforeEach(function() {
app = new AddonTestApp();

return app
.create('dummy', { skipNpm: true })
.then(app =>
app.editPackageJSON(pkg => {
pkg.devDependencies['ember-cli-fastboot'] = '*';
// [email protected] has ember-fetch as dependency, we want to test
pkg.devDependencies['ember-fetch-adapter'] = '0.4.0';
// These 2 are in ember-fetch's package.json, symlinking to dummy won't help resolve
pkg.devDependencies['abortcontroller-polyfill'] = '*';
pkg.devDependencies['node-fetch'] = '*';
})
)
.then(function() {
return app.run('npm', 'install');
})
.then(function() {
return app.startServer({
command: 'serve'
});
});
});

afterEach(function() {
return app.stopServer();
});

it('fetches in fastboot mode', function() {
return get({
url: 'http://localhost:49741/',
headers: {
Accept: 'text/html'
}
}).then(function(response) {
expect(response.body).to.contain('Hello World! fetch');
expect(response.body).to.contain('Hello World! fetch (Request)');
});
});
});
11 changes: 5 additions & 6 deletions test/fastboot-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ chai.use(require('chai-fs'));

const AddonTestApp = require('ember-cli-addon-tests').AddonTestApp;

describe('renders in fastboot build', function() {
describe('renders in fastboot build without calling fetch', function() {
this.timeout(300000);

let app;
Expand All @@ -16,7 +16,7 @@ describe('renders in fastboot build', function() {
app = new AddonTestApp();

return app
.create('dummy', { skipNpm: true })
.create('fresh', { skipNpm: true, noFixtures: true })
.then(app =>
app.editPackageJSON(pkg => {
pkg.devDependencies['ember-cli-fastboot'] = '*';
Expand Down Expand Up @@ -44,18 +44,17 @@ describe('renders in fastboot build', function() {
it('builds into dist/ember-fetch/fetch-fastboot.js ignoring sub dependency version conflict', function() {
expect(app.filePath('dist/index.html')).to.be.a.file();
expect(app.filePath('dist/ember-fetch/fetch-fastboot.js')).to.be.a.file();
expect(app.filePath('dist/assets/dummy-fastboot.js')).to.be.a.file();
expect(app.filePath('dist/assets/fresh-fastboot.js')).to.be.a.file();
});

it('fetches in fastboot mode', function() {
it('fresh serve works', function() {
return get({
url: 'http://localhost:49741/',
headers: {
Accept: 'text/html'
}
}).then(function(response) {
expect(response.body).to.contain('Hello World! fetch');
expect(response.body).to.contain('Hello World! fetch (Request)');
expect(response.body).to.contain('Congratulations, you made it!');
});
});
});

0 comments on commit b5a867e

Please sign in to comment.