This project has been migrated to https://github.com/ember-fastboot/ember-cli-fastboot/blob/master/packages/fastboot/
All issues will be transfered.
FastBoot is a library for rendering Ember.js applications in Node.js.
Home Page: http://ember-fastboot.com/
This project has been migrated to https://github.com/ember-fastboot/ember-cli-fastboot/blob/master/packages/fastboot/
All issues will be transfered.
I'm trying to transition fastboot
under the https
, it's works with redirection to http
version.
For example application.js
route
export default Ember.Route.extend({
model: function(param){
this.transitionTo('login');
}
});
request: https://domain.com
--> http://domain.com:3001/login
where 3001
fastboot port
How I can solve this problem?
When using the shoebox, it would seem that the following would make sense
let response = await fetch(...);
let jsonData = await response.json();
shoeboxStore.currentUser = jsonData;
shoebox.put('user-data', myShoeboxStore);
In my case, I ended up getting a cryptic error message (in fastboot only)
Upon investigating this, it turns out that the jsonData
I am given by way of fetch is likely modified at some point downstream (in my case a DS.Store#push
), and it then becomes a circular JSON structure as relationships are wired up.
The end result is that, at the time I call shoebox.put
, my object is serializable, but by the time the page is resolved (and the fastboot visit
completes), it becomes partially resolved into a much more complex (and circular) structure.
Some ideas for improving this experience:
If you accidentally provide an undefined
as a shoebox value, you get the stack trace:
TypeError: Cannot read property 'replace' of undefined
at escapeJSONString (/xxx/node_modules/fastboot/src/ember-app.js:478:16)
at createShoebox (/xxx/node_modules/fastboot/src/ember-app.js:453:17)
at visitRoute.then.then (/xxx/node_modules/fastboot/src/ember-app.js:316:11)
It would be easy to handle undefined and ignore them.
Hi there ๐
I'm currently working with the Ember Learning team to turn the Ember Guides into an Ember App (yay), but I have come across something that I thought was intermittent but I have been able to consistently recreate it now for the first time.
To recreate just checkout https://github.com/ember-learn/guides-app/tree/bug/fastboot-createComment-error npm i
and npm start
and you should have the new guides-app running locally. Navigate to http://localhost:4200/v2.17.0/tutorial/routes-and-templates/ and you will see an error on the command line.
Here is the stack trace:
There was an error running your app in fastboot. More info about the error:
TypeError: Cannot read property 'createComment' of undefined
at ListBlockOpcode.evaluate (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/@glimmer/runtime.js:6761:1)
at UpdatingVM.execute (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/@glimmer/runtime.js:6497:1)
at RenderResult.rerender (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/@glimmer/runtime.js:6855:1)
at RootState._this.render (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/ember-glimmer/renderer.js:65:1)
at TransactionRunner.runInTransaction (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/ember-metal.js:826:1)
at InertRenderer._renderRoots (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/ember-glimmer/renderer.js:293:1)
at InertRenderer._renderRootsTransaction (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/ember-glimmer/renderer.js:323:1)
at InertRenderer._revalidate (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/ember-glimmer/renderer.js:360:1)
at invokeWithOnError (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/backburner.js:267:1)
at Queue.flush (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/backburner.js:151:1)
at DeferredActionQueues.flush (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/backburner.js:329:1)
at Backburner.end (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/backburner.js:462:1)
at Backburner._run (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/backburner.js:793:1)
at Backburner._join (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/backburner.js:775:1)
at Backburner.join (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/backburner.js:529:1)
at Function.run.join (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/ember-metal.js:4453:1)
at Object.hash.success (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/tmp/broccoli_merge_trees-output_path-FClrsTXr.tmp/assets/addon-tree-output/modules/ember-data/adapters/rest.js:619:1)
at fire (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/node_modules/jquery-deferred/lib/jquery-callbacks.js:78:30)
at Object.fireWith (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/node_modules/jquery-deferred/lib/jquery-callbacks.js:188:7)
at Object.fire [as resolve] (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/node_modules/jquery-deferred/lib/jquery-callbacks.js:195:10)
at dataHandler (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/node_modules/najax/lib/najax.js:167:13)
at IncomingMessage.<anonymous> (/Users/mansona/git/stonecircle/opensource/ember-guides/guides-app/node_modules/najax/lib/najax.js:198:9)
at emitNone (events.js:110:20)
at IncomingMessage.emit (events.js:207:7)
at endReadableNT (_stream_readable.js:1059:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
My first thoughts are something to do with nesting {{#each}}
blocks because when you remove this line it all starts working again. I thought at first that it was the recursive component calls but the if you uncomment the following componentless implementation it still breaks.
This is what leads me to think it was the nested {{#each}}
that is causing the problem.
This issue does not happen in the browser, just in the fastboot environment.
In order to avoid conflicts w/ Dojo's require()
my addon (and others) have to change the name of the global require()
function used by Ember.
When running an example app that uses my addon in FastBoot, I see this error when I load the page: TypeError: ctx.require is not a function
, which comes from this line:
Line 179 in 8a408f6
I've been able to get around that and get the app working by passing in requireFunctionName
as one of the sandboxGlobals
and changing the above line to:
const requireFunctionName = ctx.requireFunctionName || 'require';
return ctx[requireFunctionName]('~fastboot/app-factory');
There's probably a better way, but that does work, and doesn't break any of FastBoot's existing tests.
Would you accept a PR that adds and documents that change? If not, would you recommend a different way that I can achieve the same?
This is me whining, but I thought that if I got trolled so hard by such a subtle thing, other might be and it could be a way of mitigating it.
A coworker of mine made this change in an ember-data adapter:
// Check that the returned data is of the expected format
- let headers = this.get('fastboot.request.headers');
- let contentType = headers.get('Content-Type');
+ let headers = get(this, 'fastboot.request.headers');
+ let contentType = get(headers, 'Content-Type');
By all means this seemed like a very reasonable code, it passed the review and got merged.
However, despite of what its so engrained in the mind of any Ember developer, headers.get(key)
and get(headers, key)
are not equivalent in this context.
See
fastboot/src/fastboot-headers.js
Lines 52 to 54 in bb63049
If there is a way we could prevent other developers to pull their hair, I'd be happy to help
since the index will generally point to fingerprinted assets, when i deploy updates to my ember application, the updated index will not be read by the fastboot server until i restart node. it would be really great if there was some way by which the fastboot server could detect a change to the index file on disk and re-read the index from disk--or if there was some means by which i could inform the fastboot server to re-read the index from disk (via redis or something?). or maybe fastboot could read the index from something like redis?
Parity with ember-fastboot/ember-cli-fastboot#513
cc: @rwjblue
As first discovered here the way fastboot serializes the body and head elements includes the tags themselves. Thus when the string substitution is performed to insert body & head into index.html the resulting content is a head within a head and body within body:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>HeadT</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="/" />
<!-- EMBER_CLI_FASTBOOT_TITLE --><head><meta name="ember-cli-head-start"><!-- `app/templates/head.hbs` -->
<!-- Add content you wish automatically added to the documents head -->
<!-- here. The 'model' available in this template can be populated by -->
<!-- setting values on the 'head-data' service. -->
<meta property="og:title" content="Demo App">
<meta name="ember-cli-head-end">
</head>
<link rel="stylesheet" href="assets/vendor.css">
<link rel="stylesheet" href="assets/head-t.css">
</head>
<body>
<body><div id="ember385" class="ember-view"><h2 id="title">Welcome to Ember</h2>
<!---->
</div></body>
<script src="assets/vendor.js"></script>
<script src="assets/head-t.js"></script>
</body>
</html>
clearTimeout is used by backburner, it should be exposed to the sandbox like is done with setTimeout.
Today, building app instance, booting app instance, visiting route, waiting for app on deferred promise and destroying the app instance are all done outside the context of the sandbox.
Ideally we should do it in the context of the sandbox. This issue tracks that. For more info look at PR #93 .
cc: @arjansingh @rwjblue
After upgrading to Ember 2.7 (which included the deprecation of baseURL) and starting an Ember app using Fastboot, the app tries to retrieve assets based on the rootURL specified, e.g.
However, Fastboot is still serving these assets from
This causes the assets not to be loaded.
I mentioned the issue here too, but am wondering if it's an issue with Fastboot itself.
ember install ember-cli-fastboot
fails because of ember-fastboot-server postInstall script on Windows
npm ERR! [email protected] postinstall: `scripts/is-not-legacy-vm || npm install contextify@^0.1.11`
npm ERR! Exit status 1
`scripts/is-not-legacy-vm || npm install contextify@^0.1.11`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] postinstall script 'scripts/is-not-legacy-vm || npm install contextify@^0.1.11'.
scripts/is-not-legacy-vm
won't run just by using #!/usr/bin/env node
as first line of scripts/is-not-legacy-vm
on Windows, so it tries to include contextify, which is not needed on recent node anyway, and requiring it is a kind of PITA because of prerequisites like specific version of Visual Studio installed. Changing postInstall to node scripts/is-not-legacy-vm || npm install contextify@^0.1.11
works on Windows, but perhaps something more universal would be a better idea.
In the new ember-api-docs, there is this template:
Fastbooot renders the .attribute
outside the .attributes
. On client side render it is OK.
Server side render (incorrect)
Client side render (correct)
Changing the tag name of .attributes
from p
to div
solved the issue there: https://github.com/ember-learn/ember-api-docs/pull/162/files
This is an issue with najax (najaxjs/najax#50) but based on the project's activity level, a proper fix does not look likely in the near future. It may be worth forking+patching it under ember-fastboot. We solved this with npm shrinkwrap for now but a proper downstream fix would be nice as this blocks a production release of our fastboot app.
I'm not sure if this is the right repo to open this issue, please let me know if it should be moved.
Currently the fastboot.request.protocol
is used when determining the ember data host to use for ED requests made from fastboot. See: https://github.com/ember-fastboot/ember-cli-fastboot/blob/5ecfe8e90ff07f2318eccecedce19c083b58bd21/fastboot/initializers/ajax.js#L9
It's common for load balancers to do SSL termination before sending a request to the fastboot app server. When this happens the protocol would be HTTP, but the LB would also add an X-Forwarded-Proto
header to the request.
This creates a problem because the fastboot-app-server thinks the protocol is HTTP, so when the fastboot run Ember app runs an Ember data query it will request data from http://${host}
, which will most likely 301 to https://${host}
. Since Ember data is running in fastboot/node, it will not follow redirects, and this leads to Ember data ending up with an empty request that throws an error.
One suggestion is to run the fastboot app server using only HTTPS and not have the LB terminate SSL. While this will fix the problem, not all of us have control over our load balancers. Currently, heroku does SSL termination before forwarding the request, so if you're running fastboot-app-server on heroku you'll always end up with an HTTP protocol + X-Forwarded-Proto: https
header.
My suggestion would be to have fastboot.request.protocol
check for an X-Forwarded-Proto header in the request and use that. I think this would lead to less surprises.
cc @kratiahuja @krasnoukhov since I know y'all were discussing this earlier today.
Using ember-cli-concat to concatenate all JS to a single app.js is not respected by fastboot.
It always requires a vendor.js file to be present
Relevant code from ember-fastboot-server
:
FastBootServer.prototype.insertIntoIndexHTML = function(title, body, head) {
var html = this.html.replace("<!-- EMBER_CLI_FASTBOOT_BODY -->", body);
if (title) {
html = html.replace("<!-- EMBER_CLI_FASTBOOT_TITLE -->", "<title>" + title + "</title>");
}
if (head) {
html = html.replace("<!-- EMBER_CLI_FASTBOOT_HEAD -->", head);
}
return html;
};
If I am not missing something, a title set by document.title
would be overridden by the more "general" <head>
tag. Shouldn't this order be reversed or am I missing something?
If so, I'll make a PR.
It would be terribly useful if I could start adding to the shoebox in express before my app starts rendering in fastboot. Possible API could be:
let app = new FastBoot({
distPath: 'path/to/dist',
shoebox: {
// ...
}
});
or
app.visit('/photos', {
shoebox: {
// ...
}
}).then(// ...
Does this make sense? Is there an existing alternative way to do this?
I have tried running fastboot server both from command line and as a middleware and both of them failed
As command
ember-fastboot --port 4301 --app-file app/app.js --vendor-file dist/assets/vendor.js --html-file app/index.html
throws an error: cannot find module '/Users/<username>/apps/myApp/--port'
As middleware:
var server = new FastBootServer({
appFile: path.join(root, 'app/app.js'),
vendorFile: path.join(root, 'dist/assets/vendor.js'),
htmlFile: path.join(root, 'app/index.html'),
ui: ''
});
(What should be the ui
variable set to? didn't find it readme)
throws this error: Cannot read property 'userAgent' of undefined
any help?
tracked upstream najaxjs/najax#62
When I run my app using ember fastboot
the shoebox works as expected, but when I run ember build
and then ember-fastboot dist/
the shoebox is never populated. I can see that fastboot.isFastBoot
is set to true when the response is rendered, but there's no <script>
tags containing the shoebox data in the response.
Given that Node 0.12 is not longer LTS, should we officially drop support for this in FastBoot? I believe ember-cli
dropped support for it. We also probably need to make an annoucement for the same so that users are not unhappy.
We hit this scenario at LinkedIn in production and we would like to push a similar fix to fastboot as well.
Consider the following scenario:
I think to handle such scenarios, we need to timeout the visit and destroy the app instance forcefully in such scenarios and send down a Fastboot response to let the client know.
Opening this issue so that it gets tracked.
DEBUG: -------------------------------
DEBUG: Ember : 2.3.1
DEBUG: Ember Data : 2.3.3
DEBUG: Model Fragments : 2.1.0
DEBUG: -------------------------------
/login
TypeError: Cannot read property 'writeLine' of undefined
at FastBootServer.log (/node_modules/ember-fastboot-server/lib/server.js:32:10)
at FastBootServer.handleSuccess (/node_modules/ember-fastboot-server/lib/server.js:46:8)
at success (/node_modules/ember-fastboot-server/lib/server.js:85:14)
at Timer.listOnTimeout (timers.js:119:15)`
This.ui comes from options.ui. (server.js line 20)
A) I have not found a reference to ui in the docs, so I'm not sure what to pass in.
B) According to #13, I should pass in distPath to new FastBootServer and nothing else
var server = new FastBootServer({
distPath: '../ember-test-app/fastboot-dist'
});
Should UI be completely optional?
A non-fastbooted payload is served if the insertion comments are missing from the base HTML. For those using an older version of ember-cli-html-minifier, these comments (and all comments!) are stripped and fastboot fails silently.
The aforementioned addon has added in fastboot compatibility, but I think a warning on the fastboot side is prudent as well.
Here's the offending fastboot code: https://github.com/ember-fastboot/fastboot/blob/master/src/result.js#L116-L122
I've been looking into ways to easily get chunked transfer encoding with FastBoot, the main motivation being that I'd like to have a mechanism where big shoeboxes don't unnecessarily delay initial rendering of the page.
I believe a really easy way to get this should be to send the response in 3 chunks:
</head>
</body></html>
Of course being able to send chunks of the document as it is rendered on the server side would be ideal but I guess that's a bigger change in the FastBoot internals so the above solution might be a good start?
I looked at the code and I guess it should be straight forward to add a chunks()
method (or so) to https://github.com/ember-fastboot/fastboot/blob/master/src/result.js and modify https://github.com/ember-fastboot/fastboot-express-middleware so that it writes each of the chunks instead of the complete HTML at once but I wanted to get some feedback before creating a PR.
I believe I've followed the README's usage instructions
Setup procedure
$ cd <app-dir>
$ ember install ember-cli-fastboot
$ # ... add dependencies to fastbootDependencies
$ ember build --environment production
$ cd ../new-dir
$ npm install fastboot
but I'm getting and error when I try to initialize the app:
TypeError: FastBoot.config is not a function
Full traceback
$ node --harmony
> const FastBoot = require('fastboot');
undefined
> let app = new FastBoot({distPath: '../appdir/dist'});
TypeError: FastBoot.config is not a function
at r.callback (/path/to/appdir/dist/fastboot/chexec-4b43a9d50d6c4ddb7a7238f13ffeb126.js:3:11339)
at r.exports (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:1991)
at r.build (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:2753)
at a (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:926)
at r.reify (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:2466)
at r.build (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:2740)
at a (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:926)
at r.reify (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:2466)
at r.build (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:2740)
at a (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:926)
at Object.requireModule (/path/to/appdir/dist/fastboot/vendor-a977a12b034745a0caa0ac14c4319f53.js:1:3030)
at Object.<anonymous> (/path/to/appdir-cli/node_modules/fastboot/lib/ember-app.js:129:18)
at Sandbox.VMSandbox.run (/path/to/appdir-cli/node_modules/fastboot/lib/vm-sandbox.js:18:13)
at EmberApp.retrieveSandboxedApp (/path/to/appdir-cli/node_modules/fastboot/lib/ember-app.js:128:30)
at new EmberApp (/path/to/appdir-cli/node_modules/fastboot/lib/ember-app.js:41:21)
at FastBoot._buildEmberApp (/path/to/appdir-cli/node_modules/fastboot/index.js:101:17)
at new FastBoot (/path/to/appdir-cli/node_modules/fastboot/index.js:47:10)
at repl:1:-51
at sigintHandlersWrap (vm.js:32:31)
at sigintHandlersWrap (vm.js:96:12)
at ContextifyScript.Script.runInContext (vm.js:31:12)
at REPLServer.defaultEval (repl.js:308:29)
at bound (domain.js:280:14)
at REPLServer.runBound [as eval] (domain.js:293:12)
at REPLServer.<anonymous> (repl.js:489:10)
at emitOne (events.js:101:20)
at REPLServer.emit (events.js:188:7)
at REPLServer.Interface._onLine (readline.js:232:10)
at REPLServer.Interface._line (readline.js:574:8)
at REPLServer.Interface._ttyWrite (readline.js:851:14)
at ReadStream.onkeypress (readline.js:119:10)
at emitTwo (events.js:106:13)
at ReadStream.emit (events.js:191:7)
at emitKeys (internal/readline.js:385:14)
at next (native)
at ReadStream.onData (readline.js:947:36)
at emitOne (events.js:96:13)
at ReadStream.emit (events.js:188:7)
at readableAddChunk (_stream_readable.js:177:18)
at ReadStream.Readable.push (_stream_readable.js:135:10)
at TTY.onread (net.js:542:20)
I'm likely doing something silly, but strangely, grepping for Fastboot.config
deosn't seem to turn up anything so it's not clear how I should go about debugging this...
I'm trying to start FastBoot server from command line providing this config file:
fastboot-config.js
module.exports = {
port: 8000,
appFile: "/app/app.js",
vendorFile: "fastboot-dist/assets/vendor.js",
htmlFile: "app/index.html"
};
and this is the output:
2015-12-29T06:57:16.243Z [Server 0] Server listening on port 8000
2015-12-29T06:57:16.252Z [Server 0] Starting rendering engine
2015-12-29T06:57:16.253Z [Renderer 0] Engine starting up (phantom)
/usr/local/lib/node_modules/ember-fastboot/lib/plugins/removeScriptTags.js:6
next();
^
TypeError: next is not a function
at Object.module.exports.beforeInit (/usr/local/lib/node_modules/ember-fastboot/lib/plugins/removeScriptTags.js:6:5)
at next (/usr/local/lib/node_modules/ember-fastboot/lib/renderer.js:245:14)
at PrerenderRenderer.pluginEvent (/usr/local/lib/node_modules/ember-fastboot/lib/renderer.js:252:3)
at Request._callback (/usr/local/lib/node_modules/ember-fastboot/lib/renderer.js:36:13)
at Request.self.callback (/usr/local/lib/node_modules/ember-fastboot/node_modules/request/request.js:198:22)
at emitTwo (events.js:87:13)
at Request.emit (events.js:172:7)
at Request.<anonymous> (/usr/local/lib/node_modules/ember-fastboot/node_modules/request/request.js:1035:10)
at emitOne (events.js:82:20)
at Request.emit (events.js:169:7)
Ember Version:
DEBUG: -------------------------------
DEBUG: Ember : 2.4.0-canary+2d622f12
DEBUG: Ember Data : 2.4.0-canary+24fdc95d73
DEBUG: jQuery : 1.11.3
DEBUG: -------------------------------
Ember Inspector Active
It is not clear how to serve assets when the app is booted with the command:
$ ember-fastboot path/to/dist --port 3000
What is the suggested way to do this?
@kratiahuja mentioned that we might be able to reduce memory leakage by injecting the Result
object as a global rather than just the FastBootInfo
object. I think she might have a good point.
That would involve inverting the current relationship between FastBootInfo
and Result
so it's not a trivial refactor, but it's doable.
Can someone explain the header splitting here?
fastboot/src/fastboot-headers.js
Line 8 in b62e795
this.headers[header] = headers[header].split(', ');
I noticed that it destroys the user agent in the header. Turns
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36'
into
[
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML',
'like Gecko) Chrome/55.0.2883.95 Safari/537.36'
]
which causes me to need this code in Ember:
let headers = get(this, 'fastboot.request.headers');
let userAgent = headers.get('user-agent');
if (userAgent instanceof Array) {
userAgent = userAgent.join(', ');
}
doc.title
was implemented pre ember-cli-head
. Since we are pre-1.0, I think we should consider deprecating doc.title
in favor of ember-cli-head
.
Suggested here #108 (comment)
We could use linting from eslint using ember-cli's rules as a baseline. This is great for new contributors because you don't need to know fastboot code is working, but updating the code the match the rules will get you some exposure.
https://snyk.io/test/github/ember-fastboot/fastboot shows that FastBoot is vulnerable to a ReDoS attack. FastBoot depends on glob@^4.0.5 which depends on minimatch@^2.0.1 which is vulnerable. More details about the vulnerability: https://snyk.io/vuln/npm:minimatch:20160620
glob should be updated to at least v7.1.1 where the issue was fixed.
When using rootURL on the router, FastBoot completely ignores it and runs the app with the default rootURL /
.
const Router = Ember.Router.extend({
rootURL: '/en/'
});
Here's a repo to test it: https://github.com/thorsteinsson/ember-fastboot-rooturl
I'm writing a plugin where I want to conditionally inject a loading UI dependent upon whether the page has already been rendered in Fastboot, or is initializing for the first time in the browser. For this use case, it'd be handy to be able to check for Fastboot rendered content in an instance initializer.
@arjansingh suggested using Fastboot response headers, but that involves firing off a blank XMLHttpRequest
to detect the page's initial HTTP headers, which seems a little messy.
I'm currently checking for Fastboot markup by injecting a bare component with a class .fastbooted
in a fastboot-targeted instance initializer, then in a browser-targeted instance initializer, using Ember.$('.fastbooted').length > 0
. Also messy.
My suggestion is to add an .ember-fastboot
class to the rendered body here, in the same way Ember adds an .ember-application
class to its body.
Better still, allow any attributes set on the Simple DOM body node to be passed through to the final HTML.
@pwfisher, @marcoow, and @briangonzalez. Many thanks for your help!
Redirects should not break the "Back" button. Redirecting with transitionTo
breaks the "Back" button by adding to browser history. replaceWith
replaces the current location in the browser's history so that the browser "Back" button will behave as expected.
Accordingly, FastBoot should disallow transitionTo
because it breaks the "Back" button. Instead, FastBoot should support replaceWith
for redirection.
FastBoot can extend replaceWith
to pass HTTP redirect status codes back to FastBoot Server, which would add it to the response along with the updated URL.
This could be implemented by 1) reopening Ember.Router
and modifying replaceWith
directly; 2) utilizing the willTransition
hook for Routes; or 3) adding a replaceWith
method to the FastBoot service and requiring developers to explicitly use that to opt in to FastBoot.
Ember navigation methods typically amend navigation history; however, those same methods are occasionally used to redirect the user.
http://app/protected/page
, but is unauthenticated. Here, we redirect them to http://app/login
.http://app/projects/14
, but the project with id
14 was deleted. Here, we redirect them to the main projects page, http://app/projects
.http://app/projects/14
, but the project is now grouped under Organization one, we would redirect them to the new route of http://app/organization/1/projects/14
.Redirection should not break browser history. In Ember, navigation methods alter browser history (via HTML5) as follows:
Method | HTML5 History |
---|---|
intermediateTransitionTo |
none |
transitionTo |
PUSH |
transitionToRoute |
PUSH |
Transition#retry |
PUSH |
replaceWith |
REPLACE |
Because transitionTo
adds a redirected URL to the browser history, it breaks the "Back" button by not allowing the user to navigate back past the redirect.
replaceWith
replaceWith
should be used for redirection in FastBoot because it does not add a redirected URL to the browser history. This both matches the specified behavior of HTTP 30X
status codes and does not break the "Back" button.
transitionTo
transitionTo
should only be called client-side.
GET
requestsBecause FastBoot Server is only concerned with rendering web pages, it should only handle GET
requests. Any other HTTP methods should be handled by other middleware or by a different part of the application's front-end stack.
While there is a compelling case for supporting only only temporary redirection codes, there are many situations where an Ember Application would need to support permanent redirection. In the case of Impermanent Routes, the application would want to signal the browser to update any bookmarked routes. For Permanently Redirected Routes, the same logic applies.
FastBoot should default to temporary redirection since permanent can be harmful.
Redirects in the Ember Application should:
Open Question: How do we abort rendering?
Redirects that FastBoot Server receives should be sent back to the browser, so that it can update itself accordingly and request the new URL.
Because FastBoot Server is middleware, developers can always intercept the request and handle the redirection before it reaches the client, though this is less desirable because it hides the redirection from the browser.
Ember.Router
and modify replaceWith
One way to implement this functionality is to reopen Ember.Router
and modify Router#replaceWith
to take an optional status code, abort rendering, and have it determine the new location. This solution is the most transparent to the Ember Application, but opens up a hard dependency on Ember.Router
internals.
Router#willTransition
Another way to implement this functionality is to hook into willTransition
, as the point where we abort rendering, generate a status code, and determine a new location. This is not as tightly coupled to Ember.Router
, but does present a less optimal interface for passing along the status code and determining the new location.
FastBoot#redirect
A third way is to create a redirect method on the FastBoot service that would abstract client-side vs server-side complexity from developers. FastBoot#redirect
would take the transition arguments plus an optional redirect status code.
This approach would not tightly couple FastBoot code with Ember.Router
. But it would result in FastBooted Applications having to modify their application to use FastBoot#redirect
everywhere they might use a Route#replaceWith
.
All responses must provide a target URI to the client.
Permanent redirection requires the client to update all cached references with the provided URI. Temporary redirection requires the client to not remember the provided URI and send all subsequent requests to the original URI.
Clients can redirect without user permission for GET
and HEAD
request methods. Other request methods require user permission.
Code | Status Text | Redirect Type | Redirecting Request Method |
---|---|---|---|
301 |
Moved Permanently | Permanent | May be changed |
302 |
Found | Temporary | Cannot change* |
303 |
See Other | Temporary | Must be GET |
307 |
Temporary Redirect | Temporary | Cannot change |
308 |
Permanent Redirect | Permanent | Cannot change |
* 302 status codes are not reliably implemented across browsers. Some browsers implement the request method specification properly. Others require the provided resource to be requested via GET
similar to 303
.
fastboot currently builds the application instance outside of the vm from within visitRoute
visitRoute
currently utilizies the sandbox indirectly, via this.app
which is created from an app factory returned from the sandbox.
If, instead, visitRoute
delegated its work to a function run within the sandbox context, prototype extensions would work (or at least an impediment to their working would be removed).
Hi, if didInsertElement
don't working as here https://github.com/ember-fastboot/ember-cli-fastboot#no-didinsertelement
How i do to make some after rendered DOM as like I always do without fastboot?
Rendered HTML inserted into index.html
via insertIntoIndexHTML
creates a second <title>
tag, the first being the generic <title>APP_NAME</title>
When the application route model rejects and the app enters an error substate, FastBoot should render a user-friendly error page and set a desired status code on the response.
FastBoot throws an error and renders empty page with status code 503.
Enter the error substate manually and prevent bubbling the error up:
routes/application.js
actions: {
error(err) {
const fastboot = this.get('fastboot');
if (fastboot.get('isFastBoot')) {
fastboot.set('response.statusCode', err.code);
this.intermediateTransitionTo('application_error', err);
return false;
}
return true;
}
}
It appears that you can update the body or head to be rendered by FastBoot, but even if you have added attributes to the documentElement ( tag) that they are ignored. If I am reading the code correctly the html is just the template html file from the ember app, head, and body are serialized from simpledom (but not documentElement
).
https://github.com/ember-fastboot/fastboot/blob/master/src/result.js#L128
function insertIntoIndexHTML(html, head, body) {
if (!html) { return Promise.resolve(html); }
if (body) {
let isBodyReplaced = false;
html = html.replace("<!-- EMBER_CLI_FASTBOOT_BODY -->", function() {
isBodyReplaced = true;
return body;
});
if (!isBodyReplaced) {
return missingTag('<!--EMBER_CLI_FASTBOTT_BODY-->');
}
}
if (head) {
let isHeadReplaced = false;
html = html.replace("<!-- EMBER_CLI_FASTBOOT_HEAD -->", function() {
isHeadReplaced = true;
return head;
});
if (!isHeadReplaced) {
return missingTag('<!--EMBER_CLI_FASTBOTT_HEAD-->');
}
}
return Promise.resolve(html);
}
Is this by design or could this be something to work on? It would address the following:
ember-fastboot/ember-cli-fastboot#331
Hi I've no idea what that means. I struggled to understand where this hostWhitelist should be defined without success.
My currently dirty environment.js has this:
var ENV = {
modulePrefix: 'gitconfig-client',
environment: environment,
baseURL: '/',
locationType: 'auto',
hostWhitelist: ['localhost'],
EmberENV: {
hostWhitelist: ['localhost'],
FEATURES: {
hostWhitelist: ['localhost'],
// Here you can enable experimental features on an ember canary build
// e.g. 'with-controller': true
},
EXTEND_PROTOTYPES: {
hostWhitelist: ['localhost'],
Date: false,
}
},
APP: {
hostWhitelist: ['localhost'],
// Here you can pass flags/options to your application instance
// when it is created
}
};
And the erro I get when starting FastBoot with:
ember fastboot --port 4200 --host localhost
Is this:
500 Unknown Error: Error: You are using Ember Data with no host defined in your adapter. This will attempt to use the host of the FastBoot request, which is not configured for the current host of this request. Please set the hostWhitelist property for in your environment.js. FastBoot Error: You must provide a hostWhitelist to retrieve the host
I ran into a particularly vicious error, where a stray window
reference caused the ApplicationInstance
to fail booting:
_bootPromise:
Promise {
_id: 14,
_label: undefined,
_state: 2,
_result: [TypeError: window.addEventListener is not a function],
_subscribers: [],
_onError: null } }
The failure was silent and I only detected it when I logged this.instance
inside of src/result.js
.
We should be logging these events (not swallowing them silently).
Of course, I'll open a PR but I want to know if result._finalize
is the place to do the error handling. Suggestions welcome.
This issue is an enhancement for future purposes.
Post FastBoot 1.0, we should look at emmitting some useful metrics like server side latency, memory used by the node processes so that apps using FastBoot can listen to these metrics and create useful operational dashboard.
This probably will need an RFC at some point IMO.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.