feat(spm): add trait to opt out of Firestore - #16684
Conversation
Add support for Swift Package Traits (SE-0450) by defining a default- enabled "FirebaseFirestore" trait. Previously, depending on the Firebase package pulled in Cloud Firestore and its heavy dependencies (gRPC, Abseil) regardless of whether an app used Firestore. With this trait, developers can opt out in their Package.swift or via Xcode's Package Dependencies UI to avoid fetching and downloading these dependencies during package resolution: - Define the "FirebaseFirestore" trait, enabled by default. - Gate binary and source Firestore target dependencies on the trait. - Provide a clear compile-time diagnostic in dummy.m if Firestore is included without enabling the trait. - Gate Combine extensions and integration test targets on the trait.
Disable default Swift package traits for the local Firebase dependency in FirebaseAITestApp. Because Firebase AI Logic integration tests do not depend on Cloud Firestore, opting out of the "FirebaseFirestore" trait prevents Xcode from downloading heavy underlying dependencies (gRPC, Abseil), speeding up resolution and validating trait opt-out behavior in Xcode.
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. |
Revert `#if canImport(Combine) && FirebaseFirestore` back to the original `#if canImport(Combine) && swift(>=5.0)` in Firestore Combine extensions. CocoaPods does not pass SwiftPM trait flags like `-DFirebaseFirestore`, causing the compiler to exclude the Combine extensions during CocoaPods builds and failing `sdk.combine.yml` unit tests. In SwiftPM, `FirebaseFirestoreCombineSwift` is already conditionally gated on the trait at the target dependency level in `Package.swift`, so source-level trait guards are unnecessary.
Add changelog entries in FirebaseCore and Firestore for Swift Package Traits support: - FirebaseCore: Note general support for Swift Package Traits to prune unused dependencies. - Firestore: Note the `FirebaseFirestore` trait requirement (enabled by default) and opt-out capability.
Summary of ChangesThis pull request introduces support for Swift Package Traits (SE-0450) to the Firebase iOS SDK, specifically targeting the Firestore module. By defining a default-enabled 'FirebaseFirestore' trait, the change allows developers to explicitly opt out of Firestore dependencies if they are not using the product, significantly streamlining the dependency graph for projects using only lightweight Firebase components. The implementation includes robust gating for source and binary targets, updated documentation, and diagnostic checks to ensure a smooth developer experience during configuration. Highlights
New Features🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Activity
|
There was a problem hiding this comment.
Code Review
This pull request introduces support for Swift Package Traits (SE-0450) to allow developers to opt out of heavy dependencies like Cloud Firestore (gRPC and Abseil) when they are not needed. It configures the FirebaseFirestore trait in Package.swift and conditionally compiles dependencies and imports based on this trait. The review feedback highlights critical issues in the test files where conditional compilation checks were implemented incorrectly: in Swift, #if canImport(FirebaseFirestore) should be used instead of #if FirebaseFirestore, and in Objective-C, __has_include should be used instead of checking for undefined preprocessor macros, as they do not propagate transitively to the test targets.
Rename the default package trait from "FirebaseFirestore" to "FirestoreSupport" across Package.swift, test targets, and error diagnostics. Using "FirestoreSupport" clarifies that the compilation condition (`#if FirestoreSupport`) represents a Swift Package Trait rather than a module availability check, and aligns with SE-0450 naming conventions. Also clarify the diagnostic in dummy.m to explicitly reference SwiftPM.
Rename the default Swift Package Trait from "FirebaseFirestore" to "Firestore" and refine conditional compilation across the manifest, test targets, and diagnostics: - Rename the trait to "Firestore" in Package.swift and update all target trait conditions. Because the module is "FirebaseFirestore", `#if Firestore` avoids confusion with module availability checks. - Add an inline comment in `all-imports.swift` documenting that `#if Firestore` gates imports based on the SwiftPM trait. - Rename the C preprocessor macro to `FIRESTORE_TRAIT_ENABLED` in target cSettings for both `FirebaseFirestoreTarget` and `objc-import-test`, removing dead `defined(Firestore)` checks in Objective-C test files (since SwiftPM traits only define compiler conditions for swiftc). - Update the diagnostic in `dummy.m` to explicitly reference SwiftPM and the "Firestore" trait. - Update the entry in `Firestore/CHANGELOG.md` to reference "Firestore".
# Conflicts: # FirebaseCore/CHANGELOG.md
|
Note: The CI failure is likely just due to #16690. Will re-run after merging. |
Document how developers can opt out of the "Firestore" trait using Xcode's Package Dependencies UI and refine the compile-time diagnostic: - Update FirebaseCore/CHANGELOG.md with instructions to uncheck `default` and select only desired traits in the Xcode Traits dropdown (showing `None` when all traits are disabled). - Update Package.swift doc comments to instruct unchecking unwanted traits in the Traits dropdown in Xcode (26.4+). - Refine the diagnostic in dummy.m to point specifically to the "Package Dependencies tab" of the Xcode project.
# Conflicts: # Firestore/CHANGELOG.md
|
Re-opening after #16544 merged. |
|
Ah, my bad. Main needed to be merged in. I thought merging the other PR and restarting CI was enough. CI looks good now 👍 . |
Added support for configuring the Firebase Swift Package using Traits (SE-0450) and introduced a default-enabled
Firestoretrait.Previously, adding the
firebase-ios-sdkSwift package would always download and resolve Firestore's underlying dependencies (gRPC,abseil), even if the app didn't include Firestore. With package traits, you can now opt out of Firestore to reduce package resolution time, checkout size, and project overhead. The trait is enabled by default to preserve backwards compatibility.Developer Instructions
Configuring Traits in Xcode (Xcode 26.4+)
In Xcode, select your project in the Project Navigator.
Select your project in the project editor and open the Package Dependencies tab.
In the package list, locate Firebase and find the Traits column.
Click the Traits dropdown (which shows
default (Firestore)by default).Uncheck
default(or uncheckFirestore). The dropdown will displayNonewhen all traits are disabled.Configuring Traits in Package.swift
In your
Package.swift, pass an emptytraitsarray (or list only the traits you wish to enable) in your.packagedependency declaration:Technical Details
Implementation
1. Package Trait Definition & Target Gating
let firestoreTrait = Trait(name: "Firestore", ...)and enabled it by default inpackageTraitsvia.default(enabledTraits: [firestoreTrait.name]).abseil-cpp-binary,grpc-binary,FirebaseFirestoreInternalWrapper,abseil-cpp-SwiftPM,grpc-ios, andFirebaseFirestoreCombineSwift) on.when(traits: ["Firestore"]).2. C Preprocessor Macro (
FIRESTORE_TRAIT_ENABLED)-D <Trait>flags toswiftcfor Swift conditional compilation, but do not automatically pass preprocessor defines to Clang for C/Objective-C compilation.cSettings: [.define("FIRESTORE_TRAIT_ENABLED", .when(traits: ["Firestore"]))]onFirebaseFirestoreTargetandobjc-import-testso Clang can conditionally compile Firestore-related code based on the trait.3. Compile-Time Diagnostic Guard
SwiftPM-PlatformExclude/FirebaseFirestoreWrap/dummy.m, added a#if !defined(FIRESTORE_TRAIT_ENABLED)#errorcheck to provide an immediate, actionable diagnostic if an app target attempts to linkFirebaseFirestoreTargetwithout enabling theFirestoretrait.4. Integration Tests & Conditional Imports
SwiftPMTests/swift-test/all-imports.swift, guardedimport FirebaseFirestorebehind#if Firestore // Gated by the "Firestore" SwiftPM package trait..SwiftPMTests/objc-import-test/objc-header.mandobjc-module.m, guarded imports behind#if defined(FIRESTORE_TRAIT_ENABLED).--disable-default-traits.5. CocoaPods & Combine Compatibility
#if canImport(Combine) && swift(>=5.0)guards inFirebaseCombineSwift/Sources/Firestoresource files to avoid breaking CocoaPods CI workflows (sdk.combine.yml), keeping trait gating at the target dependency level inPackage.swift.6. Integration Test App Opt-Out
FirebaseAI/Tests/TestApp/FirebaseAITestApp.xcodeproj/project.pbxprojto opt out of default package traits (traits = ()), validating trait opt-out in Xcode while avoiding unnecessary Firestore dependencies for AI Logic integration tests.Testing
swift test --test-product swift-testpassed with default traits enabled.swift test --disable-default-traits --test-product swift-testpassed with traits disabled.swift test --test-product objc-import-testpassed with default traits enabled.swift test --disable-default-traits --test-product objc-import-testpassed with traits disabled.FirebaseFirestoreTargetwith--disable-default-traitstriggered the expected diagnostic indummy.m.FirebaseAuthwithtraits: []thatabseil-cpp-binaryandgrpc-binarywere completely pruned and never downloaded during resolution.