Deployment

This guide covers deploying AngularDart applications to production.

Building for Production

Using build_runner

Build optimized JavaScript:

dart run build_runner build --release

This generates optimized files in the build/ directory.

Build Configuration

Configure build.yaml for production:

targets:
  $default:
    builders:
      build_web_compilers|entrypoint:
        generate_for:
          - web/main.dart
        options:
          compiler: dart2js
          dart2js_args:
            - -O4
            - --minify
            - --no-source-maps

Build Options

Option Description
-O4 Maximum optimization level
--minify Minify JavaScript output
--no-source-maps Exclude source maps
--fast-startup Enable fast startup
--trust-primitives Trust primitive types
--trust-type-assertions Trust type assertions

Output Structure

After building, the build/ directory contains:

build/
  web/
    main.dart.js          # Compiled JavaScript
    main.dart.js.map      # Source map (optional)
    index.html            # Entry HTML
    assets/               # Static assets
    styles.css            # Compiled styles

Deployment Options

Static Hosting

Deploy the build/web/ directory to any static hosting:

  • Netlify: Drag and drop build/web/
  • Vercel: Connect repo, set build command
  • GitHub Pages: Push build/web/ to gh-pages branch
  • Firebase Hosting: Use firebase deploy
  • AWS S3: Upload to S3 bucket with static hosting

Docker Deployment

# Build stage
FROM dart:stable AS build
WORKDIR /app
COPY . .
RUN dart pub get
RUN dart run build_runner build --release

# Serve stage
FROM nginx:alpine
COPY --from=build /app/build/web /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Nginx Configuration

server {
    listen 80;
    server_name yourdomain.com;
    root /usr/share/nginx/html;
    index index.html;

    # Enable gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;

    # Cache static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # SPA fallback
    location / {
        try_files $uri $uri/ /index.html;
    }
}

Environment Configuration

Build-time Environment

Use different configurations for environments:

# build.yaml
targets:
  $default:
    builders:
      build_web_compilers|entrypoint:
        options:
          compiler: dart2js
          dart2js_args:
            - -O4
            - --minify
            - -Denvironment=production

Access in Dart:

const environment = String.fromEnvironment('environment', defaultValue: 'development');

@Injectable()
class ConfigService {
  String get apiUrl {
    if (environment == 'production') {
      return 'https://api.yourdomain.com';
    }
    return 'http://localhost:8080';
  }
}

Runtime Configuration

For runtime configuration, use a config file:

<!-- index.html -->
<script>
  window.APP_CONFIG = {
    apiUrl: 'https://api.yourdomain.com',
    features: {
      darkMode: true,
      analytics: true
    }
  };
</script>
@JS('APP_CONFIG')
external dynamic get appConfig;

@Injectable()
class ConfigService {
  String get apiUrl => appConfig.apiUrl;
}

Performance Optimization

Code Splitting

Split your app into multiple files:

// Load feature modules on demand
Future<void> loadAdminModule() async {
  await loadLibrary('package:my_app/admin_module.dart');
}

Lazy Loading Routes

routes = [
  RouteDefinition(
    path: '/admin',
    loader: () async {
      await loadLibrary('package:my_app/admin_component.dart');
      return adminComponentFactory;
    },
  ),
];

Image Optimization

  • Use WebP format for better compression
  • Implement responsive images with srcset
  • Lazy load images below the fold

Preloading

Preload critical resources:

<link rel="preload" href="main.dart.js" as="script">
<link rel="preload" href="assets/logo.png" as="image">

Monitoring and Analytics

Error Tracking

@Injectable()
class ErrorService {
  void reportError(dynamic error, StackTrace? stack) {
    // Send to error tracking service
    print('Error: $error');
  }
}

void main() {
  runZonedGuarded(() {
    runApp(AppComponentNgFactory);
  }, (error, stack) {
    // Global error handler
    print('Unhandled error: $error');
  });
}

Analytics

@Injectable()
class AnalyticsService {
  void trackPageView(String path) {
    // Send to analytics service
  }

  void trackEvent(String category, String action, [String? label]) {
    // Send event tracking
  }
}

Security Checklist

  • Enable HTTPS
  • Set Content Security Policy headers
  • Enable CORS only for trusted domains
  • Remove source maps in production
  • Minify and obfuscate JavaScript
  • Set security headers (X-Frame-Options, X-Content-Type-Options)
  • Use secure cookies with HttpOnly and Secure flags
  • Validate all user input
  • Sanitize HTML content

CI/CD Pipeline

GitHub Actions Example

name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: dart-lang/setup-dart@v1
        with:
          sdk: stable

      - name: Install dependencies
        run: dart pub get

      - name: Build
        run: dart run build_runner build --release

      - name: Deploy to Netlify
        uses: nwtgck/actions-netlify@v2
        with:
          publish-dir: ./build/web
          production-branch: main
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

Troubleshooting

Build fails with out of memory

Increase Dart VM memory:

dart --enable-vm-service=8181 run build_runner build --release

Large bundle size

  • Check for unused dependencies
  • Use code splitting
  • Enable tree shaking
  • Analyze bundle with source_map_explorer

Slow initial load

  • Enable gzip compression
  • Preload critical resources
  • Use server-side rendering for initial content
  • Implement service worker for offline support