From 82db7a9421a8ba13b6db1fb7fe75bcaaab16b332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Fri, 2 Sep 2022 17:39:42 +0200 Subject: [PATCH 1/5] fix: swallow `ERR_STREAM_PREMATURE_CLOSE` in Node 18 --- packages/create-next-app/helpers/examples.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/create-next-app/helpers/examples.ts b/packages/create-next-app/helpers/examples.ts index 44af47b2acff..256d37b24996 100644 --- a/packages/create-next-app/helpers/examples.ts +++ b/packages/create-next-app/helpers/examples.ts @@ -79,6 +79,17 @@ export function existsInRepo(nameOrUrl: string): Promise { } } +// HACK: See: https://github.com/vercel/next.js/issues/39321 +function swallowPrematureStreamClose(e: Error & { code?: string }) { + if ( + process.version.startsWith('18') && + e.code === 'ERR_STREAM_PREMATURE_CLOSE' + ) { + return + } + throw e +} + export function downloadAndExtractRepo( root: string, { username, name, branch, filePath }: RepoInfo @@ -91,7 +102,7 @@ export function downloadAndExtractRepo( { cwd: root, strip: filePath ? filePath.split('/').length + 1 : 1 }, [`${name}-${branch.replace(/\//g, '-')}${filePath ? `/${filePath}` : ''}`] ) - ) + ).catch(swallowPrematureStreamClose) } export function downloadAndExtractExample( @@ -105,5 +116,5 @@ export function downloadAndExtractExample( return pipeline( got.stream('https://codeload.github.com/vercel/next.js/tar.gz/canary'), tar.extract({ cwd: root, strip: 3 }, [`next.js-canary/examples/${name}`]) - ) + ).catch(swallowPrematureStreamClose) } From 4004ec6ffb137819013b908a88008e48165977bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Fri, 2 Sep 2022 17:58:28 +0200 Subject: [PATCH 2/5] fix Node.js version detection --- packages/create-next-app/helpers/examples.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-next-app/helpers/examples.ts b/packages/create-next-app/helpers/examples.ts index 256d37b24996..dc0baed7dc04 100644 --- a/packages/create-next-app/helpers/examples.ts +++ b/packages/create-next-app/helpers/examples.ts @@ -82,7 +82,7 @@ export function existsInRepo(nameOrUrl: string): Promise { // HACK: See: https://github.com/vercel/next.js/issues/39321 function swallowPrematureStreamClose(e: Error & { code?: string }) { if ( - process.version.startsWith('18') && + process.version.startsWith('v18') && e.code === 'ERR_STREAM_PREMATURE_CLOSE' ) { return From 9c97f966b5be65dd9f712e662c5d8e2cf7c8035e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 5 Sep 2022 16:14:51 +0200 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: JJ Kasper --- packages/create-next-app/helpers/examples.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/create-next-app/helpers/examples.ts b/packages/create-next-app/helpers/examples.ts index dc0baed7dc04..1ec45d99aa54 100644 --- a/packages/create-next-app/helpers/examples.ts +++ b/packages/create-next-app/helpers/examples.ts @@ -79,10 +79,10 @@ export function existsInRepo(nameOrUrl: string): Promise { } } -// HACK: See: https://github.com/vercel/next.js/issues/39321 +// TODO: remove after https://github.com/npm/node-tar/issues/321 is resolved function swallowPrematureStreamClose(e: Error & { code?: string }) { if ( - process.version.startsWith('v18') && + process.version.startsWith('v18.') && e.code === 'ERR_STREAM_PREMATURE_CLOSE' ) { return From 70b4c77d1cda37f11ae9d19805da2eff99f58f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 5 Sep 2022 17:20:10 +0200 Subject: [PATCH 4/5] download tar to tmp folder --- packages/create-next-app/helpers/examples.ts | 62 +++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/packages/create-next-app/helpers/examples.ts b/packages/create-next-app/helpers/examples.ts index dc0baed7dc04..68cf202ba7f3 100644 --- a/packages/create-next-app/helpers/examples.ts +++ b/packages/create-next-app/helpers/examples.ts @@ -4,6 +4,10 @@ import tar from 'tar' import { Stream } from 'stream' import { promisify } from 'util' +import { join } from 'path' +import { tmpdir } from 'os' +import { createWriteStream } from 'fs' + const pipeline = promisify(Stream.pipeline) export type RepoInfo = { @@ -79,42 +83,44 @@ export function existsInRepo(nameOrUrl: string): Promise { } } -// HACK: See: https://github.com/vercel/next.js/issues/39321 -function swallowPrematureStreamClose(e: Error & { code?: string }) { - if ( - process.version.startsWith('v18') && - e.code === 'ERR_STREAM_PREMATURE_CLOSE' - ) { - return - } - throw e +async function downloadTar(url: string) { + const tempFile = join(tmpdir(), `next.js-cra-example.temp-${Date.now()}`) + await pipeline(got.stream(url), createWriteStream(tempFile)) + return tempFile } -export function downloadAndExtractRepo( +export async function downloadAndExtractRepo( root: string, { username, name, branch, filePath }: RepoInfo -): Promise { - return pipeline( - got.stream( - `https://codeload.github.com/${username}/${name}/tar.gz/${branch}` - ), - tar.extract( - { cwd: root, strip: filePath ? filePath.split('/').length + 1 : 1 }, - [`${name}-${branch.replace(/\//g, '-')}${filePath ? `/${filePath}` : ''}`] - ) - ).catch(swallowPrematureStreamClose) +) { + const tempFile = await downloadTar( + `https://codeload.github.com/${username}/${name}/tar.gz/${branch}` + ) + + await tar.x({ + file: tempFile, + cwd: root, + strip: filePath ? filePath.split('/').length + 1 : 1, + filter: (p) => + p.startsWith( + `${name}-${branch.replace(/\//g, '-')}${filePath ? `/${filePath}` : ''}` + ), + }) } -export function downloadAndExtractExample( - root: string, - name: string -): Promise { +export async function downloadAndExtractExample(root: string, name: string) { if (name === '__internal-testing-retry') { throw new Error('This is an internal example for testing the CLI.') } - return pipeline( - got.stream('https://codeload.github.com/vercel/next.js/tar.gz/canary'), - tar.extract({ cwd: root, strip: 3 }, [`next.js-canary/examples/${name}`]) - ).catch(swallowPrematureStreamClose) + const tempFile = await downloadTar( + 'https://codeload.github.com/vercel/next.js/tar.gz/canary' + ) + + await tar.x({ + file: tempFile, + cwd: root, + strip: 3, + filter: (p) => p.includes(`next.js-canary/examples/${name}`), + }) } From eeb66d981e4e4c0fc795cb2b95244b0ac0571422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 5 Sep 2022 17:25:28 +0200 Subject: [PATCH 5/5] remove empty line --- packages/create-next-app/helpers/examples.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/create-next-app/helpers/examples.ts b/packages/create-next-app/helpers/examples.ts index 68cf202ba7f3..64a7635cf1d1 100644 --- a/packages/create-next-app/helpers/examples.ts +++ b/packages/create-next-app/helpers/examples.ts @@ -3,7 +3,6 @@ import got from 'got' import tar from 'tar' import { Stream } from 'stream' import { promisify } from 'util' - import { join } from 'path' import { tmpdir } from 'os' import { createWriteStream } from 'fs'