Skip to content
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

feat(server-renderer): support for non-Node.js Environments #3460

Closed

Conversation

ferdinando-ferreira
Copy link

@ferdinando-ferreira ferdinando-ferreira commented Mar 22, 2021

Previous version of this package (vue-server-renderer) had support for non-Nodejs (see https://ssr.vuejs.org/guide/non-node.html).

It continued working on vue-next but regressed when this PR was merged: #1197 because stream is node only.

This PR proposes to create, like existed on vue@2, a "basic" version of server-renderer without node only requirements.

Please appreciate and review.

This PR likely fixes #3111 root cause
Also fixes #3467

@ferdinando-ferreira
Copy link
Author

Here are the steps to test this proposed change

git clone git@github.com:ferdinando-ferreira/vue-next.git --single-branch vue-next-basic-renderer
cd vue-next-basic-renderer
yarn
yarn build

This builds (using the current source with this PR merged) the vue packages, including the newly created

/src/basic.ts → packages/server-renderer/dist/server-renderer.basic-cjs.prod.js...

This repo has one extra folder: usecase, with webpack configurations for both SSR and non SSR simple vue projects. To test it:

cd usecase
npm install
npm run build

The end result, in the distfolder, will be four folders

  • dist/web: regular non SSR version, can be viewed on the browser by opening the index.html or with npm run start:web
  • dist/node: node SSR, can be viewed with npm run start:node

Then there are two non node SSR versions, compiled as some other target so it can be used with php-v8:

  • dist/phpv8/current: compiled with @vue/server-renderer as it exists today
  • dist/phpv8/proposed compiled with @vue/server-renderer aliased as ../../packages/server-renderer/dist/server-renderer.basic-cjs.js

@ferdinando-ferreira
Copy link
Author

Testing

The requirements to test these two php-v8 SSR versions are:

  • php installed and in the path
  • The extension v8js available for this php install

Here is the result of both tests

npm run start:phpv8-current results in

> use-case@1.0.0 start:phpv8-current
> php dist/phpv8/current/index.php


Fatal error: Uncaught V8JsScriptException: V8Js::compileString():19027: 
No module loader in usecase\dist\phpv8\current\index.php:8

Stack trace:
#0 usecase\dist\phpv8\current\index.php(8): V8Js->executeString('/******/ (() =>...')
#1 {main}
  thrown in usecase\dist\phpv8\current\index.php on line 8

And npm run start:phpv8-proposed results in

> use-case@1.0.0 start:phpv8-proposed
> php dist/phpv8/proposed/index.php

<html>
  <head>
    <title>Test node</title>
    <meta charset="utf-8">
    <meta name="keyword" content="vue,ssr">
    <meta name="description" content="vue srr demo">
  <script defer src="assets/index.js"></script><link href="assets/index.css" rel="stylesheet"></head>
  <body>
    <div id="app"><h1>Hello World! 0</h1><input type="button" value="Click me"></div>
  </body>
</html>

With the only difference between the two versions being the use of the newly created packages/server-renderer/dist/server-renderer.basic-cjs.prod.js version of the server-renderer, which is the desired effect of the proposed change.

@ferdinando-ferreira
Copy link
Author

Testing without php

Even without php and v8js it is possible to analyze the output of the proposed solution.

Here is the diff between dist/phpv8/current/index.js and dist/phpv8/proposed/index.js: it is essentially only the removal of renderToStream and their requirements from the build.

7104,7107c7104,7107
< /***/ "../packages/server-renderer/dist/server-renderer.cjs.js":
< /*!***************************************************************!*\
<   !*** ../packages/server-renderer/dist/server-renderer.cjs.js ***!
<   \***************************************************************/
---
> /***/ "../packages/server-renderer/dist/server-renderer.basic-cjs.js":
> /*!*********************************************************************!*\
>   !*** ../packages/server-renderer/dist/server-renderer.basic-cjs.js ***!
>   \*********************************************************************/
7118d7117
< var stream = __webpack_require__(/*! stream */ "stream");
7895,7951d7893
< const { isVNode: isVNode$1 } = vue.ssrUtils;
< async function unrollBuffer$1(buffer, stream) {
<     if (buffer.hasAsync) {
<         for (let i = 0; i < buffer.length; i++) {
<             let item = buffer[i];
<             if (shared.isPromise(item)) {
<                 item = await item;
<             }
<             if (shared.isString(item)) {
<                 stream.push(item);
<             }
<             else {
<                 await unrollBuffer$1(item, stream);
<             }
<         }
<     }
<     else {
<         // sync buffer can be more efficiently unrolled without unnecessary await
<         // ticks
<         unrollBufferSync$1(buffer, stream);
<     }
< }
< function unrollBufferSync$1(buffer, stream) {
<     for (let i = 0; i < buffer.length; i++) {
<         let item = buffer[i];
<         if (shared.isString(item)) {
<             stream.push(item);
<         }
<         else {
<             // since this is a sync buffer, child buffers are never promises
<             unrollBufferSync$1(item, stream);
<         }
<     }
< }
< function renderToStream(input, context = {}) {
<     if (isVNode$1(input)) {
<         // raw vnode, wrap with app (for context)
<         return renderToStream(vue.createApp({ render: () => input }), context);
<     }
<     // rendering an app
<     const vnode = vue.createVNode(input._component, input._props);
<     vnode.appContext = input._context;
<     // provide the ssr context to the tree
<     input.provide(vue.ssrContextKey, context);
<     const stream$1 = new stream.Readable();
<     Promise.resolve(renderComponentVNode(vnode))
<         .then(buffer => unrollBuffer$1(buffer, stream$1))
<         .then(() => {
<         stream$1.push(null);
<     })
<         .catch(error => {
<         stream$1.destroy(error);
<     });
<     return stream$1;
< }
< 
< exports.renderToStream = renderToStream;
7991,8006d7932
< /***/ "../packages/server-renderer/index.js":
< /*!********************************************!*\
<   !*** ../packages/server-renderer/index.js ***!
<   \********************************************/
< /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
< 
< "use strict";
< 
< 
< if (false) {} else {
<   module.exports = __webpack_require__(/*! ./dist/server-renderer.cjs.js */ "../packages/server-renderer/dist/server-renderer.cjs.js")
< }
< 
< 
< /***/ }),
< 
19018,19028d18943
< /***/ }),
< 
< /***/ "stream":
< /*!*************************!*\
<   !*** external "stream" ***!
<   \*************************/
< /***/ ((module) => {
< 
< "use strict";
< module.exports = require("stream");;
< 
19115c19030
< const renderer = __webpack_require__(/*! @vue/server-renderer */ "../packages/server-renderer/index.js")
---
> const renderer = __webpack_require__(/*! @vue/server-renderer */ "../packages/server-renderer/dist/server-renderer.basic-cjs.js")

@HcySunYang HcySunYang added the 🍰 p2-nice-to-have Priority 2: this is not breaking anything but nice to have it addressed. label Mar 29, 2021
@yyx990803 yyx990803 closed this in 0867222 Jul 29, 2021
@yyx990803
Copy link
Member

After 0867222, @vue/server-renderer when bundled will default to the esm-bundler build which should no longer have coupling to Node.js.

@ferdinando-ferreira
Copy link
Author

Thanks!

@ferdinando-ferreira ferdinando-ferreira deleted the basic-renderer branch August 1, 2021 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🍰 p2-nice-to-have Priority 2: this is not breaking anything but nice to have it addressed. version: minor
Projects
None yet
3 participants