분류 기타

Chrome 확장 프로그램 : 코드 재사용(4)

컨텐츠 정보

  • 조회 11 (작성일 )

본문

이 시리즈가 처음이고 이전 게시물을 읽고 싶지 않다면 다음과 같은 간단한 요약을 참조하십시오.


  • 나는 모든 포스트에서 업데이트하고 개선 한 매우 간단한 크롬 확장 프로그램을 만드는 이 시리즈를 시작했습니다.
  • 우리가 작업하고 있는 크롬 확장 프로그램은 "Acho, 우리는 어디에 있습니까?"라고 합니다.
  • Acho는 내 강아지 🐶의 이름이며,이 확장에서 그는 짖고 현재 탐색 중인 페이지의 제목을 알려줍니다.
    -, 브라우저 작업을 통해 (Chrome의 탐색 모음 오른쪽에 나타나는 팝업)
    -, 또는 화면 오른쪽 하단에 알림을 표시하는 키보드 단축키를 사용합니다.

소개 


지금까지 확장 기능에는 다음과 같은 기능이 있습니다.


  • 활성 탭의 제목과 함께 브라우저 작업 (팝업)을 표시합니다.
  • 현재 탭을 복제하는 명령
  • 활성 탭 제목과 함께 화면 오른쪽 하단에 알림을 표시하는 명령입니다.

다음은 이러한 기능의 논리를 관리하기 위해 구축 한 구성 요소입니다.


Three components (popup.js, background.js, and content.js) with their primary functions. The popup.js has the following functions: Listen OnLoad, Get active tab, and Show tab title. The background.js has the following functions: Listen OnCommand, Duplicate tab, Send a message to the content script, Get active tab. The content.js has the following functions: Build notification and Show tab title. 


"활성 탭 가져 오기"및 "탭 제목 표시"기능은 여러 구성 요소에서 사용되지만 현재는 해당 논리가 각 구성 요소 내부에 복제됩니다. 상상 하셨겠지만, 우리는 그 논리를 한 번만 작성하고 프로젝트 전체에서 공유 할 방법을 찾아야 합니다.


ℹ️ 재사용성 정보 : 코드를 재사용 하면 시간을 절약하고 프로젝트의 중복성을 줄일 수 있습니다. 동일한 코드를 여러 번 작성하는 것을 피함으로써 코드가 더 깨끗해지고 공유 논리에 대한 업데이트가 한 곳에서 수행 될 수 있기 때문에 프로젝트를 더 쉽게 유지 관리 할 수 ​​있습니다.


따라서 더 나은 버전의 앱은 다음과 같습니다.


The functions Get active tab and Show tab title appear a single time inside a new file called acho.js and are shared with popup.js, background.js, and content.js 


이 버전에서 컴포넌트는 특정 로직에 대해서만 책임이 있으며 공유 로직은 acho.js 파일에서 분리되어 쉽게 유지 및 공유 할 수 있습니다. 중복 된 논리도 없습니다.


샘플 크롬 확장에서 이를 달성하는 방법을 살펴 보겠습니다.


공유 논리를 별도의 파일로 중앙 집중화 


우선, 우리는 재사용 가능한 로직이 별도의 파일에 집중되어야 합니다. 그래서 우리는 acho.js라는 새 파일을 만들 것입니다. 여기에서 Acho라는 클래스를 만들고 나중에 각 구성 요소에서 호출 할 메서드를 추가합니다.


실제 예에서는 공유 논리에 대해 둘 이상의 파일을 사용할 수 있습니다. 예제를 단순하게 유지하기 위해 하나만 사용합니다.


acho.js 파일은 다음과 같습니다.


/** Shared logic */
class Acho {

    /**
     * Gets the active Tab
     * @returns {Promise<*>} Active tab
     */
    getActiveTab = async () => {
        const query = { active: true, currentWindow: true };
        const getTabTitlePromise = new Promise((resolve, reject) => {
            chrome.tabs.query(query, (tabs) => {
                resolve(tabs[0]);
            });
        });
        return getTabTitlePromise;
    }

    /**
     * Concatenates the tab title with Acho's barks.
     * @param {String} tabTitle Current tab title
     * @returns {String} 
     */
    getBarkedTitle = (tabTitle) => {
        const barkTitle = `${this.getRandomBark()} Ahem.. I mean, we are at: 
${tabTitle}` return barkTitle; } /** * Array of available bark sounds * @private * @returns {String[]} */ getBarks = () => { return [ 'Barf barf!', 'Birf birf!', 'Woof woof!', 'Arf arf!', 'Yip yip!', 'Biiiirf!' ]; } /** * Returns a random bark from the list of possible barks. * @private * @returns {String} */ getRandomBark = () => { const barks = this.getBarks(); const bark = barks[Math.floor(Math.random() * barks.length)]; return bark; } }


두 가지 공개 방법이 있습니다.

  • getActiveTab은 활성 탭을 반환합니다.
  • getBarkedTitle은 임의의 짖는 소리와 탭 제목이 연결된 문자열을 생성합니다. 브라우저 작업 (팝업)과 알림 모두에서 사용합니다.

그런 다음 공개 메소드의 논리를 단순화하기 위한 몇 가지 비공개 메소드가 있습니다.


재사용 가능한 코드에 액세스 


큰. 이제 재사용 가능한 로직을 많은 구성 요소에서 사용할 준비가 되었지만 그게 다가 아닙니다. 각 구성 요소에서 이 논리에 액세스하는 방법을 알아 내야 합니다.

  • 백그라운드 스크립트 (background.js)
  • 콘텐츠 스크립트 (content.js)
  • 브라우저 작업 스크립트 (popup.js)

이 문제에 접근하려면 이러한 모든 구성 요소가 동일한 확장의 일부이지만 다른 컨텍스트에서 실행된다는 점을 기억하는 것이 중요합니다.


  • popup.js는 브라우저 액션의 컨텍스트에서 실행됩니다.
  • 콘텐츠 스크립트는 웹 페이지의 컨텍스트에서 실행됩니다.
  • 백그라운드 스크립트는 브라우저에 의해 트리거 된 이벤트를 처리하며 필요할 때만 로드됩니다. 현재 웹 페이지 및 브라우저 작업과 독립적으로 작동합니다.

그렇다면 이러한 다양한 컨텍스트에서 재사용 가능한 코드를 어떻게 사용할 수 있습니까?


브라우저 액션에서 


이것은 우리가 구현할 솔루션이 정적 HTML + JS 웹 사이트에서 수행하는 작업이기 때문에 익숙 할 것입니다. 브라우저 작업 HTML 파일 (popup.html)에 스크립트로 acho.js 파일을 추가 할 것입니다. ) <script> 태그 사용 :


popup.html 파일을 열고 <body> 태그의 맨 아래에 다음과 같이 스크립트를 추가하십시오.


<body>
    <!-- the rest of the body -->

    <script src='popup.js'></script> 
    <script src='acho.js'></script> <!-- 👈 -->
</body>


끝난! 이제 popup.js의 Acho 클래스를 사용할 수 있으며 코드가 크게 줄어들 것입니다.



document.addEventListener('DOMContentLoaded', async () => {

    const dialogBox = document.getElementById('dialog-box');
    const query = { active: true, currentWindow: true };

    const acho = new Acho(); // 👈
    const tab = await acho.getActiveTab();
    const bark = acho.getBarkedTitle(tab.title);

    dialogBox.innerHTML = bark;
});


콘텐츠 스크립트에서 


여기에 있는 해결책은 명확하지 않을 수 있지만 매우 간단합니다. manifest.json 파일의 현재 콘텐츠 스크립트 객체 내에서 js 배열에 acho.js를 추가하기 만하면 됩니다.


{
    "manifest_version": 2,
    "name": "Acho, where are we?",
    ... 
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["content.js", "acho.js"], // 👈
            "css": ["content.css"]
        }
    ],
}


이제 content.js의 Acho 클래스를 인스턴스화하고 사용하여 "barked title"문자열을 생성 할 수 있습니다.


// Notification body.
const notification = document.createElement("div");
notification.className = 'acho-notification';

// Notification icon.
const icon = document.createElement('img');
icon.src = chrome.runtime.getURL("images/icon32.png");
notification.appendChild(icon);

// Notification text.
const notificationText = document.createElement('p');
notification.appendChild(notificationText);

// Add to current page.
document.body.appendChild(notification);

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {

    const notification = document.getElementsByClassName('acho-notification')[0];
    const notificationText = notification.getElementsByTagName('p')[0];

    // 👇👇👇
    const acho = new Acho();
    notificationText.innerHTML = acho.getBarkedTitle(request.tabTitle); 

    notification.style.display = 'flex';

    setTimeout(function () {
        notification.style.display = 'none';
    }, 5000);

    return true;
});



백그라운드 스크립트에서 


솔루션은 비슷합니다. manifest.json에있는 배경 객체의 스크립트 배열에 acho.js를 추가해야 합니다.


{
    "manifest_version": 2,
    "name": "Acho, where are we?",
    ... 
    "background": {
        "scripts": [ "background.js", "acho.js" ], // 👈
        "persistent": false
    }
}



마찬가지로 이제 background.js에서 Acho 클래스에 액세스 할 수 있습니다.


chrome.commands.onCommand.addListener(async (command) => {
    switch (command) {
        case 'duplicate-tab':
            await duplicateTab();
            break;
        case 'bark':
            await barkTitle();
            break;
        default:
            console.log(`Command ${command} not found`);
    }
});

/**
 * Gets the current active tab URL and opens a new tab with the same URL.
 */
const duplicateTab = async () => {
    const acho = new Acho(); // 👈 
    const tab = await acho.getActiveTab();

    chrome.tabs.create({ url: tab.url, active: false });
}

/**
 * Sends message to the content script with the currently active tab title.
 */
const barkTitle = async () => {
    const acho = new Acho(); // 👈 
    const tab = await acho.getActiveTab();

    chrome.tabs.sendMessage(tab.id, {
        tabTitle: tab.title
    });
}



acho.getActiveTab()의 약속을 기다릴 수 있도록 함수를 비 동기화 해야 했습니다. 원하는 경우 대신 acho.getActiveTab(). then ((tab) => {})을 사용할 수 있습니다.


그게 다야! 이제 모든 컴포넌트가 acho.js의 로직을 재사용하고 있습니다.


결론 


공유 논리를 포함하는 별도의 파일을 만들고 다른 전략을 사용하여 모든 구성 요소에서 해당 파일을 사용할 수 있도록 함으로써 중복 된 코드를 제거하고 재사용 성을 적용 할 수 있었습니다.


이제 확장 프로그램의 코드를 읽고 유지하기가 더 쉽습니다 👌


저장소 


저장소에서 내 모든 Chrome 확장 프로그램 예제를 찾을 수 있습니다.


https://dev.to/paulasantamaria/chrome-extensions-reusing-code-3f1g