| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Welcome to AX Workspace - WIP!
Install global nx CLI with npm i -g nx as it will make running of some commands easier. Install the dependencies with npm ci (append --legacy-peer-deps or --force)
The --legacy-peer-deps flag might need to used in case the dependencies available at the time of last workspace update did not fulfill their peerDependencies ranges perfectly. This might change again in the future as newer versions of the libraries are released and the --legacy-peer-deps flag might not be needed anymore.
This workspace provides a set of generators and executors to automate the creation of new projects and libraries which follow desired architecture to ensure maintainability and consistency across projects in this AX workspace.
Learn more about @ax/tooling/nx-plugin.
Learn more about generators and executors in general in Nx documentation.
Using multiple libraries with predefined types and clear scopes has several advantages over a single large library which is shared across multiple applications in a single NX workspace:
The architecture comes with a finite set of predefined library types which allow for clean extendable architecture while preserving enough flexibility to implement any specific use case. Following list represents a concise summary of each library type: (check out the extended version)
Based on the above described architecture, it will only make sense to generate additional components, services, pipes, ... in the feature and pattern libraries to implement specific use cases.
Besides that, it can make sense to generate also
In general, it is the best to use NX plugin for Intellij IDEs to generate new components, services, ... in the desired library.
This diagrams showcases an example of a single application which consumes multiple libraries
Please notice the concept of lazy loading, in general anything which was referenced by an eagerly loaded part of the application will be eagerly loaded as well (even if it is consumed also by a lazy feature).
This is in practice:
Everything else should be only referenced by the lazy loaded features.
If a library is referenced by more than one lazy loaded feature, the bundler might decide to extract lazy loaded "pre-bundle" which will be loaded if any of the lazy loaded features is loaded. This is not a problem and represents additional optimisation performed transparently by the bundler.
Some libraries like styles and assets represent implicit dependencies as they are not referenced directly using TypeScript imports. This means that they need a little bit of extra setup in consumer applications for them to work properly.
Asset libraries (images, translations, ...) have to be added in the consumer application's project.json file in the targest.build.assets array, for example...
{
"glob": "**/*",
"input": "libs/shared/assets/i18n/src",
"output": "assets/i18n"
},
{
"glob": "**/*",
"input": "libs/shared/assets/images/src",
"output": "assets/images"
}This entry will copy files from libs/shared/assets/i18n/src to dist/apps/<consumer-app>/assets/i18n folder and from libs/shared/assets/images/src to dist/apps/<consumer-app>/assets/images folder. We should also alwaysmake sure that such assets library is added as an implicit dependency in the project.json file of the consumer app in the implicitDependencies array, for example...
{
"implicitDependencies": ["libs/shared/assets/i18n", "libs/shared/assets/images"]
}These libraries are added automatically if the app is generayed with npm rung:app but the existing apps (and generator) might need to be updated manually if more assets libraries are added.
That way, the consumer app will re-build if there was any change in the asset library.
Sass styles libraries have to be added to the consumer application's project.json file in the targest.build.stylePreprocessorOptions.includePaths array, for example...
{
"includePaths": ["libs/shared/styles/theme/src", "libs/shared/styles/components/src"]
}Which will then allow importing of the files in the library src/ folder in the consumer *.scss files like global styles.scss or components *.component.scss files.
@import 'theme';
h1 {
color: $ax-theme-primary-color;
}We should also always add such styles library as an implicit dependency in the project.json file of the consumer app in the implicitDependencies array, for example...
{
"implicitDependencies": ["libs/shared/styles/theme", "libs/shared/styles/components"]
}That way, the consumer app will re-build if there was any change in the asset library.
NX out of the box uses path in a library name so a library generated in libs/shared/pattern/core will have name shared-pattern-core. This will be important when referencing projects when required as parameters for CLI commands like generators with --project shared-pattern-core and executors like nx test shared-pattern-core.
Sometimes it will make a sense to move (or rename) a library or remove it completely. For that we should always use the nx commands instead of just moving or removing the library folder as that will automate most of the adjustments that need to be performed in order for the workspace to work properly.
After that we should always run npm run validate -- --fix and perform any manual adjustments as listed in the output.
Some of the used generator options can be customized in the nx.json file within the generators property. This can be useful if you add additional Angular libraries which bring their own generator, and you want to customize their default options.
Additionally, default options can be evolved also for custom @ax/tooling/nx-plugin generators by adjusting libDefaultOptions in the libs/tooling/nx-plugin/src/generators/lib/types/<type>.ts files per library type.
When using NgRx, it makes sense to introduce selectors which are local to a given feature (or pattern) instead of creating a selector which delivers perfect view for that feature as a part of the data-access library.
In general, there are 4 different scenarios:
The architecture is validated (linted) and a lot of best practices are enforced with the help of the Nx enforce module boundaries rule. as defined in the .eslintrc.json file in the overrides[0].rules.@nx/enforce-module-boundaries[1].depConstraints section.
The rules configuration is updated automatically when used npm run g (lib) and npm run g:app (app) generators. Besides that it is always a good idea to validate if architecture and module boundaries rules are still in sync using provided npm run validate generator.
This generator will make sure that
are all in sync!
The reason why they can go out of sync is when we move or rename a library or an app. In that case, we can run npm run validate -- --fix which will automatically update project tags based on new folder structure.
Besides that it will print out if there are any conflicts between folder structure and module boundaries rules. These conflicts than have to be resolved manually by either renaming folders or adjusting the module boundaries rules in the .eslintrc.json file and scopes in libs/tooling/nx-plugin/src/generators/lib/schema.json.
That way we can be sure our architecture stays consistent and valid.
Bundle size is linted with the help of budgets which are specified in the project.json file of each app. These budget are evaluated on every build and if the bundle size exceeds the specified limit, the build will fail. This is useful to prevent bundle size from growing too much, especially when not intended, for example by incorrect import of a library or a component.
The butget based build errors can be debugged using npm run analyze:gesuch-app (or other apps, please add script when adding a new app) which will provide a view of what was bundled in each bundle to figure out if something was included by accident or if the budget needs to be adjusted.
Angular libs are linted using the default sets specified in
(both of which are referenced through plugin:@nx/angular in the .eslintrc.json files)
Besides these presets, we also use additional rules specified in the .eslintrc-angular.json file that proved to be beneficial in our projects.
This additional file is referenced in the extends section of the individual .eslintrc.json files of each library which was generated using provided lib generator.
NgRx (data-access) libraries are linted using the default sets specified in
This additional NgRx config is specified in the .eslintrc-ngrx.json file is referenced in the extends section of the individual .eslintrc.json files of data-access type libraries which was generated using provided lib generator.
In general, we strive to write components with little or even NO logic at all which means they don't really have to be tested. This is great because components are the most complicated part of Angular application to test and those tests execute run the slowest.
Most logic is then extracted into data-access or util type libraries which are headless and hence much easier to test.
The main product critical flows should be covered by the e2e tests which provide the best tradeoff between effective / useful coverage and effort required to write them.
You can run e2e tests in headless mode for all (npm run e2e) or for a specific app (npm run e2e:<app-name>, these have to be added to the package.json file scripts when new app is added to the workspace).
Besides that it is also possible to serve desired app in the dev mode (eg npm run serve:gesuch-app) and then start e2e tests in GUI mode with npm run e2e:gesuch-app:open which will start Cypress GUI. (again, these scripts have to be added to the package.json file scripts when new app is added to the workspace).
When writing E2E tests, always make sure to use data-test-id="some-id" attributes instead of component selectors, classes or other attributes. This way we can make sure that tests are not brittle and will not break when we change the component structure or styling.
NX monorepo is a great piece of technology, but it is not perfect. Even though caching leads to great performance it can also lead to inconsistent state, especially when removing, moving or renaming projects and files. If you run into any issues try to run nx reset (or `npm run reset) and then try to run original command again. If the problem still persists then it's most likely a real problem which than has to be solved.
| Back | FazBrowse Home | New Git URL |