+11

Tôi đã viết Chrome extension đầu tiên của mình bằng Github Copilot như thế nào?

Câu chuyện của tôi là Tôi đang học tiếng Nhật trên một trang web là Dungmori.com, và tôi học từ mới trên trang web Quizlet. Và tôi gặp khó khăn trong việc copy từ vựng từ Dungmori sang Quizlet vì cứ phải copy từng từ một. Trước đó tôi hay dùng cách copy set từ vựng có sẵn do 1 người dùng nào đó đã tạo trên Quizlet, sau đó kiểm tra nếu thiếu từ nào so với Dungmori thì tôi sẽ thêm thủ công. Việc này của tốn khá nhiều thời gian của tôi. Sau đó tôi phát hiện ra Quizlet cho phép import nhiều từ với nhiều tuỳ chọn cú pháp khác nhau. Ví dụ như 2 từ cách nhau bởi dấu phẩy, dấu tab, dấu cách, 2 card cách nhau bởi dấu xuống dòng \n, \r\n, ...

Quizlet Set import UI

Còn ở phía Dungmori, họ show từ mới với một thẻ <table> bình thường, vì thế tôi có thể dễ dàng dùng javascript để biến đổi text trong bảng này thành chuỗi text để import sang Quizlet

Dungmori Vocab table

Nhưng không lẽ mỗi lần muốn lấy từ vựng từ bảng này, tôi lại phải tìm lại đoạn code, mở Devtool, và copy code vào tab console hay sao? Câu hỏi này làm tôi nghĩ đến việc mình sẽ tạo một extension để cài lên trình duyệt. Nhưng tôi chưa từng viết extension bao giờ, tôi chỉ biết html, css, javascript thôi. Chắc Github Copilot có thể giúp tôi đấy nhỉ???

So f**king tired developer

Nên tôi bắt đầu hỏi Copilot cách tạo 1 extension from scratch, câu trả lời là tôi cần tạo 1 file manifest.json để lưu những config quan trọng của extension, 1 file popup.html để làm giao diện cho extension, 1 file popup.js để viết logic, và 1 file content.js để tương tác với các thành phần DOM của website. Copilot cũng hướng dẫn tôi cách import 1 folder code vào trình duyệt, bằng cách enable Developer mode trong cài đặt extension, sau đó chọn thư mục code và reload trình duyệt.

// manifest.json
{
  "manifest_version": 2,
  "name": "My First Chrome Extension",
  "version": "1.0",
  "description": "A simple Chrome extension",
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "permissions": ["activeTab"],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ]
}
<!-- popup.html -->
<!DOCTYPE html>
<html>
  <body>
    <h1>Hello, this is my first Chrome extension!</h1>
    <script src="popup.js"></script>
  </body>
</html>

Tôi bắt đầu viết vào file content.js đoạn logic convert phần text trong bảng thành một chuỗi có thể import được sang Quizlet rồi copy vào clipboard. Tôi sẽ không nói nhiều về phần này vì đó chỉ là các thao tác DOM cơ bản. Sau đó chạy thử và Bùm, đoạn logic đó chạy ngay khi trang web được load. Nhưng tôi muốn trigger nó bằng cách bấm vào button trong extension popup cơ. Như thế thì khi dùng tôi sẽ tốn nhiều thao tác hơn, nhưng mà nó ngầu ¯_(ツ)/¯ . Tại sao không? Rồi tôi lại hỏi Copilot và nhận được câu trả lời là do config này ở file manifest.json.

"content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ]

Giải pháp là phải xoá đoạn config đó, rồi trigger thủ công bằng phương thức `chrome.scripting.executeScript()

chrome.tabs.query({active: true, currentWindow: true}, 
    function(tabs) {
        chrome.scripting.executeScript({
            target: {tabId: tabs[0].id},
            files: ['content.js']
        }).then(() => {
            console.log('Injected the content script.');
        }).catch(err => console.error(err));
    });

Yeah và bây giờ file content.js đã có thể trigger khi tôi bấm nút trong extension popup, nhưng hàm copy to clipboard lại không hoạt động được như trước đó. Một lần nữa đấng cứu thế Copilot lại giúp tôi giải đáp rằng:

The error "Document is not focused" occurs because the document of the background page or popup loses focus when you switch to the content page, and the Clipboard API requires the document to be focused to write to the clipboard.

Và giải pháp là tôi cần phải gửi đoạn text cần copy từ file content.js sang file popup.js bằng một thứ mà tôi không rõ là cái gì, nhưng ý tưởng có vẻ giống kiểu pub/sub

// content.js
chrome.runtime.sendMessage({type: "copy", text: normalizedRows.join("\r\n")});

// background.js or popup.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.type === "copy") {
        navigator.clipboard.writeText(request.text).then(function() {
            console.log('Text copied to clipboard');
        }).catch(function(err) {
            console.error('Could not copy text: ', err);
        });
    }
});

BOOOOM! THE RESULT IS HERE! Result

Giờ thì tôi có thể copy từ vựng từ Dungmori vào clipboard chỉ với 1 thao tác bấm nút. Nhờ Copilot mà tôi chỉ mất chưa đến 1 tiếng đồng hồ để tạo ra extension này. Hãy tưởng tượng nếu tôi search google để làm, thì tôi sẽ phải mở 1 tỷ tab mỗi lần có vấn đề phát sinh. Còn với Copilot, tôi chỉ việc ở yên trong cửa sổ VS code của mình. Trước đó tôi có thử với ChatGPT và Gemini, nhưng output cũng chẳng đến đâu.

100000000000000 tabs Trên đây không phải là bài chia sẻ về công nghệ gì cao siêu, mà chỉ đơn giản là câu chuyện và trải nghiệm thú vị của tôi với Copilot. Ngoài ra, cảm ơn Dall-E giúp tôi tạo ảnh minh hoạ, và ChatGPT giúp tôi dịch sang tiếng Anh chuẩn hơn. Peace I'm out

GitLab Repository: https://gitlab.com/1337NamNori/copy-vocab-extension


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í