-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Server Side Rendering Support #65
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice one! So is this to add a React API that can be used from .NET servers? Will the generated tags be recognized by React on the frontend side? (I think they need some special attributes for that.)
match child with | ||
| Some c -> c | ||
| None -> (renderList (children |> Seq.cast)) | ||
sprintf "<%s %s>%s</%s>" tag attrs child tag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sprintf
is a bit slow, I'd use +
for string concatenation here
[ rawText (sprintf """ | ||
var __INIT_STATE__ = %s | ||
""" (toJson initState)) ] | ||
script [ _src "http://localhost:8080/public/bundle.js" ] [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if this is a sample, I'd try to avoid the URL literal here. If you can't use public/bundle.js
because Wepback dev server and Giraffe are running in different ports, I'd use a variable so to minimize the chances http://localhost:8080
reaches production.
@@ -22,9 +22,13 @@ module Props = | |||
| Key of string | |||
| Ref of (Browser.Element->unit) | |||
interface IHTMLProp | |||
[<Pojo>] | |||
type DangeousHtml = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor typo: DangerousHtml
@alfonsogarciacaro Sorry for my late, I was planning to reply in this morning but got a busy day, then I forgot...:sweat_smile: I haven't tried this with React 16's new server-side rendering API .hydrate yet, but I suppose it will be OK because the HTML generated in server looks really like those from react-dom/server. I'll add it to samples to it works or not. |
@@ -755,22 +804,21 @@ let inline ofFunction<[<Pojo>]'P> (f: 'P -> ReactElement) (props: 'P) (children: | |||
/// Example: `ofImport "Map" "leaflet" { x = 10; y = 50 } []` | |||
let inline ofImport<[<Pojo>]'P> (importMember: string) (importPath: string) (props: 'P) (children: ReactElement list): ReactElement = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking to surround ofImport
, ofType
, ofFunction
with #if FABLE_COMPILER
to remove them when compiling on server-side. But this would cause conflicts with IDEs on frontend side, because they don't define FABLE_COMPILER
. Not sure, what's the best solution. I guess ofImport
throws an exception quickly (and users won't probably import a JS file in .NET either) but I don't know what happens with ofType
and ofFunction
. Do they throw exception or fail silently?
The other option would be to extract common parts into a Fable.React.Core
package and distribute two packages: Fable.React
for JS side and Fable.ReactServer
or Fable.React.Net
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may need a design guideline for shared libraries between JS and .NET. @MangelMaxime is already working on this: haf/Http.fs#142
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess ofImport throws an exception quickly (and users won't probably import a JS file in .NET either) but I don't know what happens with ofType and ofFunction. Do they throw exception or fail silently?
I was thinking this problem, too. In my imagination, we can create a help function by wrapping runtime exceptions in a function that only executed in the client side, but not tested yet.
let hybridView (clientView: 'model -> ReactElement) (serverView: 'model -> ReactElement) (model: 'model) =
#if FABLE_COMPILER
clientView model
#else
serverView model
#endif
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And import a js module could write like this:
#if FABLE_COMPILER
let JsComp: React.ComponentClass<JsCompProps> = importDefault "./jsComp"
#else
let JsComp = Unchecked.defaultof<React.ComponentClass<JsCompProps>>
#endif
e783262
to
376bc0b
Compare
30844e7
to
88f1b03
Compare
@alfonsogarciacaro But I got some trouble when implementing an isomorphic version of [<Emit(""" require($1)[$0] """)>]
let importOrDefault<'T> (selector: string) (path: string) =
Unchecked.defaultof<'T> |
I wouldn't use the
If you've made I'm OK with merging this 👍 Is it good to go or do you want to work a bit more on it? |
@alfonsogarciacaro I think I'm done here if I don't need to implement isomorphic |
Awesome, thanks a lot for this amazing feature @zaaack! I'll merge, try locally and let you know if I have any question 😄 |
Next step: tutorial how to do it. Please please please
Am 01.03.2018 14:55 schrieb "Alfonso Garcia-Caro" <notifications@github.com
:
Merged #65 <#65>.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#65 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AADgNOilfZzCaG1A8GnIwUINBMxyyyfKks5tZ_3QgaJpZM4SVDE5>
.
|
@zaaack any chance you cou try to add SSR to https://github.com/SAFE-Stack/SAFE-BookStore also the tutotial should contain some guidance on when to use it and when not. |
Good advice, I think I can add some guidance in the tutorial, but I'm not sure how to add DotNet core advertising? Actually I'm not an experienced dotnet developer, not sure about how to do this right... |
that dotnet core advertising is something that we need to take to the MS guys. Don't worry about that. |
Pure F#, No Nodejs Required!
Recently I'm working on a web app which needs SEO, while search engines in my country don't support SPA well, so server-side-rendering becomes my first choice. At first, I was looking at something like aspnet/JavaScriptServices, but it's a little complicated, and running nodejs instances in an asp.net server would require more overhead. it's just too complicated for my case.
This approach is inspired by Giraffe's view engine, it runs fable-react in the server side by simply replace each HTML tag to an
HTMLNode
tree, so it can be rendered to HTML.Props
react-dom/server
(with NODE_ENV=production) in my macbookCons
Elements created from js native won't render.
Elements support server-side rendering:
...