Skip to content

feat(functions): add full support for Yarn 2+ (PnP and pnpm nodeLinkers)#10846

Open
ajperel wants to merge 1 commit into
mainfrom
ajp/fix-10813
Open

feat(functions): add full support for Yarn 2+ (PnP and pnpm nodeLinkers)#10846
ajperel wants to merge 1 commit into
mainfrom
ajp/fix-10813

Conversation

@ajperel

@ajperel ajperel commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Description

This commit comprehensively adds native CLI support for executing and resolving Firebase Functions inside strict Yarn 2+ ecosystems (specifically Plug'n'Play zero-install mechanisms and pnpm-emulated physical symlinked layouts).

  • Introduces robust .pnp.cjs hook parsing to resolve node_modules maps instantly in strictly sandboxed Yarn architectures.
  • Aggressively injects --require .pnp.cjs into env.NODE_OPTIONS to guarantee spawned emulator processes correctly inherit virtual file system patching.
  • Implements strict PackageJson typing to ensure safe SDK version queries.
  • Fixes #10813 by bypassing unhandled require.resolve() traps that historically crashed direct natively booted CLI processes.
  • Updates SdkVersion checks to also handle Yarn2+ cases.

Scenarios Tested

  • Yarn Workspaces strict pnp nodeLinker mode.
  • Yarn Workspaces pnpm nodeLinker mode.
  • npm Workspaces
  • Emulator successful startup
  • Tested with both latest and older firebase-functions SDK versions
  • npm test

Sample Commands

  • firebase deploy --only functions
  • firebase emulators:start

TAG=agy
CONV=a5e2bab9-4423-4b50-82ed-188ecaca31ab

@wiz-9635d3485b

wiz-9635d3485b Bot commented Jul 24, 2026

Copy link
Copy Markdown

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities -
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings 5 Medium 2 Low
Software Management Finding Software Management Findings -
Total 5 Medium 2 Low

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for emulating and deploying Cloud Functions in Yarn 2+ Plug'n'Play and pnpm nodeLinker environments by adding Yarn resolution hooks and fallback search paths for the firebase-functions binary. The review feedback highlights a critical issue where paths containing spaces in NODE_OPTIONS can cause execution failures on Windows, which can be fixed by wrapping the path in double quotes. Additionally, several improvements are suggested to align with the repository style guide, including reducing nested conditionals and avoiding the explicit use of any in catch blocks.

Comment thread src/deploy/functions/runtimes/node/index.ts
Comment on lines +204 to +217
if (resolved) {
const { pkgPath, packageJson } = resolved;
const relativeBinPath = packageJson.bin?.["firebase-functions"];
if (relativeBinPath) {
const jsBinPath = path.join(pkgPath, relativeBinPath);
if (fileExistsSync(jsBinPath)) {
logger.debug(`Found firebase-functions binary internally via Yarn PnP at '${jsBinPath}'`);
// When we return this zip path, spawnFunctionsProcess constructs a new `spawn(process.execPath)`
// containing our payload. Because the child environment correctly inherits `NODE_OPTIONS`, it
// boots up with an identically patched `fs` architecture, safely executing the zipped script!
return jsBinPath;
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

We can reduce nesting by flattening the conditional checks and combining the path resolution and existence check. This adheres to the repository style guide's rule to reduce nesting as much as possible.

    if (resolved) {
      const { pkgPath, packageJson } = resolved;
      const relativeBinPath = packageJson.bin?.["firebase-functions"];
      const jsBinPath = relativeBinPath ? path.join(pkgPath, relativeBinPath) : undefined;
      if (jsBinPath && fileExistsSync(jsBinPath)) {
        logger.debug("Found firebase-functions binary internally via Yarn PnP at '" + jsBinPath + "'");
        // When we return this zip path, spawnFunctionsProcess constructs a new `spawn(process.execPath)`
        // containing our payload. Because the child environment correctly inherits `NODE_OPTIONS`, it
        // boots up with an identically patched `fs` architecture, safely executing the zipped script!
        return jsBinPath;
      }
    }
References
  1. Reduce nesting as much as possible Code should avoid unnecessarily deep nesting or long periods of nesting. Handle edge cases early and exit or fold them into the general case. (link)

Comment thread src/deploy/functions/runtimes/node/utils.ts Outdated
Comment on lines +46 to +51
} catch (e: any) {
logger.debug(
`resolvePnpModulePath encountered error querying Yarn PnP API for ${moduleName}:`,
e,
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using catch (e: any) explicitly uses any as an escape hatch, which violates the repository style guide. Since logger.debug accepts unknown or any, we can simply use catch (e) or catch (e: unknown) to avoid using any.

Suggested change
} catch (e: any) {
logger.debug(
`resolvePnpModulePath encountered error querying Yarn PnP API for ${moduleName}:`,
e,
);
}
} catch (e) {
logger.debug(
"resolvePnpModulePath encountered error querying Yarn PnP API for " + moduleName + ":",
e,
);
}
References
  1. Never use any or unknown as an escape hatch. Define proper interfaces/types or use type guards. (link)

Comment thread src/deploy/functions/runtimes/node/utils.ts Outdated
@ajperel
ajperel force-pushed the ajp/fix-10813 branch 2 times, most recently from af4f976 to 0a2f3ee Compare July 25, 2026 00:14
This commit comprehensively adds native CLI support for executing and resolving Firebase Functions inside strict Yarn 2+ ecosystems (specifically Plug'n'Play zero-install mechanisms and pnpm-emulated physical symlinked layouts).
- Introduces robust `.pnp.cjs` hook parsing to resolve `node_modules` maps instantly in strictly sandboxed Yarn architectures.
- Aggressively injects `--require .pnp.cjs` into `env.NODE_OPTIONS` to guarantee spawned emulator processes correctly inherit virtual file system patching.
- Simplifies dependency resolution search to securely evaluate the function's structural payload inside `[sourceDir, projectDir]`.
- Implements strict `PackageJson` typing to ensure safe SDK version queries.
- Fixes `#10813` by bypassing unhandled `require.resolve()` traps that historically crashed direct natively booted CLI processes.
- Updates SdkVersion checks to also handle Yarn2+ cases.

Scenarios Tested
- Yarn Workspaces strict `pnp` nodeLinker mode.
- Yarn Workspaces `pnpm` nodeLinker mode.
- Direct native Node CLI executions (`node firebase.js`) over varied isolated virtual package boundaries.
- Emulator successful startup
- Tested with both latest and older firebase-functions SDK versions

Test Commands
- `firebase deploy --only functions`
- `firebase emulators:start`

TAG=agy
CONV=a5e2bab9-4423-4b50-82ed-188ecaca31ab
@ajperel
ajperel requested review from inlined and joehan July 25, 2026 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants