Create a new Angular application project:
ng new ngx-myapp
Create a new empty Angular project:
ng new ngx-mylib --create-application=false
Add a library to the project:
ng generate library ngx-mylib
Add a showcase application to the project:
ng generate application showcase
Every application project should internally follow the following directory structure:
Directory | Purpose |
---|---|
./app/ |
Main application module and component as pre-generated by ng cli |
./app/components/ |
Reusable components and directives, shared between multiple routes and parent components |
./app/pages/ |
Root components of application routes |
./app/pages/:page/components/ |
Components and directives used only by the parent component and not reusable anything else |
./app/pages/:page/components/:comp/components/ |
Components and directives used only by the parent component and not reusable anything else |
./app/pipes/ |
All pipes |
./app/pipes/:domain/ |
All pipes pertaining to a domain (for example "units", or "time") |
./app/services/ |
All services |
./app/services/:domain/ |
All services pertaining to a domain (for example "api", or "auth") |
./app/data/ |
All application data models |
./app/data/:domain/ |
All application data models pertaining to a domain (for example "auth", "users", etc ...) |
Library projects should follow the same structure to the extent that it is applicable.
When naming directories, by default all directories should be snake-cased
. There are a large number of special cases addressed later in the Syntax Name Casing section.
All directories, ./app
and deeper, have to contain an index.ts
file (re)exporting everything that should be accessible from the deeper structure of the directory so that other parts of the application can import while remaining agnostic of the internal structure.
EXAMPLE
./app/services/myservice/helpers/DoesInternalThing.ts
export class DoesInternalThing { ... }
./app/services/myservice/DoesUsefulThing.ts
export class DoesUsefulThing { ... }
./app/services/myservice/DoesAnotherUsefulThing.ts
export class DoesAnotherUsefulThing { ... }
... then we would need to have an index.ts
file (re)exporting DoesUsefulThing
and DoesAnotherUsefulThing
:
./app/services/myservice/index.ts
// No need to (re)export the internal DoesInternalThing service export * from "./DoesUsefulThing"; export * from "./DoesAnotherUsefulThing";
... and also an index.ts
one level deeper (re)exporting all services:
./app/services/index.ts
export * from "./myservice";
... and also an index.ts
directly inside ./app
(re)exporting everything:
./app/index.ts
export * from "./services";
... so that when importing from another part of the application, we can just do:
./app/components/mycomponent/index.ts
import { DoesUsefulThing, DoesAnotherUsefulThing } from `../../`;
For details on how to set up VS code see here
For details on how to set up a TypeScript project see here and here
To add tests which will make sure all the nested package.json
files in your project's libraries stay in sync, download package.spec.ts into the project root directory, next to package.json
.
Run this test by running: npx jasmine ./package.spec.ts
When coding, use the following name casing conventions:
Artifact | Casing | Example |
---|---|---|
function , variable , constant |
camelCase | function myFunction , let myVar , const myConst |
class , interface |
TitleCase | class MyClass , interface IMyInterface |
public [property or method] * |
camelCase | public myProperty , public myMethod |
private [property or method] * |
_camelCase | private _myProperty , protected _myMethod |
enum |
TitleCase | enum MyEnum |
enum value |
ALL_CAPS | MyEnum.SOME_VALUE |
Any
public [property or method]
that is only exposed as public to be used in that same component's template, but could otherwise be private should be cased as if they areprivate [property or method]
!
There are additional rules for casing Angular specific, higher level artifacts:
Components
Names of directories containing components should be TitleCase
. The name of the directory should match the name of the component with or (preferably) without the word "Component".
Names of component classes should be TitleCase
and should end with the word "Component".
Selectors for components should be snake-case
and start with a common prefix for the library/application, or (by default) ngx-
.
Component's template and styling files should be named index.html
and style.scss
.
// Located in directory/file: "/Something/index.ts"
// ... alternatively "/SomethingComponent/index.ts"
// Accompanied by template and styling:
// - index.html
// - style.scss
@Component({
selector: 'ngx-something',
templateUrl: 'index.html',
styleUrls: ['style.scss']
})
exports class SomethingComponent { ... }
Directives
Names of directories containing directives should be camelCase
. The name of the directory should match the name of the directive class with or (preferably) without the word "Directive".
Names of directive classes should be TitleCase
and should end with the word "Directive".
Selectors for directives should be camelCase
and start with a common prefix for the library/application, or (by default) ngx
.
// Located in directory/file: "/doSomething/index.ts"
// ... alternatively "/doSomethingDirective/index.ts"
@Component({ selector: 'ngxDoSomething' })
exports class DoSomethingDirective { ... }
Pipes
Names of directories containing pipes should be camelCase
. The name of the directory should match the name of the pipe class with or (preferably) without the word "Pipe".
Names of pipe classes should be TitleCase
and should end with the word "Pipe".
Selectors/Names for pipes should be camelCase
and start with a common prefix for the library/application, or (by default) ngx
.
// Located in directory/file: "/doSomething/index.ts"
// ... alternatively "/doSomethingPipe/index.ts"
@Pipe({name: 'ngxDoSomething'})
export class DoSomethingPipe { ... }
Services
All services need to be implemented as classes!
Names of directories containing services should be TitleCase
. The name of the directory should match the name of the service class with or (preferably) without the word "Service".
Names of service classes should be TitleCase
and should NOT end with the word "Service".
// Located in directory/file: "/Something/index.ts"
// ... alternatively "/SomethingService/index.ts"
@Injectable()
export class DoSomething { ... }
Data Models
Names of directories containing data models should be TitleCase
. The name of the directory should match the name of the data model class with or (preferably) without the word "Modal".
Names of data model classes should be TitleCase
and should end with the word "Model".
// Located in directory/file: "/Something/index.ts"
// ... alternatively "/SomethingModel/index.ts"
export class SomethingModel { ... }