Similar Posts
Boomerang: medición de rendimiento desde la perspectiva del usuario
Boomerang es una librería desarrollada por Yahoo que permite medir diferentes aspectos de rendimiento de nuestra web desde la perspectiva del usuario final. Añadiendo un script y distintas funciones, podemos comprobar diversos aspectos de nuestra web como:
- El tiempo que el usuario cree que tarda en cargarse la web
- El tiempo de carga de contenido dinámico
- El ancho de banda durante la carga de la página
- Tiempo de carga de diferentes módulos, por ejemplo módulos de Twitter o Facebook
- Latencia HTTP
- Latencia DNS
BOOMR.init({
user_ip: "",
beacon_url: "http://yoursite.com/path/to/beacon.php",
BW: {
base_url: 'http://yoursite.com/path/to/bandwidth/images/"
}
});
Además permite etiquetar páginas para realizar distintos tests y poder compararlos, realizar tests a usuarios aleatorios y evitar abusos de uso
Vía / WebAppers
Lista de ofuscadores para Javascript
Para aquellos que necesiten ofuscar su código Javascript para que sea más difÃcil de entender a los usuarios, les vendrá bastante bien esta lista de aplicaciones que modificarán nuestro código:
- Thicket™ Obfuscator for JavaScript: también válido para ECMAScript, a parte de modificar el código para dificultar su lectura, lo comprime.
- Jasob 2: modifica los nombres de variables, borra comentarios y elimina espacios entre muchas otras cosas.
- Javascript Obfuscator: trata los scripts y ficheros js contenidos en una página html, modificando los espacios, comentarios, nombres de variables y funciones y lo escribe todo en una única lÃnea, añadiendo punto y coma cuando sea necesario. Existe versión online.
- Stunnix JavaScript Obfuscator: modifica javascripts y ECMAScripts contenidos en ficheros HTML, PHP, ASP, JSP.
- JCE Pro: modifica el código javascript para que sea imposible su lectura.
- Scripts Encryptor (ScrEnc): ofusca los siguientes tipos de archivos: HTML, JavaScript/JScript, C/C++/MFC.
- Shane Ng’s GPL-licenced obfuscator: ofuscador con licencia GPL.
- Dean Edwards JavaScript Compressor/Obfuscator: online.
- ESC: ofuscador de código ECMAScript escrito en JScript.
- Jammer: modifica ficheros HTML, Javascript y VRML, comprimiendo su espacio y haciendo que sea difÃcil de entender.
- JSCruncher Pro: reduce una media del 60% del tamaño original.
- Strong JS: elimina caracteres innecesarios y modificando el nombre de variables.
- JavaScript Scrambler: fácil de usar.
- Javascript Encoder from scriptasylum.com: online.
VÃa / Ajax Digest
Hapi.js + Vue.js inicializar el frontend
El backend ya está algo configurado, por lo que voy a empezar a configurar el frontend.
Instalaré varias librerías:
- Vue.js
- Webpack: configurado para que funcione con HMR
- Eslint: para que no haya errores Javascript
- Stylelint: lo mismo para CSS
- Buefy: una librería que combina Bulma y Vue
- Sass loader
En vez de ir instalando una a una, usando el siguiente package.json y ejecutando npm i, lo tendremos todo instalado.
{
"name": "hapi-frontend",
"version": "1.0.0",
"description": "Hapi.js frontend",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --mode development --config webpack.config.dev.js",
"build": "webpack --mode production --config webpack.config.production.js"
},
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.5.4",
"babel-eslint": "^10.0.2",
"babel-loader": "^8.0.6",
"css-loader": "^3.0.0",
"eslint": "^6.0.1",
"eslint-plugin-html": "^6.0.0",
"eslint-plugin-vue": "^5.2.3",
"mini-css-extract-plugin": "^0.7.0",
"node-sass": "^4.12.0",
"sass-loader": "^7.1.0",
"stylelint": "^10.1.0",
"stylelint-config-standard": "^18.3.0",
"stylelint-webpack-plugin": "^0.10.5",
"vue-hot-reload-api": "^2.3.3",
"vue-html-loader": "^1.2.4",
"vue-loader": "^15.7.0",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.35.3",
"webpack-cli": "^3.3.5",
"webpack-dev-server": "^3.7.2",
"webpack-merge": "^4.2.1"
},
"dependencies": {
"buefy": "^0.7.10",
"vue": "^2.6.10"
}
}
Como se puede ver, existen dos scripts dentro de npm: build que compila el js y extrae los CSS, y dev, que arranca el servidor de webpack habilitando HMR (🎶 ¡ya no puedo vivir sin él! 🎶).
Ambas configuraciones de webpack usan un script en común (webpack.config.common.js):
const webpack = require( 'webpack' );
const path = require( 'path' );
// Carga los ficheros .vue
const VueLoaderPlugin = require( 'vue-loader/lib/plugin' );
// Configura stylelint
const StyleLintPlugin = require( 'stylelint-webpack-plugin' );
// Para obtener un path para los alias
function resolve( dir ) {
return path.join( __dirname, '.', dir );
}
module.exports = {
mode: 'production',
// Fichero inicial del proyecto
entry: './js/main.js',
// Fichero final para incluir
output: {
filename: 'js/main.js',
publicPath: '/dist/',
},
module: {
// Reglas para los ficheros
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.css$/,
use: [
'css-loader',
'sass-loader',
],
},
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new VueLoaderPlugin(),
new StyleLintPlugin( {
files: [ '**/*.{vue,htm,html,css,sss,less,scss,sass}' ],
} ),
],
resolve: {
extensions: [ '.js', '.vue', '.json' ],
alias: {
'@': resolve( '' ),
},
},
};
El frontend se gestiona desde el fichero main.js, que inicializará Vue y añadirá el componente principal:
import Vue from 'vue';
import Buefy from 'buefy';
import 'buefy/dist/buefy.css';
import App from './components/App.vue';
import '@/assets/scss/main.scss';
Vue.use( Buefy );
new Vue( {
el: '#app',
components: {
App,
},
render: ( c ) => c( 'app' ),
} );
// accept replacement modules
if ( module.hot ) {
module.hot.accept();
}
Y ya por último el componente App.vue, que muestra simplemente un poco de HTML
<template>
<header class="hero">
<div class="hero-head">
<h1>{{ title }}</h1>
</div>
</header>
</template>
<script>
export default {
data() {
return {
title: "Demo site",
};
},
};
</script>
<style lang="scss" scoped>
div {
h1 {
color: #fff;
}
}
</style>
Bueno, ha sido un resumen rápido, pero bajándote el código seguro que lo entiendes fácil
Hapi.js + Vue.js ejemplo mínimo de frontend: formulario login
Esta parte es solo frontend, aún no está configurado para que interactúe con el servidor.
Lo más destacado de este ejemplo es el uso de vue-router, paquete que permite la realización de SPA de forma sencilla. Como la aplicación será gestionada por un único fichero (index.html), es necesario configurar el servidor de webpack para que gestione las URLs que acceden a otras partes de la aplicación para que no devuelva un error 404.
Esto es fácil, tan solo hay que añadir historyApiFallback y ponerlo a true en la configuración del servidor.
devServer: {
inline: true,
hot: true,
port: 9999,
historyApiFallback: true,
},
Si usas Apache u otro servidor deberás usar una configuración distinta.
Lógicamente habrá que instalar el paquete vue-router.
Vale, ya está todo instalado, ahora solo hace falta configurar vue-router para que acepte distintas URLs y que muestre distintos controladores según sea el caso.
Para ello creamos un fichero router.js que posteriormente añadiremos a nuestra instancia de Vue:
Es fácil de entender, importamos los distintos controladores y configuramos las rutas (‘/‘ y ‘/login‘), a las que les asignaremos el controlador correspondiente.
Para indicar a Vue que vamos a usar vue-router, debemos importarlo en la instancia de la aplicación:
import App from './components/App.vue';
import router from './router';
Vue.use( VueRouter );
new Vue( {
el: '#app',
router,
components: {
App,
},
render: ( c ) => c( 'app' ),
} );
El siguiente paso es modificar el controlador principal de la aplicación (App.vue) para que muestre la cabecera (que tendrá su propio controlador) y la vista principal de vue-router (<router-view>):
<template>
<div>
<v-header />
<router-view />
</div>
</template>
<script>
import header from '@/js/components/layout/Header';
export default {
name: 'App',
components: {
'v-header': header,
},
};
</script>
Como no soy diseñador, pues usaré Buefy (basado en Bulma) y Material Design icons (no sé por qué le tengo algo de manía a FontAwesome).
Existe un paquete especial para usar Material Design en vue (vue-material-design-icons), que para funcionar con Buefy necesitará usar la fuente de letras de Material Design (@mdi/fonts). Instalamos todo y ya estará todo listo para empezar a diseñar nuestra página.
La cabecera (<v-header>) mostrará el logo, el menú principal y otro secundario para loguearse. No explicaré ni las clases Bulma (que yo casi ni conozco) y cómo se muestra el menú al clickar en el burger icon, ya que estos tutoriales son para llevar yo un diario de cómo desarrollar una app web con Hapi.js y Vue.js.
El controlador de la cabecera nos quedará así:
<template>
<header>
<nav
class="navbar"
role="navigation"
aria-label="main navigation"
>
<div class="navbar-brand">
<a
class="navbar-item"
href="https://sentidoweb.com"
>
<img src="/assets/images/logo.svg">
</a>
<a
role="button"
class="navbar-burger burger"
aria-label="menu"
aria-expanded="false"
:class="{ 'is-active' : showNav }"
@click="showNav = !showNav"
>
<span aria-hidden="true" />
<span aria-hidden="true" />
<span aria-hidden="true" />
</a>
</div>
<div :class="[ { 'is-active' : showNav }, 'navbar-menu' ]">
<div class="navbar-start">
<router-link class="navbar-item" to='/'>Home</router-link>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<router-link class="button is-light" to='/login'>Log in</router-link>
</div>
</div>
</div>
</div>
</nav>
</header>
</template>
<script>
export default {
data() {
return {
showNav: false,
};
},
};
</script>
Tan solo mencionar cómo vue-router gestiona la navegación, para ello hace uso de <router-link>:
<router-link class="navbar-item" to='/'>Home</router-link>
El resto del código es simplemente la página principal y el formulario “tonto”.
Hapi.js + Vue.js modelos mejorados
En este caso voy a explicar cómo añadir una ruta en el backend para gestionar usuarios.
Antes de nada vamos a instalar tres paquetes:
- @hapi/joi para validar los datos de entrada
- @hapi/boom para mostrar errores HTTP de forma sencilla
- bcrypt para encriptar la contraseña
npm i @hapi/joi
npm i @hapi/boom
npm i bcrypt
Tendremos que añadir la ruta al manifest de glee
const manifest = {
server: {
port: Config.get( '/server/port' ),
},
register: {
plugins: [
{
plugin: './api/home',
},
{
plugin: './api/user',
},
{
plugin: './plugins/db',
options: Config.get( '/db' ),
},
],
},
};
Ahora solo falta crear el controlador para las rutas de usuarios, dos en este caso:
- GET /user/[user] para recuperar un usuario
- PUT /user para crear un nuevo usuario
Lógicamente aún no hay nada de autenticación, por lo que cualquiera puede crear un usuario realizando una llamada PUT a la URL indicando userName, email y password.
Para comprobar la validez de los datos introducidos, usaremos joi. Usando las opciones de la ruta, indicaremos las reglas que deberá cumplir cada parámetro introducido. Así, para recuperar un usuario, se comprobará que user sea string, alfanumérico y que tenga una longitud de 3 a 20 caracteres:
validate: {
params: {
user: Joi.string().alphanum().min( 3 ).max( 20 ),
},
},
Así de fácil.
En el caso de comprobar los datos de entrada de la llamada PUT, en vez de usar params, usaremos payload:
validate: {
payload: {
userName: Joi.string().alphanum().min( 3 ).max( 20 ).required(),
email: Joi.string().email().required(),
password: Joi.string().min( 8 ).required(),
},
},
Por último mostrar el código para crear un nuevo usuario. Primero se comprueba si existe un usuario con ese nickname o email. Si es así, se devuelve error usando boom, si no, se genera la contraseña encriptada (aquí no me he molestado mucho en ello, ya lo haré más adelante), y se crea el usuario usando el método create de moongose:
/**
* Route handler
*
* @param {object} request
* @param {object} h Hapi object
* @returns {object}
*/
handler: async( request, h ) => { // eslint-disable-line
try {
// TODO: Add role
const user = await User
.findOne( {
$or: [
{ userName: request.payload.username },
{ email: request.payload.email },
],
} )
.exec();
if ( user ) {
return Boom.badData( 'User exists' );
}
const password = await bcrypt.hash( request.payload.password, Config.get( '/hash/PASSWORD_HASH' ) );
const userData = Object.assign( {}, request.payload, { password } );
const newUser = await User.create( userData );
return newUser ?
{
response: true,
message: 'User created',
userId: newUser.id,
} :
Boom.boomify( {
response: false,
message: 'There was an error during user creation',
}, { statusCode: 400 } );
} catch ( error ) {
return Boom.badImplementation( 'Error', { error } );
}
},
Como último apunte, he modificado la configuración para que admita ficheros .env con los datos necesarios.
Como siempre te puedes bajar el código aquí
Detectar cambio de tamaño de letra en Javascript
La verdad es que lo sencillo es lo mejor, y para cuando estés en la necesidad de detectar si se produce un cambio en el tamaño de la letra, nada mejor que el script que nos ofrece la gente de A List Apart.
Te puedes preguntar por qué vas a querer detectar el cambio de tipo de letra. Si te interesa tener un sitio accesible a gente con discapacidades, pues es buena idea que pienses en ello, ya que suele ser algo que pueden hacer con frecuencia.
Además de detectar ese cambio, puede ser necesario realizar alguna acción. Por ejemplo, si usamos una imagen para un botón, si cambiamos el tamaño de la letra, la imagen no cambia, por lo que el botón quedará demasiado pequeño para el resto del texto, ¿solución?, si hay cambio de tamaño de letra, sustituimos la imagen por un elemento input botón.
Al principio decÃa que la solución es sencilla, lo cual la hace aún mejor. Se trata de crear una capa que contenga un espacio dentro y que esté oculta. Se guarda el tamaño de la capa y cada cierto tiempo se detecta si ha habido un cambio en este tamaño, si es asÃ, se ha producido un cambio en el tamaño de la letra.
Text-Resize Detection
Demo
Código y ejemplos