Cách phát triển thư viện Angular tại địa phương

Nov 25 2022
Xin chào ! Trong câu chuyện này, tôi muốn chỉ cho bạn cách làm việc cục bộ với các thư viện Angular và phát triển chúng mà không cần phải liên tục đẩy chúng vào kho lưu trữ từ xa :) DRY - cách tránh lặp lại mã Nếu bạn làm việc trong một dự án Angular lớn và phức tạp , tôi chắc chắn rằng bạn sẽ gặp phải sự cố sao chép mã. Ví dụ: hãy tập trung vào “giao diện” của ứng dụng của bạn - tất cả các trang có thể phải có kiểu nhất quán (bạn không muốn làm người dùng nhầm lẫn và có các nút trông khác nhau trên mỗi trang).
Ảnh của Ryunosuke Kikuno trên Bapt

Xin chào ! Trong câu chuyện này, tôi muốn chỉ cho bạn cách làm việc cục bộ với các thư viện Angular và phát triển chúng mà không cần phải liên tục đẩy chúng vào kho lưu trữ từ xa :)

DRY - cách tránh lặp lại mã

Nếu bạn làm việc trong một dự án Angular lớn và phức tạp, tôi chắc chắn rằng bạn sẽ gặp phải vấn đề sao chép mã. Ví dụ: hãy tập trung vào “giao diện” của ứng dụng của bạn - tất cả các trang có thể phải có kiểu nhất quán (bạn không muốn làm người dùng nhầm lẫn và có các nút trông khác nhau trên mỗi trang). Ok, thật dễ dàng - bạn chỉ cần di chuyển các kiểu phổ biến đó vào styles.scsstệp hoặc sử dụng mẫu 7–1 để thiết kế nó một cách trang nhã.

Nhưng điều gì sẽ xảy ra nếu bạn có một số thành phần chung không chỉ trông giống nhau mà còn hoạt động giống nhau? Nó… vẫn còn dễ dàng! Chỉ cần tạo một mô-đun dùng chung trong ứng dụng của bạn, xác định các thành phần của bạn ở đó và xuất chúng trong định nghĩa mô-đun. Tuyệt quá !

Bây giờ, hãy tập trung vào vấn đề phức tạp hơn. Nếu công ty của bạn có nhiều hơn một ứng dụng Angular thì sao? Và mỗi ứng dụng sẽ trông giống nhau, ví dụ:

  • có cùng đầu trang và chân trang
  • có cùng kiểu CSS công ty
  • có cùng cách hiển thị biểu mẫu, lỗi xác thực và các thông báo khác

tạo thư viện

Tại đây bạn có thể tìm thấy trang tài liệu chính thức về cách tạo thư viện. Hãy làm theo các bước được mô tả ở đó và tạo thư viện của chúng tôi:

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

  • my-shared-workspace là không gian làm việc chung cho các thư viện của bạn
  • my-buttons là một thư viện ví dụ mà bạn có thể sử dụng lại trong các dự án khác

{
  "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

Thành phần được tạo, vì vậy chúng tôi có thể cập nhật mẫu của nó để hiển thị một nút

<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

Chúng tôi đã tạo thư viện của mình, vì vậy bây giờ là lúc dành cho ứng dụng khách. Tôi sẽ sử dụng CLI góc để tạo nó: ng new my-applicationvà tôi sẽ thêm @my-company/my-buttonslàm phần phụ thuộc vào phần phụ thuộc của ứng dụng package.json(phần phụ thuộc cuối cùng, sau 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/ **

Bạn cũng sẽ thấy một số lỗi khác như:

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

Tại đây bạn có thể tìm thấy tài liệu lệnh liên kết npm hoàn chỉnh. Tôi sẽ chỉ cho bạn cách sử dụng lệnh này để phát triển thư viện dùng chung cục bộ, với tính năng tải lại trực tiếp.

Hãy quay lại thư mục my-shared-workspace, xây dựng my-buttonsthư viện (cờ --watchchịu trách nhiệm tải lại trực tiếp) và vào thư mục của bản dựng

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

Trong thư mục my-application, angular.jsonthêm một tùy chọn nữa - bảo quảnSymlinks, tùy chọn này sẽ cho phép chúng tôi sử dụng thư viện được liên kết này.

{
  "$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

Sau đó chạy ng servelại:

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.

Hãy xem kết quả:

Tuyệt quá ! Bây giờ hãy thử thay đổi một cái gì đó trong Fancy-button-component.html

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

Bây giờ bạn có thể làm việc trên cả thư viện và ứng dụng mà không gặp bất kỳ sự bất tiện nào :)

xác minh

Để xác minh phiên bản thư viện bạn đang sử dụng, bạn có thể chạy lệnh dưới đây:

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

Sau khi bạn hoàn thành các thay đổi cục bộ, bạn có thể ngừng sử dụng thư viện được liên kết trong ứng dụng khách theo cách sau

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

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

Vật liệu