Hice una extensión de Chrome este fin de semana porque descubrí que estaba haciendo la misma tarea una y otra vez y quería automatizarla. Además, soy un nerd que vive una pandemia, así que gasto mi energía acumulada construyendo cosas. He creado algunas extensiones de Chrome a lo largo de los años, espero que esta publicación también te ayude a ponerte en marcha. ¡Empecemos!
Crea el manifiesto
El primer paso es crear un manifest.json
archivo en una carpeta de proyecto. Esto tiene un propósito similar a un package.json
, proporciona a Chrome Web Store información crítica sobre el proyecto, incluido el nombre, la versión, los permisos necesarios, etc. He aquí un ejemplo:
{
"manifest_version": 2,
"name": "Sample Name",
"version": "1.0.0",
"description": "This is a sample description",
"short_name": "Short Sample Name",
"permissions": ["activeTab", "declarativeContent", "storage", "<all_urls>"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"css": ["background.css"],
"js": ["https://css-tricks.com/how-to-build-a-chrome-extension/background.js"]
}
],
"browser_action": {
"default_title": "Does a thing when you do a thing",
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png"
}
}
}
Puede notar algunas cosas, primero: el nombres y descripciones puede ser lo que quieras.
El permisos dependen de lo que necesite hacer la extensión. Tenemos ["activeTab", "declarativeContent", "storage", "<all_urls>"]
en este ejemplo porque esta extensión en particular necesita información sobre la pestaña activa, necesita cambiar el contenido de la página, necesita acceder localStorage
y debe estar activo en todos los sitios. Si solo necesita que esté activo en un sitio a la vez, podemos eliminar el último índice de esa matriz.
Se puede encontrar una lista de todos los permisos y lo que significan en los documentos de extensión de Chrome.
"content_scripts": [
{
"matches": ["<all_urls>"],
"css": ["background.css"],
"js": ["https://css-tricks.com/how-to-build-a-chrome-extension/background.js"]
}
],
El content_scripts
sección establece los sitios donde la extensión debe estar activa. Si desea un solo sitio, como Twitter, por ejemplo, diría ["https://twitter.com/*"]
. Los archivos CSS y JavaScript son todo lo necesario para las extensiones. Por ejemplo, mi productiva extensión de Twitter usa estos archivos para anular la apariencia predeterminada de Twitter.
"browser_action": {
"default_title": "Does a thing when you do a thing",
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png"
}
}
Hay cosas en browser_action
que también son opcionales. Por ejemplo, si la extensión no necesita una ventana emergente para su funcionalidad, entonces tanto el default_title
y default_popup
se puede quitar. En ese caso, todo lo que se necesita es el icono de la extensión. Si la extensión solo funciona en algunos sitios, Chrome atenuará el ícono cuando esté inactivo.
Depuración
Una vez que los archivos de manifiesto, CSS y JavaScript estén listos, diríjase a chrome://extensions/
desde la barra de direcciones del navegador y habilite el modo de desarrollador. Eso activa el botón “Cargar descomprimido” para agregar los archivos de extensión. También es posible alternar si la versión para desarrolladores de la extensión está activa o no.
Recomiendo encarecidamente iniciar un repositorio de GitHub para controlar la versión de los archivos en este momento. Es una buena forma de salvar el trabajo.
La extensión debe volver a cargarse desde esta interfaz cuando se actualice. Aparecerá un pequeño icono de actualización en la pantalla. Además, si la extensión tiene algún error durante el desarrollo, mostrará un botón de error con un seguimiento de pila y más información aquí también.
Funcionalidad emergente
Si la extensión necesita hacer uso de una ventana emergente que sale del ícono de la extensión, afortunadamente es bastante sencillo. Después de designar el nombre del archivo con browser_action
en el archivo de manifiesto, se puede crear una página con cualquier HTML y CSS que desee incluir, incluidas imágenes (suelo usar SVG en línea).
Probablemente queramos agregar alguna funcionalidad a una ventana emergente. Eso requiere algo de JavaScript, así que asegúrese de que el archivo JavaScript esté designado en el archivo de manifiesto y también esté vinculado en su archivo emergente, así: <script src="https://css-tricks.com/how-to-build-a-chrome-extension/background.js"></script>
En ese archivo, comience creando funcionalidad y tendremos acceso al DOM emergente como este:
document.addEventListener("DOMContentLoaded", () => {
var button = document.getElementById("submit")
button.addEventListener("click", (e) => {
console.log(e)
})
})
Si creamos un botón en el popup.html
archivo, asígnele un ID llamado submit
y luego devuelve un registro de la consola, es posible que observe que no se registra nada en la consola. Eso es porque estamos en un contexto diferente, lo que significa que tendremos que hacer clic derecho en la ventana emergente y abrir un conjunto diferente de DevTools.
¡Ahora tenemos acceso al registro y la depuración! Sin embargo, tenga en cuenta que si se establece algo en localStorage
, entonces solo existirá en DevTools de la extensión localStorage
; no el navegador del usuario localStorage
. (¡Esto me mordió la primera vez que lo probé!)
Ejecutar scripts fuera de la extensión
Todo esto está muy bien, pero digamos que queremos ejecutar un script que tenga acceso a la información de la pestaña actual. Aquí hay un par de formas en que haríamos esto. Normalmente llamaría a una función separada desde el interior del DOMContentLoaded
oyente de eventos:
Ejemplo 1: activar un archivo
function exampleFunction() {
chrome.tabs.executeScript(() => {
chrome.tabs.executeScript({ file: "content.js" })
})
}
Ejemplo 2: ejecutar solo un poco de código
Esta forma es genial si solo hay un pequeño fragmento de código para ejecutar. Sin embargo, rápidamente se vuelve difícil trabajar con él, ya que requiere pasar todo como una cadena o una plantilla literal.
function exampleFunction() {
chrome.tabs.executeScript({
code: `console.log(‘hi there’)`
})
}
Ejemplo 3: activar un archivo y pasar un parámetro
Recuerde, la extensión y la pestaña funcionan en diferentes contextos. Eso hace que pasar parámetros entre ellos sea una tarea no tan trivial. Lo que haremos aquí es anidar los dos primeros ejemplos para pasar un poco de código al segundo archivo. Almacenaré todo lo que necesito en una sola opción, pero tendremos que encadenar el objeto para que funcione correctamente.
function exampleFunction(options) {
chrome.tabs.executeScript(
{ code: "var options = " + JSON.stringify(options) },
function() {
chrome.tabs.executeScript({ file: "content.js" })
}
)
}
Iconos
Aunque el archivo de manifiesto solo define dos íconos, necesitamos dos más para enviar oficialmente la extensión a Chrome Web Store: uno que es cuadrado de 128px y otro que llamo icon128_proper.png
, que también es de 128 px, pero tiene un poco de relleno en su interior entre el borde de la imagen y el icono.
Tenga en cuenta que cualquier ícono que se use debe verse bien tanto en el modo claro como en el modo oscuro para el navegador. Normalmente encuentro mis iconos en Noun Project.
Enviar a Chrome Web Store
¡Ahora podemos dirigirnos a la consola de desarrollo de Chrome Web Store para enviar la extensión! Haga clic en el botón “Nuevo elemento”, arrastre y suelte el archivo del proyecto comprimido en el cargador.
A partir de ahí, Chrome hará algunas preguntas sobre la extensión, solicitará información sobre los permisos solicitados en la extensión y por qué son necesarios. Advertencia justa: solicitando “activeTab”
o “tabs”
los permisos requerirán una revisión más prolongada para asegurarse de que el código no esté haciendo nada abusivo.
¡Eso es! ¡Esto debería prepararlo todo y comenzar a crear una extensión para el navegador Chrome! 🎉