با استفاده از Angular element ، یک کامپوننت با قابلیت استفاده مجدد بسازید

گردآوری و تالیف : عرفان کاکایی
تاریخ انتشار : 01 مهر 1397
دسته بندی ها : انگولار

استفاده مجدد از کد می‌تواند در هر پروژه نرم‌افزاری قابل توجه باشد. توسعه دهندگان با استفاده مجدد از کد، می‌توانند تا حد زیادی از هدر رفتن زمان جلوگیری کنند. به همین علت است که تمام فریم‌وورک‌ها برای توسعه نرم‌افزار، راهی برای در محفظه قرار دادن (Encapsulate کردن) عملکردها و استفاده مجدد از آن‌ها را دارند. چه مسئله کلاس‌های C# باشد، چه Java و چه ماژول‌ها در JavaScript، حتما شما هم به فکر استخراج بخشی از قطعه کدها و استفاده مجدد از آن‌ها در یک جای دیگر افتاده‌اید. تا به حال، تنها جایی که زیاد از کد مجددا در آن استفاده نمی‌شود، HTML است.

پروژه‌هایی مانند Stencil، SkateJS و حال عناصر Angular ساخت کامپوننت‌ها در فریم‌وورک‌ها و خروجی گرفتن آن‌ها به عنوان کامپوننت‌های وب را برای توسعه دهندگان آسان‌تر کرده‌اند، تا بتوانند بعدا از آن‌ها در پروژه‌های خود استفاده کنند که شاید در این فریم‌وورک‌ها نوشته نشده باشند. در این آموزش، نحوه ساخت یک عنصر Angular و استفاده از آن در HTML را به شما نشان خواهم داد.

مواردی که برای شروع کار با عناصر Angular نیاز خواهید داشت

برای شروع کار با عناصر Angular، تنها به چند چیز نیاز خواهید داشت:

  • Angular CLI
  • NPM (من از نسخه 6.2.0 استفاده می‌کنم)
  • Node (من از نسخه 10.8.0 استفاده می‌کنم)

من از Visual Studio Code استفاده می‌کنم؛ زیرا بسیار سبک و سریع است و بر روی تمام پلتفرم‌ها کار می‌کند، اما این مسئله اجباری نیست.

پروژه Angular خود را شروع کنید

با استفاده از Angular CLI، یک پروژه Angular جدید بسازید:

ng new login-element

ممکن است متوجه شده باشید که پروژه ایجاد شده، برخی آسیب‌پذیری‌ها را در Dependencyهای خود دارد. می‌توانید تمام آن‌ها را با کد «npm audit fix --force» در داخل شاخه login-element بر طرف کنید. من پس از انجام این کار دیگر مشکلی نداشتم، اما محض احتیاط خودتان باز هم آسیب‌پذیری‌ها را با اجرای برنامه، بررسی کنید.

پس از این که Angular CLI با موفقیت ساخت پروژه جدید و نصب Dependencyها را به پایان رساند، به شاخه login-element تغییر مکان داده، و @angular/elements را با استفاده از دستور ng add به پکیج اضافه کنید.

ng add @angular/elements --project=login-element

این دستور پکیجهای @angular/elements، به همراه هر چیزی که برای ساخت کامپوننت‌های وب نیاز دارد، مانند document-register-element، که یک نسخه سبک از مشخصه W3C Custom Element است را اضافه می‌کند. گرچه، مشکلی در این پکیج وجود دارد. نسخه‌ای که در هنگام نوشتن این مقاله نصب شد، نسخه 1.11.0 بود که من نتوانستم در Chrome 68 به کار بگیرم. پس از تحقیق، متوجه شدم که بهترین راه این است که نسخه پکیج Document Register Element را به 1.8.1 برگردانم؛ زیرا پشتیبانی بهتری در زمینه عناصر سفارشی در میان مرورگرها دارد. آسان‌ترین راه این است که فایل package.json خود را ویرایش کرده، و document-register-element را از 1.7.1 به 1.8.1 تغییر دهید و دستور npm install را مجددا اجرا کنید.

چرا Okta برای احراز هویت؟

احراز هویت چیزی است که تقریبا تمام وب‌اپلیکیشن‌ها امروزه به آن نیاز دارند. همچنین احراز هویت چیزی است که می‌تواند یک عذاب بزرگ برای توسعه دهنده باشد. نه فقط صفحه ورود، بلکه یک identity provider برای رسیدگی به ساخت و مدیریت کاربران. از آنجایی که شما در حال ساخت یک کامپوننت با قابلیت استفاده مجدد خواهید بود، باید یک سرویس هویت را راه‌اندازی کنید تا به ورود و مدیریت کاربر رسیدگی کنید. در اینجا Okta یک انتخاب عالی است؛ زیرا ساخت، مدیریت و احراز هویت کاربر را بسیار ساده می‌کند.

می‌توانید بر روی وبسایت آن یک حساب کاربری توسعه دهنده بسازید، و سپس آماده شروع کار خواهید بود.

یک برنامه Okta بسازید

برای شروع کار، باید یک برنامه OpenID Connect در Okta بسازید.

پس از این که وارد شدید و در صفحه داشبورد قرار گرفتید، یو‌آر‌اِل Org که در تصویر زیر مشخص شده است را کپی کنید. شما بعدا به این مورد نیاز خواهید داشت.

سپس با مرور تب Applications، کلیک بر روی Add Application و انتخاب Single-Page App، یک برنامه جدید بسازید.

بر روی صفحه تنظیمات، این مقادیر را وارد کنید:

  • Name: کامپوننت ورود
  • Base URIs: http://localhost:8081
  • Login redirect URIs: http://localhost:8081/implicit/callback

می‌توانید باقی موارد را دست نخورده باقی گذاشته، و بر روی Done‌ کلیک کنید.

حال که برنامه شما ساخته شده است، مقدار Client ID را در صفحه زیر کپی کنید، زیرا به زودی به آن نیاز خواهید داشت.

در آخر، باید پکیج @okta/okta-auth-js را وارد کنید، تا ورود اصلی به Okta را انجام دهد.

npm install @okta/okta-auth-js --save

حال شما آماده ساخت کامپوننت خود هستید.

عناصر Angular خود را بسازید

برای راحتی در استفاده، شما از فایل app.component.ts برای ساخت کامپوننت ورود خود استفاده خواهید کرد. انتخاب کننده اهمیتی نخواهد داشت؛ زیرا وقتی که کامپوننت خود را برای خروج آماده می‌کنید، آن موقع یک انتخاب کننده را اختصاص خواهید داد.

کامپوننت app.component.ts باید چنین ظاهری داشته باشد:

import { Component, Input, ViewEncapsulation, OnInit } from '@angular/core';

import * as OktaAuth from '@okta/okta-auth-js';

@Component({

  selector: 'login-element',

  templateUrl: './app.component.html',

  styleUrls: ['./app.component.css'],

  encapsulation: ViewEncapsulation.Native

})

export class AppComponent implements OnInit {

  @Input()

  companyName = 'ACME Corporation';

  @Input()

  oktaUrl: string;

  @Input()

  clientId: string;

  authClient: any;

  isAuthenticated: boolean;

  username: string;

  password: string;

  token: any;

  ngOnInit() {

    console.log(this.companyName, this.oktaUrl, this.clientId);

    this.authClient = new OktaAuth({

      url: this.oktaUrl,

      issuer: `${this.oktaUrl}/oauth2/default`,

      redirectUri: `http://localhost:${window.location.port}/implicit/callback`,

      clientId: this.clientId

    });

    this.token = this.authClient.tokenManager.get('idToken');

    if (this.token) {

      this.isAuthenticated = true;

      this.username = this.token.claims.email;

    } else {

      this.isAuthenticated = false;

    }

  }

  async login(username, password) {

    let signInResponse: any;

    try {

      signInResponse = await this.authClient.signIn({ username, password });

      if (signInResponse.status === 'SUCCESS') {

        this.token = await this.authClient.token.getWithoutPrompt({

          sessionToken: signInResponse.sessionToken,

          responseType: 'id_token',

          scopes: ['openid', 'email', 'profile']

        });

        if (this.token) {

          this.authClient.tokenManager.add('idToken', this.token);

          this.isAuthenticated = true;

          this.username = this.token.claims.email;

        }

      } else {

        throw `transaction status ${

          signInResponse.status

        } could not be handled.`;

      }

    } catch (error) {

      console.log(error);

    }

  }

}

در اینجا موارد زیادی برای بحث وجود دارند. در ابتدا، قرارگیری در محفظه (Encapsulate شدن) برای کامپوننت را برابر با ViewEncapsulation.Native قرار داده‌ایم. این تضمین می‌کند که کامپوننت مورد نظر از Shadom DOM استفاده می‌کند. شما همچنین Dependency جاوااسکریپت Okta را وارد کرده‌اید.

سپس، در اینجا سه @Input وجود دارد. companyName صرفا به صورت نمایشی است، اما oktaUrl و clientId برای کار کردن کامپوننت مورد نیاز خواهند بود. ساختن این ورودی‌ها یعنی این که کاربران کامپوننت می‌توانند این مقادیر را برابر با Okta Org Url خود قرار داده، و ClientId خود را نیز تعیین کنند. همچنین در متد ngOnInit شما بررسی می‌کنید تا ببینید که آیا کاربر از قبل وارد شده است یا نه. این بخش نشانه کاربر را از tokenManager می‌گیرد و به کامپوننت می‌گوید که اگر کاربر در زمان بارگذاری صفحه از قبل وارد شده است، پیغام خوش‌آمدگویی را به جای فرم ورود نمایش دهد. این کد همچنین به یک بارگذاری مجدد صفحه رسیدگی می‌کند.

در آخر، متد login(). این متد از آبجکت Okta authClient استفاده می‌کند تا به Okta وارد شود، و سپس وقتی که یک نشانه session از Okta با استفاده از یک نام کاربری و رمز عبور گرفت، یک id_token را با استفاده از ایمیل و پروفایل کاربر بگیرد. هر دوی این‌ها promiseهایی را بر می‌گردانند که شما در حال await کردن هستید، تا همه چیز را کمی خواناتر کنید.

سپس، به عناصر HTML اصلی برای کامپوننت خود نیاز خواهید داشت. محتویات فایل app.component.html را با این موارد جایگزین کنید:

<section class="login-form">

  <h1>{{companyName}} Login</h1>

  <div *ngIf="!isAuthenticated">

    <input type="email" #username name="username" id="username" placeholder="username">

    <input type="password" #password name="password" id="password" placeholder="password">

    <button (click)="login(username.value, password.value)">Login</button>

  </div>

  <div class="greeting" *ngIf="isAuthenticated">

    Welcome {{username}}!

  </div>

</section>

اگر مقداری تجربه قبلی در Angular داشته باشید، کد بالا کاملا ساده است. این کد فقط وقتی که کاربر وارد نشده باشد صفحه ورود را نمایش می‌دهد، و اگر وارد شده باشد هم پیغام خوش‌آمدگویی را نمایش می‌دهد. دکمه فرم ورود، متد login() را با نام کاربری و رمز عبور وارد شده، فراخوانی می‌کند.

کمی استایل به آن اضافه کنید تا کمتر خسته کننده شود:

.login-form {

  border: solid 1px #666;

  padding: 1rem;

  border-radius: 0.5rem;

  width: 25%;

  margin: auto;

}

input,

button {

  display: block;

  padding: 0.25rem;

  border-radius: 0.25rem;

  width: 95%;

  margin: 0.5rem;

}

.greeting {

  font-weight: bold;

  font-style: italic;

  font-size: 1.25rem;

}

حال شما یک کامپوننت دارید. تنها کاری که باید انجام دهید، این است که به Angular بگویید که این کامپوننت یک عنصر Angular است، و سپس هم آن را بسته بندی کنید تا بتوانید برای دوستان خود ارسال کنید.

کامپوننت را تبدیل به یک عنصر Angular‌ کنید

برای اطمینان از این که Angular می‌داند این کامپوننت قرار است که یک عنصر Angular با قابلیت استفاده مجدد باشد، باید مقداری تغییرات به فایل app.module.ts اعمال کنید:

import { BrowserModule } from '@angular/platform-browser';

import { NgModule, Injector } from '@angular/core';

import { createCustomElement } from '@angular/elements';

import { AppComponent } from './app.component';

@NgModule({

  declarations: [AppComponent],

  imports: [BrowserModule],

  providers: [],

  entryComponents: [AppComponent]

})

export class AppModule {

  constructor(private injector: Injector) {

    const el = createCustomElement(AppComponent, { injector });

    customElements.define('login-element', el);

  }

  ngDoBootstrap() {}

}

اولین چیزی که ممکن است درباره کد ماژول متوجه شوید این است که یک آرایه entryComponent را به اعلامیه @NgModule اضافه می‌کند. این به Angular می‌گوید که به جای bootstrap کردن برنامه Angular از AppComponent، شما آن را کمپایل خواهید کرد تا از آن به عنوان یک کامپوننت وب استفاده کنید. همچنین، AppModule حال یک constructor دارد تا تابع createCustomElement() را راه‌اندازی کند که AppComponent و تزریق کننده (injector) را می‌گیرد. این تزریق کننده برای ساخت نمونه‌های جدید از کامپوننت استفاده خواهد شد که به صورت مستقل از یکدیگر کار می‌کنند. سپس شما عنصر سفارشی و انتخاب کننده login-element را تعریف می‌کنید، که برای استفاده شدن در برنامه‌های دیگر تعریف خواهد شد. متد آخر یعنی ngDoBootstrap()، از آنجای که یک برنامه Angular طبیعی نخواهد بود، فرایند bootstrap کردن طبیعی عنصر را دور می‌زند.

عناصر Angular خود را پکیچ کنید

حال شما آماده‌اید که این عناصر را پکیج کنید. راه‌های زیادی برای انجام این کار وجود دارد، اما در اینجا برخی پکیج‌های node ساده راخواهید دید، که یک اسکریپت node می‌سازند تا بتوانید همه چیز را در یک فایل جمع کنید. به طور پیشفرض، Angular CLI چهار فایل خواهد ساخت. برای دیدن آن‌ها، سعی کنید این دستور را اجرا کنید:

ng build --prod

در اینجا خواهید دید که یک پوشه به نام dist با چهار فایل JavaScript در داخل خود ساخته شده است. این فایل‌ها برخی کاراکترهای hash را به عنوان نام خود خواهند داشت، و کار کردن با آن‌ها کمی سخت‌تر از توزیع معمولی یک برنامه برای استفاده مردم است. برای جلوگیری از این مسئله، برخی پکیج‌های npm را نصب کنید تا به شما کمک کنند:

npm install --save-dev concat fs-extra

سپس فایل جدیدی به نام build-elements.js را در شاخه ریشه پروژه بسازید،‌ تا بعدا از آن استفاده کنید و تمام اسکریپت‌های npm خود را در یک فایل جمع کنید:

const fs = require('fs-extra');

const concat = require('concat');

(async function build() {

  const files = [

    './dist/air/runtime.js',

    './dist/air/polyfills.js',

    './dist/air/scripts.js',

    './dist/air/main.js'

  ];

  await fs.ensureDir('elements');

  await concat(files, 'elements/login-element.js');

})();

حال برای اطمینان از این که این فایل اجرا شده و هر کدام از فایل‌های مورد نظر را پیدا می‌کند، اسکریپت جدیدی به فایل package.json اضافه کنید. من اسکریپت خود را دقیقا بعد از اسکریپت build اضافه کردم:

"build:elements": "ng build --prod --output-hashing none && node build-elements.js",

این اسکریپت، ng build --prod را با غیر فعال کردن hashing اجرا می‌کند، تا فایل‌ها نامی مانند main.0476473b3749bc742\928d.js را به جای main.js نداشته باشند، و یافتن آن‌ها برای build-elements.js راحت‌تر شود.

حال با اجرای این کد آن را بسازید:

npm run build:elements

حال خواهید دید که پوشه جدیدی به نام elements در پوشه ریشه شما به همراه یک فایل در خود ساخته شده است: ligon-element.js که می‌توانید به راحتی از آن در هر جایی استفاده کنید.

از عناصر Angular خود استفاده کنید

در پوشه جدید یعنی elements، فایلی به نام Index.html بسازید و این محتویات را به آن اضافه کنید، و مقادیر صفت را با مقادیر مشخص خود جایگزین کنید:

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <meta http-equiv="X-UA-Compatible" content="ie=edge">

  <title>Document</title>

  <base href="/">

</head>

<body>

  <login-element company-name="{yourCompanyName}" okta-url="https://{yourOktaDomain}" client-id="{yourClientId}"></login-element>

  <script type="text/javascript" src="login-element.js"></script>

</body>

</html>

شما می‌توانید این را سریعا با استفاده از یک سرور HTTP داخلی اجرا کنید. http-server یک پکیج ساده است که برای هر پوشه‌ای که به عنوان یک فولدر وب اجرا می‌شود، حکم سرور را دارد. آن را با استفاده از این دستور نصب کنید:

npm install -g http-server

سپس سرور HTTP را از داخل پوشه elements اجرا کنید.

http-server

وقتی که به آدرس http://localhost:8081 بروید، خواهید دید که کامپوننت ورود نمایش داده می‌شود. می‌توانید با مدارک Okta خود وارد شوید و ببینید که کامپوننت تغییر می‌کند، تا نام کاربری شما را در پیغام خوش‌آمدگویی نمایش دهد.

حال شما یک فایل تکی دارید که می‌توانید آن را توزیع کرده، و از آن مجددا استفاده کنید، و به هر وب‌اپلیکیشنی ورود Okta را اضافه کنید. چه برنامه مورد نظر در Angular، React، Vue یا فقط HTML و JavaScript ساده نوشته شده باشد.

همچنین بخوانید:

منبع

مقالات پیشنهادی

8 دليلي كه نبايد از يك مديريت محتوا استفاده كنيد

من تمايل دارم افرادي رو پيدا كنم كه در قدم اول ميخوان به مشتريان چنين ايده اي رو، ترويج بدن كه اون ها ميتونن سايت خودشون رو "به راحتي به كمك يه واژه پ...

با استفاده از Nuxt.js، یک وب‌اپلیکیشن پیش‌رونده بسازید

از زمان معرفی شدن وب‌اپلیکیشن‌ها توسط گوگل و از آنجایی که بسیاری از وب‌اپلیکیشن‌های سنتی در حال تبدیل شدن به وب‌اپلیکیشن‌های پیش‌رونده هستند، میزان پذ...

آیکون های فروشگاهی و بازاریابی

در این پست لذت بخش من میخوام به شما یک مجموعه از آیکون های زیبا و ضررویه بازاریابی و فروشگاهی رو معرفی کنم که شامل +100 آیکون Swificons با 3 نوع مختلف...

ساخت یک برنامه چت Realtime با استفاده از اندروید، Node.js و Socket.io

WebSocketها ابزار زیبایی هستند که ما را قادر می‌سازند تا یک ارتباط Realtime در وب‌اپلیکیشن‌های مدرن برقرار کنیم. در واقع،‌ این مکانیزم بسیار قدرتمند ب...