Este tutorial crea el prototipo más pequeño y útil de Chrome Manifest V3: un área de texto privada montada en páginas Pin de Pinterest, codificada por el ID numérico del Pin y guardada en chrome.storage.local. Es intencionalmente un prototipo, no un clon listo para producción de las notas anteriores de Pinterest.
El DOM de Pinterest puede cambiar sin previo aviso. Mantenga los selectores aislados, evite imitar la marca protegida de Pinterest y pruebe en los tipos de páginas y configuraciones regionales que admita.
1. Cree la extensión Manifest V3
Crea una carpeta con manifiesto.json y contenido.js. cromo referencia manifiesta es la fuente de verdad para las claves disponibles.
{
"versión_manifestación": 3,
"name": "Prototipo de contexto de fijación",
"versión": "0.1.0",
"description": "Guardar una nota local privada para un Pin de Pinterest.",
"permisos": ["almacenamiento"],
"content_scripts": [{
"coincidencias": ["https://*.pinterest.com/*"],
"js": ["contenido.js"],
"run_at": "document_idle"
}]
}
La coincidencia de host es amplia porque Pinterest utiliza navegación del lado del cliente. Si su función admite menos rutas o dominios de países, limite y documente ese alcance.
2. Derive una clave estable a partir de la URL del Pin.
No claves notas según la posición de una tarjeta o el título visible. Extraer el ID numérico de un canónico /pin/…/ camino y regreso nulo en todas partes.
función getPinId(url = ubicación.href) {
prueba {
const {nombre de ruta} = nueva URL(url);
coincidencia constante = nombreruta.match(//pin/(d+)/?/);
partido de vuelta? coincidencia[1] : nulo;
} atrapar {
devolver nulo;
}
}
Pruebe URL detalladas válidas, cadenas de consulta, páginas sin PIN, URL con formato incorrecto y cualquier patrón local que afirme admitir. Nunca adjunte una nota en silencio cuando la identificación sea incierta.
3. Almacenar un registro versionado
Mantenga el esquema explícito para que sean posibles migraciones futuras:
función asíncrona readNote(pinId) {
clave const = 'nota-pin:' + pinId;
resultado constante = esperar chrome.storage.local.get(clave);
devolver resultado[clave] ?? {versión: 1, pinId, texto: '', actualizado en: nulo};
}
función asíncrona writeNote(pinId, texto) {
clave const = 'nota-pin:' + pinId;
registro constante = {
versión: 1,
identificador pin,
texto,
actualizado en: nueva fecha().toISOString()
};
await chrome.storage.local.set({ [clave]: registro });
registro de devolución;
}
Chrome documenta un límite predeterminado de 10 MB para almacenamiento.local, con un separado almacenamiento ilimitado permiso para aumentarlo. Chrome también documenta que el almacenamiento de la extensión local se borra cuando se elimina la extensión. leer la actualidad Documentación de la API de almacenamiento y exporte el diseño antes de invitar a datos importantes.
4. Monte un editor aislado y accesible
Un Shadow DOM reduce las colisiones accidentales de estilos. El ejemplo se adjunta al cuerpo de la página para que no dependa de un frágil nombre de clase de Pinterest:
función asíncrona mountEditor (pinId) {
if (document.querySelector('[datos-pin-context-root]')) retorno;
const host = document.createElement('aparte');
host.dataset.pinContextRoot = '';
host.setAttribute('aria-label', 'Nota de Pin privado');
documento.body.append(host);
const root = host.attachShadow({ modo: 'abrir' });
etiqueta constante = document.createElement('etiqueta');
label.textContent = 'Nota privada';
editor constante = document.createElement('área de texto');
editor.setAttribute('aria-label', 'Nota privada para este Pin');
estado constante = document.createElement('span');
status.setAttribute('rol', 'estado');
const guardado = espera lecturaNota(pinId);
editor.valor = texto.guardado;
root.append(etiqueta, editor, estado);
bindAutosave(editor, estado, pinId);
}
Crear texto de interfaz con contenido de texto, no desconfiado HTML interno. Agregue estilos de enfoque visibles, suficiente contraste, una etiqueta real, acceso al teclado y texto de estado que no robe el foco.
5. Guarde sin escribir en cada pulsación de tecla
función bindAutosave(editor, estado, pinId) {
dejar guardar el temporizador;
editor.addEventListener('entrada', () => {
status.textContent = 'No guardado';
clearTimeout(guardarTimer);
saveTimer = setTimeout(async () => {
prueba {
aguarde writeNote(pinId, editor.value);
status.textContent = 'Guardado localmente';
} captura (error) {
console.error('Error al guardar la nota en el pin', error);
status.textContent = 'No se pudo guardar';
}
}, 400);
});
}
Para producción, también vacíe las entradas pendientes en la transición de página, proteja contra dos pestañas que se sobrescriban entre sí, defina un tamaño máximo de nota y muestre errores de cuota.
6. Manejar la navegación del lado del cliente de Pinterest
Un controlador de carga de página única pierde la navegación entre las vistas de feed y detalles. Utilice una función de reconciliación idempotente y observe los cambios sin volver a montar en cada mutación:
dejar programado = falso;
función asíncrona reconciliar() {
programado = falso;
const pinId = getPinId();
const existente = document.querySelector('[raíz-contexto-pin-datos]');
si (!pinId) {
¿existente?.remove();
devolver;
}
si (¿existente?.dataset.pinId === pinId) retorno;
¿existente?.remove();
aguarde mountEditor(pinId);
const montado = document.querySelector('[raíz-contexto-pin-datos]');
if (montado) montado.dataset.pinId = pinId;
}
nuevo MutationObserver(() => {
si regreso (programado);
programado = verdadero;
requestAnimationFrame(conciliar);
}).observe(document.documentElement, { childList: verdadero, subárbol: verdadero });
conciliar();
Una versión de producción también debería observar el estado de navegación directamente cuando sea posible y desconectar a los observadores que ya no necesita. Perfilar el código en transmisiones largas; una característica correcta que degrada el rendimiento de la página sigue siendo una mala extensión.
7. Respete las restricciones de seguridad del Manifest V3
Manifest V3 prohíbe el código ejecutable alojado de forma remota. Combine JavaScript ejecutable con la extensión, mantenga la política de seguridad de contenido predeterminada a menos que tenga un cambio justificado, evite la ejecución de código dinámico y solicite solo los permisos que requiere la función. cromo Descripción general del manifiesto V3 explica el modelo de plataforma.
8. Agregue las características que necesita un producto real
- Exportación/importación JSON con validación de esquemas y manejo de conflictos;
- exportación legible por humanos para recuperación;
- búsqueda y etiquetas opcionales;
- informes de cuotas y uso de almacenamiento;
- eliminación por nota y para todos los datos;
- una política de privacidad que coincida con el comportamiento observable;
- pruebas de migración entre versiones de esquema;
- borrar las advertencias de desinstalación y no sincronización;
- telemetría de errores solo con una minimización y divulgación cuidadosas.
9. Pruebe las rutas de falla
- Cargue la extensión descomprimida desde
cromo://extensiones. - Visite un feed, un tablero, una página de detalles de Pin y una ruta que no sea de Pin.
- Navega entre dos Pines sin recargar y confirma el aislamiento de notas.
- Abra el mismo Pin en dos pestañas y pruebe el comportamiento en conflicto.
- Deshabilite el almacenamiento o simule una falla de cuota y verifique la advertencia.
- Exporte, elimine un registro de prueba y restáurelo.
- Pruebe la navegación con el teclado, el zoom, las etiquetas del lector de pantalla y las condiciones de página oscura/clara.
La lección de ingeniería.
El área de texto es la parte fácil. Una extensión de Pinterest confiable depende de una identidad estable, un manejo resistente del ciclo de vida, una interfaz de usuario accesible, permisos restringidos, almacenamiento documentado y una ruta de salida probada. Desarrolle esas cualidades antes de expandir la lista de características.
Sigue construyendo tu sistema Pinterest
Continúe con la guía que coincida con su próximo paso:
Obtenga la extensión de Chrome Notestopin
Agrega notas privadas a cualquier Pin, etiquétalas y busca tus partidas guardadas más tarde.
Agregar a Chrome