
Bu yazıda, Facebook’u kullanarak tepki olarak bir chrome uzantısının nasıl oluşturulacağını inceleyeceğiz. oluştur-tepki-uygulaması bize donatılacak yetenekler verecek olan araç. Bu, yapabileceğiniz anlamına gelir npm install
favori düğüm modüllerinizi seçin ve bunları krom uzantılarınızı geliştirmek için kullanın. Kodumuzu doğrudan bir sayfaya enjekte edeceğiz ve ona erişimimiz olacak. document
.
Uzantımızın, bir web sayfasına sağ tıkladığımızda görünen özel bir menü öğesi sunmasını sağlayacağız. Odak noktamız, arama sonuçları aracılığıyla bir youtube’un videolar sayfasında olacaktır. Arama sonuçları aracılığıyla videoları görüntülerken, uzantımız video süresinin belirli bir minimum süreden az veya belirli bir maksimum süreden yüksek olduğu durumlarda videoları sürekli olarak sonuçlardan kaldıracaktır. Bu yüzden sürekli aşağı kaydırdığımızda ve youtube sürekli bize yeni videolar beslediğinde, uzantımız sürekli görmek istemediğimiz videoları kaldıracak 🙂
“Amaç ne?” diye sorabilirsiniz. youtube zaten süre için bir filtre verdiğinde. Bu doğrudur, ancak kullanıcıların yalnızca 4 dakikadan kısa veya 20 dakikadan uzun süreleri filtrelemesine izin verir. Sizi bilmem ama süresi 8 ila 15 dakika arasında olan videoları filtrelemek gibi daha dar bir şeyi filtrelemenin inanılmaz derecede güçlü olduğunu düşünüyorum.
Ya sadece 5 ila 10 dakika arasında bir süreye sahip videoları görmek istiyorsak? Gerçek suç kanal? 4 dakikadan kısa veya 20 dakikadan uzun videoları filtrelemek tamamen işe yaramaz. 5-10 dakika arası videolar görmek istiyoruz parçalara ayrılmış bölümleri ararken 1. bölümün 4. bölümü, 2. bölümün, 3. bölümün vb. beğenin çünkü bu videolar genellikle ortalama 6 dakika sürüyor. Arama sonuçlarımıza bakarken 40 dakikalık podcast videolarıyla bombardımana tutulmak istemiyoruz.
Ayrıca, ne kadar basit olabileceğini görmek için araç çubuğundaki simgesine tıkladığınızda bir açılır pencerenin yanı sıra bir seçenekler sayfası da oluşturacağız.
(GitHub deposunun bağlantısını istiyorsanız, burada)
Bu gönderi, krom uzantılarının nasıl çalıştığının üzerinden geçmeyecek, bu yüzden daha fazla okumadan önce bunu göz önünde bulundurarak onların üzerinden geçmenizi tavsiye ederim. genel bakış Bu öğreticinin geri kalanını anlamak için gereken temel bir anlayışa sahip olmak.
Ve son olarak, bu eğitimin sonunda, muhtemelen bu yazıda inşa edeceğimiz şeyin tepki vermeye bile ihtiyacı olmadığını fark edeceksiniz. Ancak asıl mesele, kendi başınıza başlamanız için tepkinin nasıl uygulanabileceğini göstermektir.
Lafı fazla uzatmadan başlayalım!
Kod yapımız
Genel olarak krom uzantıları oluşturduğumuzda, içerik komut dosyaları koddan uzak arka plan komut dosyaları. Bu nedenle, kod paketlemenin avantajlarını ve paketleyicileri kullanan modern projelerde bulacağınız diğer özellikleri korumak istiyorsak, kodumuzu iki ayrı kod tabanında geliştirmek için birkaç ek adım gerekir.
Ayrıca tepki bileşenlerimizi doğrudan bir web sayfasına enjekte edeceğiz, böylece ona erişebiliriz. document
DOM’yi değiştirebilmemiz için body nesnesi.
projeyi oluştur
Yapacağımız ilk şey, bir oluştur-tepki-uygulaması proje. Yeni projemize bir isim vermemiz gerekecek ve bu derste projemize bir isim vereceğiz “react-chrome-ext
“.
Bunu terminale girelim:
npx create-react-app react-chrome-ext
Şimdi bittikten sonra dizini girin:
Yapacağımız ilk şey, bu eğitim için ihtiyacımız olmayan şeylerden kurtulmak. Temizlemeden sonra proje dizinimiz:
Uzantımızın mevcut bir sekmeye erişmesi için bir yol sağlamamız gerekiyor. document
uzantımız kullanıldığında. Tepki bileşenlerimiz büyük olasılıkla henüz bu tür bir erişime sahip olmayacak çünkü kimliğe sahip bir öğeye enjekte ediliyor. root
açtığımızda gördüğümüz gibi index.js
:
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))
Olduğu gibi bırakırsak, uzantımız yalnızca bir web sayfasında kimliği olan gerçek bir DOM öğesi olduğunda çalışabilecektir. 'root'
. Bunu biraz tersine çevireceğiz içine kendi elementimizi enjekte etmek document.body
yürütmeden önce ReactDOM.render
.
Bunu yapmak için bir eleman oluşturacağız ve onu document.body
:
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
const rootEl = document.createElement('div')
rootEl.id = 'react-chrome-ext'
document.body.appendChild(rootEl)
ReactDOM.render(<App />, rootEl)
Şimdi içeri gireceğiz App
bileşen ve bu, uzantımız için özel kod mantığımızı uygulamaya başlayacağımız yerdir (Not: Bu, temelde bizim içerik komut dosyamızdır).
Unutmayın, bu uzantıyı bir youtube’un arama özelliklerini kullanarak video listesi için yapıyoruz. Bu yüzden sayfadayken, bağlam menüsünü açmak için sayfayı sağ tıklatabilmek istiyoruz ve içeride filtreleyiciyi çağırmak için tıklayabileceğimiz özel menü öğemiz olacak. Filtreleyiciyi çalıştırabilmemiz için içerik komut dosyalarımızın click olayını dinlemesini istiyoruz ve bunun için bağlam menüsünü arka plan komut dosyaları aracılığıyla kaydetmemiz ve tıklama olay dinleyicisini buraya eklememiz gerekiyor. Geri arama başlatıldığında, kromu kullanacağız İleti api, sinyali içerik komut dosyalarına göndermek için. Mesajlar için içerik tarafına bir dinleyici eklediğimiz için tıklama işlemini bu şekilde algılayacaktır.
İçinde App.js
dinleyicileri bir React.useEffect
şöyle:
import React from 'react'
function App() {
React.useEffect(() => {
chrome.runtime.onMessage.addListener((action) => {
switch (action.type) {
case 'filter-by-duration': {
console.log('received click event from context menu')
break
}
default:
break
}
})
}, [])
return null
}
export default App
chrome.runtime.onMessage
arka plan komut dosyamızdan gelen herhangi bir mesajı dinler.
Daha sonra adında bir dizin oluşturacağız. erkek arkadaş içinde kaynak dizini oluşturun ve background.js
içindeki dosya şöyle:
Bu, uzantının kurulum sırasında menü öğelerini bağlam menüsüne kaydetmesi ve ayrıca tıklandığında ne olacağı için kod uygulamamız gereken yerdir:
chrome.runtime.onInstalled.addListener((message) => {
const contexts = [
'page',
'selection',
'link',
'editable',
'image',
'video',
'audio',
]
chrome.contextMenus.create({
title: 'Filter by duration',
id: 'filter-by-duration',
contexts: [...contexts, 'browser_action'],
})
})
function getActiveTab(callback) {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const activeTab = tabs[0]
callback(activeTab)
})
}
chrome.contextMenus.onClicked.addListener((info) => {
console.log(info)
if (info.menuItemId === 'filter-by-duration') {
getActiveTab((tab) => {
if (info.menuItemId === 'filter-by-duration') {
chrome.tabs.sendMessage(tab.id, {
type: 'filter-by-duration',
...info,
})
}
})
}
})
bu chrome.runtime.onInstalled.addListener((message) => {
hat, uzantı kurulduğunda aranacak geri aramamızı kaydeder. Burada gördüğümüz gibi bağlam menüsünü burada oluşturuyoruz:
chrome.contextMenus.create({
title: 'Filter by duration',
id: 'filter-by-duration',
contexts: [...contexts, 'browser_action'],
})
Bu kod parçası daha sonra bu menü öğesini oluşturacaktır (altta):
biz yarattık getActiveTab
gelecekte ek eylemler için yeniden kullanabilmemiz için yardımcı işlevi. Geçtiği geri aramayı çağırır ve size bulunduğunuz sekmeyi temsil eden bir nesne verir.
Ve son olarak, aşağıda gördüğümüz gibi menü maddesi tıklandığında click olayını işlemek için işleyiciyi ekledik:
chrome.contextMenus.onClicked.addListener((info) => {
console.log(info)
if (info.menuItemId === 'filter-by-duration') {
getActiveTab((tab) => {
if (info.menuItemId === 'filter-by-duration') {
chrome.tabs.sendMessage(tab.id, {
type: 'filter-by-duration',
...info,
})
}
})
}
})
Bakılması gereken önemli kısım şudur:
chrome.tabs.sendMessage(tab.id, {
type: 'filter-by-duration',
...info,
})
Bu, olayı şu adrese gönderir: içerik komut dosyaları (ki bizim App
bileşen alacaktır).
Bu neden sahip olduğumuzu açıklıyor chrome.runtime.onMessage.addListener
satırda App
bileşen:
import React from 'react'
function App() {
React.useEffect(() => {
chrome.runtime.onMessage.addListener((action) => {
switch (action.type) {
case 'filter-by-duration': {
console.log('received click event from context menu')
break
}
default:
break
}
})
}, [])
return null
}
export default App
Şimdi switch ifadesinin içine videoları süreye göre filtreleme mantığını ekleyeceğiz. İsteğe bağlı olarak sekmeyi görüntülerken filtrenin süre değerini değiştirmenin bir yolunu sağlamak gibi sonunda uygulamak isteyeceğiniz ekstra özellikleri kodlamayacağız çünkü bu sizin için. Bu eğitimin iyiliği için sadece süreyi sabit kodlayacağız.
devam etmeden önce Youtube ve bir şey arayın. Bu eğitim için sadece arayacağız yol öfkesi. İşte aldığımız şey:
Filtreleyicimizde minimum 10 dakikalık ve maksimum 15 dakikalık bir süreyi sabit kodlayacağız, bu nedenle filtreyi kullandığımızda ekran görüntüsüne bakarak ilk videoyu görememeliyiz (23:42) ve dördüncü video (9:02).
Bunu başarmak için sayfanın bilgilerini sorgulamalı ve geçmeliyiz. document
nesne. Sayfaya sağ tıklayıp Elemanı İncele gibi seçicileri kullanarak ihtiyacınız olan öğeleri nasıl hedefleyeceğinizi anlayabilirsiniz. Document.querySelector (Ya da aşağıdaki snippet’imi kopyalayabilirsiniz). Videonun süresini gösteren öğeyi hedef almamız ve bir sayıya dönüştürmemiz gerekiyor (çünkü bunlar dizeler), böylece amacımıza ulaşmak için matematik işlemleri uygulayabiliriz.
Şimdi devam edelim ve filtreyi uygulayalım:
const convertToMs = (ms, type) => {
switch (type) {
case 'seconds':
return ms * 1000
case 'minutes':
return ms * 60000
case 'hours':
return ms * 36000000
default:
break
}
}
function filterByDuration(duration) {
return () => {
const container = document.querySelector(
'#contents.style-scope.ytd-item-section-renderer',
)
const elemsList = container.querySelectorAll('ytd-video-renderer')
elemsList.forEach((elem) => {
const durationElem = elem.querySelector(
'span.style-scope.ytd-thumbnail-overlay-time-status-renderer',
)
if (durationElem) {
let durationTime = durationElem.innerText.trim()
const durationParts = durationTime.split(':')
let hour = 0
let min = 0
let sec = 0
switch (durationParts.length) {
case 2:
min = Number(durationParts[0])
sec = Number(durationParts[1])
break
case 3:
hour = Number(durationParts[0])
min = Number(durationParts[1])
sec = Number(durationParts[3])
break
default:
break
}
let currentDurationInMs = convertToMs(hour, 'hours')
currentDurationInMs += convertToMs(min, 'minutes')
currentDurationInMs += convertToMs(sec, 'seconds')
const minMs = convertToMs(duration.min, 'minutes')
const maxMs = convertToMs(duration.max, 'minutes')
if (currentDurationInMs < minMs || currentDurationInMs > maxMs) {
elem.parentNode.removeChild(elem)
}
}
})
}
}
React.useEffect(() => {
chrome.runtime.onMessage.addListener((action) => {
switch (action.type) {
case 'filter-by-duration': {
const filter = filterByDuration({ min: 10, max: 15 })
filter()
window.addEventListener('scroll', filter)
break
}
default:
break
}
})
}, [])
Bu, uzantımızın çalışması için yeterli kod olmalı, ancak uzantımızı kroma yüklemeden önce birkaç şey daha yapmamız gerekiyor.
Yapmak isteyeceğimiz bir şey, ne zaman şikayet eden eslint hatasından kurtulmaktır. chrome is not defined
. ekleyerek çözebiliriz webextensions: true
bizim için eslintConfig
içindeki mülk package.json
:
"eslintConfig": {
"extends": "react-app",
"env": {
"webextensions": true
}
}
Sonra bizim düzenlemek zorunda kalacağız manifest.json
dosyamız public
dizin. Biz ne zaman inşa etmek projemiz, bu manifest.json
dosya üzerine kopyalanır build
chrome’a yükleyeceğiniz dizin olan dizin. biraz temizleyelim böylece chrome uzantımızı anlayabilir:
{
"manifest_version": 2,
"version": "1.0.1",
"name": "React Chrome Extension",
"content_security_policy": "script-src 'self' 'sha256-xr+HqUtnq8KF3IBn+TQ37Vz0elxg11bPYmNJy5M/p38='; object-src 'self'",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": ["activeTab", "tabs", "contextMenus"]
}
Ayrıca bir belirtmemiz gerekiyor content_scripts
chrome’un onları almasını istiyorsak, bildirimdeki özellik. Tipik olarak burası, bizim gibi içerik komut dosyalarımızı girdiğimiz yerdir. App.js
dosya, ancak buradaki sorun, kromun aktarılmamış tepki kodunu anlamamasıdır. Bu yüzden, gönderilen çıktı dosyalarını aktarmamız gerekiyor. build
çalıştırdığımızda klasör npm run build
.
Devam edelim ve koşalım npm run build
. Derleme klasörümüz aşağıdaki gibi görünecek:
Manifest’e dahil etmek istediğimiz javascript dosyaları şu üç dosyadır:
static/js/2.2e3b5afd.chunk.js
static/js/main.bf10c391.chunk.js
static/js/runtime-main.0741577f.js
…sonuç şuna benzer:
{
"manifest_version": 2,
"version": "1.0.1",
"name": "React Chrome Extension",
"content_security_policy": "script-src 'self' 'sha256-xr+HqUtnq8KF3IBn+TQ37Vz0elxg11bPYmNJy5M/p38='; object-src 'self'",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [
"/static/js/2.2e3b5afd.chunk.js",
"/static/js/main.bf10c391.chunk.js",
"/static/js/runtime-main.0741577f.js"
]
}
],
"permissions": ["activeTab", "tabs", "contextMenus"]
}
Bu iyi, ama şimdi sorunumuz şu ki, her koştuğumuzda npm run build
bu javascript dosyalarının dosya adı değişir, bu da dosya adındaki dinamik güncellemelerden haberdar olmak için bu satırları manuel olarak değiştirmemiz gerektiği anlamına gelir. Bu zayıf bir geliştirme deneyimi, bu yüzden bunu aşmamız gerekecek. fırlatma çıktının nasıl üretildiğini kontrol etme projemiz.
Devam et ve koş npm run eject
Bunu yaptıktan sonra, kendinize gidin config
klasör ve aç webpack.config.js
için bir arama yapın .[hash:8]
ve her iki oluşumu da kaldırın.
Birincisi name: 'static/media/[name].[hash:8].[ext]',
öyleyse değiştir name: 'static/media/[name].[ext]',
ve diğeri için aynısını yapın.
Şimdi başka bir arama yapın ve arayın .[contenthash:8]
ve bunların tüm oluşumlarını da silin. Senin js
dosyalar artık her çalıştırdığınızda aynı dosya adına sahip olacak. build
emretmek.
Yani şimdi koştuğunda npm run build
bu çıktı dosyaları her seferinde aynı kalır:
Bunları artık güvenli bir şekilde manifest.json
:
{
"manifest_version": 2,
"version": "1.0.1",
"name": "React Chrome Extension",
"content_security_policy": "script-src 'self' 'sha256-xr+HqUtnq8KF3IBn+TQ37Vz0elxg11bPYmNJy5M/p38='; object-src 'self'",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [
"/static/js/2.chunk.js",
"/static/js/main.chunk.js",
"/static/js/runtime-main.js"
]
}
],
"permissions": ["activeTab", "tabs", "contextMenus"]
}
Harika! Şimdi koş npm run build
ve bunu kroma yükleyelim. Yazın chrome:extensions
adres çubuğunuza, ardından “Paketlenmemiş yük” düğmesini seçin ve build
dizin.
Uzantınız şimdi yüklenmelidir!
Hadi gidelim www.youtube.com ve ara “yol öfkesi”. Sayfaya sağ tıklayın ve tıklayın “Süreye göre filtrele”. Buna tıkladıktan sonra, uzantı artık süre filtrenize göre öğeleri ekrandan kaldırmalıdır! Yaşasın!
Hatırlayın, önceki ekran görüntülerimizden birinde birkaç video sonucumuz vardı ve video süresinden bahsetmiştik. 23:54 ve 9:42 filtremiz uygulandığında gösterilmemeli mi?
Bakalım bu doğru mu:
Yaşasın!
Bu öğreticiyi bitirmeden önce devam edelim ve bir seçenekler sayfanın yanı sıra bir açılır.
Seçenekler sayfası, sağ tık araç çubuğunda uzantınızın simgesini tıklayın ve seçenekler öğe.
Açılır pencere benzer şekilde kullanılır. sol tık araç çubuğundaki uzantınızın simgesi.
sadece bir tane oluşturabiliriz options.html
ve popup.html
içinde src/bg/
aşağıdaki gibi:
O zaman bir giriş yapabiliriz postbuild
bizim için komut dosyası package.json
bina tamamlandıktan sonra otomatik olarak çalışan:
"scripts": {
"start": "node scripts/start.js",
"prebuild": "rm -rf build",
"build": "node scripts/build.js",
"postbuild": "cp src/bg/* build"
}
Çözüm
Ve bu yazının sonu burada bitiyor! Umarım bunu değerli bulmuşsunuzdur ve gelecekte daha fazlasını ararsınız!