> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synapsebuilder.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Best Practices

> Optimization techniques and quality standards

## Overview

Follow these best practices to create high-quality, performant, and maintainable Shopify extensions with Synapse.

## Performance Optimization

<CardGroup cols={2}>
  <Card title="Bundle Size" icon="box">
    Keep extensions under 50KB

    * Remove unused imports
    * Avoid large dependencies
    * Use tree-shaking
    * Code splitting
  </Card>

  <Card title="Load Time" icon="bolt">
    Load in under 500ms

    * Lazy load components
    * Minimize initial render
    * Cache API responses
    * Optimize images
  </Card>

  <Card title="Re-renders" icon="arrows-rotate">
    Minimize unnecessary renders

    * Use React.memo
    * Optimize useEffect deps
    * Memoize calculations
    * Avoid inline functions
  </Card>

  <Card title="Function Speed" icon="gauge">
    Functions under 5ms

    * Use Rust over JavaScript
    * Minimize loops
    * Cache results
    * Limit query surface
  </Card>
</CardGroup>

## Code Quality

### TypeScript Best Practices

<Tabs>
  <Tab title="Strict Types">
    Use strict TypeScript configuration:

    ```typescript theme={null}
    // tsconfig.json
    {
      "compilerOptions": {
        "strict": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "strictFunctionTypes": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true
      }
    }
    ```

    **Benefits:**

    * Catch errors early
    * Better IDE support
    * Self-documenting code
    * Easier refactoring
  </Tab>

  <Tab title="Type Guards">
    Handle undefined values safely:

    ```tsx theme={null}
    // ❌ Bad: Assumes value exists
    const country = address.country;

    // ✅ Good: Type guard
    const country = address?.country ?? 'US';

    // ✅ Good: Conditional rendering
    if (!address) return null;
    const country = address.country;

    // ✅ Good: Type narrowing
    function isProductVariant(
      item: any
    ): item is ProductVariant {
      return item.__typename === 'ProductVariant';
    }
    ```
  </Tab>

  <Tab title="Interface Definitions">
    Define clear interfaces:

    ```typescript theme={null}
    interface DeliveryEstimate {
      startDate: string;
      endDate: string;
      confidence: 'high' | 'medium' | 'low';
      method: string;
    }

    interface ExtensionProps {
      address: Address;
      cartTotal: number;
      onEstimateCalculated?: (estimate: DeliveryEstimate) => void;
    }

    function Extension({ 
      address, 
      cartTotal,
      onEstimateCalculated 
    }: ExtensionProps) {
      // Implementation
    }
    ```
  </Tab>
</Tabs>

### Component Structure

<Steps>
  <Step title="Single Responsibility">
    Each component does one thing:

    ```tsx theme={null}
    // ❌ Bad: Component does too much
    function DeliveryEstimate() {
      const address = useShippingAddress();
      const lines = useCartLines();
      const [estimate, setEstimate] = useState(null);
      
      useEffect(() => {
        // Complex calculation
        // API calls
        // Formatting
      }, [address, lines]);
      
      return (
        <View>
          {/* Complex rendering */}
        </View>
      );
    }

    // ✅ Good: Separated concerns
    function DeliveryEstimate() {
      const estimate = useDeliveryEstimate();
      return <DeliveryDisplay estimate={estimate} />;
    }

    function useDeliveryEstimate() {
      // Custom hook handles logic
    }

    function DeliveryDisplay({ estimate }) {
      // Component handles rendering
    }
    ```
  </Step>

  <Step title="Extract Custom Hooks">
    Reuse logic with custom hooks:

    ```tsx theme={null}
    // hooks/useDeliveryEstimate.ts
    export function useDeliveryEstimate() {
      const address = useShippingAddress();
      const [estimate, setEstimate] = useState<DeliveryEstimate | null>(null);
      const [loading, setLoading] = useState(false);
      const [error, setError] = useState<string | null>(null);
      
      useEffect(() => {
        if (!address) return;
        
        setLoading(true);
        calculateDeliveryDate(address)
          .then(setEstimate)
          .catch((err) => setError(err.message))
          .finally(() => setLoading(false));
      }, [address]);
      
      return { estimate, loading, error };
    }

    // Usage
    function Extension() {
      const { estimate, loading, error } = useDeliveryEstimate();
      
      if (loading) return <SkeletonText />;
      if (error) return <ErrorBanner message={error} />;
      if (!estimate) return null;
      
      return <DeliveryDisplay estimate={estimate} />;
    }
    ```
  </Step>

  <Step title="Memoize Expensive Operations">
    Use useMemo for calculations:

    ```tsx theme={null}
    function Extension() {
      const lines = useCartLines();
      
      // ❌ Bad: Recalculates every render
      const total = lines.reduce((sum, line) => 
        sum + parseFloat(line.cost.totalAmount.amount), 0
      );
      
      // ✅ Good: Only recalculates when lines change
      const total = useMemo(() => 
        lines.reduce((sum, line) => 
          sum + parseFloat(line.cost.totalAmount.amount), 0
        ),
        [lines]
      );
      
      return <Total amount={total} />;
    }
    ```
  </Step>
</Steps>

## Function Optimization

### Rust vs JavaScript

<Tabs>
  <Tab title="When to Use Rust">
    **Use Rust for:**

    * Production functions
    * Performance-critical logic
    * Complex calculations
    * Large-scale operations

    **Benefits:**

    * 10-100x faster than JS
    * Compiled to WebAssembly
    * Type safety
    * No garbage collection

    **Example:**

    ```rust theme={null}
    // Fast execution, < 1ms typical
    fn calculate_discount(lines: &[CartLine]) -> Vec<Discount> {
        lines.iter()
            .filter_map(|line| {
                if line.quantity >= 10 {
                    Some(create_discount(line, 20.0))
                } else {
                    None
                }
            })
            .collect()
    }
    ```
  </Tab>

  <Tab title="When to Use JavaScript">
    **Use JavaScript for:**

    * Rapid prototyping
    * Simple logic
    * Development/testing
    * Easy modifications

    **Benefits:**

    * Easier to modify
    * Faster iteration
    * No compilation
    * Familiar syntax

    **Example:**

    ```javascript theme={null}
    // Simple logic, easy to modify
    export function run(input) {
      return {
        discounts: input.cart.lines
          .filter(line => line.quantity >= 10)
          .map(line => createDiscount(line, 20))
      };
    }
    ```
  </Tab>

  <Tab title="Performance Tips">
    **Optimization techniques:**

    ```rust theme={null}
    // ✅ Good: Single pass
    let discounts: Vec<_> = lines.iter()
        .filter_map(|line| calculate_discount(line))
        .collect();

    // ❌ Bad: Multiple passes
    let eligible: Vec<_> = lines.iter()
        .filter(|line| is_eligible(line))
        .collect();
    let discounts: Vec<_> = eligible.iter()
        .map(|line| calculate_discount(line))
        .collect();

    // ✅ Good: Early return
    if input.cart.lines.is_empty() {
        return Ok(FunctionRunResult { 
            operations: vec![] 
        });
    }

    // ✅ Good: Avoid cloning
    fn process_line(line: &CartLine) -> Option<Discount> {
        // Use references, avoid clones
    }
    ```
  </Tab>
</Tabs>

## Error Handling

<AccordionGroup>
  <Accordion title="Graceful Degradation" icon="shield">
    Handle failures without breaking:

    ```tsx theme={null}
    function Extension() {
      const { data, error } = useQuery();
      
      // ❌ Bad: Throws error
      if (error) throw error;
      
      // ✅ Good: Shows fallback
      if (error) {
        return (
          <Banner status="warning">
            Unable to load delivery estimate. 
            Standard shipping applies.
          </Banner>
        );
      }
      
      // ✅ Good: Degrades gracefully
      if (!data) {
        return <SkeletonText />;  // Loading state
      }
      
      return <Content data={data} />;
    }
    ```
  </Accordion>

  <Accordion title="Error Boundaries" icon="shield-halved">
    Catch component errors:

    ```tsx theme={null}
    import { ErrorBoundary } from '@shopify/ui-extensions-react/checkout';

    export default reactExtension(
      'purchase.checkout.block.render',
      () => (
        <ErrorBoundary
          onError={(error) => {
            console.error('Extension error:', error);
            // Log to monitoring service
          }}
        >
          <Extension />
        </ErrorBoundary>
      )
    );
    ```
  </Accordion>

  <Accordion title="Function Error Handling" icon="function">
    Never panic in functions:

    ```rust theme={null}
    // ❌ Bad: Panics on error
    let quantity = line.quantity.parse::<i64>().unwrap();

    // ✅ Good: Returns default
    let quantity = line.quantity.parse::<i64>().unwrap_or(0);

    // ✅ Good: Returns empty on error
    fn run(input: Input) -> Result<FunctionRunResult> {
        let operations = match calculate_operations(&input) {
            Ok(ops) => ops,
            Err(e) => {
                eprintln!("Error: {}", e);
                vec![]  // Return empty, don't crash
            }
        };
        
        Ok(FunctionRunResult { operations })
    }
    ```
  </Accordion>

  <Accordion title="User-Friendly Messages" icon="message">
    Explain errors clearly:

    ```tsx theme={null}
    // ❌ Bad: Technical jargon
    <Banner status="critical">
      GraphQL query failed: Field 'deliveryAddress' not found
    </Banner>

    // ✅ Good: User-friendly
    <Banner status="info">
      Unable to calculate delivery estimate. 
      Please enter your shipping address.
    </Banner>

    // ✅ Good: Actionable
    <Banner status="warning">
      Delivery estimate temporarily unavailable.
      <Button onPress={retry}>Try Again</Button>
    </Banner>
    ```
  </Accordion>
</AccordionGroup>

## Testing

<Tabs>
  <Tab title="Unit Tests">
    Test individual functions:

    ```typescript theme={null}
    // utils.test.ts
    import { describe, it, expect } from 'vitest';
    import { calculateDeliveryDate } from './utils';

    describe('calculateDeliveryDate', () => {
      it('adds business days correctly', () => {
        const result = calculateDeliveryDate({
          country: 'US',
          province: 'CA'
        });
        
        expect(result.startDate).toBeDefined();
        expect(result.endDate).toBeDefined();
        expect(result.confidence).toBe('high');
      });
      
      it('handles invalid addresses', () => {
        const result = calculateDeliveryDate({
          country: 'XX'
        });
        
        expect(result.error).toBe('Invalid country');
      });
      
      it('accounts for weekends', () => {
        const result = calculateDeliveryDate({
          country: 'US'
        }, new Date('2025-10-31')); // Friday
        
        // Should skip weekend
        expect(result.startDate).not.toBe('2025-11-01');
      });
    });
    ```
  </Tab>

  <Tab title="Integration Tests">
    Test extension rendering:

    ```typescript theme={null}
    // Extension.test.tsx
    import { render, screen } from '@testing-library/react';
    import { Extension } from './Extension';

    describe('Extension', () => {
      it('renders delivery estimate', () => {
        render(<Extension address={mockAddress} />);
        
        expect(screen.getByText(/estimated delivery/i)).toBeInTheDocument();
      });
      
      it('shows loading state', () => {
        render(<Extension address={null} />);
        
        expect(screen.getByRole('progressbar')).toBeInTheDocument();
      });
      
      it('handles errors gracefully', async () => {
        mockFetch.mockRejectedValueOnce(new Error('API error'));
        
        render(<Extension address={mockAddress} />);
        
        expect(await screen.findByText(/unable to calculate/i))
          .toBeInTheDocument();
      });
    });
    ```
  </Tab>

  <Tab title="Function Tests">
    Test Shopify Functions:

    ```bash theme={null}
    # Create test input
    cat > test-input.json << EOF
    {
      "cart": {
        "lines": [
          {
            "quantity": 5,
            "merchandise": {
              "id": "gid://shopify/ProductVariant/123"
            }
          }
        ]
      }
    }
    EOF

    # Test function
    cargo run < test-input.json > output.json

    # Verify output
    cat output.json | jq '.discounts | length'
    # Should be > 0 for quantity >= 5
    ```
  </Tab>
</Tabs>

## Accessibility

<CardGroup cols={2}>
  <Card title="Keyboard Navigation" icon="keyboard">
    Support keyboard users:

    ```tsx theme={null}
    // ✅ Use Button component
    <Button onPress={handleClick}>
      Submit
    </Button>

    // ❌ Don't use div
    <div onClick={handleClick}>Submit</div>
    ```
  </Card>

  <Card title="Screen Readers" icon="volume">
    Label everything:

    ```tsx theme={null}
    // ✅ Good labels
    <TextField
      label="Gift message"
      value={message}
      onChange={setMessage}
    />

    <Icon 
      source="delivery" 
      accessibilityLabel="Delivery truck"
    />
    ```
  </Card>

  <Card title="Color Contrast" icon="palette">
    Ensure readability:

    * Use Shopify UI components (compliant by default)
    * Avoid custom colors
    * Test with contrast checker
    * Minimum 4.5:1 ratio
  </Card>

  <Card title="Focus States" icon="bullseye">
    Visible focus indicators:

    * Shopify components have focus states
    * Don't remove with CSS
    * Test with Tab key
    * Ensure focus order logical
  </Card>
</CardGroup>

## Security

<AccordionGroup>
  <Accordion title="Input Validation" icon="filter">
    Validate all user inputs:

    ```tsx theme={null}
    function validateGiftMessage(message: string): string | null {
      if (message.length > 200) {
        return "Message too long (max 200 characters)";
      }
      
      if (/<script|javascript:/i.test(message)) {
        return "Invalid characters detected";
      }
      
      if (!message.trim()) {
        return "Message cannot be empty";
      }
      
      return null; // Valid
    }
    ```
  </Accordion>

  <Accordion title="API Security" icon="lock">
    Secure API calls:

    ```tsx theme={null}
    // ✅ Good: HTTPS, authentication
    const response = await fetch('https://api.example.com/endpoint', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${sessionToken}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ data }),
    });

    // ❌ Bad: HTTP, no auth
    fetch('http://api.example.com/endpoint', {
      method: 'POST',
      body: data,
    });
    ```
  </Accordion>

  <Accordion title="Sensitive Data" icon="eye-slash">
    Never log or expose:

    ```tsx theme={null}
    // ❌ Bad: Logs sensitive data
    console.log('Customer data:', customer);
    console.log('Payment info:', paymentMethod);

    // ✅ Good: Logs safely
    console.log('Processing order:', { orderId: order.id });
    console.log('Payment method type:', paymentMethod.type);
    ```
  </Accordion>
</AccordionGroup>

## Deployment Best Practices

<Steps>
  <Step title="Test Locally First">
    ```bash theme={null}
    npm run dev
    # Test in browser
    # Verify all features work
    ```
  </Step>

  <Step title="Review MCP Validation">
    Check validation output before deploying

    * All APIs valid
    * No deprecated components
    * TypeScript compiles
    * No console errors
  </Step>

  <Step title="Monitor Deployment">
    Watch logs during deployment:

    ```bash theme={null}
    shopify app function logs --watch
    ```

    Verify deployment succeeds
  </Step>

  <Step title="Test in Dev Store">
    * Add items to cart
    * Go through checkout
    * Test all code paths
    * Verify on mobile
  </Step>

  <Step title="Monitor Performance">
    * Check loading times
    * Review error rates
    * Monitor function execution time
    * Track user feedback
  </Step>
</Steps>

## Documentation

Write clear documentation:

```markdown theme={null}
# Delivery Estimate Extension

Shows estimated delivery dates in checkout.

## Features

- Calculates delivery based on shipping address
- Displays date range (e.g., "Nov 5-8")
- Handles international shipping
- Shows loading state while calculating

## Configuration

Configure in Shopify admin:
1. Settings → Checkout → Customize
2. Add "Delivery Estimate" block
3. Position after shipping address
4. Save

## Technical Details

- Target: `purchase.checkout.delivery-address.render-after`
- Uses: `useShippingAddress()` hook
- API: No external calls, pure calculation
- Performance: < 100ms load time

## Troubleshooting

**Not showing?**
- Verify added to checkout editor
- Check shipping address is entered
- Review console for errors
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Debugging" icon="bug" href="/advanced/debugging">
    Learn debugging techniques
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/advanced/troubleshooting">
    Common issues and solutions
  </Card>

  <Card title="Extension Standards" icon="shield-check" href="/guides/extension-standards">
    Quality guidelines
  </Card>

  <Card title="Validation" icon="check-circle" href="/concepts/validation">
    MCP validation process
  </Card>
</CardGroup>
