Skip to content

fix(functions): use dart build cli for Dart function bundles - #10926

Open
demolaf wants to merge 7 commits into
firebase:mainfrom
demolaf:dart-functions-build-cli
Open

fix(functions): use dart build cli for Dart function bundles#10926
demolaf wants to merge 7 commits into
firebase:mainfrom
demolaf:dart-functions-build-cli

Conversation

@demolaf

@demolaf demolaf commented Aug 12, 2026

Copy link
Copy Markdown
Member

Closes #10591

Following the release of Dart 3.13.0, we can now cross-compile with dart build cli (previously only dart compile exe supported --target-os/--target-arch), which unblocks using build hooks for Dart functions.

dart compile exe produces a single ahead-of-time compiled executable and skips Dart's native build hooks, so functions depending on packages with native assets don't build correctly. Switching to dart build cli runs those hooks and produces a proper bundle instead of a bare executable.

This updates the Dart runtime delegate to invoke dart build cli with the same target/os/arch flags, and updates prepare.ts to look for the resulting server executable at its new bundle path (build/cli/linux_x64/bundle/bin/server) instead of bin/server.

Related to firebase/firebase-functions-dart#201

@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 updates the Dart functions deployment process by transitioning from dart compile exe to dart build cli for building the Dart linux-x64 bundle. As a result, the executable path is updated to build/cli/linux_x64/bundle/bin/server, and the manual creation of the bin directory is removed. I have no feedback to provide.

@codecov-commenter

codecov-commenter commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 55.55556% with 8 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@c50833e). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/deploy/functions/prepare.ts 14.28% 6 Missing ⚠️
src/deploy/functions/runtimes/dart/index.ts 81.81% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #10926   +/-   ##
=======================================
  Coverage        ?   59.32%           
=======================================
  Files           ?      638           
  Lines           ?    41954           
  Branches        ?     8539           
=======================================
  Hits            ?    24891           
  Misses          ?    15001           
  Partials        ?     2062           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@demolaf
demolaf force-pushed the dart-functions-build-cli branch from 2d8df26 to 77647b0 Compare August 13, 2026 08:57

@wandamora wandamora 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.

It seems more changes are required for this to work.

  1. config.set("functions.ignore", [".dart_tool", "build"]);
    Because build is in config.ignore, readdirRecursive (
    const ignore = config.ignore || ["node_modules", ".git"];
    ignore.push(
    "firebase-debug.log",
    "firebase-debug.*.log",
    CONFIG_DEST_FILE /* .runtimeconfig.json */,
    );
    try {
    const files = await fsAsync.readdirRecursive({ path: sourceDir, ignoreStrings: ignore });
    hashes.push(...(await addFilesToArchive(archive, files, sourceDir, options?.executablePaths)));
    ) skips the entire build/ directory. The uploaded archive will omit build/cli/linux_x64/bundle/bin/server and its companion native asset libraries (build/cli/linux_x64/bundle/lib/), causing Cloud Run deployments to fail at runtime. We would need to change the default ignore config for dart and also ensure that build/cli/** files are discoverable before calling prepareFunctionUpload:
    const isDart = supported.runtimeIsLanguage(wantBuilds[codebase].runtime, "dart");
    const executablePaths = isDart ? ["bin/server"] : [];
    const packagedSource = await prepareFunctionsUpload(

To avoid archive bloat, we could change the ignored files to allowlist the bundle:

"ignore": [
  ".dart_tool",
  "build/**",
  "!build/cli/linux_x64/bundle/**"
]
  1. bin/server should be updated to build/ in the .gitignore template:

Comment thread src/deploy/functions/runtimes/dart/index.ts Outdated
Comment thread src/deploy/functions/prepare.ts Outdated
@wandamora

Copy link
Copy Markdown
Contributor

Also, adding some test cases could be useful:

  1. In src/deploy/functions/runtimes/dart/index.spec.ts:

    • validate(): Verify that an installed Dart SDK < 3.13.0 rejects with a FirebaseError instructing the user to upgrade.
    • build(): Verify that spawn is called with arguments ["build", "cli", "--target", "bin/server.dart", "--target-os", "linux", "--target-arch", "x64"].
    • build() failure: Verify that non-zero exit codes throw a FirebaseError containing the updated dart build cli --target ... remediation command.
    • build() emulator check: Verify that build() is skipped when EmulatorRegistry.isRunning(Emulators.FUNCTIONS) is true.
  2. In src/deploy/functions/prepare.spec.ts:

    • Verify that prepare() sets executablePaths to ["build/cli/linux_x64/bundle/bin/server"] when wantBuilds[codebase].runtime is Dart.

@demolaf
demolaf requested a review from wandamora August 14, 2026 15:45
const isDart = supported.runtimeIsLanguage(wantBuilds[codebase].runtime, "dart");
const executablePaths = isDart ? ["bin/server"] : [];
const executablePaths = getExecutablePaths(wantBuilds[codebase].runtime);

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.

So, for new projects using firebase init, we don't need to worry about excluding the build/ files now. However for existing users, they'll continue to have the build/ directory ignored (the template won't change for them. We may need to add some work around in prepare.ts, such as:

let uploadCfg = localCfg;
if (isDart && uploadCfg.ignore?.includes("build")) {
  uploadCfg = {
    ...uploadCfg,
    ignore: uploadCfg.ignore.filter((i) => i !== "build" && i !== "build/"),
  };
}

const packagedSource = await prepareFunctionsUpload...

with a comment explaining why.

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.

[cloud functions for dart] Allow functions in a folder different than "bin" to workaround build hook issues

5 participants