swiftgen-integration
12
总安装量
8
周安装量
#26432
全站排名
安装命令
npx skills add https://github.com/kaakati/rails-enterprise-dev --skill swiftgen-integration
Agent 安装分布
claude-code
7
antigravity
6
opencode
6
codex
6
windsurf
5
Skill 文档
SwiftGen Integration â Expert Decisions
Expert decision frameworks for SwiftGen choices. Claude knows asset catalogs and localization â this skill provides judgment calls for when SwiftGen adds value and configuration trade-offs.
Decision Trees
When SwiftGen Adds Value
Should you use SwiftGen for this project?
ââ > 20 assets/strings
â ââ YES â Type safety prevents bugs
â Typos caught at compile time
â
ââ < 10 assets/strings, solo developer
â ââ MAYBE â Overhead vs. benefit
â Quick projects may not need it
â
ââ Team project with shared assets
â ââ YES â Consistency + discoverability
â Autocomplete reveals available assets
â
ââ Assets change frequently
â ââ YES â Broken references caught early
â CI catches missing assets
â
ââ CI/CD pipeline exists
ââ YES â Validate assets on every build
Prevents runtime crashes
The trap: Using SwiftGen on tiny projects or for assets that rarely change. The setup overhead may exceed the benefit.
Template Selection
Which template should you use?
ââ Strings
â ââ Hierarchical keys (auth.login.title)
â â ââ structured-swift5
â â L10n.Auth.Login.title
â â
â ââ Flat keys (login_title)
â ââ flat-swift5
â L10n.loginTitle
â
ââ Assets (Images)
â ââ swift5 (default)
â Asset.Icons.home.image
â
ââ Colors
â ââ swift5 with enumName param
â Asset.Colors.primary.color
â
ââ Fonts
â ââ swift5
â FontFamily.Roboto.bold.font(size:)
â
ââ Storyboards
ââ scenes-swift5
StoryboardScene.Main.initialViewController()
Asset Organization Strategy
How should you organize assets?
ââ Small app (< 50 assets)
â ââ Single Assets.xcassets
â Feature folders inside catalog
â
ââ Medium app (50-200 assets)
â ââ Feature-based catalogs
â Auth.xcassets, Dashboard.xcassets
â Multiple swiftgen inputs
â
ââ Large app / multi-module
â ââ Per-module asset catalogs
â Each module owns its assets
â Module-specific SwiftGen runs
â
ââ Design system / shared assets
ââ Separate DesignSystem.xcassets
Shared across targets
Build Phase Strategy
When should SwiftGen run?
ââ Every build
â ââ Run Script phase (before Compile Sources)
â Always current, small overhead
â
ââ Only when assets change
â ââ Input/Output files specified
â Xcode skips if unchanged
â
ââ Manual only (CI generates)
â ââ Commit generated files
â No local SwiftGen needed
â Risk: generated files out of sync
â
ââ Pre-commit hook
ââ Lint + generate before commit
Ensures consistency
NEVER Do
Configuration
NEVER hardcode paths without variables:
# â Breaks in different environments
strings:
inputs: /Users/john/Projects/MyApp/Resources/en.lproj/Localizable.strings
outputs:
output: /Users/john/Projects/MyApp/Generated/Strings.swift
# â
Use relative paths
strings:
inputs: Resources/en.lproj/Localizable.strings
outputs:
output: Generated/Strings.swift
NEVER forget publicAccess for shared modules:
# â Generated code is internal â can't use from other modules
xcassets:
inputs: Resources/Assets.xcassets
outputs:
- templateName: swift5
output: Generated/Assets.swift
# Missing publicAccess!
# â
Add publicAccess for shared code
xcassets:
inputs: Resources/Assets.xcassets
outputs:
- templateName: swift5
output: Generated/Assets.swift
params:
publicAccess: true # Accessible from other modules
Generated Code Usage
NEVER use string literals alongside SwiftGen:
// â Defeats the purpose
let icon = UIImage(named: "home") // String literal!
let title = NSLocalizedString("auth.login.title", comment: "") // String literal!
// â
Use generated constants everywhere
let icon = Asset.Icons.home.image
let title = L10n.Auth.Login.title
NEVER modify generated files:
// â Changes will be overwritten
// Generated/Assets.swift
enum Asset {
enum Icons {
static let home = ImageAsset(name: "home")
// My custom addition <- WILL BE DELETED ON NEXT RUN
static let customIcon = ImageAsset(name: "custom")
}
}
// â
Extend in separate file
// Extensions/Asset+Custom.swift
extension Asset.Icons {
// Extensions survive regeneration
}
Build Phase
NEVER put SwiftGen after Compile Sources:
# â Generated files don't exist when compiling
Build Phases order:
1. Compile Sources <- Fails: Assets.swift doesn't exist!
2. Run Script (SwiftGen)
# â
Generate before compiling
Build Phases order:
1. Run Script (SwiftGen) <- Generates Assets.swift
2. Compile Sources <- Now Assets.swift exists
NEVER skip SwiftGen availability check:
# â Build fails if SwiftGen not installed
swiftgen config run # Error: command not found
# â
Check availability, warn instead of fail
if which swiftgen >/dev/null; then
swiftgen config run --config "$SRCROOT/swiftgen.yml"
else
echo "warning: SwiftGen not installed, skipping code generation"
fi
Version Control
NEVER commit generated files without good reason:
# â Merge conflicts, stale files
git add Generated/Assets.swift
git add Generated/Strings.swift
# â
Gitignore generated files
# .gitignore
Generated/
*.generated.swift
# Exception: If CI doesn't run SwiftGen, commit generated files
# But then add pre-commit hook to keep them fresh
NEVER leave swiftgen.yml uncommitted:
# â Team members can't regenerate
.gitignore
swiftgen.yml <- WRONG!
# â
Commit configuration
git add swiftgen.yml
git add Resources/ # Source assets
String Keys
NEVER use inconsistent key conventions:
# â Mixed conventions â confusing
"LoginTitle" = "Log In";
"login.button" = "Sign In";
"AUTH_ERROR" = "Error";
# â
Consistent hierarchical keys
"auth.login.title" = "Log In";
"auth.login.button" = "Sign In";
"auth.error.generic" = "Error";
Essential Patterns
Complete swiftgen.yml
# swiftgen.yml
## Strings (Localization)
strings:
inputs:
- Resources/en.lproj/Localizable.strings
outputs:
- templateName: structured-swift5
output: Generated/Strings.swift
params:
publicAccess: true
enumName: L10n
## Assets (Images)
xcassets:
- inputs:
- Resources/Assets.xcassets
outputs:
- templateName: swift5
output: Generated/Assets.swift
params:
publicAccess: true
## Colors
colors:
- inputs:
- Resources/Colors.xcassets
outputs:
- templateName: swift5
output: Generated/Colors.swift
params:
publicAccess: true
enumName: ColorAsset
## Fonts
fonts:
- inputs:
- Resources/Fonts/
outputs:
- templateName: swift5
output: Generated/Fonts.swift
params:
publicAccess: true
SwiftUI Convenience Extensions
// Extensions/SwiftGen+SwiftUI.swift
import SwiftUI
// Image extension
extension Image {
init(asset: ImageAsset) {
self.init(asset.name, bundle: BundleToken.bundle)
}
}
// Color extension
extension Color {
init(asset: ColorAsset) {
self.init(asset.name, bundle: BundleToken.bundle)
}
}
// Font extension
extension Font {
static func custom(_ fontConvertible: FontConvertible, size: CGFloat) -> Font {
fontConvertible.swiftUIFont(size: size)
}
}
// Usage
struct ContentView: View {
var body: some View {
VStack {
Image(asset: Asset.Icons.home)
.foregroundColor(Color(asset: Asset.Colors.primary))
Text(L10n.Home.title)
.font(.custom(FontFamily.Roboto.bold, size: 24))
}
}
}
Build Phase Script
#!/bin/bash
# Xcode Build Phase: Run Script
# Move BEFORE "Compile Sources"
set -e
# Check if SwiftGen is installed
if ! which swiftgen >/dev/null; then
echo "warning: SwiftGen not installed. Install via: brew install swiftgen"
exit 0
fi
# Navigate to project root
cd "$SRCROOT"
# Create output directory if needed
mkdir -p Generated
# Run SwiftGen
echo "Running SwiftGen..."
swiftgen config run --config swiftgen.yml
echo "SwiftGen completed successfully"
Input Files (for incremental builds):
$(SRCROOT)/swiftgen.yml
$(SRCROOT)/Resources/Assets.xcassets
$(SRCROOT)/Resources/en.lproj/Localizable.strings
$(SRCROOT)/Resources/Colors.xcassets
$(SRCROOT)/Resources/Fonts
Output Files:
$(SRCROOT)/Generated/Assets.swift
$(SRCROOT)/Generated/Strings.swift
$(SRCROOT)/Generated/Colors.swift
$(SRCROOT)/Generated/Fonts.swift
Multi-Module Setup
# Module: DesignSystem/swiftgen.yml
xcassets:
- inputs:
- Sources/DesignSystem/Resources/Colors.xcassets
outputs:
- templateName: swift5
output: Sources/DesignSystem/Generated/Colors.swift
params:
publicAccess: true # Must be public for cross-module
# Module: Feature/swiftgen.yml
strings:
- inputs:
- Sources/Feature/Resources/en.lproj/Feature.strings
outputs:
- templateName: structured-swift5
output: Sources/Feature/Generated/Strings.swift
params:
publicAccess: false # Internal to module
enumName: Strings
Quick Reference
Template Options
| Asset Type | Template | Output |
|---|---|---|
| Images | swift5 | Asset.Category.name.image |
| Colors | swift5 | Asset.Colors.name.color |
| Strings | structured-swift5 | L10n.Category.Subcategory.key |
| Strings (flat) | flat-swift5 | L10n.keyName |
| Fonts | swift5 | FontFamily.Name.weight.font(size:) |
| Storyboards | scenes-swift5 | StoryboardScene.Name.viewController |
Common Parameters
| Parameter | Purpose | Example |
|---|---|---|
| publicAccess | Public access level | true for shared modules |
| enumName | Custom enum name | L10n, Asset, Colors |
| allValues | Include allValues array | true for debugging |
| preservePath | Keep folder structure | true for fonts |
File Structure
Project/
âââ swiftgen.yml # Configuration (commit)
âââ Resources/
â âââ Assets.xcassets # Images (commit)
â âââ Colors.xcassets # Colors (commit)
â âââ Fonts/ # Custom fonts (commit)
â âââ en.lproj/
â âââ Localizable.strings # Strings (commit)
âââ Generated/ # Output (gitignore)
âââ Assets.swift
âââ Colors.swift
âââ Fonts.swift
âââ Strings.swift
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| “No such module” | Generated before adding to target | Add to target membership |
| Build fails | Run Script after Compile | Move before Compile Sources |
| Stale generated code | Missing input/output files | Specify all inputs/outputs |
| Wrong bundle | Multi-target project | Use correct BundleToken |
Red Flags
| Smell | Problem | Fix |
|---|---|---|
| String literals for assets | Bypasses type safety | Use generated constants |
| Modified generated files | Changes get overwritten | Use extensions instead |
| Run Script after Compile | Files don’t exist | Move before Compile Sources |
| No availability check | Build fails without SwiftGen | Add which swiftgen check |
| Committed generated files | Merge conflicts, staleness | Gitignore, generate on build |
| Missing publicAccess | Can’t use across modules | Add publicAccess: true |
| Mixed key conventions | Inconsistent L10n structure | Use hierarchical keys |