How I Applied Design Tokens Across 200 Flutter Pages in One Commit
How I Applied Design Tokens Across 200 Flutter Pages in One Commit The Problem My solo SaaS project Jibun Kabushiki Kaisha has ~200 Flutter Web pages. Over time, color usage became inconsistent: // Page A color: Colors.grey, // Page B color: Color(0xFF9E9E9E), // Page C color: Colors.grey[600], The design system (docs/DESIGN.md) mandates Color(0xFFB0B0B0) for grey. Manual fixes across 200 pages aren't feasible. Here's how I automated it. grep -rn "Colors\.grey\b" lib/ --include="*.dart" | wc -l # → 312 occurrences across 73 files import os, re target_dir = "lib/" replacements = [ (r'\bColors\.grey\b(?!\[)', 'const Color(0xFFB0B0B0)'), (r'\bColors\.grey\[700\]', 'const Color(0xFF616161)'), (r'\bColors\.grey\[600\]', 'const Color(0xFF757575)'), (r'\bColors\.grey\[400\]', 'const Color(0xFFBDBDBD)'), (r'\bColors\.grey\[200\]', 'const Color(0xFFEEEEEE)'), ] for root, dirs, files in os.walk(target_dir): for file in files: if not file.endswith('.dart'): continue path = os.path.join(root, file) content = open(path, 'r', encoding='utf-8').read() new_content = content for pattern, replacement in replacements: new_content = re.sub(pattern, replacement, new_content) if new_content != content: open(path, 'w', encoding='utf-8').write(new_content) print(f"Updated: {path}") dart format lib/ --set-exit-if-changed flutter analyze lib/ # → No issues found! git add lib/ git commit -m "style: design token batch replace — Colors.grey→Color(0xFFB0B0B0) 43 pages" Colors.white12 and Colors.white38 are valid Flutter constants. A naive \bColors\.white\b pattern breaks them: # ❌ This matches "white" inside "white12" r'\bColors\.white\b' # ✅ Negative lookahead excludes digit suffixes r'\bColors\.white\b(?!\d)' We learned this the hard way — 13 files had Colors.white12 → Color(0x1FFFFFFF) wrongly substituted, causing 13 CI failures that needed manual fixes. Metric Before After Design token compliance ~65% ~95% Hardcoded colors 312 12 CI lint errors 0 0 Pages fixed - 43 in 1 commit Always end with flutter analyze 0 errors — the linter will revert partial fixes on next run Use strict regex boundaries — partial matches cause cascading fix commits dart format is mandatory — CI's Check formatting step will catch any missed formatting The batch approach turns what would be a week of manual work into a 10-minute script. The only investment is getting the regex right the first time. Building in public: https://my-web-app-b67f4.web.app/ FlutterWeb #Dart #buildinpublic #designsystem
