Adding a Feature Library
Feature libraries encapsulate domain-specific functionality (login, tickets, products, etc.) and are consumed by the applications (unpispas-pos, upp-test). This guide walks through creating a new feature from scratch.
Existing Features
The monorepo already includes these feature libraries under libs/feature/:
| Feature | Path | Module |
|---|---|---|
| Login | libs/feature/login/ | FeatureLoginModule |
| Ticket | libs/feature/ticket/ | FeatureTicketModule |
| Product | libs/feature/product/ | FeatureProductModule |
| Place | libs/feature/place/ | FeaturePlaceModule |
| Category | libs/feature/category/ | FeatureCategoryModule |
| Employee | libs/feature/employee/ | FeatureEmployeeModule |
| User | libs/feature/user/ | FeatureUserModule |
| Offer | libs/feature/offer/ | FeatureOfferModule |
| Extra | libs/feature/extra/ | FeatureExtraModule |
| QR Code | libs/feature/qrcode/ | FeatureQrcodeModule |
| Assets | libs/feature/assets/ | FeatureAssetsModule |
| Top Bar | libs/feature/topbar/ | FeatureTopbarModule |
| Period | libs/feature/period/ | FeaturePeriodModule |
| Shortcut | libs/feature/shortcut/ | FeatureShortcutModule |
Step 1 — Generate the Library
Use the Nx generator to scaffold the library:
npx nx generate @nx/angular:library \
--name=feature-<name> \
--directory=libs/feature/<name> \
--importPath=@unpispas/feature-<name> \
--prefix=upp \
--style=scss \
--standalone=false
This creates the standard structure:
libs/feature/<name>/
├── src/
│ ├── lib/
│ │ └── feature-<name>.module.ts
│ ├── components/
│ │ └── <component>/
│ │ ├── upp-<component>.ts
│ │ ├── upp-<component>.html
│ │ └── upp-<component>.scss
│ ├── index.ts
│ └── test-setup.ts
├── project.json
├── tsconfig.json
├── tsconfig.lib.json
└── tsconfig.spec.json
Step 2 — Set Up the Module
The module follows a consistent pattern. Import the shared modules and declare your components:
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { UppBaseModule } from '@unpispas/upp-base';
import { UppWdgtModule } from '@unpispas/upp-wdgt';
import { UppDataModule } from '@unpispas/upp-data';
import { MyPageComponent } from '../components/my-page/upp-my-page';
import { MyFeatureComponent } from '../components/my-feature/upp-my-feature';
@NgModule({
declarations: [
MyPageComponent,
MyFeatureComponent,
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
IonicModule,
UppBaseModule,
UppWdgtModule,
UppDataModule,
],
exports: [
MyFeatureComponent,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class FeatureMyFeatureModule {}
Key conventions
- Import
UppBaseModule,UppWdgtModule, andUppDataModuleas needed. - Only export the components that consuming apps need to use directly.
- Use
CUSTOM_ELEMENTS_SCHEMAfor Ionic web-component selectors.
Step 3 — Create Components
Place each component in its own folder under src/components/:
src/components/my-page/
├── upp-my-page.ts
├── upp-my-page.html
└── upp-my-page.scss
Follow the naming convention: prefix with upp-, separate the template and styles into .html and .scss files.
Step 4 — Export from index.ts
The barrel file re-exports the module and any public components:
export * from './lib/feature-my-feature.module';
export * from './components/my-feature/upp-my-feature';
Step 5 — Import in the Application
In the consuming app module (e.g. unpispas-pos):
import { FeatureMyFeatureModule } from '@unpispas/feature-my-feature';
@NgModule({
imports: [
FeatureMyFeatureModule,
// ...
],
})
export class AppModule {}
Step 6 — Routing (if applicable)
If the feature has navigable pages, add routes in the application's routing module that point to the feature's page components.
Feature Structure Convention
A well-structured feature library follows this layout:
libs/feature/<name>/
├── src/
│ ├── lib/
│ │ └── feature-<name>.module.ts ← NgModule declaration
│ ├── components/
│ │ ├── <name>/ ← Main feature component (exported)
│ │ │ ├── upp-<name>.ts
│ │ │ ├── upp-<name>.html
│ │ │ └── upp-<name>.scss
│ │ └── <name>-page/ ← Page-level component (internal)
│ │ ├── upp-<name>.ts
│ │ ├── upp-<name>.html
│ │ └── upp-<name>.scss
│ ├── index.ts ← Barrel exports
│ └── test-setup.ts
Keep reusable logic in the shared libraries (upp-base, upp-data, upp-wdgt); feature libraries should be thin wrappers that compose UI from shared widgets and connect to data services.