8
8
} from 'vue'
9
9
import { isString , isPromise } from '@vue/shared'
10
10
import { renderComponentVNode , SSRBuffer , SSRContext } from './render'
11
- import { Readable } from 'stream'
11
+ import { Readable , Writable } from 'stream'
12
12
13
13
const { isVNode } = ssrUtils
14
14
@@ -99,51 +99,64 @@ export function renderToStream(
99
99
100
100
export function renderToNodeStream (
101
101
input : App | VNode ,
102
- context : SSRContext = { } ,
103
- UserReadable ?: typeof Readable
102
+ context : SSRContext = { }
104
103
) : Readable {
105
- const stream : Readable = UserReadable
106
- ? new UserReadable ( )
107
- : __NODE_JS__
104
+ const stream : Readable = __NODE_JS__
108
105
? new ( require ( 'stream' ) . Readable ) ( )
109
106
: null
110
107
111
108
if ( ! stream ) {
112
109
throw new Error (
113
- `ESM build of renderToStream() requires explicitly passing in the Node.js ` +
114
- `Readable constructor the 3rd argument. Example:\n\n` +
115
- ` import { Readable } from 'stream'\n` +
116
- ` const stream = renderToStream(app, {}, Readable)`
110
+ `ESM build of renderToStream() does not support renderToNodeStream(). ` +
111
+ `Use pipeToNodeWritable() with an existing Node.js Writable stream ` +
112
+ `instance instead.`
117
113
)
118
114
}
119
115
120
116
return renderToSimpleStream ( input , context , stream )
121
117
}
122
118
123
- const hasGlobalWebStream = typeof ReadableStream === 'function'
119
+ export function pipeToNodeWritable (
120
+ input : App | VNode ,
121
+ context : SSRContext = { } ,
122
+ writable : Writable
123
+ ) {
124
+ renderToSimpleStream ( input , context , {
125
+ push ( content ) {
126
+ if ( content != null ) {
127
+ writable . write ( content )
128
+ } else {
129
+ writable . end ( )
130
+ }
131
+ } ,
132
+ destroy ( err ) {
133
+ writable . destroy ( err )
134
+ }
135
+ } )
136
+ }
124
137
125
138
export function renderToWebStream (
126
139
input : App | VNode ,
127
- context : SSRContext = { } ,
128
- Ctor ?: { new ( ) : ReadableStream }
140
+ context : SSRContext = { }
129
141
) : ReadableStream {
130
- if ( ! Ctor && ! hasGlobalWebStream ) {
142
+ if ( typeof ReadableStream !== 'function' ) {
131
143
throw new Error (
132
- `ReadableStream constructor is not available in the global scope and ` +
133
- `must be explicitly passed in as the 3rd argument:\n\n` +
134
- ` import { ReadableStream } from 'stream/web'\n` +
135
- ` const stream = renderToWebStream(app, {}, ReadableStream)`
144
+ `ReadableStream constructor is not available in the global scope. ` +
145
+ `If the target environment does support web streams, consider using ` +
146
+ `pipeToWebWritable() with an existing WritableStream instance instead.`
136
147
)
137
148
}
138
149
150
+ const encoder = new TextEncoder ( )
139
151
let cancelled = false
140
- return new ( Ctor || ReadableStream ) ( {
152
+
153
+ return new ReadableStream ( {
141
154
start ( controller ) {
142
155
renderToSimpleStream ( input , context , {
143
156
push ( content ) {
144
157
if ( cancelled ) return
145
158
if ( content != null ) {
146
- controller . enqueue ( content )
159
+ controller . enqueue ( encoder . encode ( content ) )
147
160
} else {
148
161
controller . close ( )
149
162
}
@@ -158,3 +171,29 @@ export function renderToWebStream(
158
171
}
159
172
} )
160
173
}
174
+
175
+ export function pipeToWebWritable (
176
+ input : App | VNode ,
177
+ context : SSRContext = { } ,
178
+ writable : WritableStream
179
+ ) : void {
180
+ const writer = writable . getWriter ( )
181
+ const encoder = new TextEncoder ( )
182
+
183
+ writer . ready . then ( ( ) => {
184
+ renderToSimpleStream ( input , context , {
185
+ push ( content ) {
186
+ if ( content != null ) {
187
+ writer . write ( encoder . encode ( content ) )
188
+ } else {
189
+ writer . close ( )
190
+ }
191
+ } ,
192
+ destroy ( err ) {
193
+ // TODO better error handling?
194
+ console . log ( err )
195
+ writer . close ( )
196
+ }
197
+ } )
198
+ } )
199
+ }
0 commit comments