platform
platform copied to clipboard
Schematics: Improve schematics for more consistency and modern usage
Which @ngrx/* package(s) are relevant/related to the feature request?
schematics
Information
Our schematics are generally supposed to reflect the most recent patterns used in NgRx, but they have drifted along the way. This effort would improve the schematics for consistency and update them to modern NgRx patterns.
Such as
- createActionGroup
- createFeature with extraSelectors
- Updating entity selectors to accept a singular input (user) instead of plural (users) so they generated code doesn't become loadUserss
- Other improvements as needed
Describe any alternatives/workarounds you're currently using
No response
I would be willing to submit a PR to fix this issue
- [ ] Yes
- [ ] No
@tomastrajan has some suggestions to recommend here also.
Preface
The Angular schematics (and NX generators as they can re-use them) are really great way to streamline development in large envs with many devs and teams, therefore we should pay extra attention to consistency of the generated code.
In general we want to achieve a state when generated code has predictable repeatable structure, naming which promotes using of best practices and is easy to compose (re-using selectors from other state features) and refactor (easy to extract part of the state feature to other state feature, for example when extracting part of state from lazy feature to new core state feature to be reused by multiple lazy features.
Without consistent base schematics provided by the library, people often reimplement them on per project basis (or extract in private library) to provide consistent experience in their environments.
eg https://github.com/angular-experts-io/nx-plugin/tree/main/libs/tooling/nx-plugin/generators/src/generators/lib/files/state/lib
Variables, files, APIs
- consistent existence (eg their either always exist or never, not ad hoc based on provided flag when running schematics)
- consistent naming (and pluralization)
- consistent location (order of appearance)
Example
NgRx feature without (and with --entity flag)
Without
ng g @ngrx/schematics:feature features/example-basic/example
// previous code omitted for brevity
export const exampleFeature = createFeature({
name: exampleFeatureKey,
reducer,
});
example.selectors.tswill exist
With
ng g @ngrx/schematics:feature features/example-entity/example --entity
// previous code omitted for brevity
export const examplesFeature = createFeature({
name: examplesFeatureKey, // <-- hardocded pluralization (probably makes sense because of entity collection but still
reducer,
extraSelectors: ({ selectExamplesState }) => ({
...adapter.getSelectors(selectExamplesState)
}),
});
export const {
selectIds,
selectEntities,
selectAll,
selectTotal,
} = examplesFeature;
example.selectors.tsdoesn't exists
Proposal
Come up with an ideal reducer (or maybe even <name>.feature.ts ), action (or maybe even <name>.events.ts ), ... file structure and once consensus was achieved, implement it as an updated consistent version of NgRx schematics.
Ideas
-
why preserving
examplesFeatureKeyif we could instead docreateFeature({ name: 'actual-name' })as currently the features can be registered directly withprovideState(examplesFeature)(andStoreModule.forFeature(examplesFeature) -
come up with a consistent easy to compose way to define selectors, eg always (or never) create
<name>.selectors.tsfile, so that when composing state, it is consistently recommended to use either feature (with extra selectors) or standalone selectors in dedicated file, but what was generated should be consistent -
when using
--entityflag, the generated reducer follows "command pattern" eg (add, update, ...) while consuming actions group created with createActionsGroupAPI which defines a object ofeventsso it would be great if the generated code followed events naming instead, egExampleActions(or evenExampleEvents).loadExamplesSuccess(orexamplesLoadedSuccess)
I hope this proposal can start some conversation and bring together various time tested best practices of folks who figured them out over time in their codebases so that we can provide great out of the box experience for anybody starting with NgRx and make it attractive to build on top of base NgRx schematics instead of from scratch when creating a custom solution for some specific environment!