spatie / server-side-rendering

Server side rendering JavaScript in a PHP application
https://sebastiandedeyne.com/posts/2018/server-side-rendering-javascript-from-php
MIT License
602 stars 34 forks source link

Renderer supports JSON results #19

Closed robinvdvleuten closed 6 years ago

robinvdvleuten commented 6 years ago

I've added the functionality to return JSON objects from the JS script. This way the renderer becomes quite flexible and should allow you to return additional context like rendered CSS for example.

AlexeyTcapaev commented 6 years ago

@robinvdvleuten hi,u can show how u use it,for example?

robinvdvleuten commented 6 years ago

@AlexeyTcapaev sure, it's quite easy actually! Suppose you have the following "server-side" script;

import React from 'react'
import { renderToString } from 'react-dom/server'

// Render a React component to an HTML string
const Hello = () => <div>Hello, world!</div>
const renderedComponent = renderToString(<Hello />)

// Render the CSS-in-JS somehow (depending on your library)
const renderedStyling = 'body { color: #000 }'

// Dispatch the rendered output as HTML to the PHP side.
dispatch(JSON.stringify({ html: renderedComponent, css: renderedStyling }));

Then when invoking the script through this library in PHP;

// The result is already JSON decoded
$result = $this->renderer
   ->entry('server.js')
   ->render();

print <<<HTML
<html>
  <head>
    <style>${result['css']}</style>
  </head>
  <body>
    ${result['html']}
  </body>
</html>
>>>;
robinvdvleuten commented 6 years ago

@sebastiandedeyne did you already find the time to look at this?

AlexeyTcapaev commented 6 years ago

@robinvdvleuten ty for it,but I'm using a vue, but the difference is not great.

now i try to open environment with v8js and vue(vue-meta vuex vue router) and i have some problem to configure this:) u ever do something like that?

UPD: I just saw that you are not using the blade, right?

robinvdvleuten commented 6 years ago

@AlexeyTcapaev I am not using blade for the moment as I am using styled-components in my app and thus need to pass the styling to the HTML somehow, so I let Node.js render the complete HTML result and pass it back to Laravel.

I had some problems with V8js in the beginning so I went to Node.js immediately. If you look at my SSR setup (https://github.com/webstronauts/laravel-liftoff/blob/master/resources/assets/js/entry-server.js) and compare it with the Vue docs (https://ssr.vuejs.org/guide/#rendering-a-vue-instance), you would get very far I guess.

AlexeyTcapaev commented 6 years ago

@robinvdvleuten its true, i think me need to create without blade,and think about compile .vue files with styles.

ty for your fast answers!

robinvdvleuten commented 6 years ago

@AlexeyTcapaev you're welcome! I've created a single "template" in my application which just renders the React result. By using React router solely (or Vue's router in your case), it's quite easy to render different results from a single Blade template where my Blade template just looks like this;

{!! ssr('../server.js')
    ->context([
        'locale' => app()->getLocale(),
        'csrfToken' => csrf_token(),
        'data' => Auth::check() ? [ 'session' => ['user' => Auth::user()] ] : [],
    ])
    ->render()
!!}
AlexeyTcapaev commented 6 years ago

@robinvdvleuten and u have not problem with config webpack (laravel mix)? its task was not very trivial for me.

because if need style i find one solution extractVueStyles , but if i try use vue-loader ,than i have error for 'window'

robinvdvleuten commented 6 years ago

@AlexeyTcapaev I use my own Webpack scripts (https://github.com/webstronauts/liftoff-scripts) instead of Laravel Mix for that.

AlexeyTcapaev commented 6 years ago

@robinvdvleuten I will study it, thanks

robinvdvleuten commented 6 years ago

@sebastiandedeyne sorry but did you find the find to look into this PR?

sebastiandedeyne commented 6 years ago

Hi Robin,

Was on holiday and currently time is a bit scarce with client work. I'm gonna try to ge to this in the next 2 or 3 weeks, sorry for the delay!

robinvdvleuten commented 6 years ago

@sebastiandedeyne no problem!

sebastiandedeyne commented 6 years ago

I expected this to be a super complex feature so was amazed when I looked at the code here haha!

Gonna merge this. Maybe one thing we can do better: could we modify the dispatch function to take care of JSON.stringify? That way the package user doesn't need to know about any of this. They can just do dispatch({ html: '...' }) or dispatch('html'). I actually think we can always stringify the result, since strings stay strings.

robinvdvleuten commented 6 years ago

@sebastiandedeyne good thought! That shouldn't be too hard, just a sec then 👍

robinvdvleuten commented 6 years ago

@sebastiandedeyne there you go

sebastiandedeyne commented 6 years ago

Perfect, thanks!

alexandre-tobia commented 5 years ago

@robinvdvleuten Hi ! Does this work with vue-meta ? thanks !

cr-lgl commented 4 years ago

@robinvdvleuten It's work. Here is my example.

See also this issue.

You must use version vue-meta 2.3 or later.

https://vue-meta.nuxtjs.org/api/#debouncewait The key point is to set this property to zero.

cr-lgl commented 4 years ago

At this point, I think it is necessary to revise the example guided by Spatie.