open-next icon indicating copy to clipboard operation
open-next copied to clipboard

Next.js 16 fails to build

Open ovflowd opened this issue 2 months ago • 10 comments

Getting some weird copy errors from files that do not exist:

[WebServer] Error: ENOENT: no such file or directory, copyfile '/home/runner/work/nodejs.org/nodejs.org/apps/site/.next/standalone/apps/site/.next/server/chunks/ssr/[root-of-the-server]__92b48411._.js' -> '/home/runner/work/nodejs.org/nodejs.org/apps/site/.open-next/server-functions/default/apps/site/.next/server/chunks/ssr/[root-of-the-server]__92b48411._.js'
[WebServer]     at copyFileSync (node:fs:3086:11)
[WebServer]     at file:///home/runner/work/nodejs.org/nodejs.org/node_modules/.pnpm/@[email protected]/node_modules/@opennextjs/aws/dist/build/copyTracedFiles.js:196:13
[WebServer]     at Map.forEach (<anonymous>)
[WebServer]     at copyTracedFiles (file:///home/runner/work/nodejs.org/nodejs.org/node_modules/.pnpm/@[email protected]/node_modules/@opennextjs/aws/dist/build/copyTracedFiles.js:169:17)
[WebServer]     at generateBundle (file:///home/runner/work/nodejs.org/nodejs.org/node_modules/.pnpm/@[email protected][email protected]/node_modules/@opennextjs/cloudflare/dist/cli/build/open-next/createServerBundle.js:120:60)
[WebServer]     at createServerBundle (file:///home/runner/work/nodejs.org/nodejs.org/node_modules/.pnpm/@[email protected][email protected]/node_modules/@opennextjs/cloudflare/dist/cli/build/open-next/createServerBundle.js:74:11)
[WebServer]     at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
[WebServer]     at async build (file:///home/runner/work/nodejs.org/nodejs.org/node_modules/.pnpm/@[email protected][email protected]/node_modules/@opennextjs/cloudflare/dist/cli/build/build.js:64:5)
[WebServer]     at async buildCommand (file:///home/runner/work/nodejs.org/nodejs.org/node_modules/.pnpm/@[email protected][email protected]/node_modules/@opennextjs/cloudflare/dist/cli/commands/build.js:13:5) {
[WebServer]   errno: -2,
[WebServer]   code: 'ENOENT',
[WebServer]   syscall: 'copyfile',
[WebServer]   path: '/home/runner/work/nodejs.org/nodejs.org/apps/site/.next/standalone/apps/site/.next/server/chunks/ssr/[root-of-the-server]__92b48411._.js',
[WebServer]   dest: '/home/runner/work/nodejs.org/nodejs.org/apps/site/.open-next/server-functions/default/apps/site/.next/server/chunks/ssr/[root-of-the-server]__92b48411._.js'
[WebServer] }
[WebServer]  ELIFECYCLE  Command failed with exit code 1.

Ref PR: https://github.com/nodejs/nodejs.org/pull/8218

cc @vicb @dario-piotrowicz

ovflowd avatar Oct 23 '25 13:10 ovflowd

Could that be a turbopack build?

You have to explicitly use next build --webpack with Next 16 to opt-out of the now default turbopack which is not yet supported

vicb avatar Oct 23 '25 14:10 vicb

Could that be a turbopack build?

You have to explicitly use next build --webpack with Next 16 to opt-out of the now default turbopack which is not yet supported

Weren't Turbopack builds working with OpenNext on Next.js 15? Or was it just that it was using Webpack by default?

ovflowd avatar Oct 23 '25 15:10 ovflowd

15 was using webpack by default. turbopack builds never worked - should hopefully be fixed in a few weeks.

vicb avatar Oct 23 '25 15:10 vicb

My personal advice is to hold off on upgrading your app to 16 until a couple months after release, as Vercel usually rushes out the release for their October conference. Like the prior years, the Major.0 releases have some major bugs. Eg for 16, the default turbopack breaks Portals...

khuezy avatar Oct 24 '25 00:10 khuezy

The issue is turbopack moving the css files to a different directory. You can fix this by having the following script move them to the directory opennext expects them to be in :

update your package.json to include this script to run post build:

next build --turbopack && node scripts/fix-css-paths.js

#!/usr/bin/env node

const fs = require('fs');
const path = require('path');

// Define paths
const buildDir = '.next';
const standaloneDir = path.join(buildDir, 'standalone/engagement/frontend/.next/static');
const mainStaticDir = path.join(buildDir, 'static');
const mainChunksDir = path.join(mainStaticDir, 'chunks');
const standaloneChunksDir = path.join(standaloneDir, 'chunks');
const standaloneCssDir = path.join(standaloneDir, 'css');

/**
 * Copy CSS files from source to destination directory
 */
function copyCssFiles(sourceDir, destDir, label) {
  if (!fs.existsSync(sourceDir)) {
    return { files: [], count: 0 };
  }

  // Create destination directory if it doesn't exist
  if (!fs.existsSync(destDir)) {
    fs.mkdirSync(destDir, { recursive: true });
  }

  const files = fs.readdirSync(sourceDir);
  const cssFiles = files.filter((file) => file.endsWith('.css'));

  if (cssFiles.length === 0) {
    return { files: [], count: 0 };
  }

  const copiedFiles = [];
  cssFiles.forEach((file) => {
    const sourcePath = path.join(sourceDir, file);
    const destPath = path.join(destDir, file);

    // Only copy if file doesn't exist in destination
    if (!fs.existsSync(destPath)) {
      try {
        fs.copyFileSync(sourcePath, destPath);
        console.log(`Copied: ${file}`);
        copiedFiles.push(file);
      } catch (error) {
        console.error(`Failed to copy ${file}:`, error.message);
      }
    }
  });

  return { files: copiedFiles, count: copiedFiles.length };
}

/**
 * Update manifest files to reference CSS files in the correct location
 */
function updateManifests() {
  const manifestPaths = [
    path.join(buildDir, 'build-manifest.json'),
    path.join(standaloneDir, '../build-manifest.json'),
    path.join(buildDir, 'app-build-manifest.json'),
    path.join(standaloneDir, '../app-build-manifest.json'),
  ];

  manifestPaths.forEach((manifestPath) => {
    if (fs.existsSync(manifestPath)) {
      try {
        const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
        let updated = false;

        // Function to update paths in manifest
        function updatePaths(obj) {
          if (Array.isArray(obj)) {
            return obj.map((item) => {
              if (typeof item === 'string' && item.includes('static/chunks/') && item.endsWith('.css')) {
                updated = true;
                return item.replace('static/chunks/', 'static/css/');
              }
              return typeof item === 'object' ? updatePaths(item) : item;
            });
          } else if (obj && typeof obj === 'object') {
            const result = {};
            for (const [key, value] of Object.entries(obj)) {
              result[key] = updatePaths(value);
            }
            return result;
          }
          return obj;
        }

        const updatedManifest = updatePaths(manifest);

        if (updated) {
          fs.writeFileSync(manifestPath, JSON.stringify(updatedManifest, null, 2));
          console.log(`Updated manifest: ${path.basename(manifestPath)}`);
        }
      } catch (error) {
        console.error(`Failed to update manifest ${manifestPath}:`, error.message);
      }
    }
  });
}

// Main execution
try {
  let totalCopied = 0;

  // Copy CSS files from main chunks directory to standalone css directory
  const mainResult = copyCssFiles(mainChunksDir, standaloneCssDir, 'Main chunks');
  totalCopied += mainResult.count;

  // Also copy from standalone chunks directory if it exists (backup)
  const standaloneResult = copyCssFiles(standaloneChunksDir, standaloneCssDir, 'Standalone chunks');
  totalCopied += standaloneResult.count;

  // Update manifest files to reference CSS files in the correct location
  updateManifests();

  if (totalCopied > 0) {
    console.log(`Successfully organized ${totalCopied} CSS file(s) for OpenNext compatibility`);
  } else {
    console.log('No new CSS files to organize');
  }
} catch (error) {
  console.error('Error during CSS file organization:', error.message);
  process.exit(1);
}

pinoniq avatar Oct 24 '25 06:10 pinoniq

@vicb it seems to fail even on Webpack mode. Since it tries to search for middleware.js

[custom build] Running: wrangler-build-time-fs-assets-polyfilling --assets pages --assets snippets --assets-output-dir .open-next/assets
[custom build] 🛠️  Setting up Wrangler fs polyfills (v0.0.0)
[custom build] 
[custom build] 
[custom build] 
✘ [ERROR] Custom build failed: Error: Build failed with 1 error:

  .open-next/middleware/handler.mjs:562:34: ERROR: Could not resolve "./.next/server/middleware.js"
      at failureErrorWithLog
  (/home/cwunder/GitHub/nodejs.org/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1463:15)
      at
  /home/cwunder/GitHub/nodejs.org/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:924:25
      at
  /home/cwunder/GitHub/nodejs.org/node_modules/.pnpm/[email protected]/node_modules/esbuild/lib/main.js:1341:9
      at process.processTicksAndRejections (node:internal/process/task_queues:105:5) {
    errors: [Getter/Setter],
    warnings: [Getter/Setter]
  }



✘ [ERROR] Build failed with 1 error:

  ✘ [ERROR] Could not resolve
  "./.next/server/middleware.js"
  
      .open-next/middleware/handler.mjs:562:34:
        562 │ ...e = await (await import("./.next/server/middleware.js")).default;

ovflowd avatar Oct 28 '25 14:10 ovflowd

Can you rename your proxy.ts back to middleware.ts. It's deprecated but it should still work?

khuezy avatar Oct 28 '25 17:10 khuezy

Can you rename your proxy.ts back to middleware.ts. It's deprecated but it should still work?

Right, or, I could make a PR upstream (OpenNext) to add support to proxy.ts? Let me know if that's a sound alternative :)

ovflowd avatar Oct 30 '25 12:10 ovflowd

My personal advice is to hold off on upgrading your app to 16 until a couple months after release, as Vercel usually rushes out the release for their October conference. Like the prior years, the Major.0 releases have some major bugs. Eg for 16, the default turbopack breaks Portals...

I missed this, but we're not aiming to migrate now, but we often do early builds with Node for new releases of Next.js to see early compatibility problems.

ovflowd avatar Oct 30 '25 12:10 ovflowd

Can you rename your proxy.ts back to middleware.ts. It's deprecated but it should still work?

Right, or, I could make a PR upstream (OpenNext) to add support to proxy.ts? Let me know if that's a sound alternative :)

Conico is working on https://github.com/opennextjs/opennextjs-aws/pulls. Perhaps you can check out that branch and see if the proxy changes works.

khuezy avatar Oct 30 '25 14:10 khuezy