Designing Scalable Angular Apps: Pages, Containers and Views

栏目: IT技术 · 发布时间: 3年前

内容简介:Angular is one of the popular front-end frameworks for building single-page applications. Working with more than a dozen Angular projects, one common pitfall I have seen is that the focus for unit tests dries up over time.Another problem that appears most

Terminology and a methodology that would help you build a scalable Angular application.

Angular is one of the popular front-end frameworks for building single-page applications. Working with more than a dozen Angular projects, one common pitfall I have seen is that the focus for unit tests dries up over time.

Another problem that appears most is the increase of coupling in components, services, and state management. It’s no brainer that these symptoms are ticking time bombs unless we address them at their earliest.

Designing Scalable Angular Apps: Pages, Containers and Views

There could be many reasons underlying these issues. But in this article, I would like to talk about one thing that mostly slips through our fingers. It’s no other than how we use Angular components within the project.

Test Your Project is Structured Correctly with Bit.dev

Before moving forward, I’d like to share a trick I’ve found to test if my components are indeed independent — because, as you know, a modular codebase is a scalable codebase.

I use Bit.dev , a cloud component hub, to publish (and document) Angular components from whatever codebase I’m working on, to a shared component collection (on Bit.dev ).

Designing Scalable Angular Apps: Pages, Containers and Views
Exploring published components on Bit.dev

Bit tracks your components dependencies to help you isolate components and ensure each component is published as an autonomous and independent Lego piece. It lets you know which components are coupled and if there are any dependency issues (all that, before publishing them to the Bit’s registry).

After each component gets published, it can be examined in Bit’s playground, rendered in an isolated environment, completely decoupled from its “origin codebase” — so you know how it looks and behaves in environments different from yours.

This way you kill two birds with one stone:

  1. You have a way to test your project is structured correctly
  2. You get to publish independent components so that you and your team may reuse them in other projects/repositories.

Pitfalls with Angular Components

With Angular, we can structure the components in a hierarchy. One common approach is to structure these components is as follows.

my-app
├── src
│   ├── App
│       ├── shared
│           ├── shared_component_1
│       ├── component_1
│           ├── sub_component_1
│               ├── sub_component_1.html
│               ├── sub_component_1.ts
│               ├── sub_component_1.spec.ts
│               ├── sub_component_1.scss
│           ├── sub_component_2
│               ├── sub_component_2.html
│               ├── sub_component_2.ts
│               ├── sub_component_2.spec.ts
│               ├── sub_component_2.scss
│       ├── component_2
│           ├── component_2.html
│           ├── component_2.ts
│           ├── component_2.spec.ts
│           ├── component_2.scss
│       ├── component_3
│       ├── app.component.html
│       ├── app.component.scss
│       ├── app.component.ts
│       ├── app.module.ts
│   ├── environments
│   ├── assets
│   ├── index.html
│   ├── main.ts
├── package.json
├── node_modules

The philosophy behind this structure is that each component is self-contained and relates to business functionality. Each component has sub-components most of the time. If there are components reusable between any parent components, they are placed under shared.

So if you look at the project folder structure, it closely assembles the dependencies as a tree. In this structure, any parent component knows about its child components or any related shared component, but not the other way around.

One of the fundamental problems I see with this structure is that the responsibilities of the parent and child components are not divided. Even if you define some guidelines, it might not reflect in the code structure leading to inconsistencies over time.

As a result, developers find it difficult to unit test these components due to dependencies with other components, services, shared states &, etc. If any Angular project comes to this stage, it’s a clear indication of increased coupling.

So what are we missing here? How can we stop the issue from occurring?

Pages, Containers, and Views

To address the issue mentioned above, we need to identify the root cause of the problem. We can see that not every component is the same. Some are parent components, and some are children, and some are shared.

But what’s the difference between a parent and a child? Is it only just composition and dependency direction? To address these questions, we need to define a precise terminology that everyone understands, divide their responsibilities, and structure the project accordingly.

In this article, I’m going to present a terminology that you can use to divide Angular components. The three categories of components are called Pages, Containers, and Views.

my-app
├── src
│   ├── App
│       ├── view_components
│           ├── view_component_1
│           ├── view_component_2
│           ├── view_component_3
│           ├── view_component_4
│           ├── view_component_5
│       ├── container_components
│           ├── container_component_1
│           ├── container_component_2
│           ├── container_component_3
│       ├── page_components
│           ├── page_component_1
│           ├── page_component_2
│       ├── app.component.html
│       ├── app.component.scss
│       ├── app.component.ts
│       ├── app.module.ts
│   ├── environments
│   ├── assets
│   ├── index.html
│   ├── main.ts
├── package.json
├── node_modules

To give an overview, the Page Component has Container components as children. Then each Container component has View components as children (Pages -> Containers -> Views). To help you understand the structure, I will be explaining the different roles of each component type going from inside out.

View Components

View components are UI components that comprise the visual elements. They are dumb components that accept data from outside and triggers events for actions like button click. These custom components are typically a composition of UI elements, from libraries like ng-bootstrap or Angular Material created for business functionality.

We can unit test these View components easily to test the actions and visualization of data since they don’t have any direct dependencies with services or external states.

Container Components

Container components are the components that bind, View components, services, and state management together to deliver business functionality.

The Container components use the services to fetch data from backend and bind them to the View components. They also listen to the events coming from View components and update the state of each View components and communicates with the backend.

As you see, Container components are the hub of connecting things, dealing with business logic, delegating the presentation to View components.

Page Components

Page components are the components that define the layout of a page based on URL paths. For instance, you can compose a page component with a header, footer, and an area in the middle. So basically, you can define a Page component for each parent route. Inside each Page component, you can place your Container components. In some instances, you can place View components directly inside the Page components, when the view components don’t need any dynamic behavior.

By using Page components, it will help the Container components to know less bout the fixed layout of a page and focus more on dynamic component placement based on business logic. It will also help to reduce the depth of Container components to reuse the layout across different routes.

Looking at the Big Picture

When developing a new feature, without having a classification for Angular components, a developer needs to think about the hierarchy of the component structure and how each sub-component manages state, visualization of data &, etc. Besides, the developer also needs to decide which sub-components are meant for reuse to place under shared components. These decisions are tougher to take and could lead to many inconsistencies.

As you have seen in this article, when we divide the components to have different component types with responsibilities, the message is evident across the development team. The decisions that each developer needs to take is less regarding components. For example, it is easier for them to decide on creating View components and Container components since the responsibilities are clear. They have less complexity in reusing a View component between multiple containers since the dependencies are less.

Besides, with the component responsibility separation, you can increase the unit test coverage across all the View components. You can also use unique strategies to unit test, Container, Page components, and Services.

Also, use the component types combined with other best practices like state management with ngrx-store , unit testing, we can avoid the majority of the issues that affect the maintainability in Angular applications.


以上所述就是小编给大家介绍的《Designing Scalable Angular Apps: Pages, Containers and Views》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

我是一只IT小小鸟

我是一只IT小小鸟

胡江堂、李成、唐雅薇、秦琴、蒋宇东、刘未鹏、居振梁、刘帅、温卫斌、张弦、张凯峰、庄表伟、宋劲杉、程露、黄小明、易晓东、简朝阳、林健、高昂、徐宥、辜新星 / 电子工业出版社 / 2009 / 29.80

一群IT小小鸟—— 来自十几所院校,或男生,或女生;或科班,或半路转行。 分布在不同的公司,或外企,或国企,或民企,老板有土有洋。 有失意,有快意;有泪水,有欢笑。在失望中追求希望,在迷茫中辨别方向。 他们用自己的成长故事,告诉在校的师弟师妹们: 青春太宝贵,千万别浪费;要想不浪费,万事早准备。一起来看看 《我是一只IT小小鸟》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

html转js在线工具
html转js在线工具

html转js在线工具