1- import { execSync , spawnSync } from "child_process" ;
1+ import { execSync } from "child_process" ;
2+ import { spawn , sync as spawnSync } from "cross-spawn" ;
23import { mkdir , copyFile } from "fs/promises" ;
34import { dirname , join } from "path" ;
45import type { NextConfig } from "next" ;
@@ -11,6 +12,10 @@ import { existsSync } from "fs";
1112import { gte } from "semver" ;
1213import { IncomingMessage , ServerResponse } from "http" ;
1314import * as clc from "colorette" ;
15+ import { chain } from "stream-chain" ;
16+ import { parser } from "stream-json" ;
17+ import { pick } from "stream-json/filters/Pick" ;
18+ import { streamObject } from "stream-json/streamers/StreamObject" ;
1419
1520import {
1621 BuildResult ,
@@ -34,7 +39,7 @@ import {
3439 isUsingMiddleware ,
3540 allDependencyNames ,
3641} from "./utils" ;
37- import type { Manifest , NpmLsReturn } from "./interfaces" ;
42+ import type { Manifest , NpmLsDepdendency } from "./interfaces" ;
3843import { readJSON } from "../utils" ;
3944import { warnIfCustomBuildScript } from "../utils" ;
4045import type { EmulatorInfo } from "../../emulator/types" ;
@@ -345,33 +350,52 @@ export async function ɵcodegenPublicDirectory(sourceDir: string, destDir: strin
345350export async function ɵcodegenFunctionsDirectory ( sourceDir : string , destDir : string ) {
346351 const { distDir } = await getConfig ( sourceDir ) ;
347352 const packageJson = await readJSON ( join ( sourceDir , "package.json" ) ) ;
353+ // Bundle their next.config.js with esbuild via NPX, pinned version was having troubles on m1
354+ // macs and older Node versions; either way, we should avoid taking on any deps in firebase-tools
355+ // Alternatively I tried using @swc /spack and the webpack bundled into Next.js but was
356+ // encountering difficulties with both of those
348357 if ( existsSync ( join ( sourceDir , "next.config.js" ) ) ) {
349- // Bundle their next.config.js with esbuild via NPX, pinned version was having troubles on m1
350- // macs and older Node versions; either way, we should avoid taking on any deps in firebase-tools
351- // Alternatively I tried using @swc /spack and the webpack bundled into Next.js but was
352- // encountering difficulties with both of those
353- const dependencyTree : NpmLsReturn = JSON . parse (
354- spawnSync ( "npm" , [ "ls" , "--omit=dev" , "--all" , "--json" ] , {
358+ try {
359+ const productionDeps = await new Promise < string [ ] > ( ( resolve ) => {
360+ const dependencies : string [ ] = [ ] ;
361+ const pipeline = chain ( [
362+ spawn ( "npm" , [ "ls" , "--omit=dev" , "--all" , "--json" ] , { cwd : sourceDir } ) . stdout ,
363+ parser ( { packValues : false , packKeys : true , streamValues : false } ) ,
364+ pick ( { filter : "dependencies" } ) ,
365+ streamObject ( ) ,
366+ ( { key, value } : { key : string ; value : NpmLsDepdendency } ) => [
367+ key ,
368+ ...allDependencyNames ( value ) ,
369+ ] ,
370+ ] ) ;
371+ pipeline . on ( "data" , ( it : string ) => dependencies . push ( it ) ) ;
372+ pipeline . on ( "end" , ( ) => {
373+ resolve ( [ ...new Set ( dependencies ) ] ) ;
374+ } ) ;
375+ } ) ;
376+ // Mark all production deps as externals, so they aren't bundled
377+ // DevDeps won't be included in the Cloud Function, so they should be bundled
378+ const esbuildArgs = productionDeps
379+ . map ( ( it ) => `--external:${ it } ` )
380+ . concat (
381+ "--bundle" ,
382+ "--platform=node" ,
383+ `--target=node${ NODE_VERSION } ` ,
384+ `--outdir=${ destDir } ` ,
385+ "--log-level=error"
386+ ) ;
387+ const bundle = spawnSync ( "npx" , [ "--yes" , "esbuild" , "next.config.js" , ...esbuildArgs ] , {
355388 cwd : sourceDir ,
356- } ) . stdout . toString ( )
357- ) ;
358- // Mark all production deps as externals, so they aren't bundled
359- // DevDeps won't be included in the Cloud Function, so they should be bundled
360- const esbuildArgs = allDependencyNames ( dependencyTree )
361- . map ( ( it ) => `--external:${ it } ` )
362- . concat (
363- "--bundle" ,
364- "--platform=node" ,
365- `--target=node${ NODE_VERSION } ` ,
366- `--outdir=${ destDir } ` ,
367- "--log-level=error"
389+ } ) ;
390+ if ( bundle . status ) {
391+ throw new FirebaseError ( bundle . stderr . toString ( ) ) ;
392+ }
393+ } catch ( e : any ) {
394+ console . warn (
395+ "Unable to bundle next.config.js for use in Cloud Functions, proceeding with deploy but problems may be enountered."
368396 ) ;
369- const bundle = spawnSync ( "npx" , [ "--yes" , "esbuild" , "next.config.js" , ...esbuildArgs ] , {
370- cwd : sourceDir ,
371- } ) ;
372- if ( bundle . status ) {
373- console . error ( bundle . stderr . toString ( ) ) ;
374- throw new FirebaseError ( "Unable to bundle next.config.js for use in Cloud Functions" ) ;
397+ console . error ( e . message ) ;
398+ copy ( join ( sourceDir , "next.config.js" ) , join ( destDir , "next.config.js" ) ) ;
375399 }
376400 }
377401 if ( await pathExists ( join ( sourceDir , "public" ) ) ) {
0 commit comments