Agregar uso compartido en redes sociales en una aplicación de una sola página de Node.js
() translation by (you can also view the original English article)
Las aplicaciones de una sola página (SPA) funcionan con plantillas de representación del lado del cliente, que brindan al usuario final una experiencia muy dinámica. Recientemente, Google anunció que rastrean páginas web y ejecutan JavaScript como lo haría un usuario normal, lo que da como resultado que los sitios impulsados por marcos SPA (Angular, Ember y Vue, por nombrar algunos) se rastreen sin penalización de Google.
Más allá de la búsqueda, otros rastreadores web son importantes para la visibilidad de tu sitio, es decir, los robots ricos para compartir en redes sociales que se basan en meta etiquetas aún son ciegos para JavaScript.
En este tutorial, crearemos una ruta alternativa y un módulo de representación para tu servidor Express y Node.js que puedes usar con la mayoría de los frameworks SPA y que permitirá que tu sitio comparta contenido en Twitter, Facebook y Pinterest.
Una palabra de advertencia
Este tutorial trata exclusivamente con robots web que extraen información para compartir en redes sociales. No intentes esta técnica con rastreadores web de motores de búsqueda. Las empresas de motores de búsqueda pueden tomar este tipo de comportamiento en serio y tratarlo como spam o comportamiento fraudulento, por lo que tu clasificación puede hundirse rápidamente.
De manera similar, con información rica para compartir en redes sociales, asegúrate de representar el contenido de una manera que alinee lo que ve el usuario con lo que lee el robot. No mantener esta alineación podría resultar en restricciones de los sitios de redes sociales.
Intercambio social enriquecido
Si publicas una actualización en Facebook e incluye una URL, un robot de Facebook leerá el HTML y buscará las meta etiquetas de OpenGraph. Aquí hay un ejemplo de la página de inicio de Envato Tuts +:



Inspeccionando la página, en la etiqueta head
, aquí están las etiquetas relevantes que generan esta vista previa:
1 |
<meta content="Envato Tuts+" property="og:title"> |
2 |
<meta content="Envato Tuts+ teaches creative and technical skills across many topics to millions of people worldwide. We offer tutorials, articles, news and insights that help you take your knowledge to the next level." property="og:description"> |
3 |
<meta content="http://static.tutsplus.com/assets/favicon-8b86ba48e7f31535461f183680fe2ac9.png" property="og:image"> |
Pinterest usa el mismo protocolo que Facebook, OpenGraph, por lo que compartir funciona de la misma manera.
En Twitter, el concepto se llama "tarjeta", y Twitter tiene algunas variedades diferentes dependiendo de cómo desees presentar tu contenido. Aquí hay un ejemplo de una tarjeta de Twitter de GitHub:



Y aquí está el HTML que genera esta tarjeta:
1 |
<meta content="@github" name="twitter:site"> |
2 |
<meta content="summary" name="twitter:card"> |
3 |
<meta content="NodeRedis/node_redis" name="twitter:title"> |
4 |
<meta content="redis client for node. Contribute to node_redis development by creating an account on GitHub." name="twitter:description"> |
5 |
<meta content="https://avatars1.githubusercontent.com/u/5845577?v=3&s=400" name="twitter:image:src"> |
Nota: GitHub utiliza una técnica similar a la que se describe en este tutorial. El HTML de la página es ligeramente diferente en la etiqueta con el atributo de nombre establecido en twitter:description
. Tuve que cambiar el agente de usuario como se describe más adelante en el artículo para obtener la meta etiqueta correcta.
El problema con el renderizado del lado del cliente
Agregar las metaetiquetas no es un problema si solo deseas un título, descripción o imagen para todo el sitio. Simplemente codifica los valores en la etiqueta head
de tu documento HTML. Sin embargo, es probable que estés creando un sitio que sea mucho más complejo y desese que tu intercambio social enriquecido varíe según la URL (que probablemente sea una envoltura de la API de historial de HTML5 que tu marco está manipulando).
El primer intento podría ser crear tu plantilla y agregar los valores a las meta etiquetas como lo harías con cualquier otro contenido. Dado que, en este momento, los bots que extraen esta información no ejecutan JavaScript, terminará con las etiquetas de tu plantilla en lugar de los valores deseados cuando intente compartir.
Para que los bots puedan leer el sitio, estamos construyendo un middleware que detecta el agente de usuario de los bots de intercambio social y luego un enrutador alternativo que entregará el contenido correcto a los bots, evitando el uso de tu marco de SPA.
El middleware del agente de usuario
Los clientes (robots, rastreadores web, navegadores) envían una cadena de agente de usuario (UA) en los encabezados HTTP de cada solicitud. Se supone que esto identifica el software del cliente; mientras que los navegadores web tienen una gran variedad de cadenas UA, los bots tienden a ser más o menos estables. Facebook, Twitter y Pinterest publican las cadenas de agentes de usuario de sus bots como cortesía.
En Express, la cadena UA está contenida en el objeto request como user-agent
. Estoy usando una expresión regular para identificar los diferentes bots que me interesan que ofrezcan contenido alternativo. Lo contendremos en un middleware. Los middlewares son como rutas, pero no necesitan una ruta o método y (generalmente) pasan la solicitud a otro middleware o a las rutas. En Express, las rutas y los middlewares son secuenciales, así que colócalo por encima de cualquier otra ruta en tu aplicación Express.
1 |
app.use(function(req,res,next) { |
2 |
var
|
3 |
ua = req.headers['user-agent']; |
4 |
|
5 |
if (/^(facebookexternalhit)|(Twitterbot)|(Pinterest)/gi.test(ua)) { |
6 |
console.log(ua,' is a bot'); |
7 |
}
|
8 |
|
9 |
next(); |
10 |
});
|
La expresión regular anterior busca "facebookexternalhit", "Twitterbot" o "Pinterest" al comienzo de la cadena UA. Si existe, registrará el UA en la consola.
Aquí está todo el servidor:
1 |
var
|
2 |
express = require('express'), |
3 |
app = express(), |
4 |
server; |
5 |
|
6 |
app.use(function(req,res,next) { |
7 |
var
|
8 |
ua = req.headers['user-agent']; |
9 |
|
10 |
if (/^(facebookexternalhit)|(Twitterbot)|(Pinterest)/gi.test(ua)) { |
11 |
console.log(ua,' is a bot'); |
12 |
}
|
13 |
|
14 |
next(); |
15 |
});
|
16 |
|
17 |
app.get('/',function(req,res) { |
18 |
res.send('Serve SPA'); |
19 |
});
|
20 |
|
21 |
server = app.listen( |
22 |
8000, |
23 |
function() { |
24 |
console.log('Server started.'); |
25 |
}
|
26 |
);
|
Prueba tu middleware
En Chrome, navega hasta tu nuevo servidor (que debería ser http: // localhost: 8000 /
). Abre DevTools y activa el "Modo de dispositivo" haciendo clic en el icono del teléfono inteligente en la parte superior izquierda del panel del desarrollador.



En la barra de herramientas del dispositivo, coloca “Twitterbot / 1.0” en el cuadro de edición de UA.



Ahora, vuelve a cargar la página.
En este punto, deberías ver "Serve SPA" en la página, pero mirando la salida de la consola de tu aplicación Express, deberías ver:
Twitterbot / 1.0 es un bot
Enrutamiento alternativo
Ahora que podemos identificar los bots, creemos un enrutador alternativo. Express puede utilizar varios enrutadores, que a menudo se utilizan para dividir rutas por rutas. En este caso, usaremos un enrutador de una manera ligeramente diferente. Los enrutadores son esencialmente middlewares, por lo que exceptúan req
, res
y next
, como cualquier otro middleware. La idea aquí es generar un conjunto diferente de rutas que tengan los mismos caminos.
1 |
nonSPArouter = express.Router(); |
2 |
nonSPArouter.get('/', function(req,res) { |
3 |
res.send('Serve regular HTML with metatags'); |
4 |
});
|
Nuestro middleware también debe cambiarse. En lugar de simplemente registrar que el cliente es un bot, ahora enviaremos la solicitud al nuevo enrutador y, lo que es más importante, solo la pasaremos junto con next ()
si la prueba UA falla. Entonces, en resumen, los bots obtienen un enrutador y todos los demás obtienen el enrutador estándar que sirve al código SPA.
1 |
var
|
2 |
express = require('express'), |
3 |
app = express(), |
4 |
|
5 |
nonSPArouter
|
6 |
= express.Router(), |
7 |
server; |
8 |
|
9 |
nonSPArouter.get('/', function(req,res) { |
10 |
res.send('Serve regular HTML with metatags'); |
11 |
});
|
12 |
|
13 |
app.use(function(req,res,next) { |
14 |
var
|
15 |
ua = req.headers['user-agent']; |
16 |
|
17 |
if (/^(facebookexternalhit)|(Twitterbot)|(Pinterest)/gi.test(ua)) { |
18 |
console.log(ua,' is a bot'); |
19 |
nonSPArouter(req,res,next); |
20 |
} else { |
21 |
next(); |
22 |
}
|
23 |
});
|
24 |
|
25 |
app.get('/',function(req,res) { |
26 |
res.send('Serve SPA'); |
27 |
});
|
28 |
|
29 |
server = app.listen( |
30 |
8000, |
31 |
function() { |
32 |
console.log('Server started.'); |
33 |
}
|
34 |
);
|
Si probamos usando la misma rutina anterior, configurando UA en Twitterbot / 1.0
, el navegador mostrará al recargar:
Servir HTML normal con meta etiquetas
Mientras que con Chrome UA estándar obtendrás:
Servir SPA
Meta etiquetas
Como examinamos anteriormente, el intercambio social enriquecido se basa en meta
etiquetas dentro del encabezado de tu documento HTML. Dado que estás construyendo un SPA, es posible que ni siquiera tengas instalado un motor de plantillas. Para este tutorial, usaremos jade. Jade es un lenguaje tentador bastante simple donde los espacios y las pestañas son relevantes y no se necesitan etiquetas de cierre. Lo podemos instalar ejecutando:
npm install jade
En el código fuente de nuestro servidor, agrega esta línea antes de tu app.listen
.
app.set('view engine', 'jade');
Ahora, ingresaremos la información que queremos entregar solo al bot. Modificaremos el nonSPArouter
. Dado que hemos configurado el motor de visualización en el conjunto de aplicaciones, res.render
hará el renderizado de jade.
Configuremos una pequeña plantilla jade para servir a los bots de intercambio social:
1 |
doctype html |
2 |
html |
3 |
head |
4 |
title= title |
5 |
meta(property="og:url" name="twitter:url" content= url) |
6 |
meta(property="og:title" name="twitter:title" content= title) |
7 |
meta(property="og:description" name="twitter:description" content= descriptionText) |
8 |
meta(property="og:image" content= imageUrl) |
9 |
meta(property="og:type" content="article") |
10 |
meta(name="twitter:card" content="summary") |
11 |
body |
12 |
h1= title |
13 |
img(src= img alt= title) |
14 |
p= descriptionText |
La mayor parte de esta plantilla son las meta
etiquetas, pero también puedes ver que incluí la información en el cuerpo del documento. En el momento de redactar este tutorial, ninguno de los bots para compartir en redes sociales parece mirar nada más allá de las meta etiquetas, pero es una buena práctica incluir la información de una manera legible por humanos, en caso de que se implemente algún tipo de verificación humana en una fecha más adelante.
Guarda la plantilla en el directorio view
de su aplicación y asígnale el nombre bot.jade
. El nombre de archivo sin una extensión ("bot") será el primer argumento de la función res.render.
Si bien siempre es una buena idea desarrollar localmente, necesitarás exponer tu aplicación en su ubicación final para depurar completamente tus meta
etiquetas. Una versión desplegable de nuestro pequeño servidor se ve así:
1 |
var
|
2 |
express = require('express'), |
3 |
app = express(), |
4 |
|
5 |
nonSPArouter
|
6 |
= express.Router(), |
7 |
server; |
8 |
|
9 |
nonSPArouter.get('/', function(req,res) { |
10 |
var
|
11 |
img = 'placeholder.png'; |
12 |
|
13 |
res.render('bot', { |
14 |
img : img, |
15 |
url : 'https://bot-social-share.herokuapp.com/', |
16 |
title : 'Bot Test', |
17 |
descriptionText
|
18 |
: 'This is designed to appeal to bots', |
19 |
imageUrl : 'https://bot-social-share.herokuapp.com/'+img |
20 |
});
|
21 |
});
|
22 |
|
23 |
app.use(function(req,res,next) { |
24 |
var
|
25 |
ua = req.headers['user-agent']; |
26 |
|
27 |
if (/^(facebookexternalhit)|(Twitterbot)|(Pinterest)/gi.test(ua)) { |
28 |
console.log(ua,' is a bot'); |
29 |
nonSPArouter(req,res,next); |
30 |
} else { |
31 |
next(); |
32 |
}
|
33 |
});
|
34 |
|
35 |
app.get('/',function(req,res) { |
36 |
res.send('Serve SPA'); |
37 |
});
|
38 |
app.use('/',express.static(__dirname + '/static')); |
39 |
app.set('view engine', 'jade'); |
40 |
server = app.listen( |
41 |
process.env.PORT || 8000, |
42 |
function() { |
43 |
console.log('Server started.'); |
44 |
}
|
45 |
);
|
También ten en cuenta que estoy usando el middleware express.static
para entregar la imagen desde el directorio /static
.
Depurando tu aplicación
Una vez que hayas implementado tu aplicación en un lugar de acceso público, debes verificar que sus meta
etiquetas funcionen como lo deseas.
En primer lugar, puedes probar con el depurador de Facebook. Ingresa tu URL y haz clic en Obtener nueva información.
Deberías ver algo como:



A continuación, puedes pasar a probar tu tarjeta de Twitter con el Validador de tarjetas de Twitter. Para este, debes iniciar sesión con tu cuenta de Twitter.



Pinterest proporciona un depurador, pero este ejemplo no funcionará de inmediato porque Pinterest solo permite "pines enriquecidos" en URL que no sean tu página de inicio.
Próximos pasos
En tu implementación actual, deberás manejar la integración de tu fuente de datos y enrutamiento. Es mejor mirar las rutas especificadas en tu código SPA y crear una versión alternativa para todo lo que creas que se puede compartir. Una vez que hayas establecido las rutas que probablemente se compartirán, configura las meta
etiquetas en tu plantilla principal que funcionen como tu respaldo en caso de que alguien comparta una página que no esperaba.
Si bien Pinterest, Facebook y Twitter representan una gran parte del mercado de las redes sociales, es posible que tengas otros servicios que desees integrar. Algunos servicios publican el nombre de sus robots para compartir en redes sociales, mientras que otros pueden no hacerlo. Para determinar el agente de usuario, puedes usar console.log
y examinar la salida de la consola; intenta esto primero en un servidor que no sea de producción, ya que puedes pasar un mal rato tratando de determinar el agente de usuario en un sitio ocupado. Desde ese punto, puedes modificar la expresión regular en nuestro middleware para capturar también al nuevo agente de usuario.
Los recursos compartidos enriquecidos en las redes sociales pueden ser una excelente manera de atraer a las personas a tu elegante sitio web basado en aplicaciones de una sola página. Al dirigir de forma selectiva a los robots a contenido legible por máquina, puedes proporcionar la información correcta a los robots.