Project dependent installation

Node and NPM installation

There are many online tutorials, you can search by yourself, 2 links are given below:

The installation of the MAC

The installation of the PC

The installation of the NX

Install the NX CLI globally

npm install -g @nrwl/schematics
Copy the code

Install the Angular CLI globally

npm install -g @angular/cli
Copy the code

Website tutorial

Ng – packagr installation

Install in the project

> npm i ng-packagr --save-dev
Copy the code

​ github

Create a Workspace project

Start by creating a workspace through the NX command line

> create-nx-workspace example
Copy the code

The required dependencies will be automatically installed during this process. Make sure to create a workspace using the nx command to avoid additional installation of dependencies when creating projects using WebPack or ng-CLI.

After the nX workspace is set up, we need to create the corresponding project in Example’s app

> ng generate app myapp --routing
Copy the code

Where, myapp is the name of the project, and routing is automatically adding the routing dependency parameter. Since the project will use routing, we take this parameter when establishing the project. If you forget to add routing parameters, you can manually add them later, which does not affect actual development.

Sometimes unexpected errors occur when nX or some dependent version is updated

Error: Cannot find module '~/example/node_modules/prettier/bin/prettier.js'
Copy the code

At this point, you can refer to the official website issue. Such problems are generally caused by dependency updates. Updating the dependency can solve similar problems

> NPM install [email protected] -dCopy the code

When the project is completed, we can see the directory myApp under the apps directory and the complete code structure. Also in vscode we will find.angular-cli.json has been updated, which is added to the project configuration of myapp, and generally there is no need to change the configuration.

{
      "name": "myapp"."root": "apps/myapp/src"."outDir": "dist/apps/myapp"."assets": [
        "assets"."favicon.ico"]."index": "index.html"."main": "main.ts"."polyfills": "polyfills.ts"."test": ".. /.. /.. /test.js"."tsconfig": "tsconfig.app.json"."testTsconfig": ".. /.. /.. /tsconfig.spec.json"."prefix": "app"."styles": [
        "styles.css"]."scripts": []."environmentSource": "environments/environment.ts"."environments": {
        "dev": "environments/environment.ts"."prod": "environments/environment.prod.ts"}}Copy the code

Once we’ve set up MyApp, we can run the example and see if it works

> ng serve -a=myapp
Copy the code

After typing the command line, we can view it from http://localhost:4200/ address. 4200 is the default port of ng serve, which can also be changed by -port= port number. -a= myApp specifies to run myApp, if any other project is opened in the same way. When we happily see the NX flag in our browser, it means that our project has run.

Spice up the APP

Create a lib to serve myApp

Before workspace, the usual development process was to implement it in an APP, then split the finished code into another library and put it into an NPM package. This method is extremely difficult to maintain, and even doing it through Git’s submodule is not very smooth. Now NX provides a quick way to do this.

>ng g lib myapp-feature --routing
Copy the code

Almost in the same way we created the app, we created a lib named myapp-feature in the libs directory, and since we needed a route, we included the route. Look at.angular-cli.json. Also, the new lib has been updated.

    {
      "name": "myapp-feature"."root": "libs/myapp-feature/src"."test": ".. /.. /.. /test.js"."appRoot": ""
    }
Copy the code

The next step is to reference lib in myApp. NX provides a convenient way to reference aliases.

import { MyappFeatureModule } from '@ebiz-example/myapp-feature';
Copy the code

We add a reference under app.module.ts where ebiz-example is the value of our name configuration item in package.json and myapp-feature is the directory under libs. Add console to constructor under the module of app and Lib respectively, and then run the app. We can see that lib has been successfully introduced.

Add nGRX-based State Manage for MyApp

For communication between components, we need to find a solution for state Manage, and NGRX, which inherits the Redux idea, is a good choice. Fortunately, NX has integrated a way to quickly add NGRX.

> ng g ngrx root -m=apps/myapp/src/app/app.module.ts --root
Copy the code

After executing this command, we will notice that there is an extra +state directory in the app directory. Because we use -m, we add the corresponding code in the app.module.ts file, and -root specifies that we use forRoot.

import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { rootReducer } from './+state/root.reducer';
import { rootInitialState } from './+state/root.init';
import { RootEffects } from './+state/root.effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '.. /environments/environment';
import { StoreRouterConnectingModule } from '@ngrx/router-store';

@NgModule({ imports: [ StoreModule.forRoot({ root: rootReducer }, { initialState: { root: rootInitialState } }), EffectsModule.forRoot([RootEffects]), ! environment.production ? StoreDevtoolsModule.instrument() : [], StoreRouterConnectingModule ], })Copy the code

Not only @Ngrx/Store and @Ngrx/Effects, but Devtools is ready for us. Let’s start the server, open Up Chrome’s Redux Devtools, and we can see that NGRX has started smoothly.

In addition to app, lib will also have the requirement of state manage, we can also use ng-CLI to add a module for lib, and add state to the module.

> ng g module subfeature -a=myapp-feature -- routing > ng g component subfeature-a=myapp-feature
> ng g ngrx userinfo -m=libs/myapp-feature/src/subfeature/subfeature.module.ts
Copy the code

We added modules and Components without a problem, and if we need to inject myapp-feature automatically, we can add -m to do so. After adding NGRX, the same +state is added to the code, where there is a slight difference in subfeatures.module.ts that needs to be noted.

@NgModule({
  imports: [
    StoreModule.forFeature('userinfo', userinfoReducer, { initialState: userinfoInitialState }),
    EffectsModule.forFeature([UserinfoEffects])
  ]
})
Copy the code

In child modules we should use forFeature, and only in root modules we use -root.

Add subfeature to myapp-feature to start the service again, we open Redux Devtools, we can confirm that userInfo has been added to the state tree.

Prepare to share Lib

Deliver the developed Lib

When the project development reaches a certain stage, we often want to share the function modules in the libs directory with other teams. If we want to share the code, the recommended way is to use git submodule. For details, please refer to help.

> git submodule --help
Copy the code

Package the code and manage it

Sometimes we don’t want other teams to change our code, so it’s a good idea to package the finished Lib as NPM and make it available for them to rely on.

For Private libs, we generally don’t commit to a Public repO, so you’ll need to build your own NPM repO, such as Nexus. When the Nexus is installed, we also need to set up package.json, mainly two configuration items.

  "publishConfig": {
    "registry": "http://private/repository/ebiz-npm-private/"
  },
Copy the code
  "private": false,
Copy the code

These two configurations ensure that your NPM package is publishable and properly published to the Private NPM repO.

Use nG-packagr for packaging

If it is an ES library, we can happily publish directly, or if it is a TS library, we can compile TSC first and then happily publish.

However, as an Angular lib, especially one with various components, this process is much more cumbersome. We all know that the Component templateUrl and styleUrls fetch resource files as characters, which obviously makes packaging less pleasant and requires additional processing, such as gulp preprocessing code and packaging.

Fortunately, we can also use ng-packagr for packaging, so let’s start by creating a new ng-package.json file.

{
  "$schema": "./node_modules/ng-packagr/ng-package.schema.json"."lib": {
    "entryFile": "public_api.ts"."externals": {
      "primeng/primeng": "primeng"."primeng/components/common/messageservice":
        "primeng/components/common/messageservice"."rxjs": "Rx"."@nrwl/nx": "@nrwl/nx"."@ngrx":"@ngrx"."@ngrx/store":"@ngrx/store"."@ngrx/store-devtools":"@ngrx/store-devtools"."@ngrx/effects":"@ngrx/effects"}}}Copy the code

This defines the SCHEMA for nG-packagr, as well as some third-party libraries that you want to recognize correctly when external references are made. One of the key ones is entryFile. This configuration item is an entry point that we set up, for which we created a new public_api.ts file.

	export * from "./libs/myapp-feature";
Copy the code

Here we can specify one or more lib packages into an NPM package, so define what you want to pack in this file.

After these two files are defined, we can execute the packaging command, first write this command in package.json, easy to run.

"scripts": {
    "packagr": "ng-packagr -p ng-package.json",
    }
Copy the code

Run the NPM run packagr, sometimes some references may find errors, we need to explicitly reference these dependencies.

BUILD ERROR Error at /Users/aaronjin/eBizprise/ebiz-example/.ng_pkg_build/ebiz-example/ts/libs/myapp-feature/src/subfeature/+state/userinfo.e ffects.ts:11:3: Public property'loadData' of exported class has or is using name 'Observable' from external module "/Users/aaronjin/eBizprise/ebiz-example/node_modules/rxjs/Observable" but cannot be named.
Copy the code

For errors like this, you need to add references.

import { Observable } from 'rxjs/Observable';
Copy the code

Json externals can be configured to solve some of the problems encountered by ng-packagr packaging, such as third-party loading can not be identified.

Published to the Nexus

If there is nothing wrong with the code, you can find the dist directory under the project, and this is the code that we packaged.

The code is named according to the package.json name, and we don’t need to change it. Look at package.json in the dist directory.

"Name" : "ebiz - example", "version" : "0.0.0", "license" : "MIT", "publishConfig" : {" registry ": "http://dkh01.ebizprise.com/repository/ebiz-npm-private/" },Copy the code

We changed ebiz-example to @ebiz-ex/feature to distinguish online and local projects, and changed version to 0.0.1. Of course, NPM version patch can be used to improve version in pre-publish.

We then execute NPM publish Dist and return the following information to see that the NPM has been published successfully.

+ @ ebiz ex/[email protected]Copy the code

Reference the packaged lib through NPM

Before using the Private lib, we will switch to the Nexus server and usually use the standard official website address to speed up access

> npm config setRegistry http://private/repository/ebiz-npm-all/ or > NPM configset registry  http://registry.npmjs.org
Copy the code

Use the NPM command to introduce the packaged lib package into the project.

> npm i @ebiz-ex/feature --save
Copy the code

Modify the references in app.module.ts.

import { MyappFeatureModule } from '@ebiz-ex/feature';
Copy the code

Running ng Server again, we find that using the packaged NPM package is consistent with the lib package we used in the NX project.

Reference the packaged lib through a file

Sometimes we don’t have a Private REPO, so can we use packaged NPM? The answer is yes, package the dist directory as TGZ and put it in your project, adding a reference to package.json.

"@ ebiz - ex/feature", "file:. Feature - 0.0.1..tgz",Copy the code

Modify the references in app.module.ts.

import { MyappFeatureModule } from '@ebiz-ex/feature';
Copy the code

Running ng Server again, we find that using the packaged NPM package is consistent with the lib package we used in the NX project.

Whether to use this scheme

Mono Repo or Muti Repo

The pros and cons of the two options don’t need to be explained, except that NX is a Workspace solution based on Mono Repo, and if the project is more Muti Repo oriented, don’t consider NX at all.

The biggest advantages of NX are unified management, ease of deployment, no need to repeatedly synchronize NPM packages for different apps or libbs, and the ability to split code easily. If these hit the nail on the head, don’t hesitate to go for NX.

Invasiveness of NX

NX integrates a lot of functionality, some of which may not be necessary, such as not using @Ngrx or not wanting to use @Ngrx/Effects. These are the categories that need to be considered. However, the biggest problem with NX is the intrusion of nG-CLI. If we look at package.json, we can see that file is called.

"@angular/cli": "file:.angular_cli.tgz".Copy the code

Another problem with this series of intrusions is that when Lib is under the project, AOT compilation is normal, but when we use NG-packagr to pack NPM and then introduce AOT, there is a problem.

ERROR in ./apps/myapp/src/main.ts
Module not found: Error: Can't resolve './app/app.module.ngfactory' in '/Users/aaronjin/eBizprise/ebiz-example/apps/myapp/src'
resolve './app/app.module.ngfactory' in '/Users/aaronjin/eBizprise/ebiz-example/apps/myapp/src'
Copy the code

This problem is caused by a conflict between ng and TS versions. The specific solution has not yet been found. Therefore, use this solution with caution.

Ng – packagr is insufficient

In addition to the possibility of version conflicts, this packaging scheme has some other disadvantages, such as the loadChildren asynchronous mechanism using ng Router, which can cause such metadata loss.

No NgModule metadata found for 'MyappFeatureModule'.
Copy the code

Making the address

NX-packagr