vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
208k stars 33.69k forks source link

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

Closed lerouxju closed 8 years ago

lerouxju commented 8 years ago

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 commented 8 years ago

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.

bratao commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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

muthu32 commented 7 years ago

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.

ghost commented 7 years ago

Has any progress been made in this area?

youssef-lr commented 7 years ago

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

rohmanhm commented 7 years ago

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

rjvim commented 7 years ago

+1

martinsotirov commented 7 years ago

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 commented 7 years ago

+1

bratao commented 7 years ago

@yyx990803 Could you please revisit this issue ?

acidjazz commented 7 years ago

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

posva commented 7 years ago

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: https://github.com/vuejs/vue/issues/5415

jkoudys commented 7 years ago

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 commented 6 years ago

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

ghost commented 6 years ago

@SevenEcks Legendary! :tada: Thank you.