Hello.

I am Paul Kinlan.

A Developer Advocate for Chrome and the Open Web at Google.

Grep your git commit log

Paul Kinlan

Finding code that was changed in a commit

Read More

Paul Kinlan

Trying to make the web and developers better.

RSS Github Medium

Performance and Resilience: Stress-Testing Third Parties by CSS Wizardry

Paul Kinlan

Hace un par de semanas estuve en China para el Día del desarrollador de Google y les mostré a todos mi QRCode scanner, estaba funcionando muy bien hasta que me desconecté. Cuando el usuario estaba fuera de línea (o parcialmente conectado), la cámara no se iniciaría, lo que significaba que no podía ajustar los códigos QR. Me tomó una edad para averiguar qué estaba pasando, y resultó que estaba arrancando la cámara por error en mi evento onload y la solicitud de Google Analytics se bloqueó y no se resolvió de manera oportuna. Fue este compromiso el que lo arregló.

Because these types of assets block rendering, the browser will not paint anything to the screen until they have been downloaded (and executed/parsed). If the service that provides the file is offline, then that’s a lot of time that the browser has to spend trying to access the file, and during that period the user is left potentially looking at a blank screen. After a certain period has elapsed, the browser will eventually timeout and display the page without the asset(s) in question. How long is that certain period of time?

It’s 1 minute and 20 seconds.

If you have any render-blocking, critical, third party assets hosted on an external domain, you run the risk of showing users a blank page for 1.3 minutes.

Below, you’ll see the DOMContentLoaded and Load events on a site that has a render-blocking script hosted elsewhere. The browser was completely held up for 78 seconds, showing nothing at all until it ended up timing out.

Leer publicación completa.

Te animo a leer el post porque hay mucha información excelente.

Chrome Bug 897727 - MediaRecorder using Canvas.captureStream() fails for large canvas elements on Android

Paul Kinlan

El fin de semana que estuve jugando con un codificador de video de efecto Boomerang, puedes hacerlo funcionar casi en tiempo real (lo explicaré más adelante). Lo tengo funcionando en Chrome on Desktop, pero nunca funcionaría correctamente en Chrome en Android. Ver el código aquí.

Parece que cuando usas captureStream () en un <canvas>que tiene una resolución relativamente grande (1280x720 en mi caso), la API de MediaRecorder no podrá codificar los videos y no se producirá un error y no se puede detectar que no puede codificar el video con anticipación.

(1) Capture a large res video (from getUM 1280x720) to a buffer for later processing. (2) Create a MediaRecorder with a stream from a canvas element (via captureStream) sized to 1280x720 (3) For each frame captured putImageData on the canvas (4) For each frame call canvasTrack.requestFrame() at 60fps

context.putImageData(frame, 0, 0); canvasStreamTrack.requestFrame();

Demo: https://boomerang-video-chrome-on-android-bug.glitch.me/ Code: https://glitch.com/edit/#!/boomerang-video-chrome-on-android-bug?path=script.js:21:42

What is the expected result?

For the exact demo, I buffer the frames and then reverse them so you would see the video play forwards and backwards (it works on desktop). In generall I would expect all frames sent to the canvas to be processed by the MediaRecorder API - yet they are not.

What happens instead?

It only captures the stream from the canvas for a partial part of the video and then stops. It’s not predicatable where it will stop.

I suspect there is a limit with the MediaRecorder API and what resolution it can encode depending on the device, and there is no way to know about these limits ahead of time.

As far as I can tell this has never worked on Android. If you use https://boomerang-video-chrome-on-android-bug.glitch.me which has a 640x480 video frame it records just fine. The demo works at higher-resolution just fine on desktop.

Leer publicación completa.

Si quieres jugar con la demo que funciona en ambos, haz clic aquí (0)

Why Microsoft and Google love progressive web apps | Computerworld

Paul Kinlan

Un buen post sobre PWA de Mike Elgan. No estoy seguro de cuál es el objetivo de Microsoft con PWA, pero creo que el nuestro es bastante simple: queremos que los usuarios tengan acceso al contenido y la funcionalidad de manera instantánea y de la forma en que esperan poder interactuar con ellos en sus dispositivos. La web debe llegar a todos los dispositivos conectados y el usuario debe poder acceder a su modalidad preferida, como una aplicación si así lo esperan (móvil, tal vez) o voz en un asistente, etc.

Todavía estamos lejos de la web sin cabeza, sin embargo, una cosa realmente me impresionó en el artículo:

Another downside is that PWAs are highly isolated. So it’s hard and unlikely for different PWAs to share resources or data directly.

Leer publicación completa.

Los sitios y las aplicaciones en la web no deben estar aislados, la web es vinculable, indexable, efímera, pero cada vez que creamos un sitio más en silos. Estamos creando silos no deseados porque la plataforma no permite fácilmente a los usuarios ingresar * sus * datos dentro y fuera de los sitios fácilmente. No estoy hablando de RDF ni nada de eso, las operaciones básicas como copiar y pegar, arrastrar y soltar, compartir en el sitio y compartir desde el sitio se rompen en la web de hoy, y eso es antes de que lleguemos al IPC entre marcos, trabajadores y ventanas.

Building a video editor on the web. Part 0.1 - Screencast

Paul Kinlan

Debería poder crear y editar videos usando solo la web en el navegador. Debería ser posible proporcionar una interfaz de usuario similar a Screenflow que le permita crear un video de salida que combine múltiples videos, imágenes y audio en un video que se puede cargar a servicios como YouTube. Siguiendo con la mi publicación anterior que describe brevemente los requisitos del editor de video, en esta publicación solo quería mostrar rápidamente cómo construí la grabadora de cámara web y también cómo crear una presentación de pantalla.

Read More

894556 - Multiple video tracks in a MediaStream are not reflected on the videoTracks object on the video element

Paul Kinlan

El primer problema que encontré al intentar construir un editor de video en la web.

Tengo varias secuencias de video (computadora de escritorio y cámara web) y quería poder alternar entre las secuencias de video en un elemento de video para poder cambiar rápidamente entre la cámara web y la computadora de escritorio y no interrumpir el MediaRecorder.

Parece que deberías poder hacerlo alternando la propiedad selected en el objetovideoTracks en el <video> Elementopero no puede, la matriz de pistas contiene solo 1 elemento (la primera pista de video en MediaStream).

What steps will reproduce the problem? (1) Get two MediaStreams with video tracks (2) Add them to a new MediaStream and attach as srcObject on a videoElement (3) Check the videoElement.videoTracks object and see there is only one track

Demo at https://multiple-tracks-bug.glitch.me/

What is the expected result? I would expect videoElement.videoTracks to have two elements.

What happens instead? It only has the first videoTrack that was added to the MediaStream.

Leer publicación completa.

Caso de repro.

window.onload = () => {
  if('getDisplayMedia' in navigator) warning.style.display = 'none';

  let blobs;
  let blob;
  let rec;
  let stream;
  let webcamStream;
  let desktopStream;

  captureBtn.onclick = async () => {

       
    desktopStream = await navigator.getDisplayMedia({video:true});
    webcamStream = await navigator.mediaDevices.getUserMedia({video: { height: 1080, width: 1920 }, audio: true});
    
    // Always 
    let tracks = [...desktopStream.getTracks(), ... webcamStream.getTracks()]
    console.log('Tracks to add to stream', tracks);
    stream = new MediaStream(tracks);
    
    console.log('Tracks on stream', stream.getTracks());
    
    videoElement.srcObject = stream;
    
    console.log('Tracks on video element that has stream', videoElement.videoTracks)
    
    // I would expect the length to be 2 and not 1
  };

};

Building a video editor on the web. Part 0.

Paul Kinlan

Debería poder crear y editar videos usando solo la web en el navegador. Debería ser posible proporcionar una interfaz de usuario similar a Screenflow que le permita crear un video de salida que combine múltiples videos, imágenes y audio en un video que se puede cargar a servicios como YouTube. Este post es realmente solo una declaración de intenciones. Voy a comenzar el largo proceso de averiguar qué está y qué no está disponible en la plataforma y ver qué tan lejos podemos llegar hoy.

Read More

Barcode detection in a Web Worker using Comlink

Paul Kinlan

Soy un gran fan de los códigos QR, son una forma muy simple y ordenada de intercambiar datos entre el mundo real y el mundo digital. Desde hace unos años he tenido un pequeño proyecto paralelo llamado QRSnapper & mdash; bueno, ha tenido algunos nombres, pero este es el que me he fijado en & mdash; que utiliza la API getUserMedia para tomar datos en vivo de la cámara del usuario para que pueda escanear los códigos QR casi en tiempo real.

El objetivo de la aplicación era mantener 60 fps en la interfaz de usuario y la detección casi instantánea del código QR, lo que significaba que tenía que colocar el código de detección en un trabajador web (cosas bastante estándar). En este post solo quería compartir rápidamente cómo usé comlink para simplificar enormemente la lógica en el Worker.

qrclient.js

import * as Comlink from './comlink.js';

const proxy = Comlink.proxy(new Worker('/scripts/qrworker.js')); 

export const decode = async function (context) {
  try {
    let canvas = context.canvas;
    let width = canvas.width;
    let height = canvas.height;
    let imageData = context.getImageData(0, 0, width, height);
    return await proxy.detectUrl(width, height, imageData);
  } catch (err) {
    console.log(err);
  }
};

qrworker.js (trabajador web)

import * as Comlink from './comlink.js';
import {qrcode} from './qrcode.js';

// Use the native API's
let nativeDetector = async (width, height, imageData) => {
  try {
    let barcodeDetector = new BarcodeDetector();
    let barcodes = await barcodeDetector.detect(imageData);
    // return the first barcode.
    if (barcodes.length > 0) {
      return barcodes[0].rawValue;
    }
  } catch(err) {
    detector = workerDetector;
  }
};

// Use the polyfil
let workerDetector = async (width, height, imageData) => {
  try {
    return qrcode.decode(width, height, imageData);
  } catch (err) {
    // the library throws an excpetion when there are no qrcodes.
    return;
  }
}

let detectUrl = async (width, height, imageData) => {
  return detector(width, height, imageData);
};

let detector = ('BarcodeDetector' in self) ? nativeDetector : workerDetector;
// Expose the API to the client pages.
Comlink.expose({detectUrl}, self);

Realmente amo a Comlink, creo que es un cambio de juego de una biblioteca, especialmente cuando se trata de crear JavaScript idiomático que funciona a través de hilos. Finalmente, lo bueno aquí es que la API de detección de código de barras nativa se puede ejecutar dentro de un trabajador, por lo que toda la lógica está encapsulada fuera de la interfaz de usuario.

Leer publicación completa.

Running FFMPEG with WASM in a Web Worker

Paul Kinlan

Me encanta FFMPEG.js, es una buena herramienta compilada con asm.js` y me permite crear aplicaciones web JS que pueden editar videos rápidamente. FFMPEG.js también trabaja con trabajadores web para que pueda codificar videos sin bloquear el hilo principal.

También me encanta Comlink. Comlink me permite interactuar fácilmente con los trabajadores web al exponer funciones y clases sin tener que lidiar con una compleja máquina de estados postMessage.

Recientemente pude combinar los dos juntos. Estaba experimentando para que FFMPEG fuera exportado a Web Assembly (funciona - yay) y quería limpiar todo el trabajo posterior al mensaje en el proyecto FFMPEG.js actual. A continuación se muestra cómo se ve el código: creo que es bastante claro. Tenemos un trabajador que importa ffmpeg.js y comlink y simplemente expone la interfaz ffmpeg, y luego tenemos la página web que carga al trabajador y luego usa comlink para crear un proxy para la API de ffmpeg.

Ordenado.

worker.js

importScripts('https://cdn.jsdelivr.net/npm/comlinkjs@3.0.2/umd/comlink.js');
importScripts('../ffmpeg-webm.js'); 
Comlink.expose(ffmpegjs, self);

client.html

let ffmpegjs = await Comlink.proxy(worker);
let result = await ffmpegjs({
   arguments: ['-y','-i', file.name, 'output.webm'],
   MEMFS: [{name: file.name, data: data}],
   stdin: Comlink.proxyValue(() => {}),
   onfilesready: Comlink.proxyValue((e) => {
     let data = e.MEMFS[0].data;
     output.src = URL.createObjectURL(new Blob([data]))
     console.log('ready', e)
   }),
   print: Comlink.proxyValue(function(data) { console.log(data); stdout += data + "\n"; }),
   printErr: Comlink.proxyValue(function(data) { console.log('error', data); stderr += data + "\n"; }),
   postRun: Comlink.proxyValue(function(result) { console.log('DONE', result); }),
   onExit: Comlink.proxyValue(function(code) {
     console.log("Process exited with code " + code);
     console.log(stdout);
   }),
});

Me gusta mucho cómo pueden jugar juntos los módulos compilados de Comlink, Workers y WASM. Obtengo JavaScript idiomático que interactúa con el módulo WASM directamente y se ejecuta fuera del hilo principal.

Leer publicación completa.

Translating a blog using Google Cloud Translate and Hugo

Paul Kinlan

Recientemente volví de un viaje a la India para asistir al evento Google4India (informe pronto) y para reunirme con una gran cantidad de empresas y desarrolladores. Uno de los cambios más interesantes discutidos fue la promoción de más contenido en el idioma de los usuarios en el país, y fue particularmente evidente en todos los productos de Google, que van desde facilitar la búsqueda en el idioma de los usuarios, hasta encontrar contenido, y también para leerlo a los usuarios en forma de texto o voz.

Todo el viaje me hizo pensar. Mi blog está construido con Hugo. Hugo ahora admite contenido escrito en varios idiomas. Hugo es totalmente estático, por lo que crear contenido nuevo es cuestión de simplemente crear un nuevo archivo y dejar que el sistema de compilación lo haga. Así que tal vez pueda construir algo que haga que mi contenido esté más disponible para más personas ejecutando mi contenido estático a través de una herramienta de traducción porque la traducción humana del contenido es muy costosa.

Un par de horas antes de mi vuelo de regreso al Reino Unido, creé un pequeño script que tomará mis archivos de marcado y los ejecutará a través de Google Cloud Translate para crear un archivo rápido. traducción de la página que puedo alojar rápidamente. La solución completa se presenta a continuación. Es un procesador relativamente básico, ignora el preámbulo de Hugo que ignora el ‘código’ e ignora las comillas de extracción - mi suposición era que estas siempre deben dejarse tal como fueron escritas.

Nota: Parece que nuestro software de aprendizaje para traducciones utiliza, por lo que es importante marque su página para que las herramientas de aprendizaje no usen el contenido traducido de Google como entrada a sus algoritmos.

// Imports the Google Cloud client library
const Translate = require('@google-cloud/translate');
const program = require('commander');
const fs = require('fs');
const path = require('path');

program
  .version('0.1.0')
  .option('-s, --source [path]', 'Add in the source file.')
  .option('-t, --target [lang]', 'Add target language.')
  .parse(process.argv);

// Creates a client
const translate = new Translate({
  projectId: 'html5rocks-hrd'
});

const options = {
  to:  program.target,
};

async function translateLines(text) {
  if(text === ' ') return ' ';
  const output = [];
  let results = await translate.translate(text, options);

  let translations = results[0];
  translations = Array.isArray(translations)
    ? translations
    : [translations];

  translations.forEach((translation, i) => {
    output.push(translation)
  });

  return output.join('\n');
};

// Translates the text into the target language. "text" can be a string for
// translating a single piece of text, or an array of strings for translating
// multiple texts.
(async function (filePath, target) {

  const text = fs.readFileSync(filePath, 'utf8');

  const lines = text.split('\n');
  let translateBlock = [];
  const output = [];

  let inHeader = false;
  let inCode = false;
  let inQuote = false;
  for (const line of lines) {
    // Don't translate preampble
    if (line.startsWith('---') && inHeader) { inHeader = false; output.push(line); continue; }
    if (line.startsWith('---')) { inHeader = true; output.push(line); continue; }
    if (inHeader) { output.push(line); continue; }

    // Don't translate code
    if (line.startsWith('```') && inCode) { inCode = false; output.push(line); continue; }
    if (line.startsWith('```')) { inCode = true; output.push(await translateLines(translateBlock.join(' '))); translateBlock = []; output.push(line); continue; }
    if (inCode) { output.push(line); continue; }

    // Dont translate quotes
    if (inQuote && line.startsWith('>') === false) { inQuote = false; }
    if (line.startsWith('>')) { inQuote = true; output.push(await translateLines(translateBlock.join(' '))); translateBlock = []; output.push(line); }
    if (inQuote) { output.push(line); continue; }

    if (line.charAt(0) === '\n' || line.length === 0) { output.push(await translateLines(translateBlock.join(' '))); output.push(line); translateBlock = []; continue;} 

    translateBlock.push(line);
  }

  if(translateBlock.length > 0) output.push(await translateLines(translateBlock.join(' ')))

  const result = output.join('\n');
  const newFileName = path.parse(filePath);
  fs.writeFileSync(`content/${newFileName.name}.${target}${newFileName.ext}`, result);

})(program.source, program.target);

En general, estoy muy contento con el proceso. Entiendo que la traducción automática no es perfecta, pero mi pensamiento es que puedo aumentar el alcance de mi contenido a personas que podrían estar buscando en sus propios idiomas y no en inglés. Puedo aumentar el área de superficie de descubrimiento de mi contenido y espero ayudar más. gente.

Tomará un tiempo para ver si esto realmente ayuda a las personas, por lo que informaré cuando tenga más datos … Ahora para ejecutar mi script en más de mi sitio :)

Apple - Web apps - All Categories

Paul Kinlan

¿Recuerdas cuando las aplicaciones web eran * una * forma recomendada de usar aplicaciones en el iPhone?

What are web apps? Learn what they are and how to use them.

Leer la publicación completa.

Alrededor de 2013, Apple comenzó a redirigir el directorio / webapps / top-level a / iphone /

El caso es que el directorio en realidad era bastante bueno, muchas de las aplicaciones todavía funcionan hoy en día. Sin embargo, al mirar AppStore resolvió muchos más problemas que tenían los desarrolladores: Mejor descubrimiento y búsqueda específicamente porque la AppStore estaba directamente en el dispositivo. La AppStore también estaba comenzando a introducir esa fricción eliminada de los usuarios y desarrolladores específicamente con respecto a los pagos.

Gears API

Paul Kinlan

Estoy escribiendo una publicación en un blog sobre las primeras API de la Web móvil y Alex Russell me recordó a Google Gears

Gears modules include:

  • LocalServer Cache and serve application resources (HTML, JavaScript, images, etc.) locally
  • Database Store data locally in a fully-searchable relational database
  • WorkerPool Make your web applications more responsive by performing resource-intensive operations asynchronously

Leer publicación completa.

Creo que es interesante ver que AppCache y WebSQL, Geolocalización y WebWorkers surgieron de las ideas en Google Gears y solo sobrevivieron los dos últimos. WebSQL nunca fue ampliamente compatible, y fue reemplazado por IndexedDB; y AppCache reemplazado por ServiceWorker

RSS Feed to Google Chat Webhook using Cloud Functions for Firebase and Superfeedr

Paul Kinlan

Usamos Google Chat internamente mucho para comunicarnos en todo nuestro equipo; es algo así como nuestra holgura; También creamos una gran cantidad de contenido que se puede acceder a través de fuentes RSS, incluso tenemos un feed de equipo que todos pueden ver. No fue hasta hace poco que descubrí que era bastante fácil crear un bot simple solo por correo a través de WebHooks y eso Me dio la idea, puedo crear un servicio simple que sondee los feeds RSS y luego los envíe a nuestro webhook para que se publiquen directamente en el chat de nuestro equipo.

Al final fue bastante simple, y he incluido todo el código a continuación. Utilicé las funciones de Firebase. Sospecho que esto es igual de fácil en otros sitios de Función como servicio y Superfeedr. Superfeedr es un servicio que puede escuchar Pubsubhubbub ping (ahora WebSub) y también sondeará canales RSS que no tienen configurado Pubsub. Luego, cuando encuentre un feed, hará ping a una URL configurada (en mi caso, mi Función de nube en Firebase) con una representación XML o JSON de los nuevos datos de feed: todo lo que tienes que hacer es analizar los datos y hacer algo con ellos.

const functions = require('firebase-functions');
const express = require('express');
const cors = require('cors');
const fetch = require('node-fetch');
const app = express();

// Automatically allow cross-origin requests
app.use(cors({ origin: true }));

app.post('/', (req, res) => {
  const { webhook_url } = req.query;
  const { body } = req;
  if (body.items === undefined || body.items.length === 0) {
    res.send('');
    return;
  }

  const item = body.items[0];
  const actor = (item.actor && item.actor.displayName) ? item.actor.displayName : body.title;

  fetch(webhook_url, {
    method: 'POST',
    headers: {
      "Content-Type": "application/json; charset=utf-8",
    },
    body: JSON.stringify({
      "text": `*${actor}* published <${item.permalinkUrl}|${item.title}>. Please consider <https://twitter.com/intent/tweet?url=${encodeURIComponent(body.items[0].permalinkUrl)}&text=${encodeURIComponent(body.items[0].title)}|Sharing it>.`
    })  
  }).then(() => {
    return res.send('ok');
  }).catch(() => {
    return res.send('error')
  });
})
// Expose Express API as a single Cloud Function:
exports.publish = functions.https.onRequest(app);

Leer la publicación completa.

Me sorprendió y me deleitó lo fácil que fue configurarlo.

Using HTTPArchive and Chrome UX report to get Lighthouse score for top visited sites in India.

Paul Kinlan

A quick dive in to how to use Lighthouse,HTTPArchive and Chrome UX report to try and understand how users in a country might experience the web.

Read More

Getting Lighthouse scores from HTTPArchive for sites in India.

Paul Kinlan

A quick dive in to how to use Lighthouse to try and understand how users in a country might experience the web.

Read More

'Moving to a Chromebook' by Rumyra's Blog

Paul Kinlan

Ruth John se mudó a Chrome OS (temporalmente):

The first thing, and possibly the thing with the least amount of up to date information out there, was enabling Crostini. This runs Linux in a container on the Chromebook, something you pretty much want straight away after spending 15 minutes on it.

I have the most recent Pixel, the 256GB version. Here’s what you do.

  • Go to settings.
  • Click on the hamburger menu (top left) - right at the bottom it says ‘About Chrome OS’
  • Open this and there’s an option to put your machine into dev mode
  • It’ll restart and you’ll be in dev mode - this is much like running Canary over Chrome and possibly turning on a couple of flags. It may crash, but what the hell you’ll have Linux capabilities ��
  • Now you can go back into Settings and in regular settings there’s a ‘Linux apps’ option. Turn this on. It’ll install Linux. Once this is complete you’ll have a terminal open for you. Perfect

Leer la publicación completa.

Ruth tiene un gran relato de mudarse a Chrome OS porque su máquina principal se rompió.

Me mudé a Chrome OS a tiempo completo hace 4 meses (antes de Google I / O) y solo me mudé a la Mac porque rompí mi PixelBook (ahora corregido).

Para mí es una de las mejores máquinas de desarrollo web que existe hoy en día. Es el único dispositivo con el que puedo probar el “verdadero móvil”: puede instalar Chrome en dispositivos móviles en él, Firefox Mobile, el navegador Samsung, Brave, etc. a través de la plataforma ARC. Crostini también cambia las reglas del juego para Chrome OS, ya que aporta gran parte del ecosistema de aplicaciones de Linux al sistema operativo Chrome y realmente comienza a llenar una gran brecha de aplicaciones para mí en Chrome OS; Tengo Firefox, vim, git, VS Code, Node, npm, todas mis herramientas de compilación, GIMP e Inkscape … Eso no quiere decir que haya sido perfecto, Crostini podría ser más rápido, aún no está acelerado por GPU y podría estar más integrado con Filemanager, etc., y, finalmente, el PixelBook realmente necesita más puertos físicos; puedo adjuntar dos pantallas 4k, pero no puedo cargar al mismo tiempo.

Creo que el resumen de Ruth también es bastante preciso, el PixelBook es una máquina costosa, pero estoy muy emocionado de ver que esto llegue a más y más dispositivos (especialmente a precios mucho más bajos).

Would I pay full price for it? I’m not sure I would pay full price for anything on the market right now. Point me in the direction of a system that will run my graphics software and makes a good dev machine (with minimal setup) and lasts more than 18 months, point me in the direction of a worthy investment and I will pay the money.

Sip.

PWA: Progressive Web All-the-things

Paul Kinlan

PWA. Aplicaciones web progresivas. Frances Berriman y Alex Russell acuñaron el término “aplicaciones web progresivas” en 2015 con lo que creo que es una publicación seminal “Aplicaciones web progresivas: escapando pestañas sin perder nuestro alma”. 3 años después, hemos recorrido un largo camino. De una colección suelta de tecnologías: Trabajador de servicio, Manifiesto, Agregar a pantalla de inicio, Web Push, que originalmente solo se implementaron en un motor de navegador, a una marca que comenzó a extenderse a toda la industria con empresas y desarrolladores, y todas las principales proveedores de navegador implementando la mayoría de la pila ‘PWA’.

Read More

What are the pain points for web designers? - Mustafa Kurtuldu

Paul Kinlan

Mustafa escribe:

Tooling is complicated, we are a tooling focused industry, and they change so much. I have used maybe rough eight different tools, from Photoshop to Sketch. That’s before we add prototyping tools to the mix. This may be something we just have to accept. After all, type standards only really started to settle in the 90s, and typography is a 500-year-old discipline.

Designers are still finding it difficult to prove the importance of the process. I think this is something that we have to take on board: to learn how to educate and not just expect everyone to trust us by default. That takes time — perhaps using scenario-based design or design workshops like a design sprint would help. Getting non-designers to observe users while using a prototype they created is one of the best experiences I have seen in this field.

Cross-browser support is lacking crucial features. Designers need to understand developer tooling, to better scope out what is possible. I think using paired programming or the design process described above can help.

Responsive design is still challenging. I think this is in part due to the tools we use; I would love Chrome Design Tools that would help turn the browser into a creative tool. This space is where I think the next evolutionary step for site and web app creation is at. Mozilla is doing some fantastic work in this space, with their layout and shapes tooling.

All in all the challenges that we face seem to be all the age-old ones. Process, tools, and respect.

Leer la publicación completa.

Me pareció una publicación muy interesante que también complementa una publicación que escribí sobre desafíos para desarrolladores web. No es sorprendente que la compatibilidad con el navegador sea un problema, pero lo que todavía preocupa es que construir para IE11 todavía es algo que está frenando a la industria. Del mismo modo, Mustafa señala que todavía existe un problema con las herramientas en torno al diseño receptivo y el énfasis en una sola solución receptiva siempre conduce a lo siguiente (que está en la publicación de Mustafa):

Designing once and using everywhere is still hard to reach ambition.

Este es un problema con el que creo que todos aún luchamos. Por un lado, queremos que todos creen una solución receptiva que pueda servir a todos en cada factor de forma de dispositivo; por otro lado, el contexto del usuario es importante y, a menudo, el usuario solo estará dispuesto a realizar determinadas acciones en determinados momentos; Vemos esto mucho en la industria del comercio minorista y el comercio: las personas navegarán en dispositivos móviles y las completarán en computadoras de escritorio, y la pregunta que se tiene es: ¿se atiende más a este modelo multimodal o se crea una experiencia consistente en todos los dispositivos? … sospeche que la respuesta es ‘depende’, pero de cualquier forma es un problema difícil para todos, desde equipos de productos hasta equipos de ingeniería.

Page Lifecycle API - Philip Walton

Paul Kinlan

Philip Walton tiene una profunda inmersión en una nueva API en la que el equipo de Chrome ha estado trabajando para darle a usted (el desarrollador) el control sobre cómo responder cuando el navegador descarga sus pestañas.

Application lifecycle is a key way that modern operating systems manage resources. On Android, iOS, and recent Windows versions, apps can be started and stopped at any time by the OS. This allows these platforms to streamline and reallocate resources where they best benefit the user.

On the web, there has historically been no such lifecycle, and apps can be kept alive indefinitely. With large numbers of web pages running, critical system resources such as memory, CPU, battery, and network can be oversubscribed, leading to a bad end-user experience.

While the web platform has long had events that related to lifecycle states — like load, unload, and visibilitychange — these events only allow developers to respond to user-initiated lifecycle state changes. For the web to work reliably on low-powered devices (and be more resource conscious in general on all platforms) browsers need a way to proactively reclaim and re-allocate system resources.

In fact, browsers today already do take active measures to conserve resources for pages in background tabs, and many browsers (especially Chrome) would like to do a lot more of this — to lessen their overall resource footprint.

The problem is developers currently have no way to prepare for these types of system-initiated interventions or even know that they’re happening. This means browsers need to be conservative or risk breaking web pages.

The Page Lifecycle API attempts to solve this problem by:

  • Introducing and standardizing the concept of lifecycle states on the web.
  • Defining new, system-initiated states that allow browsers to limit the resources that can be consumed by hidden or inactive tabs.
  • Creating new APIs and events that allow web developers to respond to transitions to and from these new system-initiated states.
  • This solution provides the predictability web developers need to build applications resilient to system interventions, and it allows browsers to more aggressively optimize system resources, ultimately benefiting all web users.

The rest of this post will introduce the new Page Lifecycle features shipping in Chrome 68 and explore how they relate to all the existing web platform states and events. It will also give recommendations and best-practices for the types of work developers should (and should not) be doing in each state.

Leer publicación completa.

Mi primer comentario es que deberías leer la publicación de Philips. Es increíble.

En dispositivos móviles, Chrome puede ser bastante agresivo al generar fondos (congelar o descartar) la página para conservar recursos cuando el usuario no la está usando (por ejemplo, cuando intercambias pestañas o te mueves desde la aplicación Chrome en Android), cuando el navegador Como desarrollador, usted tradicionalmente no tiene conocimiento de cuándo sucede esto, por lo que no puede mantener fácilmente el estado o incluso cerrar los recursos abiertos, y lo que es más importante cuando su aplicación vuelve a hidratar el estado limpiamente. Cuando los desarrolladores tienen el control, pueden tomar decisiones más informadas, lo que también significa que el navegador puede ser más agresivo en la conservación de recursos en el futuro sin afectar severamente la experiencia del usuario o desarrollador.

Finalmente, el diagrama a continuación explica todo bastante bien.

API de página de Lifecycle

Add to homescreen changes in Chrome 68 - Pete LePage

Paul Kinlan

Pete LePage escribe sobre cambios importantes para Agregar a la pantalla de inicio en Chrome

Add to Home Screen changes

If your site meets the add to home screen criteria, Chrome will no longer show the add to home screen banner. Instead, you’re in control over when and how to prompt the user.

To prompt the user, listen for the beforeinstallprompt event, then, save the event and add a button or other UI element to your app to indicate it can be installed.

Leer publicación completa.

Tenía sentimientos encontrados sobre esto porque mucha gente no maneja el evento beforeinstallprompt, significaba que, de repente, la cantidad de instalaciones de Web APK caería significativamente, pero creo que es lo correcto.

El objetivo es reducir el número de mensajes molestos que suceden en la web, y lo último que necesitamos en la industria es que aparezca un mensaje relativamente grande cuando creemos que el usuario podría querer instalar un PWA, en su lugar, ahora necesita piense en dónde y cuándo ** desea solicitar una instalación y debe hacerlo en respuesta a un gesto del usuario.

Lo bueno es que nosotros (Chrome) estamos introduciendo formas más ambientadas de dejar que el usuario sepa que se puede instalar una experiencia, ahora es la pequeña barra inferior que aparece en la primera carga, y con suerte en el futuro podemos explorar formas más sutiles de dejar que el usuario sepa que puede tomar medidas.