Wie man Angular-Bibliotheken lokal entwickelt

Nov 25 2022
Hi ! In dieser Geschichte möchte ich Ihnen zeigen, wie Sie lokal mit Angular-Bibliotheken arbeiten und sie entwickeln können, ohne sie ständig in das Remote-Repository verschieben zu müssen :) DRY - wie Codewiederholungen vermieden werden Wenn Sie an einem großen und komplexen Angular-Projekt arbeiten , ich bin sicher, dass Sie mit einem Problem der Codeduplizierung konfrontiert werden. Konzentrieren wir uns als Beispiel auf das "Aussehen" Ihrer Anwendung - alle Seiten sollten wahrscheinlich ein einheitliches Design haben (Sie möchten Ihre Benutzer nicht verwirren und auf jeder Seite unterschiedlich aussehende Schaltflächen haben).
Foto von Ryunosuke Kikuno auf Unsplash

Hi ! In dieser Geschichte möchte ich Ihnen zeigen, wie Sie lokal mit Angular-Bibliotheken arbeiten und sie entwickeln können, ohne sie ständig in das Remote-Repository verschieben zu müssen :)

DRY - wie man Codewiederholungen vermeidet

Wenn Sie an einem großen und komplexen Angular-Projekt arbeiten, bin ich sicher, dass Sie mit einem Problem der Code-Duplizierung konfrontiert werden. Konzentrieren wir uns als Beispiel auf das "Aussehen" Ihrer Anwendung - alle Seiten sollten wahrscheinlich ein einheitliches Design haben (Sie möchten Ihre Benutzer nicht verwirren und auf jeder Seite unterschiedlich aussehende Schaltflächen haben). Ok, das ist einfach - Sie können diese gängigen Stile einfach in die styles.scssDatei verschieben oder das 7–1-Muster verwenden , um sie elegant zu gestalten.

Aber was ist, wenn Sie einige gemeinsame Komponenten haben , die nicht nur gleich aussehen, sondern sich auch gleich verhalten sollen? Es ist… immer noch einfach! Erstellen Sie einfach ein gemeinsam genutztes Modul in Ihrer Anwendung, definieren Sie dort Ihre Komponenten und exportieren Sie sie in die Moduldefinition. Groß !

Konzentrieren wir uns nun auf das komplexere Problem. Was ist, wenn Ihr Unternehmen mehr als eine Angular-Anwendung hat? Und jede Anwendung sollte ähnlich aussehen, zum Beispiel:

  • dieselbe Kopf- und Fußzeile haben
  • denselben CSS-Stil des Unternehmens haben
  • können Formulare, Validierungsfehler und andere Meldungen auf die gleiche Weise anzeigen

Erstellung einer Bibliothek

Hier finden Sie die offizielle Dokumentationsseite zum Erstellen von Bibliotheken. Folgen wir den dort beschriebenen Schritten und erstellen unsere Bibliothek:

ng new my-shared-workspace --no-create-application
cd my-shared-workspace
ng generate library my-buttons

  • my-shared-workspace ist ein gemeinsamer Arbeitsbereich für Ihre Bibliotheken
  • my-buttons ist eine Beispielbibliothek, die Sie in anderen Projekten wiederverwenden können

{
  "name": "@my-company/my-buttons",
  "version": "0.0.1",
  "peerDependencies": {
    "@angular/common": "^14.2.0",
    "@angular/core": "^14.2.0"
  },
  "dependencies": {
    "tslib": "^2.3.0"
  }
}

my-shared-workspace/projects/my-buttons/src/lib> ng g c fancy-button

Die Komponente wird erstellt, sodass wir ihre Vorlage aktualisieren können, um eine Schaltfläche anzuzeigen

<button>fancy-button works!</button>

@NgModule({
  declarations: [
    MyButtonsComponent,
    FancyButtonComponent
  ],
  imports: [
  ],
  exports: [
    MyButtonsComponent,
    FancyButtonComponent // <-- here
  ]
})
export class MyButtonsModule { }

/*
 * Public API Surface of my-buttons
 */

export * from './lib/my-buttons.service';
export * from './lib/my-buttons.component';
export * from './lib/my-buttons.module';
export * from './lib/fancy-button/fancy-button.component'; // <-- here

Wir haben unsere Bibliothek bereits erstellt, also ist es jetzt an der Zeit für die Client-Anwendung. Ich verwende Angular CLI, um es zu generieren: ng new my-application, und ich füge @my-company/my-buttonses als Abhängigkeit in der Anwendung hinzu package.json(letzte Abhängigkeit, nach zone.js)

{
  "name": "my-application",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^14.2.0",
    "@angular/common": "^14.2.0",
    "@angular/compiler": "^14.2.0",
    "@angular/core": "^14.2.0",
    "@angular/forms": "^14.2.0",
    "@angular/platform-browser": "^14.2.0",
    "@angular/platform-browser-dynamic": "^14.2.0",
    "@angular/router": "^14.2.0",
    "rxjs": "~7.5.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.11.4",
    "@my-company/my-buttons": "0.0.1"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^14.2.6",
    "@angular/cli": "~14.2.6",
    "@angular/compiler-cli": "^14.2.0",
    "@types/jasmine": "~4.0.0",
    "jasmine-core": "~4.3.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.0.0",
    "typescript": "~4.7.2"
  }
}

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MyButtonsModule } from '@my-company/my-buttons';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    MyButtonsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

<lib-fancy-button></lib-fancy-button>

Error: src/app/app.component.html:1:1 - error NG8001: 'lib-fancy-button' is not a known element:
1. If 'lib-fancy-button' is an Angular component, then verify that it is part of this module.
2. If 'lib-fancy-button' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.

1 <lib-fancy-button></lib-fancy-button>
  ~~~~~~~~~~~~~~~~~~

  src/app/app.component.ts:5:16
    5   templateUrl: './app.component.html',
                     ~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component AppComponent.




** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **

Sie sehen auch einige weitere Fehler wie:

Error: src/app/app.module.ts:3:33 - error TS2307: Cannot find module '@my-company/my-buttons' or its corresponding type declarations.

3 import { MyButtonsModule } from '@my-company/my-buttons';

npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/@my-company%2fmy-buttons - Not found
npm ERR! 404
npm ERR! 404  '@my-company/[email protected]' is not in this registry.
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.
Npm link to the rescue

Hier finden Sie die vollständige npm-Link- Befehlsdokumentation. Ich zeige Ihnen, wie Sie diesen Befehl verwenden, um gemeinsam genutzte Bibliotheken lokal mit Live-Neuladen zu entwickeln.

Lassen Sie uns zurück zum my-shared-workspaceVerzeichnis gehen, my-buttonsBibliothek erstellen (Flag --watchist für das Live-Neuladen verantwortlich) und in das Verzeichnis des Builds gehen

my-shared-workspace> ng build my-buttons --configuration development --watch
Building Angular Package

------------------------------------------------------------------------------
Building entry point '@my-company/my-buttons'
------------------------------------------------------------------------------
✔ Compiling with Angular sources in Ivy full compilation mode.
✔ Writing FESM bundles
✔ Copying assets
✔ Writing package manifest
✔ Built @my-company/my-buttons

------------------------------------------------------------------------------
Built Angular Package
 - from: /Users/<user>/<path>/my-shared-workspace/projects/my-buttons
 - to:   /Users/<user>/<path>/my-shared-workspace/dist/my-buttons
------------------------------------------------------------------------------

my-shared-workspace> cd dist/my-buttons
my-shared-workspace/dist/my-buttons> npm link

added 1 package, and audited 3 packages in 1s

found 0 vulnerabilities

Fügen Sie im my-applicationVerzeichnis angular.jsoneine weitere Option hinzu -konservierenSymlinks, die es uns ermöglicht, diese verknüpfte Bibliothek zu verwenden.

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "my-application": {
      "projectType": "application",
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss"
        }
      },
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/my-application",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "inlineStyleLanguage": "scss",
            "preserveSymlinks": true,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.scss"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "500kb",
                  "maximumError": "1mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "2kb",
                  "maximumError": "4kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "outputHashing": "all"
            },
            "development": {
              "buildOptimizer": false,
              "optimization": false,
              "vendorChunk": true,
              "extractLicenses": false,
              "sourceMap": true,
              "namedChunks": true
            }
          },
          "defaultConfiguration": "production"
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "configurations": {
            "production": {
              "browserTarget": "my-application:build:production"
            },
            "development": {
              "browserTarget": "my-application:build:development"
            }
          },
          "defaultConfiguration": "development"
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "my-application:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "inlineStyleLanguage": "scss",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.scss"
            ],
            "scripts": []
          }
        }
      }
    }
  }
}

my-application> npm link @my-company/my-buttons

added 1 package, removed 1 package, and audited 918 packages in 2s

121 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Danach ng serveerneut ausführen:

my-application> ng serve
✔ Browser application bundle generation complete.

Initial Chunk Files   | Names         |  Raw Size
vendor.js             | vendor        |   3.30 MB |
polyfills.js          | polyfills     | 318.02 kB |
styles.css, styles.js | styles        | 210.56 kB |
main.js               | main          |  12.32 kB |
runtime.js            | runtime       |   6.53 kB |

                      | Initial Total |   3.84 MB

Build at: 2022-11-24T18:27:00.803Z - Hash: 7669daf65ca2f665 - Time: 4598ms

** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **


✔ Compiled successfully.

Sehen wir uns das Ergebnis an:

Groß ! Versuchen Sie nun, etwas in fancy-button-component.html zu ändern

<button>fancy-button works - live reload!</button>

Jetzt können Sie ohne Unannehmlichkeiten sowohl an der Bibliothek als auch an der Anwendung arbeiten :)

Überprüfung

Um zu überprüfen, welche Version der Bibliothek Sie verwenden, können Sie den folgenden Befehl ausführen:

npm list -g
/usr/local/lib
├── @angular/[email protected]
├── @my-company/[email protected]+1669314745555 -> ./../../../Users/<user>/<path>/my-shared-workspace/dist/my-buttons

Nachdem Sie die Arbeit an Ihren Änderungen lokal abgeschlossen haben, können Sie die Verwendung der verknüpften Bibliothek in der Clientanwendung auf folgende Weise beenden

my-application> npm unlink @my-company/my-buttons --no-save

my-shared-workspace/dist/my-buttons> npm rm -g @my-company/my-buttons

Materialien