Chủ Nhật, 14 tháng 2, 2021

Cách viết một Chrome Extension

 

Intro

Chrome extension thì có lẽ không cần phải nói nhiều rồi, nó đã quá phổ biến và cực kì tiện dụng luôn. Các bạn ở đây chắn chắn ai cũng đã dùng qua một lần rồi. Với những extension hàng triệu người dùng trên Chrome web store kia thì bản thân mình cũng ao ước tạo ra một sản phẩm mang lại sự hữu ích cho mọi người. Vì vậy mà hôm nay mình sẽ hướng dẫn các bạn cách để viết một extension, nó cực kì dễ luôn (mình nói đùa đó :V ). Thật sự lúc bắt đầu thì mình chả biết phải làm thế nào luôn, nó như một cánh cửa mở ra một chân trời mới vậy nhưng sau thời gian tìm hiểu thì mình nhận thấy: để build một extension không hề khó nhưng để tạo được một sản phẩm tốt thì thật sự không hề dễ dàng. Nào, bắt đầu thôi...

Sơ lược về Chrome extension

Extensions are made of different, but cohesive, components. Components can include background scriptscontent scripts, an options pageUI elements and various logic files. Extension components are created with web development technologies: HTML, CSS, and JavaScript. An extension's components will depend on its functionality and may not require every option.

Cái này mình copy trên trang chủ Developer Chrome: https://developer.chrome.com/docs/extensions/mv2/getstarted

Tổng quan bạn có thể hiểu như sau: Extension là một đối tượng (1 cục code) có thể chạy trên 3 môi trường

  • Môi trường trình duyệt: Các tab khi ta mở browser.
  • Môi trường popup: Khi ta click vào những icon của extension, trình duyệt mở ra một popup và ta thao tác trên popup đó.
  • Môi trường background: Những tiến trình chạy ngầm, ta có thể check bằng cách mở Task manager lên. Điều này giải đáp thắc mắc của các bạn vì sao khi mở có 1 tab Chrome nhưng task manager lại chạy nhiều tiến trình của Chrome như vậy. Nếu mỗi tiến trình có yêu cầu quyền chạy background thì khi ta mở trình duyệt, đồng thời extension được khởi chạy và nó sẻ chiếm một tiến trình trong background của PC

Ta có thể viết một extension bằng một số kĩ năng về HTML, CSS, JS thuần hoặc có thể build một ứng dụng có sử dụng Back end server như Node. Việc sử dụng này cần có một thằng gọi là Bundler để bundle mớ code của bạn trước khi chạy trên web store. Trong bài viết này mình chỉ hướng đến việc xây một extension đơn giản sử dụng HTML, CSS, JS.

Tổng quan sản phẩm sắp thực hiện

Extension này mình đặ tên cho nó là Smart bookmark nha. Cụ thể công dụng của nó là Bookmark lại những trang web mà chúng ta cảm thấy thú vị hoặc tùy thích. Mình nhận thấy nó khá hay và đáp ứng tốt nhu cầu sử dụng hàng ngày của bản thân.

Hình ảnh này không có thuộc tính alt; tên tập tin này là image.png

Khi ta gặp một trang web muốn bookmark thì chỉ cần chọn vào extension, lựa chọn category phù hợp rồi bấm nút Add (+). Hoặc trong ta cũng có thể xóa một item khỏi bằng cách chọn Del (-)

Khi ta chọn vào một item đã lưu thì chrome sẽ mở ra một tab mới và dẫn ta đến địa chỉ đã lưu

Quá đơn giản đúng không nè. Bây giờ thì bắt đầu thôi...

Cấu trúc một folder code

Hình ảnh này không có thuộc tính alt; tên tập tin này là image-1.png

Đây là cách tổ chức folder của mình nhưng ở đây bạn chỉ cần quan tâm duy nhất 1 file có tên là manifest.json. File này chứa các thông tin định nghĩa cho extension của bạn

{
  "manifest_version": 2,
  "name": "Smart bookmark",
  "version": "1.0",

  "description": "Commonly useful tools for dev",
  "icons": {
    "16": "src/icons/popup.png",
    "48": "src/icons/popup.png",
    "128": "src/icons/popup.png"
  },
  "author": "PA_NQT",
  "browser_action": {
    "default_icon": {
      "16": "src/icons/popup.png",
      "24": "src/icons/popup.png",
      "32": "src/icons/popup.png"
    },
    "default_title": "Smart bookmark",
    "default_popup": "popup.html"
  },
  "permissions": ["tabs"],
  "toggle-feature-foo": {
    "suggested_key": {
      "default": "Shift+S+B",
      "mac": "Shift+S+B"
    },
    "description": "Toggle feature smart bookmark"
  },
  "content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
}

Một số fields ta cần quan tâm ở đây như:

  • "manifest_version": Version của extension (hiện tại có 3 phiên bản 1, 2, 3)
  • "icons": Icon hiện thị ngang với khung URL
  • "browser_action": có một field cần chú ý đó là "default_popup" đây là đường dẫn tới file HTML khi người dùng click vào icon của extension
  • "permissions": Cần trình duyệt cấp những quyền gì để chạy extension
  • "content_security_policy": Cái này mình mô tả để load AJAX call API vì mặc định browser chặn việc này

Các bạn có thể xem thêm các fields cụ thể hơn cần thiết cho dự án tại: https://developer.chrome.com/docs/extensions/mv2/manifest/

Oke khá là đơn giản, bây giờ ta thực hành luôn..

Setup server API

Mình không có ý định up extension này lên web store nên bây giờ mình sẽ hướng dẫn các bạn xây 1 API Server để sử dụng extension này cực dể bằng công cụ có sẵn: Mock API

  1. Vào trang chủ của nó và đăng kí một tài khoản: https://mockapi.io/
  2. New một project và đặt tên tùy ý
  3. Chọn project vừa tạo và New resource đặt tên là tools nha... đặt vậy để đỡ sửa code chứ không vấn đề gì

Kết quả như hình đây:

Mock API

À phần data bây giờ bạn mới thêm vô nè: Ta lấy data trong file store.json (nhớ copy cho đúng nha) rồi đặt vào đấy để làm data ban đầu.

Ở đây còn có một thông tin thêm là API URL: https://600e379f3bb1d100179de841.mockapi.io/api/v1/:endpoint

Endpoind ở đây chính là tools lúc nảy vừa tạo. Bạn có thể test thử server đã hoạt động chưa bằng cách vào đây: https://600e379f3bb1d100179de841.mockapi.io/api/v1/tools

Nó ra một đống Data là oke rồi nha...

Coding thôi

Phần giao diện popup

Ta không cần nói nhiều ha... Tùy thẩm mĩ của mỗi người

https://github.com/Nguyen-Quoc-Thai/smart-bookmark/blob/master/popup.html

Phần code chính

File util.js

https://github.com/Nguyen-Quoc-Thai/smart-bookmark/blob/master/src/js/util.js

File này chứa các utilities function... để giảm bớt số lượng code đó mà

/** Utils func */

// Item template
const itemTemplate = (resource) => {
  return `
    <div class="item">
      <button type="button" class="btn btn-light btn-sm" src=${
        resource.link
      } id="${resource.id}"
      data-toggle="tooltip" data-placement="bottom" title="${resource.name}"
      >
        <img class="icon" src=${resource.icon} alt=${
    resource.name
  } style="width: 18px; height: 18px;"/>
        <span class="name">${
          resource.name.length < 13
            ? resource.name
            : `${resource.name.slice(0, 10)}...`
        }</span>
      </button>
      <div class="btn-del"><span></span></div>
    </div>
  `;
};

// Add event click on an item
const addEventNewTabForEachBtn = (selector, except_selector, attr_url) => {
  $(selector)
    .not(except_selector)
    .click(function () {
      const url = $(this).attr(attr_url);

      // Create new tab
      chrome.tabs.create(
        {
          url
        },
        function () {}
      );
    });
};

Ta có các phần để rút ngắn code như là mỗi item thì có cấu trúc như nhau nên ta định nghĩa một template chung. Mỗi item lại cần sự kiện click để mở nên ta cũng làm tương tự.

Function addEventNewTabForEachBtn có sử dụng một lời gọi chrome.tabs chỉ định thao tác này cần tương tác với các tabs của trình duyệt (ta cần cấp permission cho thao tác này trong file manifest.json nha)

File main.js

https://github.com/Nguyen-Quoc-Thai/smart-bookmark/blob/master/src/js/main.js

Ta định nghĩa các thao tác để xữ lí dữ liệu thông qua API đã đề cập như:

  1. GetAll resource rồi render ra khi người dùng click mở popup
  2. Thêm một bookmark mới khi người dùng bấm Add
  3. Xóa một bookmark khi người dùng tùy chọn

Task 1:

fetch(`${BASE_API_URL}/tools`)
    .then((response) => response.json())
    .then((store) => { // Xử lí data render })

Sau khi render thì ta AddEventListener click cho từng button bằng function đã tạo ở file util

// Handle add listener: choose an item (create new tab)
$(window).ready(function () {
     addEventNewTabForEachBtn('.dev-engine button', '.btn-add', 'src');
});

Task 2:

$('.dev-engine .btn-add').click(function () {
      const curr = $(this);
      chrome.tabs.query({ active: true, lastFocusedWindow: true }, (tabs) => {
          // Handle new API and POST req API
      })
})

Với mỗi btn-add của mỗi resource ta bắt sự kiện click. Lấy thông tin của tab hiện hành và POST req API đến Mock server

// Call API -  send new item
fetch(`${BASE_API_URL}/tools`, {
          method: 'POST',
          headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json'
          },
          body: JSON.stringify(newItem)
      })
         .then((response) => response.json())
         .then((newResource) => {
              // Update view
         })
})
Task 3:

Tương tự task 2 nhưng lần này ta send req với Method là DELETE

$('.dev-engine .btn-del').click(function () {
      const curr = $(this);
      const id = curr.prev().attr('id');

      fetch(`${BASE_API_URL}/tools/${id}`, {
          method: 'DELETE'
      })
          .then((response) => response.json())
          .then((result) => {
              // Update view
           })
})

Okii vậy là hoàn tất bât giờ ta load thử extension lên Chrome nhé...

Vào đây: chrome://extensions/

Bật Developer mode rồi chọn Load unpacked và trỏ tới thư mục code là được.

Toàn bộ source code tại: https://github.com/Nguyen-Quoc-Thai/smart-bookmark

Đấy nó chỉ đơn giản thế thôi.. Cảm các bạn đã đọc...

WriterQuốc Thái

Follow me via:
Facebook
Github

Share:

1 nhận xét: