diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index 4fa14e0815a9..d9d7a058aaed 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -1172,10 +1172,7 @@ export async function copyTracedFiles( if (symlink) { console.log('symlink', path.relative(tracingRoot, symlink)) - await fs.symlink( - path.relative(tracingRoot, symlink), - fileOutputPath - ) + await fs.symlink(symlink, fileOutputPath) } else { await fs.copyFile(tracedFilePath, fileOutputPath) } diff --git a/test/integration/pnpm-support/app-multi-page/.npmrc b/test/integration/pnpm-support/app-multi-page/.npmrc new file mode 100644 index 000000000000..84db07921228 --- /dev/null +++ b/test/integration/pnpm-support/app-multi-page/.npmrc @@ -0,0 +1,2 @@ +# put modules outside of the app folder, to simulate what happens in a pnpm workspace +virtual-store-dir=../pnpm \ No newline at end of file diff --git a/test/integration/pnpm-support/app-multi-page/next.config.js b/test/integration/pnpm-support/app-multi-page/next.config.js new file mode 100644 index 000000000000..d6cec9e13193 --- /dev/null +++ b/test/integration/pnpm-support/app-multi-page/next.config.js @@ -0,0 +1,9 @@ +const path = require('path') + +module.exports = { + experimental: { + outputStandalone: true, + // pnpm virtual-store-dir is outside the app directory + outputFileTracingRoot: path.resolve(__dirname, '../'), + }, +} diff --git a/test/integration/pnpm-support/app/next.config.js b/test/integration/pnpm-support/app/next.config.js new file mode 100644 index 000000000000..0568ecc9e540 --- /dev/null +++ b/test/integration/pnpm-support/app/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + experimental: { + outputStandalone: true, + }, +} diff --git a/test/integration/pnpm-support/test/index.test.js b/test/integration/pnpm-support/test/index.test.js index fb50ef49fe7a..0bb49f0fabce 100644 --- a/test/integration/pnpm-support/test/index.test.js +++ b/test/integration/pnpm-support/test/index.test.js @@ -13,8 +13,33 @@ const APP_DIRS = { 'app-multi-page': path.join(__dirname, '..', 'app-multi-page'), } +// runs a command showing logs and returning the stdout +const runCommand = (cwd, cmd, args) => { + const proc = execa(cmd, [...args], { + cwd, + stdio: [process.stdin, 'pipe', process.stderr], + }) + + let stdout = '' + proc.stdout.on('data', (data) => { + const s = data.toString() + process.stdout.write(s) + stdout += s + }) + return new Promise((resolve, reject) => { + proc.on('exit', (code) => { + if (code === 0) { + return resolve({ ...proc, stdout }) + } + reject( + new Error(`Command ${cmd} ${args.join(' ')} failed with code ${code}`) + ) + }) + }) +} + const runNpm = (cwd, ...args) => execa('npm', [...args], { cwd }) -const runPnpm = (cwd, ...args) => execa('npx', ['pnpm', ...args], { cwd }) +const runPnpm = (cwd, ...args) => runCommand(cwd, 'npx', ['pnpm', ...args]) async function usingTempDir(fn) { const folder = path.join(os.tmpdir(), Math.random().toString(36).substring(2)) @@ -134,16 +159,66 @@ describe('pnpm support', () => { expect(packageJson.pnpm.overrides[dependency]).toMatch(/^file:/) } - const { stdout, stderr } = await runPnpm(appDir, 'run', 'build') - console.log(stdout, stderr) + const { stdout } = await runPnpm(appDir, 'run', 'build') + expect(stdout).toMatch(/Compiled successfully/) }) }) + it('should execute client-side JS on each page in outputStandalone', async () => { + await usingPnpmCreateNextApp(APP_DIRS['app-multi-page'], async (appDir) => { + const { stdout } = await runPnpm(appDir, 'run', 'build') + + expect(stdout).toMatch(/Compiled successfully/) + + let appPort + let appProcess + let browser + try { + appPort = await findPort() + const standaloneDir = path.resolve(appDir, '.next/standalone/app') + + // simulate what happens in a Dockerfile + await fs.remove(path.join(appDir, 'node_modules')) + await fs.copy( + path.resolve(appDir, './.next/static'), + path.resolve(standaloneDir, './.next/static'), + { overwrite: true } + ) + appProcess = execa('node', ['server.js'], { + cwd: standaloneDir, + env: { + PORT: appPort, + }, + stdio: 'inherit', + }) + + await waitFor(1000) + + await renderViaHTTP(appPort, '/') + + browser = await webdriver(appPort, '/', { + waitHydration: false, + }) + expect(await browser.waitForElementByCss('#world').text()).toBe('World') + await browser.close() + + browser = await webdriver(appPort, '/about', { + waitHydration: false, + }) + expect(await browser.waitForElementByCss('#world').text()).toBe('World') + await browser.close() + } finally { + await killProcess(appProcess.pid) + await waitFor(5000) + } + }) + }) + it('should execute client-side JS on each page', async () => { await usingPnpmCreateNextApp(APP_DIRS['app-multi-page'], async (appDir) => { - const { stdout, stderr } = await runPnpm(appDir, 'run', 'build') - console.log(stdout, stderr) + const { stdout } = await runPnpm(appDir, 'run', 'build') + expect(stdout).toMatch(/Compiled successfully/) let appPort @@ -151,7 +226,11 @@ describe('pnpm support', () => { let browser try { appPort = await findPort() - appProcess = runPnpm(appDir, 'run', 'start', '--', '--port', appPort) + appProcess = execa('pnpm', ['run', 'start', '--', '--port', appPort], { + cwd: appDir, + stdio: 'inherit', + }) + await waitFor(5000) await renderViaHTTP(appPort, '/')