Angular project structure / folder structure / architecture

Shared Module:

The Shared module should contain components, directives, pipes, and services that can be reused across multiple other modules in the application. It typically includes:

  1. Reusable components: UI components that are used in multiple parts of the application, like buttons, input fields, or navigation elements.
  2. Common directives: Custom directives that are used in several components or modules, such as input formatters or accessibility enhancements.
  3. Shared pipes: Custom pipes that are used for formatting or transforming data in multiple components or modules, like date formatters or text filters.
  4. Utility services: Services that provide generic functionality, which can be used by multiple components or modules, like API services or data manipulation services.

Core Module:

The Core module should contain essential services, components, and configurations that are required for the application to function properly and are used only once. It typically includes:

  1. Singleton services: Services that should have only one instance throughout the application, like authentication, user management, or application state management services.
  2. Core components: Components that are used only once in the application, such as the application shell, header, footer, or navigation components.
  3. Application-wide configurations: Configurations that affect the entire application, like environment-specific settings, global constants, or third-party library configurations.
  4. Interceptors: HTTP interceptors for handling request/response transformations, error handling, or adding authentication headers to API calls.
  5. Guards: Route guards that control access to specific routes or parts of the application based on user roles, permissions, or authentication status.

In summary, the Shared module contains reusable elements that can be used in multiple places within your application, while the Core module contains unique elements that are essential for the proper functioning of the application and are used only once.

Angular folder structure best practice:

Follow LIFT principle: Do structure the app such that you can Locate code quickly, Identify the code at a glance, keep the Flattest structure you can, and Try to be DRY.

Folders and files inside of the "app" folder:


|- core

   |- components

      |- navbar

         |- navbar.component.html|scss|ts

      |- page-not-found

         |- page-not-found.component.html|scss|ts

   |- constants

   |- enums

   |- utils

   |- guards

      |- auth.guard.ts

   |- pipes

   |- interceptors

      |- error.interceptor.ts

      |- token.interceptor.ts

   |- services

   |- core.module.ts

|- feature-a (for example: users, posts, etc)

   |- components

      |- scoped-component-a

         |- scoped-component-a.component.html|scss|ts

      |- scope-component-b

         |- scoped-component-b.component.html|scss|ts

   |- models

      |- scoped-model-a.model.ts

      |- scoped-model-b.model.ts

   |- services

      |- scoped-service-a.service.ts

      |- scoped-service-b.service.ts

   |- feature-a-routing.module.ts

   |- feature-a.module.ts

   |- feature-a.component.html|scss|ts

|- shared

   |- components

   |- models

   |- services

   |- pipes

   |- shared.module.ts

CoreModule

All services which have to have one and only one instance per application (singleton services) should be implemented here. Typical example can be authentication service or user service.

A Core Module is an NgModule containing code that will be used to instantiate your app and load some core functionality.

In the Core Module we commonly place our singleton services and modules that will be used across the app but only need to be imported once. Examples are an Authentication Service or LocalStorage Service, but also modules like HttpClientModule , StoreModule.forRoot(…), TranslateModule.forRoot(…) . The CoreModule is then imported into the AppModule .

In short, when using a Core Module:

  • DO import modules that should be instantiated once in your app.
  • DO place services in the module, but do not provide them.
  • DO NOT declare components, pipes, directives.
  • DO NOT import the CoreModule into any modules other than the AppModule.

SharedModule - https://angular.io/guide/sharing-ngmodules

All the “dumb” components and pipes should be implemented here. These components don’t import and inject services from core or other features in their constructors. They should receive all data though attributes in the template of the component using them. This all sums up to the fact that SharedModule doesn’t have any dependency to the rest of our application. It is also the perfect place to import and re-export Angular Material components.

The SharedModule contains classes and resources which are used in more than one dynamically loaded module. By always loading with the application the shared components are ready whenever a module requests them.

The shared module is a good place to import and export the FormsModule and the ReactiveFormsModule. It is also good for the FontAwesomeModule and any other resource used by some modules some of the time.

In short, when using a Shared Module:

  • DO declare components, pipes, directives, and export them.
  • DO import FormsModule, ReactiveFormsModule and other (3rd-party) modules you need.
  • DO import the SharedModule into any other Feature Modules.
  • DO NOT provide app-wide singleton services in your SharedModule. Instead move these to the CoreModule.
  • DO NOT import the SharedModule into the AppModule.

For example, as in our case, there is a core module that contains the functionality that is globally available to the whole application and is also loaded immediately when the application is started — such as the error handling.

Another typical module is the shared module. As the name suggests, this module contains functionality that can be reused in several other modules of the application. These are mostly stateless user interface components (or so-called dump components), such as loading spinners or dialogs, which can be controlled by a service.

FeatureModule

We are going to create multiple feature modules for every independent feature of our application. Feature modules should only import services from CoreModule. If feature module A needs to import service from feature module B consider moving that service into core.

Rule of thumb is to try to create features which don’t depend on any other features just on services provided by CoreModule and components provided by SharedModule.

This will keep our code clean, easy to maintain and extend with new features. It also reduces effort needed for refactoring. If followed properly, we will be confident that changes to one feature can’t affect or break the rest of our application.

LazyLoading

We should lazy load our feature modules whenever possible. Theoretically only one feature module should be loaded synchronously during the app startup to show initial content. Every other feature module should be loaded lazily after user triggered navigation.

Folders and files inside of the "assets" folder:


|- images

|- icons

|- styles

   |- styles.scss

These instructions are to install this directory structure to a brand new ng version 10 or above created application. Before you can execute these instructions you must remove the comments from the tsconfig.json file and other json files because comments in a json file are not valid json:


ng generate module Core

ng generate module Shared

ng generate module Data

mkdir src/app/layout

ng generate component layout/main

ng generate component layout/header

ng generate component layout/nav

ng generate component layout/footer

mkdir assets/styles && mkdir assets/images

Leave a Comment