+4

Làm quen với chrome extension

Trong các trình duyệt hiện đại ngày nay, hầu hết chúng đều hộ trợ những tiện ích mở rộng (extensions) nhằm giúp bổ sung những tính năng hữa ích cho trình duyệt. Đi đầu về hộ trợ extension phải kể đến Firefox. Từ rất lâu, extension chính là điểm mạnh nhất của Firefox. Tuy nhiên, với sự phát triển mạnh mẽ của Google chrome, nó đã nổi lên là một trình duyệt được nhiều người dùng nhất, cùng với đó là sự quan tâm của các lập trình viên trong việc xây dựng extension cho nó. Trong bài viết này tôi muốn giới thiệu với các bạn những khái niệm, thành phần cơ bản trong một chrome extension, đồng thời demo một extension nhỏ để lấy thông tin của một pull request trên github. Trước tiên, chúng ta sẽ đi tìm hiểu chrome extension là gì và thành phần cơ bản của nó gồm những gì.

1. Tổng quan

Extension là một tập các file như: Html, css, javascript, images và bất kì những thành phần khác mà bạn cần được nén lại trong một thư mục. Nó nhằm mục đích mở rộng những chức năng cho trình duyệt Google Chrome. Extentions về cơ bản là những web pages, chúng có thể sử dụng tất cả các APIs mà trình duyệt cung cấp, từ XMLHttpRequest tới JSON, HTML5. Như các bạn có thể thấy nó thực sự không quá phức tạp như chúng ta nghĩ.

2. Các thành phần chính

2.1 Extension UIs

Mỗi extension có thể có một browser action hoặc page action. Chọn một browser action khi extension là liên quan đến hầu hết các trang. Chọn một page action khi nó các tác dụng trên những trang nhất định. Những extensions có thể trình diễn theo những cách khác như: thêm context menu, cung cấp một option page, hoặc sử dụng content script để thay đổi hiển thị trên web page,...Các bạn có thể biết một số ví dụ về extension UI:

Google Mail Checker extension Mappy extension Set Page Color extension

2.2 Files

Mỗi extension về cơ bản có những file sau:

  • Một file manifest
  • Một hoặc nhiều file HTML
  • Optional: Một hoặc nhiều file JavaScript
  • Optional: Bất kì file gì mà bạn cần, ví dụ: images

Manifest File manifest là một file json nhằm cung cấp các thông tin cơ bản về extension như: Name, version, description, icon, backgroud, permisions, browser_action, ... Các bạn có thể tìm hiểu chi tiết về cấu hình file manifest tại đây. Dưới đây là một minh họa cho file manifest:

{
  "name": "My Extension",
  "version": "2.1",
  "description": "Gets information from Google.",
  "icons": { "128": "icon_128.png" },
  "background": {
    "persistent": false,
    "scripts": ["bg.js"]
  },
  "permissions": ["http://*.google.com/", "https://*.google.com/"],
  "browser_action": {
    "default_title": "",
    "default_icon": "icon_19.png",
    "default_popup": "popup.html"
  }
}

3. Kiến trúc của extension

3.1 Backgroud page

Backgroud pages được định nghĩa bởi backgroud.html có thể bao gồm code JavaScript để điều khiển các sự kiện của extension. Có hai kiểu backgroud pages: persistent backgroud pages và event pages. Persistent backgroud pages luôn luôn mở. Còn event pages chỉ mở khi cần. Khuyến khích sử dụng event page trừ khi bạn cần backgroud page chạy trong mọi thời điểm.

3.2. UI pages

Extension có thể chứa những trang HTML thông thường nhằm hiển thị UI của extension. một browser action có thể có một popup, cũng được xây dựng bởi html. Bất kì extension nào cũng có thể có một option page, cái mà cho người dùng tùy chỉnh hoạt động của extension. Một kiểu page đặc biệt khác là override page. Và cuối cùng, bạn có thể sử dụng tabs.create hoặc window.open() để hiển thị những file html khác nữa. Hình dưới đây minh họa các thành phần UI cơ bản của extension:

3.3 Content scripts

Làm thế nào để extension có thể tương tác với trang web hiện tại ? Câu hỏi này được trở lời bởi content script, các bạn chỉ có thể lấy thông tin, thay đổi, thêm mới các element trên trang web với content script. Các bạn không thể làm điều này trên các đối tượng backgroud hay popup. Hình dưới mô tả vai trò của content script:

Content scripts không hoàn toàn cắt đứt liên hệ với extension cha của chúng. Nó có thể trao đổi thông điệp với extension cha. Ví dụ một content script có thể gửi thông điệp bất kì khi nào tìm thấy một RSS feed trong trang web. Hoặc backgroud page có thể gửi thông điệp đến content script để thay đổi giao diện của trang web. Hình bên dưới minh họa mối quan hệ giữa chúng:

4. Xây dựng một extension đơn giản cho Google Chrome

Trong demo này tôi sẽ xây dựng một extension đơn giản để lấy một số thông tin cơ bản của một pull request trên github. Đầu tiên ta cần cấu hình file manifest

manifest.json

{
  "name": "Pull request analytics",
  "manifest_version": 2,
  "version": "1.0",
  "description": "This extension allows you analytics infomation of pull request in github",
  "icons": {
      "128": "images/icon.png"
  },
  "browser_action": {
      "default_title": "Pull request analytics",
      "default_icon": "images/icon.png",
      "default_popup": "popup.html"
  },
  "content_scripts": [
    {
      "matches": [
          "*://github.com/*"
      ],
      "js": [
          "scripts/jquery.10.2.min.js",
          "scripts/content.js"
      ],
      "run_at": "document_start"
    }
  ],
  "permissions": [
      "tabs"
  ],
  "content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
}

Bỏ qua một số thông tin cơ bản, tôi xin giải thích một số configs quan trọng:

  • "browser_action": Cấu hình này dành cho tất cả các page, bao gồm tooltip khi di chuột vào, icon, popup page khi người dùng click vào icon.
  • "content_scripts": Bao gồm "matches" chỉ định những trang mà code content.js có thể tương tác, trong trường hợp này là github.com, các trang khác nó không thể tương tác. "Js" liệt kê những file js cần thiết, kể cả thư viện bên ngoài như jquery, "run_at" chỉ định content.js chạy thời điểm nào.
  • "permissions": Chỉ định phạm vi và quyền mà extension có thể tương tác. Có thể là tabs, bookmark, storange,.. Ở đây tôi chỉ định phạm vi tương tác là các tabs.

Content.js Ở đây tôi sẽ thực hiện việc lấy thông tin trong DOM tại page hiện tại. Chúng ta hoàn toàn có thể dùng jquery để find bất kì element nào trong DOM và lấy giá trị của chúng. Có một lưu ý quan trọng ở đây là: từ content script chúng ta không thể truyền dữ liệu tới popup page (trang sẽ hiện thị thông tin của pull request hiện tại). Do vậy, có một giải pháp để thực hiện điều này, nó hơi ngược với những gì chúng ta nghĩ. Đầu tiên, khi popup bắt đầu được mở lên, tôi sẽ send một message về content script. Thực hiện như bên dưới:

window.addEventListener('DOMContentLoaded', function () {
  chrome.tabs.query({
    active: true,
    currentWindow: true
  }, function (tabs) {
    chrome.tabs.sendMessage(
        tabs[0].id,
        {from: 'popup', subject: 'DOMInfo'},
        setDOMInfo);
  });
});

Sau đó, tại content.js tôi nhận message này:

chrome.runtime.onMessage.addListener(function (msg, sender, response) {
  if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {
      var commentCount = $(".review-comments").length;
      var numberOfChangedCode = $(".text-green").html();
      numberOfChangedCode = numberOfChangedCode.replace("+", "");
      numberOfChangedCode = numberOfChangedCode.replace(",", "");
      var customerConvension = "";
      var prInfo = {
          issue: $(".issue-link").first().text(),
          author: $(".pull-header-username").text(),
          commentCount: commentCount,
          numberOfChangedCode: numberOfChangedCode,
          changedFiles: $("#files_tab_counter").text(),
          commentsPerchangedLineCode: commentCount/parseInt(numberOfChangedCode) * 100
    };

    response(prInfo);
  }
});

Như các bạn thấy ở code trên, tôi thực hiện lấy thông tin của pull request dựa trên các thẻ html có sẵn (tôi dùng jquery) như: số comment, author, issue number, tổng số dòng code thay đổi, số file thay đổi. Tiếp đó, tôi tổng hợp chúng vào một object và response nó tới popup page.

Popup.js Tại đây ngoài việc send một message gửi về content script như code phía trên, tôi cần bind những thông tin nhận được từ content script lên html

function setDOMInfo(info) {
    document.getElementById('issue').textContent = info.issue;
    document.getElementById('totalComments').textContent = info.commentCount;
    document.getElementById('author').textContent = info.author;
    document.getElementById('totalComments').textContent = info.commentCount;
    document.getElementById('changedCode').textContent = info.numberOfChangedCode;
    document.getElementById('changedFiles').textContent = info.changedFiles;
    document.getElementById('ratio').textContent = info.commentsPerchangedLineCode + " %";
}

Popup.html

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="scripts/popup.js"></script>
    <link href="css/popup.css" rel="stylesheet" type="text/css">
</head>
<body>
    <h3 style="font-weight:bold; text-align:center;">Pull request info</h3>
    <table border="1" cellpadding="3" style="border-collapse:collapse;">
      <tr>
        <td nowrap>Issue:</td>
        <td align="right"><span id="issue">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Author:</td>
        <td align="right"><span id="author">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Total of comments:</td>
        <td align="right"><span id="totalComments">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Number of changed lines:</td>
        <td align="right"><span id="changedCode">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Changed files:</td>
        <td align="right"><span id="changedFiles">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Comments per changed lines(%):</td>
        <td align="right"><span id="ratio">N/A</span></td>
      </tr>
    </table>
</body>
</html>

Các bạn có thể thấy những code trên hoàn toàn quen thuộc với những ai đã lập trình web. Nó không quá phức tạp.

Load extension

  • Gõ trên trình duyệt chrome://extensions

  • Đảm bảo Developer mode checkbox trên góc phải là được tích.

  • Click Load unpacked extension… để mở file-selection dialog.

  • Tìm đến thư mục mà bạn đặt code của extension và chọn nó.

Nếu extension là hợp lệ nó sẽ được load và hoạt động đúng như mong muốn, ngược lại nó sẽ hiện thị thông báo lỗi cụ thể. Link code demo : Pull request analytics

5. Thảo luận

Bài viết này là những tìm hiểu ban đầu của tôi về extension, tôi không có tham vọng để nói về những kiến thức sâu hơn về chrome extension. Nhưng hy vọng những nội dung này cũng sẽ giúp các bạn chưa biết về chrome extension có thể dễ dàng làm quen với nó. Các bạn có thể nghiên cứu sâu hơn về chrome extension tại Chrome extension Mong nhận được được những đóp góp quý báu của các các bạn.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí