Subscribe on changes!

renderToStream causes error in some cases.

avatar
May 29th 2021

Version

3.0.11

Reproduction link

https://replit.com/@07akioni/vuessr

image

Steps to reproduce

Follow the link.

const { createApp, resolveComponent, h } = require("vue");
const { renderToStream: _renderToStream } = require("@vue/server-renderer");

const app = createApp({
  render() {
    const Foo = resolveComponent("foo");
    return h(Foo);
  },
});
app.component("foo", {
  render: () => h("div", "foo"),
});

const promisifyStream = (stream) => {
  return new Promise((resolve, reject) => {
    let result = "";
    console.log("ondata");
    stream.on("data", (data) => {
      result += data;
    });
    stream.on("error", () => {
      reject(result);
    });
    stream.on("end", () => {
      resolve(result);
    });
  });
};

const renderToStream = (app) => promisifyStream(_renderToStream(app));

renderToStream(app).then((v) => {
  console.log(v);
});

What is expected?

No error.

What is actually happening?

internal/streams/readable.js:642
  throw new ERR_METHOD_NOT_IMPLEMENTED('_read()');
  ^

Error [ERR_METHOD_NOT_IMPLEMENTED]: The _read() method is not implemented
    at Readable._read (internal/streams/readable.js:642:9)
    at Readable.read (internal/streams/readable.js:481:10)
    at resume_ (internal/streams/readable.js:968:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21) {
  code: 'ERR_METHOD_NOT_IMPLEMENTED'
}

It's wired that in stackbliz web container and vue's jest test there is no error.

https://stackblitz.com/edit/node-daswhe?file=index.js

image

avatar
May 31st 2021

I found that the reason why the tests passed is jest mutates Promise. Emmm...

https://github.com/facebook/jest/issues/11497

avatar
May 31st 2021

The error comes from replit not implementing the needed functionality

avatar
Jun 1st 2021

@posva The original example is simplified to help people find the crucial part.

I've update it. Now it is the original logic extracted from a vue test case. The error happens in the same way.

avatar
Jun 1st 2021

the code sample runs fine in node 14:

// index.mjs
import { createApp, resolveComponent, h } from 'vue'
import { renderToStream as _renderToStream } from '@vue/server-renderer'

const app = createApp({
  render() {
    const Foo = resolveComponent('foo')
    return h(Foo)
  },
})
app.component('foo', {
  render: () => h('div', 'foo'),
})

const promisifyStream = (stream) => {
  return new Promise((resolve, reject) => {
    let result = ''
    console.log('ondata')
    stream.on('data', (data) => {
      result += data
    })
    stream.on('error', () => {
      reject(result)
    })
    stream.on('end', () => {
      resolve(result)
    })
  })
}

const renderToStream = (app) => promisifyStream(_renderToStream(app))

renderToStream(app).then((v) => {
  console.log(v)
})

Do you have a boiled down reproduction that fails?

avatar
Jun 1st 2021

the code sample runs fine in node 14:

// index.mjs
import { createApp, resolveComponent, h } from 'vue'
import { renderToStream as _renderToStream } from '@vue/server-renderer'

const app = createApp({
  render() {
    const Foo = resolveComponent('foo')
    return h(Foo)
  },
})
app.component('foo', {
  render: () => h('div', 'foo'),
})

const promisifyStream = (stream) => {
  return new Promise((resolve, reject) => {
    let result = ''
    console.log('ondata')
    stream.on('data', (data) => {
      result += data
    })
    stream.on('error', () => {
      reject(result)
    })
    stream.on('end', () => {
      resolve(result)
    })
  })
}

const renderToStream = (app) => promisifyStream(_renderToStream(app))

renderToStream(app).then((v) => {
  console.log(v)
})

Do you have a boiled down reproduction that fails?

.mjs works for me too. However please try cjs. My node version is v14.17.0.

https://github.com/07akioni/vue-ssr-bug-reprod (the same example)

The mjs and cjs modes seem to have some difference underhood.

➜  vue-ssr git:(main) NODE_DEBUG=stream node work.mjs 
STREAM 75760: resume
STREAM 75760: readableAddChunk <div>foo</div>
STREAM 75760: readableAddChunk null
STREAM 75760: onEofChunk
STREAM 75760: emitReadable false false
STREAM 75760: emitReadable true
STREAM 75760: resume false
STREAM 75760: read 0
STREAM 75760: flow true
STREAM 75760: read undefined
STREAM 75760: need readable false
STREAM 75760: length less than watermark true
STREAM 75760: reading or ended false
STREAM 75760: endReadable false
STREAM 75760: read undefined
STREAM 75760: endReadable false
STREAM 75760: read 0
STREAM 75760: endReadable false
STREAM 75760: emitReadable_ false 0 true
STREAM 75760: flow true
STREAM 75760: read undefined
STREAM 75760: endReadable false
STREAM 75760: endReadableNT false 0
STREAM 75760: endReadableNT true 0
STREAM 75760: endReadableNT true 0
STREAM 75760: endReadableNT true 0
<div>foo</div>
➜  vue-ssr git:(main) NODE_DEBUG=stream node notwork.cjs.js 
STREAM 75780: resume
STREAM 75780: resume false
STREAM 75780: read 0
STREAM 75780: need readable false
STREAM 75780: length less than watermark true
STREAM 75780: do read
internal/streams/readable.js:642
  throw new ERR_METHOD_NOT_IMPLEMENTED('_read()');
  ^

Error [ERR_METHOD_NOT_IMPLEMENTED]: The _read() method is not implemented
    at Readable._read (internal/streams/readable.js:642:9)
    at Readable.read (internal/streams/readable.js:481:10)
    at resume_ (internal/streams/readable.js:977:12)
    at processTicksAndRejections (internal/process/task_queues.js:82:21) {
  code: 'ERR_METHOD_NOT_IMPLEMENTED'
}
avatar
Jun 1st 2021

I think the problem is you shouldn't be using on('data'), which creates the need for read() but I'm really not sure.

avatar
Jun 1st 2021

I think the problem is you shouldn't be using on('data'), which creates the need for read() but I'm really not sure.

All the test cases do with events. I'm not quite good at node. Is there any best practice?