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

Server-Side Rendering with PHP V8Js (without node.js) #4101

Closed
lerouxju opened this Issue Nov 3, 2016 · 17 comments

Comments

Projects
None yet
@lerouxju

lerouxju commented Nov 3, 2016

Feature description

PHP V8Js allows to execute JS server side. It is some sort of alternative to node.js.

Currently it is not possible to execute Vue.js this way. It complains that "setTimeout" & "document" are not defined.

As Vue.js is running fine server side with node.js it should be possible to run it with PHP V8Js.

Code sample

`<?php

$vueSource = file_get_contents('https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js');
$v8 = new V8Js();
$result = $v8->executeString($vueSource);
?>`

Result

V8Js::executeString():5628: ReferenceError: document is not defined"

@yyx990803

This comment has been minimized.

Member

yyx990803 commented Nov 3, 2016

The file you are importing is the standalone build that assumes browser environment. But regardless, I don't think it's possible (or involves non-trivial effort) to do Vue SSR in PHP V8js because:

  1. The vue-server-renderer package has other Node package dependencies, e.g. he and de-indent. This can be solved by bundling the whole package and these dependencies into one file;
  2. Some features rely on Node.js native modules like vm and stream. So even if you can get normal SSR working, you wouldn't be able to use stream mode or the bundleRenderer.

Basically, this is not something we are planning to work on, but we are definitely open to community contributions if anyone wants to make it work.

@yyx990803 yyx990803 closed this Nov 3, 2016

@bratao

This comment has been minimized.

bratao commented Dec 5, 2016

This is also a major decision blocker between React and Vuejs. The react have a v8js plugin and works perfectly.
I can allocate sometime next week to look if I can get any workaround. But if anyone have any progress in this use case, please inform here in this topic

@nirazul

This comment has been minimized.

nirazul commented Dec 5, 2016

Sever-side rendering without a node dependency would be a huge improvement for us as our backend heavily depends on a python stack. A V8 plugin would come in very handy.

@7ammer

This comment has been minimized.

7ammer commented Jan 29, 2017

Has any progress been made in this area? The Laravel community really needs something like this where Vuejs is concerned.

@muthu32

This comment has been minimized.

muthu32 commented Feb 11, 2017

If vue has to be used with php(Laravel), Then we have to sacrifice SEO for app.
If you need SEO (Serverside Rendering), Then you have to rely on node.js.If v8js is supported in vue, then that will be huge help to laravel community.

@gxrneyme

This comment has been minimized.

gxrneyme commented Mar 17, 2017

Has any progress been made in this area?

@youssef-lr

This comment has been minimized.

youssef-lr commented Mar 18, 2017

How cool would it be to have a blade directive @render_vue('my-vue-component', ['prop' => 1]) ?

@rohmanhm

This comment has been minimized.

Contributor

rohmanhm commented Mar 18, 2017

Maybe you can try this package https://github.com/lukechilds/browser-env if you had document not defined
I'm not sure yet

@rjvim

This comment has been minimized.

rjvim commented Apr 3, 2017

+1

@martinsotirov

This comment has been minimized.

martinsotirov commented Apr 5, 2017

We definitely need a workaround for setTimeout and the other missing things in non-Node V8 implementations.

I was trying to render my Vue.js app with some Go-based JS environments the other day and it didn't work for the same reason – setTimeout missing.

@neronmoon

This comment has been minimized.

neronmoon commented Apr 11, 2017

+1

@bratao

This comment has been minimized.

bratao commented Apr 22, 2017

@yyx990803 Could you please revisit this issue ?

@acidjazz

This comment has been minimized.

acidjazz commented Apr 30, 2017

@yyx990803 would be really awesome to have this! +9001

@posva

This comment has been minimized.

Member

posva commented Apr 30, 2017

Please, do not spam. The answer below is clear
We are open to community contributions, so if you have something to share, please, do it by commenting here. But do not comment to say +1 or Any updates? or any equivalent phrase
This issue may also be interesting: #5415

@jkoudys

This comment has been minimized.

jkoudys commented Sep 28, 2017

It looks like (nearly?) all the calls to setTimeout are using it to either defer a function call immediately (so they'll be called next pass in the event loop, ie 4ms), or for transition effects (which would be irrelevant for server side rendering).

A vue solution would be to implement your own stack to push functions to run on the next tick to instead of using setTimeout's stack. Shouldn't be too hard to write, but personally I rather like the pattern of using setTimeout to push await things I don't want blocking me.

This could be solved outside of vue by using an event loop implementation in your V8js. It does support a sleep() function already, which is all you'd really need to create your own loop with setTimeout & setInterval implemented. For it to work with php, ultimately your code will need to resolve at some point (ie resume synchronous execution), so doing events more advanced than that could be tricky (and some may argue, not very valuable).

let timeouts = [];
window.setTimeout = (cb, delay = 0, ...args) => {
  timeouts = timeouts.concat({ cb, args, end: Date.now() + delay });
};

/* require your actual code..., then: */


const endTimeCompare = ({ end: a }, { end: b }) => a - b;
timeouts = timeouts.sort(endTimeCompare);
while (timeouts.length > 0) {
  sleep(0.004);
  const runNow = timeouts.filter(({ end }) => end <= Date.now());
  for (const { cb, args } of runNow) cb(...args);
  timeouts = timeouts.filter(timeout => !runNow.includes(timeout)).sort(endTimeCompare);
}

I'm writing this from bed at midnight, haven't run any of this, am sure there's some es7 I'll need to make less-pretty so it works on older engines, and am very sleepy, but you can get the general idea from this. Please let me know if this idea solves what everyone's looking for here, and I'll make a repo and put this in with something that includes setInterval too.

@SevenEcks

This comment has been minimized.

SevenEcks commented Apr 6, 2018

This may be of interest to those finding this thread in the future: Server-Side Rendering With Laravel and Vue.js 2.5

@gxrneyme

This comment has been minimized.

gxrneyme commented Apr 9, 2018

@SevenEcks Legendary! 🎉 Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment