Skip to content

Provide Server-Side-Rendering helper using more purely JavaScript #5415

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

Closed
denghongcai opened this issue Apr 11, 2017 · 23 comments
Closed

Provide Server-Side-Rendering helper using more purely JavaScript #5415

denghongcai opened this issue Apr 11, 2017 · 23 comments

Comments

@denghongcai
Copy link

denghongcai commented Apr 11, 2017

What problem does this feature solve?

Current Server-Side-Rendering implementation is bond to Node.js, makes it hard to use in Nashorn (lightweight high-performance JavaScript runtime in Java with a native JVM) or other JavaScript runtime.

Foundations needed by Vue like vm and fs modules may be passed into renderer or runner as parameter which implements some interfaces.

What does the proposed API look like?

@posva
Copy link
Member

posva commented Apr 11, 2017

Added a note about Nashorn

@wojtask9
Copy link

wojtask9 commented Apr 12, 2017

I would love to see that happen.

I'm trying to use Vue.js with nashorn too.
It will be great if Vue.js SSR added interfaces such a FileSystem or Engine to externalize
some functionalities that are bind to node.js

I've made some research:

  1. path in all places can be abstracted
    currently used path.extname, path.join, path.isAbsolute, path.dirname

  2. fs in all places can be abstracted too
    currently used fs.existsSync, fs.readFileSync

  3. module
    only one usage NativeModule.wrap
    According to docs and soruce code this only wrap script code with

(function (exports, require, module, __filename, __dirname) {
// Your module code actually lives in here
});

so this is can be replaced with function if we are not on node.js

  1. resolve , vm used in create-bundle-runner.js
    This file can be somehow abstracted :) not sure how and what interface could look

  2. stream, source-map-support TODO :)

I made small modifications in source code to get rid of stream and path
my entry:

//import 'core-js/modules/es6.array.find.js';
//import 'core-js/modules/es6.object.assign.js';
//import 'nashorn-polyfill'
//import 'event-loop'
import  Vue from './web-runtime-with-compiler'
export { Vue }
export { createRenderer/*, createBundleRenderer*/} from './web-server-renderer'

result sizes:

  1. only createRenderer() and removed path and stream requires (commented stream functions and replaced path with own simple implementation)
    after browserify -> 430KB
  2. only createRenderer() (commented out bundleRenderer form entry)
    after browserify run -> 580KB
  3. createRenderer() and createBundleRenderer() (not modified at all)
    after browserify -> 700KB

@denghongcai
Copy link
Author

@wojtask9 suprised to see you go further! Would you mind share us a demo code?

@wojtask9
Copy link

Yes of course. I can share my code. But you must be patient (because of Easter Holiday)
JS part I'll try share tomorrow evening and java part probably on Tuesday.

@denghongcai
Copy link
Author

@wojtask9 Thanks! I will also try to design and implement some helper for Nashorn, to see how it will be going.

@danspeck
Copy link

@wojtask9 Hey, we're interested in seeing your solution as well. Can you post it somewhere?

@wojtask9
Copy link

yeah. I'm finishing it. have been busy for the last days.
Currently trying to run ssr tests on nashorn to be sure if everything is OK.
Please be patient :)

@wojtask9
Copy link

You can find "my" code here:
https://github.com/wojtask9/vue

packages/vue-server-renderer-nashorn/vue-nashorn.js -> complete JS file with all required dependencies and polyfills for Nashorn.

I tried to do modify Vue sources as less as possible.
People can build Vue for Nashorn typing npm run build:ssr-nashorn
For jasmine tests in Nashorn type npm run test:ssr-nashorn (on windows you must change path to jjs.exe in package.json)

Currently only renderToString works.
renderToStream have some issues with threads but should be resolved soon.

createBundleRenderer is currently commented because first I must resolve issues with Streams but on my TODO :)

If you have any questions I'll try answer :)

@wojtask9
Copy link

wojtask9 commented Apr 26, 2017

Ok i fixed streams and other issues.

There is only one left issue that I'm aware of ( read -> everything works)
For big data (like benchmark/ssr/common.js) renderToString and renderToStream doesn't return output.
If I change rows and columns in generateGrid to 10,10 from 1000, 10 everything is OK.

Not sure where the problem is :/

Another thing that make me wonder is event-loop. Currently setTimeout is invoked in thread that is different from main-thread. This is difference between node.js and nashorn.
I'll made implementation that behaves like node.js but currently it is more complicated.
But first I'll focus on issue mentioned above.

@wojtask9
Copy link

Now everything is solved.
MAX_STACK_DEPTH was too big for nashorn (original 1000 and currently on nashorn 190).

Performance (on the same linux machine)
nashorn full version 1.8.0_121-b13
--- renderToString ---
Complete time: 20982.00ms

--- renderToStream ---
first chunk: 1202.00ms
complete: 28488.00ms

node.js v6.10.0
--- renderToString ---
Complete time: 2164.08ms

--- renderToStream ---
first chunk: 90.15ms
complete: 2005.17ms

so it is rather slow :/ but why?

@denghongcai
Copy link
Author

denghongcai commented Apr 27, 2017

The result is consistent to what i tried using React. repo

Benchmark using JMH framework shows that typically nashorn version server side render is 1000% slower than Node.js version. I thought of wasting time in create/destroy nashorn context.

Since Vue.js use vm module and React.js not, I expected better performance ssr using Vue.js.

Run SSR in Nashorn is more robust than in Node.js. Thread-control, ability to terminate render at any time, cache across thread.

@wojtask9 how about share your benchmark code to see if something can be optimized?

@yyx990803
Copy link
Member

I honestly think this is simply because V8 produces much better optimized machine code than Nashorn... not much can be done in Vue/React to solve that :/

@denghongcai
Copy link
Author

Nashorn directly map js to JVM bytecode, implementation now may not great enough as V8. I believe things will get better. It's valuable to make Vue.js SSR not bond to a specific JavaScript Runtime. Nashorn (etc. Browser's Service-Worker, Embedded JavaScript Engine)

Define some abstract interface and provide Node.js implementation as default will be great.

@yyx990803
Copy link
Member

@denghongcai yeah, that's probably what we will do in the future - but for now we want to focus on providing a good, stable and performant Node-based SSR solution first.

@wojtask9
Copy link

wojtask9 commented Apr 27, 2017

@denghongcai
benchmarks added (to my fork of Vue.js)
javac NashornVue.java && java NashornVue or use script ./benchmarks/nashorn/nashorn-benchmark.js

Vue with my packackage doesn't use vm or any external modules (only bundled process and utils but without process there isn't any difference ).

I think nashorn doesn't optimize recursive calls at beginning and doesn't like huge stacks.
After 5 iterations performance is good (probably JIT goes in).

results (nashorn)
--- renderToString ---
0 Complete time: 13288.00ms
1 Complete time: 9400.00ms
2 Complete time: 8476.00ms
3 Complete time: 6587.00ms
4 Complete time: 6690.00ms
5 Complete time: 2805.00ms
6 Complete time: 2318.00ms
7 Complete time: 5442.00ms
8 Complete time: 2382.00ms
9 Complete time: 2859.00ms

Maybe there is room for improvements in Vue. For example instead of recursion use iterate version?

image

@wojtask9
Copy link

wojtask9 commented Jul 25, 2017

I removed recursion from next() function (some async test are falling but benchrmarks don't use asyncComponents and currently it's out of my scope). Now StackTraces looks nicer and I see performance improvement (sadly no difference using node.js)

Some results (btw i generate dynamic data on every loop to be sure that nashorn don't optimize whole scripts).
After 5th loop I see results are better than with node.js :)
Not sure if my benchmarks are correct or simply nashorn optimizes code very well.

Loading benchmarks
--- renderToString ---

#0 Complete time: 11637.00ms
#1 Complete time: 7140.00ms
#2 Complete time: 1692.00ms
#3 Complete time: 1419.00ms
#4 Complete time: 1481.00ms
#5 Complete time: 781.00ms
#6 Complete time: 889.00ms
#7 Complete time: 937.00ms
#8 Complete time: 556.00ms
#9 Complete time: 323.00ms
#8 Complete time: 654.00ms
#9 Complete time: 1021.00ms
#10 Complete time: 604.00ms
#11 Complete time: 576.00ms
#12 Complete time: 554.00ms
#13 Complete time: 1119.00ms
#14 Complete time: 572.00ms
#15 Complete time: 561.00ms
#16 Complete time: 630.00ms
#17 Complete time: 1083.00ms
#18 Complete time: 500.00ms
#19 Complete time: 470.00ms
#20 Complete time: 519.00ms
#21 Complete time: 1330.00ms
#22 Complete time: 455.00ms
#23 Complete time: 457.00ms
#24 Complete time: 524.00ms
#25 Complete time: 444.00ms
#26 Complete time: 507.00ms
#27 Complete time: 446.00ms
#28 Complete time: 491.00ms
#29 Complete time: 535.00ms
#30 Complete time: 474.00ms
#31 Complete time: 454.00ms
#32 Complete time: 593.00ms
#33 Complete time: 284.00ms
#34 Complete time: 249.00ms
#35 Complete time: 315.00ms
#36 Complete time: 272.00ms
#37 Complete time: 287.00ms
#38 Complete time: 269.00ms
#39 Complete time: 292.00ms

@denghongcai
Copy link
Author

@wojtask9 I can't find your optimized code in your repo...

@grahamle
Copy link

I just get a hint that you're definitely from alibaba. hahah

@wojtask9
Copy link

@denghongcai
I forgot about your last comment. I'll push my changes probably next weekend because currently I'm very busy.
I have also other small improvements (bundle size reduction), working Buffers/Streams with java API and working on bundleRenderer in nashorn

@yyx990803
Copy link
Member

FYI: in 2.4 we already shipped a pure js build of vue-server-renderer, but we haven't announced it yet. It only supports the base renderer, but is decoupled from Node.js APIs. Feel free to try integrating it in other contexts.

@sowhatdoido
Copy link

sowhatdoido commented Sep 12, 2017

@yyx990803,

Given your comment above, if I were to write something simple like this:
const renderer = require('vue-server-renderer').createRenderer();
and run it through webpack, I shouldn't be getting messages like:
Module not found: Error: Can't resolve 'fs' , correct?

@yyx990803
Copy link
Member

@sowhatdoido fs a native Node module. You can't just webpack it. Use vue-server-renderer/basic instead.

@sowhatdoido
Copy link

@yyx990803 Ah! Sorry, I thought when you said the base renderer, you meant createRenderer vs createBundleRenderer. Thanks for your help!

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

No branches or pull requests

7 participants