markdown角度结构和最佳实践(代码片段)

author author     2022-12-15     372

关键词:

# Angular Project Structure and Best Practices
[SOURCE](https://medium.com/@michelestieven/organizing-angular-applications-f0510761d65a), [SOURCE](https://stackoverflow.com/a/46622924/1602807), [SOURCE](https://medium.com/@tomastrajan/6-best-practices-pro-tips-for-angular-cli-better-developer-experience-7b328bc9db81)

## Feature Modules
In Angular, every module which is not the AppModule is technically a Feature Module, and it has the following caveats:

- It must declare all the components, directives and pipe it needs.
- It must import `CommonModule` instead of `BrowserModule`:
While `BrowserModule` must be imported in `AppModule` (it’s required in order to run the app in the browser), this module must not be imported elsewhere: instead, we must import `CommonModule`, which contains Angular’s common directives, such as `ngIf`, `ngFor`, `ngClass`, etc… `BrowserModule` also re-exports `CommonModule`, so that you can use this directives in AppModule too.
- It doesn’t bootstrap anything:
The only module responsible for bootstrapping a component is, obviously, `AppModule`
- We use Feature Modules to define one unique feature of our app which could be a collection of screens.  In general,  **each module should have its own routing**. By organizing this way , there’s no need for the parent module to import your child module’s components to put them in the routing configuration. For example, from `localhost/contacts/` on, the `ContactsModule` will be responsible for its routes. 
In addition to that, by having its own routing, modules can be lazily loaded ([Gist](https://gist.github.com/vxhviet/ebac8f6dbe820d859b3d63b67bab3d68), [Cacher](https://snippets.cacher.io/snippet/ad2d6b985d84139d34bc))
- **Advance**:  see the [SOURCE](https://medium.com/@michelestieven/organizing-angular-applications-f0510761d65a) to see how we can use the `loadChildren` keyword without actually Lazy Loading the module and define a preloading strategy for lazily loaded modules:

Example of a feature module:

```typescript
import  ProductComponent  from "./product.component";
import  BestProductComponent  from "./best-product/best-product.component";
import  ProductListComponent  from "./product-list/product-list.component";
import  ProductDetailComponent  from "./product-detail/product-detail.component";
import  SharedModule  from "@shared/shared.module";

const ProductRoutes: Routes = [
  
    path: "",
    component: ProductListComponent,
    pathMatch: "full"
  ,
  
    path: "all-products",
    component: ProductListComponent
  ,
  
    path: "product/:id",
    component: ProductDetailComponent
  
];


@NgModule(
  imports: [
    CommonModule,
    RouterModule.forChild(ProductRoutes),
    SharedModule,
  ],
  declarations: [
    ProductComponent,
    BestProductComponent,
    ProductListComponent,
    ProductDetailComponent,
  ],
  exports: [BestProductComponent]
)
export class ProductModule 
```

**Summary:**
- 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`.
- 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.
- **Extra:** Ideally feature module will only need have access to services from the `CoreModule` and components from `SharedModule`. Sometimes this might not be enough to solve particular business case and we will also need some kind of *shared feature module* which is providing functionality for a limited subset of other feature modules. Like this:

![image](https://cdn-images-1.medium.com/max/1600/1*6iBDGXV1ONrIMXm664kKHg.png)
 
## Core Module
The answer to the question “Where should I put all my global services?” would be: `AppModule`. This is because services are **(in general) app-scoped, which means that they can be accessed from every module**.

As briefly described in the Lazy Loading article ([Gist](https://gist.github.com/vxhviet/ebac8f6dbe820d859b3d63b67bab3d68), [Cacher](https://snippets.cacher.io/snippet/ad2d6b985d84139d34bc)),  **every lazy module has its own injector**! What that means is that a service provided in a lazy module is only accessible in that module. But it can still access the services previously provided by non-lazy modules (such as `AppModule`)!

So technically, global singleton services such as `AuthService` or `UserService` in `AppModule`, since they’ll be available to everyone. However, we really don’t want our `AppModule` to be a complete mess… What Angular recommends is to put all of our global services in a separated module, called `CoreModule`, and import it **ONLY** in `AppModule`. This way is the same as providing the services in AppModule directly!

In order to prevent inexperienced developers from re importing the `CoreModule` we use this little trick: inside our `CoreModule`, we can… **inject CoreModule**! If Angular injects it correctly, it means that a `CoreModule` has been already created, and we can throw an error:

```
@NgModule(
  providers: [
    // Your services
  ]
)
export class CoreModule 
constructor(@Optional() @SkipSelf() core: CoreModule) 
    if (core) 
      throw new Error('CoreModule should only be imported once in App Module');
    
  

```

**Summary:**
- Consider making `CoreModule` a **pure services module with no declarations** (no components, pipes, etc)
- Should be imported only **ONCE** in AppModule.

## Shared Modules
A shared module is the perfect place to declare components, pipes, directives in order to make them reusable: this way, you won’t re-import the same components in every module, you’ll just import the shared module.

Example shared module:

```typescript
@NgModule(
  imports: [
    CommonModule,
    FormsModule,
    HttpClientModule,
    RouterModule,
  ],
  declarations: [
    NoProductsFoundComponent,
    PriceFormatPipe,
    ProductCellComponent,
    ProductCarouselComponent
  ],
  exports: [
    NoProductsFoundComponent,
    PriceFormatPipe,
    ProductCellComponent,
    ProductCarouselComponent
  ],
  providers: [
    // services should not be declared here
  ]
)
export class SharedModule 
  // this should be use in AppModule only.
  // for lazy loaded modules, we should import SharedModule normally.
  static forRoot(): ModuleWithProviders 
    return 
      ngModule: SharedModule,
      providers: [
        // If you have a very good reason to have services in shared module,
        // use this to declare your services. Otherwise, consider moving the service
        // to Core Module.
        // For more explanation, See: https://stackoverflow.com/a/46622924/1602807
      ]
    ;
  

```

Still remember that:
- Lazy modules have their own injector which means if they import a module which provides some services, they’ll create their own instances of those services.
- Services and components have different scopes.

So how can we import only the component, directive, pipe part of shared module into lazy modules and import the service part to `AppModule`?

Angular gives us a special interface we can use to **attach services to modules**, it’s called `ModuleWithProviders`, here it is:

```
export interface ModuleWithProviders 
    ngModule: Type<any>;
    providers?: Provider[];

```

So we don’t provide our services in the `SharedModule` metadata; instead, we define a static method inside the module, which returns the `SharedModule` istelf **AND** the array of providers just like in the example!

Now in the `AppModule` you can import `SharedModule.forRoot()`, while in all the other modules you can import `SharedModule` (this is exactly how `RouterModule` works).

This trick is for the case you absolutely need to have a mixed shared module. To make matters simpler, just try to keep Shared Module free from services.

**Summary:**
- All the *dumb* components, directives and pipes should be implemented here. 
- These components **don’t import and inject services from core or other feature modules** in their constructors. 
- They should **receive all data though attributes in the template** of the component using them (using `@Input()` and `@Output()` decorator). 
- 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.
- You should import this `SharedModule` into the specific Feature Modules as needed. You **DO NOT** import the `SharedModule` into your main `AppModule` or `CoreModule`.

## Note for App wide components:
For app wide components such as Header and Footer, we can consider putting them in AppModule. If we want to clean up AppModule even more, we can put those in CoreModule. 

Only app wide components should be put in AppModule or CoreModule.

For the first page, Index or Home, we should put it in AppModule.

markdown企业初创企业的最佳实践(代码片段)

查看详情

markdown最佳实践:将权限用作bitflags(代码片段)

查看详情

markdown用python开发的“最佳实践最佳”(bobp)指南。(代码片段)

查看详情

markdown用python开发的“最佳实践最佳”(bobp)指南。(代码片段)

查看详情

markdown用python开发的“最佳实践最佳”(bobp)指南。(代码片段)

查看详情

markdown用python开发的“最佳实践最佳”(bobp)指南。(代码片段)

查看详情

markdown用python开发的“最佳实践最佳”(bobp)指南。(代码片段)

查看详情

markdown用python开发的“最佳实践最佳”(bobp)指南。(代码片段)

查看详情

markdown用python开发的“最佳实践最佳”(bobp)指南。(代码片段)

查看详情

markdown在vuex中使用apollo的最佳实践(代码片段)

查看详情

markdown角度样式绑定和ngstyle(代码片段)

查看详情

javaweb应用的代码分层最佳实践

...性大大提升,更加有利于后期的维护和升级。从另外一个角度来看,好的代码分层架构,应该是可以很好的匹配上单一职责原则的。这样就可以降低层与层之间的依赖,还能最大程度的复用各层的逻辑。本文就来介绍下JavaWeb项... 查看详情

c++最佳实践|2.代码风格(代码片段)

...安全性、可维护性、可移植性、多线程、性能、正确性等角度全面介绍了现代C++项目的最佳实践。本文是该系列的第二篇。C++最佳实践:1.工具2.代码风格(本文)3. 安全性4. 可维护性5. 可移植性及多线程6. ... 查看详情

c++最佳实践|2.代码风格(代码片段)

...安全性、可维护性、可移植性、多线程、性能、正确性等角度全面介绍了现代C++项目的最佳实践。本文是该系列的第二篇。C++最佳实践:1.工具2.代码风格(本文)3. 安全性4. 可维护性5. 可移植性及多线程6. ... 查看详情

c++最佳实践|6.性能(代码片段)

...安全性、可维护性、可移植性、多线程、性能、正确性等角度全面介绍了现代C++项目的最佳实践。本文是该系列的第六篇。C++最佳实践:1.工具2.代码风格3. 安全性4. 可维护性5. 可移植性及多线程6. 性能(本文&#x... 查看详情

c++最佳实践|1.工具(代码片段)

...安全性、可维护性、可移植性、多线程、性能、正确性等角度全面介绍了现代C++项目的最佳实践。本文是该系列的第一篇。C++最佳实践:1.工具(本文)2.代码风格3. 安全性4. 可维护性5. 可移植性及多线程6. ... 查看详情

c++最佳实践|1.工具(代码片段)

...安全性、可维护性、可移植性、多线程、性能、正确性等角度全面介绍了现代C++项目的最佳实践。本文是该系列的第一篇。C++最佳实践:1.工具(本文)2.代码风格3. 安全性4. 可维护性5. 可移植性及多线程6. ... 查看详情

serilog最佳实践(代码片段)

Serilog最佳实践概述Serilog[1]是Microsoft.NET的结构化日志记录库,并已成为Checkout.com上NET的首选日志记录库。它支持各种日志记录目的地(称为接收器[2])包从标准控制台和基于文件的接收器到日志服务,如Datadog。本... 查看详情