Featured image of post Modern Angular 01 - Project Setup

Modern Angular 01 - Project Setup

Modern Angular
01 - The Project Setup

Disclaimer for this Series:

This is by no means the only way of doing things, or even necessarily best practices. It’s simply my way — and it works for me! 🚀

Philosophy

My philosophy is a direct rejection of the bloated monoliths and scattered files that plague legacy Angular projects. I pursue radical simplicity for maximum velocity, building with hyper-focused, single-file components that are easy to maintain. This modern approach is completed by using Tailwind for rapid, functional UI development and Bun for a blazing-fast toolchain, delivering lean, performant applications free from the complexity of the past.

  • Hyper-Focused Components:
    Building small, atomic components inspired by React’s philosophy to create a clean, reusable library and avoid legacy monoliths.
  • Single-File Simplicity:
    Adopting the ergonomic single-file component pattern from React and Vue to co-locate all logic, template, and styles, drastically reducing boilerplate.
  • Utility-First UI:
    Leveraging Tailwind CSS for rapid, functional styling directly in the markup, a pragmatic approach dominant in modern ecosystems like Next.js.
  • Performance-First Tooling:
    Using Bun for a blazing-fast workflow, mirroring the industry shift to high-performance compilers seen in Next.js and the Vue ecosystem.

Tech Stack

  • Runtime: Bun - replaces NPM and speeds up everything
  • Angular 20 - Obviously go for the latest and greatest
    • Standalone Components
    • Zoneless - Focus on a clean event-driven setup for greenfield projects!
    • Single-File Components - Template, styling, and logic in one place
      (This is radical and most of you will hate me for it, but trust the process! 😅)
    • Tailwind - Essential for keeping components lean

Preparation

Requirements:

  • VSCode - We will set this up with Dev Containers. This is something, you definitly want to do with VSCode.
  • Docker Container Runtime - I sugjest OrbStack if you are using MacOS
    ⚠️ Warning: OrbStack Free is not for commercial use!

Setup Dev-Containers

Dev Containers are a game-changer! 🚀 They elegantly solve all the major headaches that developers previously dealt with through hacky workarounds.

Key Benefits for Web Development:

  • 🎯 Version Control: Lock down your Node.js sersion per project (no more “works on my machine”)
  • 📦 Isolated Dependencies: Keep global npm packages contained per project
  • 🔒 Secure Environment: Shield your home directory from potentially malicious dependencies (while not a true sandbox, it’s excellent protection against modern automated attacks)
1
2
3
4
# Create a new project
mkdir my-project && cd ./my-project
# Create devcontainer folder
mkdir .devcontainer

.devcontainer/devcontainer.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
  "name": "Frontend-Container - Bun",
  "dockerComposeFile": [
    "docker-compose.yml"
  ],
  "service": "frontend-container",
  "workspaceFolder": "/workspace",
  "features": {
    "ghcr.io/devcontainers/features/docker-outside-of-docker:1.6.3": {
      "version": "latest",
      "moby": true
    }
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "Angular.ng-template",
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "johnpapa.Angular2",
        "ms-azuretools.vscode-docker",
        "christian-kohler.path-intellisense",
        "christian-kohler.npm-intellisense",
        "bradlc.vscode-tailwindcss",
        "redhat.vscode-yaml",
        "formulahendry.auto-rename-tag",
        "formulahendry.auto-close-tag",
        "eamodio.gitlens"
      ]
    },
    "settings": {
      "files.watcherExclude": {
        "**/.git/objects/**": true,
        "**/.git/subtree-cache/**": true,
        "**/node_modules/*/**": true
      }
    }
  },
  "forwardPorts": [
    4200
  ],
  "shutdownAction": "stopCompose",
  "postCreateCommand": "sudo chmod +x .devcontainer/postCreate.sh &&sh .devcontainer/postCreate.sh",
  "mounts": [
    "type=bind,source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/vscode/.ssh,readonly"
  ]
}

.devcontainer/docker-compose.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
volumes:
  node_modules:
services:
  frontend-container:
    image: mcr.microsoft.com/devcontainers/typescript-node:1-22
    volumes:
      - ../:/workspace:cached
      - node_modules:/workspace/node_modules
    command: sleep infinity
    environment:
      - GO111MODULE=on
    working_dir: /workspace

.devcontainer/postCreate.sh

1
2
3
4
5
6
7
sudo chown -R $(id -u):$(id -g) /workspace/node_modules 
npm install -g bun
bun install -g @angular/cli
if ! grep -q '$HOME/.bun/bin' ~/.bashrc; then
    echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.bashrc
fi
#bun install #initially commented out

Opening the Project in VSCode

Once you have all the configuration files in place, opening your project in a DevContainer is super simple!

  1. Open your project folder in VSCode
  2. Press Cmd+Shift+P (macOS) to open the command palette
  3. Type “Dev Containers: Reopen in Container”
  4. Hit Enter and let the magic happen! ✨

What happens next? 🔄

  • VSCode will build your container (first time takes a few minutes)
  • Your extensions get installed automatically
  • The postCreate.sh script runs to set up Bun
  • You’ll have a fully isolated development environment!

Pro Tip: 💡 The green “Dev Container” indicator in the bottom-left corner of VSCode shows you’re running inside the container. You can click it anytime to manage your container or reopen locally.

Angular Project

Initialize Angular Project

Since Angular CLI is already installed with the postCreate.sh, we can directly head to the project creation. To get the most modern and progressive project-setup, we can use this command:

1
2
3
4
5
6
7
8
ng new \
  --package-manager bun \     # Use bun instead of npm for package management
  --style scss \              # Use SCSS for styling instead of CSS
  --zoneless \                # Use Angular's new zoneless change detection
  --routing \                 # Add Angular Router with routing configuration
  --inline-style \            # Put component styles inline instead of separate files
  --inline-template \         # Put component templates inline instead of separate files
  --directory=./              # Create project in current directory instead of new folder
1
ng new --package-manager bun --style scss --zoneless --routing --inline-style --inline-template --directory=./

This will ask you for a project name and if you want to use server-side rendering. I would skip server-side rendering, if not explictly needed in you use-case.

Setup Tailwind

Tailwind CSS is essential for our modern Angular setup! It enables rapid, utility-first styling that keeps components lean and maintainable. Here’s how to integrate it seamlessly:

1. Install Tailwind CSS

1
bun add -D tailwindcss @tailwindcss/postcss postcss

2. Configure Tailwind

Create a .postcssrc.json file in the root of your project and add the @tailwindcss/postcss plugin to your PostCSS configuration.

1
2
3
4
5
{
  "plugins": {
    "@tailwindcss/postcss": {}
  }
}

3. Add Tailwind directives

Replace the content in src/styles.scss with:

1
@use "tailwindcss";

4. Test your setup

Update src/app/app.ts to test Tailwind:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet],
  template: `
    <h1 class="text-3xl font-bold underline">Welcome to {{ title() }}!</h1>
    <router-outlet />
  `,
  styles: [],
})
export class App {
  protected readonly title = signal('m0landing');
}

Tailwind Pro Tips:

  • The Tailwind VSCode extension (already included in the devcontainer) provides excellent IntelliSense
  • Use Tailwind’s responsive prefixes (sm:, md:, lg:) for mobile-first design
  • Leverage Tailwind’s color palette and spacing system for consistent design

Start your development server

1
ng serve --host 0.0.0.0

Serving from the Dev Container is a bit special. We need to add --host 0.0.0.0 to our serve command. If not, we would bind to loopback of the container and can not access the web app from the browser, running on the host system.

Project Structure

I usually recommend a clean project structure, to prevent chaos. The way to go for me is most of the time something like this:

  graph LR
    A[src/app/] --> B[components/]
    A --> C[model/]
    A --> D[services/]
    A --> E[views/]
    
    B --> B1[button/]
    B --> B2[modal/]
    B --> B3[input/]
    
    E --> E1[dashboard/]
    E --> E2[profile/]
    E --> E3[login/]
    
    E1 --> E1a[components/]
    E1 --> E1b[services/]
    
    E2 --> E2a[components/]
  • components/ - Reusable UI components that act as a shared library across the application
  • model/ - TypeScript interfaces, classes, and data models representing the application’s domain
  • services/ - Global business logic services; component-specific services are co-located with their respective components
  • views/ - Full-page components representing complete user interfaces; view-specific components and services are nested within their parent view directories

This structure promotes code reusability, maintainability, and clear boundaries between different layers of the application.

Usefull commands for your project:

  • ng g c components/<name> - Creates a new component
  • ng g c views/<name> - Creates a new component in the views directory
  • ng g s services/<name> - Creates a new service
  • ng g i model/<name> - Creates a new model interface
  • ng g cl components/<name> - Creates a new model class
  • ng serve --host 0.0.0.0 - Starts the development server

(For total Angular newbies: You can keep the server running. It will pick up changes, on the fly.)

Update Dev-Container

Finally we can update the postCreate.sh for our Dev Container .devcontainerpostCreate.sh

1
2
3
4
5
6
7
sudo chown -R $(id -u):$(id -g) /workspace/node_modules 
npm install -g bun
bun install -g @angular/cli
if ! grep -q '$HOME/.bun/bin' ~/.bashrc; then
    echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.bashrc
fi
bun install #Initially commented out - Now add it, for automatic install if container needs to be recreated

Achievements

Congratulations! 🎉 You’ve successfully set up a modern Angular development environment that’s production-ready and follows current best practices. Here’s what you’ve accomplished:

What You’ve Learned

  • Dev Container Mastery: Created an isolated, reproducible development environment using Docker
  • Modern Angular Setup: Initialized a project with zoneless change detection, standalone components, and single-file architecture
  • Bun Integration: Leveraged Bun for faster package management and tooling
  • Tailwind CSS: Configured utility-first styling with PostCSS for rapid UI development
  • Project Architecture: Established a clean, scalable folder structure for components, services, and views

Current State

Your project now includes:

  • Clean Angular 20 Foundation: Zoneless, standalone components with inline templates and styles
  • Tailwind CSS Ready: Fully configured with PostCSS plugin for modern styling
  • Bun-Powered Toolchain: Fast package management and build processes
  • Containerized Development: Consistent environment across different machines
  • Organized Structure: Clear separation between reusable components, views, and services

What’s Next?

In Modern Angular 02, we’ll dive into the heart of reactive Angular development:

  • Building Your First Component: Create a data-driven component using modern Angular patterns
  • Reactive Data Flow: Connect components to services using signals and observables
  • HTTP Integration: Implement proper data fetching with Angular’s HttpClient
  • Component Communication: Master parent-child communication and state management
  • Real-World Example: Build a practical component that showcases all these concepts

You now have the perfect foundation to start building reactive, maintainable Angular applications. The next tutorial will show you how to bring this setup to life with actual functionality! 🚀