我将要开始一个相当大的项目,该项目将在其前端使用Angular,并且我有一个问题,即如何管理Angular的增长以实现最大的可维护性。
对于到目前为止的每个角度项目,我都有一个views文件夹,它模仿路由层次结构,并且我的模块结构基于业务功能的分组。这对于新入职的新开发人员以及这些中小型应用程序的维护目的都非常有效。
我的问题集中在何时在大型企业应用程序中使用模块。
我最近听说要在每个页面和/或每个组件创建模块。这种方法似乎有很多前期开销,但是在测试创建和长期维护方面节省了很多。
我没有在angular.io样式指南中看到任何关于一种或另一种方法的指导,但是我想从那些已经构建了企业规模的角度应用程序的人们那里找到了一种适合自己的特定方法,他们。
更新 我在这里得到了很多很好的答案。我相信所有人都按功能强调模块的共同点,并针对核心,共享(和bryan提到的资源)额外使用模块。我还将把我的路由视图移到它们各自的功能文件夹中,而不是当前使用的“视图”文件夹中。阅读以下答案后,随着应用程序的增长,“ views”文件夹可能很难管理。
有人还建议我阅读Nrwl在做什么,所以我做到了,并且被他们与应用程序分开使用库而感到好奇。 Nrwl MonoRepo Pattern Book (Free)。他们有很多很好的建议,与大家在这里所说的相提并论,除了将跨平台的通用功能抽象到库中之外。由于我确定要构建的应用程序将需要定位到网络世界之外的移动设备,因此这似乎也是一个好主意。
感谢所有花时间详细答复的人。
答案 0 :(得分:3)
我将在每个域中使用一个模块,例如身份验证模块,其中有注册,登录和忘记密码,产品模块,付款模块等。每个视图一个模块是总开销。 Angular文档强烈支持通用服务的核心模块,以及跨App的通用组件和指令的共享模块。每个模块都应根据需要具有组件,指令和服务目录。您也可以使用barrel,因为目录中的模块中有许多用于干净导入的元素。强烈建议不要嵌套组件目录。
为具有多个视图的模块创建单独的路由模块是一个好主意。
// barrel
import { firstComponent, .... ,lastComponent } from './components';
const routs = [ ... ];
export class FeatureRoutingModule {
const static components = [
firstComponent,
.
.
.
lastComponent
]
};
然后在功能模块中可以用这种方式导入它。如果您分开布线,这将帮助您避免多次导入组件。
import { FeatureRoutingModule } from './freature-rotuing.module';
@NgModule({
imports: [
SharedModule, // if you have one
FeatureRoutingModule
],
declarations: [FeatureRoutingModule.components]
})
export class FeatureModule { }
祝您好运,更好地组织代码。
答案 1 :(得分:3)
首先,我在构建应用程序时尝试使用LIFT指南:
然后我的文件夹结构如下:
app/
core/
models/ // All models
not-found/ // A core feature (not-found component for example)
...
core.module.ts
feature1/ // Feature 1 folder
sub-feature1-1/ // A sub feature for the feature 1
sub-feature1-2/ // A sub feature for the feature 1
feature1.service.ts
feature1.module.ts
feature2/ // Feature 2 folder
sub-feature2-1/ // A sub feature for the feature 2
sub-feature2-2/ // A sub feature for the feature 2
feature1.service.ts
feature1.module.ts
shared/
card/ // A shared feature (card component for example)
...
shared.module.ts
app-routing.module.ts
app.component.html
app.component.scss
app.component.spec.ts
app.component.ts
app.module.ts
在这种结构中,我总是尝试在子功能上仅保持一个级别。所有功能都应尽可能独立,并且仅应承担一项责任。
答案 2 :(得分:3)
首先:多年来,我已经使用Angular构建了一些Enterprise应用程序,并且看到了行之有效的方法以及我从未尝试过的方法。好消息是:如今,重构/开发工具非常好,当您发现项目结构变得不规则时,可以在项目中切换项目结构。唯一的坏消息是:它将创建合并梦night,以测试您的git-fu。
样式指南确实提到了folders by feature,听起来像您已经在做。我会坚持您当前正在做的事情,并且应该按比例缩放。您已经有使用它的经验,它可以正常工作,并且第一次运行更大的应用程序时尝试完全不同的尝试听起来像是灾难的秘诀。
要避免的主要事情是拥有不必要复杂的文件夹结构,该文件夹结构实际上不会反映您应用程序的结构。例如,如果您有一个配置文件管理部分,则不要将其放在/dashboard/user/components/profile/edit
或类似的内容中,除非它实际上模仿您的应用程序结构。似乎很明显,但是人们一直在这样做,这使您的代码不那么容易发现。我认为LIFT概念涵盖了这一点:
执行结构化应用程序,以便您可以快速定位代码,一目了然地识别代码,保持最扁平的结构并尝试变干。
执行,定义结构以遵循这四个基本准则,并按重要性顺序列出。
为什么? LIFT提供了一个一致的结构,该结构可以很好地扩展,模块化并且可以通过快速查找代码来提高开发人员效率。为了确认您对特定结构的直觉,请问:我可以快速打开并开始使用此功能的所有相关文件吗?
接着提到要尽可能保持平面文件夹结构:
要做,请尽可能保持平面文件夹结构。
考虑,当文件夹包含七个或更多文件时,创建子文件夹。
考虑,将IDE配置为隐藏分散的,不相关的文件,例如生成的.js和.js.map文件。
为什么?没有人想要通过七个级别的文件夹搜索文件。扁平结构易于扫描。
对于大型项目,这是最关键的要点之一。当您使用具有20个模块的应用程序时,不必要的复杂文件夹结构会带来一点麻烦。当您使用150个模块时,本能地在打开IDE时畏缩。 overall structural guidelines是项目的一个很好的起点,它演示了何时保留/feature/
和何时使用子功能文件夹。
关于每个组件的模块:
执行为每个功能区域创建一个NgModule。
为什么? NgModules使延迟加载可路由功能变得容易。
为什么??NgModules使隔离,测试和重用功能更加容易。
您可以扩展为说应该为每个组件创建一个模块,但是实际上我会避免使用它,除非您对给定的模块有特定的需求。再一次-根据我的经验,为您自己创建开销会变得更大,而您的项目会变得更多。在小型项目中那些看起来有些烦人的事情变成了大型项目中的噩梦。
最后说明:可以更改。您和您的同事可以花一个星期的时间来规划您的项目结构,而一旦真正开始使用它,就会发现它是错的。第一次尝试就很难100%正确地解决问题。慢慢迭代直到达到接近完美的状态比较容易。
我的项目通常看起来像这样:
app/
| core/
| | constants/ // Keep all constants in a single place and avoid magic IDs/strings.
| | |-http-status-codes.enum.ts
| | guards/ // I like to group my guards in a single place
| | http-interceptors/ // Same with interceptors
| | pipes/ // Some pipes might be section-specific but they are usually core
| | services/ // Core services. Utilities, error handling, etc.
| | |-error-handler.service.ts
| | validators/
| section1/
| | models/
| | sub1/ // I try not to nest too deeply
| | |-sub1.component.ts|html|css|spec.ts
| |-section1-routing.module.ts // Routing by section
| |-section1.component.ts|html|css|spec.ts
| |-section1.module.ts // Module per section for lazy loading, etc.
| |-section1.service.ts // Section-specific service
| shared/
| | models/
| | app-modal-dialog/
| | my-awesome-widget/
| | some-custom-input/
|-app.component.ts|html|css|spec.ts
|-app.module.ts
|-app-routing.module.ts
assets/ // Static content
environments/
|-environment.x.ts // Stripe public keys, etc.
再次-与style guide非常一致。
答案 3 :(得分:3)
这里有很多很好的答案,我发现有一些细微的差别,我发现它们有助于构建到目前为止尚未提及的大型应用程序,这是功能与资源之间的区别。功能是您的应用程序执行的事情,资源是您的应用程序使用的事情。一个功能可能正在使用一个或多个资源,我认为这一点很重要,以反映到您的项目结构中。
通常我会遇到类似的东西:
app/
core/
... core stuff like nav bars and single use components or core services...
app-shared/ (prefix it!!!!)
... shared app utilities like tables, accordions, validators, form helpers, pipes etc ...
resource1/ <- represents some backend resource usually
resource1.model <- the models
resource1-model.service <- API interaction layer, single http calls
resource1-domain.service <- abstraction for everything I can do with this resource (think combinations of multiple model service calls or model service calls with common defaults)
views/
... here we have all the components (data views, forms etc) that concern only this resource and the needed view services ...
... rinse repeat for all app resources ...
feature1/ <- this is an application feature that combines multiple resources or possibly only uses a single resource. this is pretty much primarily a page of your app
feature1-application.service <- this combines the various resources needed for this feature
feature1-container.component <- the prime container for this feature. does the service layer interactions and holds the views of this feature or the needed resource views
views/ <- maybe not needed depending on the feature
... here is where we have components and view services that are part of this feature that combine multiple resources, these can contain resource views if needed ...
... rinse repeat for all app features ...
注释: