Skip to content

Commit 51559f5

Browse files
authored
Use zen-observable library (#28214)
Our `Observable` use has gotten sufficiently complex that it makes sense to just use a 3rd party implementation and not worry about maintaining it ourselves. As a bonus, it doesn't rely on Node APIs.
1 parent ce18756 commit 51559f5

File tree

14 files changed

+142
-211
lines changed

14 files changed

+142
-211
lines changed

packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { setLazyProp, getCookieParser } from '../../../../server/api-utils'
1111
import { getRedirectStatus } from '../../../../lib/load-custom-routes'
1212
import getRouteNoAssetPath from '../../../../shared/lib/router/utils/get-route-from-asset-path'
1313
import { PERMANENT_REDIRECT_STATUS } from '../../../../shared/lib/constants'
14-
import { resultToChunks } from '../../../../server/utils'
14+
import { resultsToString } from '../../../../server/utils'
1515

1616
export function getPageHandler(ctx: ServerlessHandlerCtx) {
1717
const {
@@ -334,7 +334,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
334334
defaultLocale: i18n?.defaultLocale,
335335
})
336336
)
337-
const html = result2 ? (await resultToChunks(result2)).join('') : ''
337+
const html = result2 ? await resultsToString([result2]) : ''
338338
sendPayload(
339339
req,
340340
res,
@@ -402,7 +402,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
402402
}
403403

404404
if (renderMode) return { html: result, renderOpts }
405-
return result ? (await resultToChunks(result)).join('') : null
405+
return result ? await resultsToString([result]) : null
406406
} catch (err) {
407407
if (!parsedUrl!) {
408408
parsedUrl = parseUrl(req.url!, true)
@@ -464,7 +464,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
464464
err: res.statusCode === 404 ? undefined : err,
465465
})
466466
)
467-
return result2 ? (await resultToChunks(result2)).join('') : null
467+
return result2 ? await resultsToString([result2]) : null
468468
}
469469
}
470470

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Copyright (c) 2018 zenparsing (Kevin Smith)
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights to
6+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7+
of the Software, and to permit persons to whom the Software is furnished to do
8+
so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

packages/next/compiled/zen-observable/esm.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name":"zen-observable","main":"esm.js","license":"MIT"}

packages/next/export/worker.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { extname, join, dirname, sep } from 'path'
33
import { renderToHTML } from '../server/render'
44
import { promises } from 'fs'
55
import AmpHtmlValidator from 'next/dist/compiled/amphtml-validator'
6+
import Observable from 'next/dist/compiled/zen-observable'
67
import { loadComponents } from '../server/load-components'
78
import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic'
89
import { getRouteMatcher } from '../shared/lib/router/utils/route-matcher'
@@ -18,7 +19,7 @@ import { FontManifest } from '../server/font-utils'
1819
import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path'
1920
import { trace } from '../telemetry/trace'
2021
import { isInAmpMode } from '../shared/lib/amp'
21-
import { resultFromChunks, resultToChunks } from '../server/utils'
22+
import { resultsToString } from '../server/utils'
2223
import { NextConfigComplete } from '../server/config-shared'
2324
import { setHttpAgentOptions } from '../server/config'
2425

@@ -274,7 +275,7 @@ export default async function exportPage({
274275

275276
// if it was auto-exported the HTML is loaded here
276277
if (typeof mod === 'string') {
277-
renderResult = resultFromChunks([mod])
278+
renderResult = Observable.of(mod)
278279
queryWithAutoExportWarn()
279280
} else {
280281
// for non-dynamic SSG pages we should have already
@@ -352,7 +353,7 @@ export default async function exportPage({
352353
}
353354

354355
if (typeof components.Component === 'string') {
355-
renderResult = resultFromChunks([components.Component])
356+
renderResult = Observable.of(components.Component)
356357
queryWithAutoExportWarn()
357358
} else {
358359
/**
@@ -417,8 +418,7 @@ export default async function exportPage({
417418
}
418419
}
419420

420-
const htmlChunks = renderResult ? await resultToChunks(renderResult) : []
421-
const html = htmlChunks.join('')
421+
const html = renderResult ? await resultsToString([renderResult]) : ''
422422
if (inAmpMode && !curRenderOpts.ampSkipValidation) {
423423
if (!results.ssgNotFound) {
424424
await validateAmp(html, path, curRenderOpts.ampValidatorPath)
@@ -460,8 +460,9 @@ export default async function exportPage({
460460
)
461461
}
462462

463-
const ampChunks = await resultToChunks(ampRenderResult)
464-
const ampHtml = ampChunks.join('')
463+
const ampHtml = ampRenderResult
464+
? await resultsToString([ampRenderResult])
465+
: ''
465466
if (!curRenderOpts.ampSkipValidation) {
466467
await validateAmp(ampHtml, page + '?amp=1')
467468
}

packages/next/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@
185185
"@types/text-table": "0.2.1",
186186
"@types/webpack": "5.28.0",
187187
"@types/webpack-sources": "0.1.5",
188+
"@types/zen-observable": "0.8.3",
188189
"@vercel/ncc": "0.27.0",
189190
"@vercel/nft": "0.12.2",
190191
"amphtml-validator": "1.0.33",
@@ -248,7 +249,8 @@
248249
"unistore": "3.4.1",
249250
"web-vitals": "2.1.0",
250251
"webpack": "4.44.1",
251-
"webpack-sources": "1.4.3"
252+
"webpack-sources": "1.4.3",
253+
"zen-observable": "0.8.15"
252254
},
253255
"engines": {
254256
"node": ">=12.0.0"

packages/next/server/next-server.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
ParsedUrlQuery,
1111
} from 'querystring'
1212
import { format as formatUrl, parse as parseUrl, UrlWithParsedQuery } from 'url'
13+
import Observable from 'next/dist/compiled/zen-observable'
1314
import { PrerenderManifest } from '../build'
1415
import {
1516
getRedirectStatus,
@@ -76,12 +77,7 @@ import { sendRenderResult, setRevalidateHeaders } from './send-payload'
7677
import { serveStatic } from './serve-static'
7778
import { IncrementalCache } from './incremental-cache'
7879
import { execOnce } from '../shared/lib/utils'
79-
import {
80-
isBlockedPage,
81-
RenderResult,
82-
resultFromChunks,
83-
resultToChunks,
84-
} from './utils'
80+
import { isBlockedPage, RenderResult, resultsToString } from './utils'
8581
import { loadEnvConfig } from '@next/env'
8682
import './node-polyfill-fetch'
8783
import { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'
@@ -1267,7 +1263,7 @@ export default class Server {
12671263
req,
12681264
res,
12691265
resultOrPayload: requireStaticHTML
1270-
? (await resultToChunks(body)).join('')
1266+
? await resultsToString([body])
12711267
: body,
12721268
type,
12731269
generateEtags,
@@ -1296,8 +1292,7 @@ export default class Server {
12961292
if (payload === null) {
12971293
return null
12981294
}
1299-
const chunks = await resultToChunks(payload.body)
1300-
return chunks.join('')
1295+
return resultsToString([payload.body])
13011296
}
13021297

13031298
public async render(
@@ -1472,7 +1467,7 @@ export default class Server {
14721467
return {
14731468
type: 'html',
14741469
// TODO: Static pages should be written as chunks
1475-
body: resultFromChunks([components.Component]),
1470+
body: Observable.of(components.Component),
14761471
}
14771472
}
14781473

@@ -1751,7 +1746,7 @@ export default class Server {
17511746
return {
17521747
value: {
17531748
kind: 'PAGE',
1754-
html: resultFromChunks([html]),
1749+
html: Observable.of(html),
17551750
pageData: {},
17561751
},
17571752
}
@@ -1830,7 +1825,7 @@ export default class Server {
18301825
if (isDataReq) {
18311826
return {
18321827
type: 'json',
1833-
body: resultFromChunks([JSON.stringify(cachedData.props)]),
1828+
body: Observable.of(JSON.stringify(cachedData.props)),
18341829
revalidateOptions,
18351830
}
18361831
} else {
@@ -1841,7 +1836,7 @@ export default class Server {
18411836
return {
18421837
type: isDataReq ? 'json' : 'html',
18431838
body: isDataReq
1844-
? resultFromChunks([JSON.stringify(cachedData.pageData)])
1839+
? Observable.of(JSON.stringify(cachedData.pageData))
18451840
: cachedData.html,
18461841
revalidateOptions,
18471842
}
@@ -2076,7 +2071,7 @@ export default class Server {
20762071
}
20772072
return {
20782073
type: 'html',
2079-
body: resultFromChunks(['Internal Server Error']),
2074+
body: Observable.of('Internal Server Error'),
20802075
}
20812076
}
20822077
}

0 commit comments

Comments
 (0)