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

Ich war vor ein paar Wochen für den Google Developer Day in China und habe allen meinen QRCode-Scanner gezeigt, es funktionierte großartig, bis ich offline ging. Wenn der Benutzer offline war (oder teilweise verbunden war), konnte die Kamera nicht starten, was dazu führte, dass QR-Codes nicht ausgelöst werden konnten. Ich brauchte ein ganzes Alter, um herauszufinden, was passierte, und es stellte sich heraus, dass ich irrtümlich die Kamera bei meinem Onload-Ereignis gestartet hatte und die Google Analytics-Anfrage hängen blieb und nicht rechtzeitig gelöst werden konnte. Es war dieses Festschreiben, das es reparierte.

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.

Ganzen Beitrag lesen.

Ich ermutige Sie, den Beitrag zu lesen, weil es viele großartige Einblicke gibt.

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

Paul Kinlan

Am Wochenende habe ich mit einem Boomerang-Effekt-Video-Encoder herumgespielt, man kann es quasi in Echtzeit arbeiten lassen (ich werde es später erklären). Ich habe es auf Chrome auf dem Desktop funktioniert, aber es würde nie richtig in Chrome unter Android funktionieren. Siehe der Code hier.

Es sieht so aus, als wenn Sie captureStream () auf einem verwenden <canvas>das hat eine relativ große Auflösung (1280x720 in meinem Fall) ist die MediaRecorder API nicht in der Lage, die Videos zu codieren und es wird kein Fehler und Sie können nicht feststellen, dass es das Video nicht vor der Zeit codieren kann.

(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.

Ganzen Beitrag lesen.

Wenn du mit der Demo spielen willst, die auf beiden funktioniert, dann klick hier

Why Microsoft and Google love progressive web apps | Computerworld

Paul Kinlan

Ein schöner Post über PWA von Mike Elgan. Ich bin mir über Microsofts Ziel bei PWA nicht sicher, aber meiner Meinung nach ist es ziemlich einfach: Wir möchten, dass Benutzer sofort und auf eine Art und Weise Zugriff auf Inhalte und Funktionen haben, von denen sie erwarten, dass sie auf ihren Geräten mit ihnen interagieren können. Das Web sollte jeden über jedes angeschlossene Gerät erreichen und ein Benutzer sollte in der Lage sein, auf seine bevorzugte Modalität zuzugreifen, als eine App, wenn sie es so erwarten (Handy, vielleicht), oder Stimme auf einem Assistenten usw.

Wir sind immer noch ein langer Weg vom kopflosen Web, aber eine Sache hat mich in dem Artikel wirklich beeindruckt:

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

Ganzen Beitrag lesen.

Websites und Apps im Internet sollen nicht isoliert sein, das Web ist linkbar, indexierbar, ephemeral, aber wir werden mit jeder Site, die wir erstellen, mehr isoliert. Wir erstellen unbeabsichtigte Silos, weil die Plattform es Benutzern nicht leicht macht, * ihre * Daten einfach von Websites zu bekommen. Ich spreche nicht über RDF oder ähnliches, grundlegende Operationen wie Kopieren und Einfügen, Ziehen und Ablegen, Freigabe zur Site und Freigabe von der Site sind im heutigen Web gebrochen, und das ist bevor wir zur IPC zwischen Frames, Workern gelangen und Fenster.

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

Paul Kinlan

Sie sollten Videos nur über das Web im Browser erstellen und bearbeiten können. Es sollte möglich sein, eine Benutzeroberfläche ähnlich wie bei Screenflow bereitzustellen, mit der Sie ein Ausgabevideo erstellen können, das mehrere Videos, Bilder und Audio zu einem Video kombiniert, das zu Diensten wie YouTube hochgeladen werden kann. Im Anschluss an den meinem vorheriger Beitrag, der kurz die Anforderungen des Videoeditors beschreibt, wollte ich in diesem Beitrag nur schnell in einem Screencast zeigen, wie ich den Web Cam Recorder gebaut habe, und wie man einen Screencast erstellt Recorder :)

Read More

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

Paul Kinlan

Das erste Problem, das ich gefunden habe, versucht einen Videoeditor im Internet zu erstellen.

Ich habe mehrere Videostreams (Desktop und Web Cam) und wollte zwischen den Videoströmen eines Videoelements wechseln können, um schnell zwischen der Webcam und dem Desktop wechseln zu können und den MediaRecorder nicht zu zerbrechen.

Es sieht so aus, als ob Sie dies tun können, indem Sie die Eigenschaft selected auf demvideoTracks Objekt auf dem <video>Element, aber Sie können nicht, das Array von Tracks enthält nur 1 Element (die erste Videospur auf dem 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.

Ganzen Beitrag lesen.

Repro-Fall.

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

Sie sollten Videos nur über das Web im Browser erstellen und bearbeiten können. Es sollte möglich sein, eine Benutzeroberfläche ähnlich wie bei Screenflow bereitzustellen, mit der Sie ein Ausgabevideo erstellen können, das mehrere Videos, Bilder und Audio zu einem Video kombiniert, das zu Diensten wie YouTube hochgeladen werden kann. Dieser Beitrag ist wirklich nur eine Absichtserklärung. Ich werde mit dem langen Prozess beginnen, herauszufinden, was auf der Plattform verfügbar ist und was nicht, und sehen, wie weit wir heute kommen können.

Read More

Barcode detection in a Web Worker using Comlink

Paul Kinlan

Ich bin ein großer Fan von QRCodes, sie sind eine sehr einfache und nette Möglichkeit, Daten zwischen der realen Welt und der digitalen Welt auszutauschen. Seit ein paar Jahren habe ich ein kleines Nebenprojekt namens QRSnapper & mdash; Nun, es hatte ein paar Namen, aber das ist die, auf die ich mich festgelegt habe & mdash; Diese nutzt die API “getUserMedia”, um Live-Daten von der Kamera des Benutzers zu empfangen, so dass sie fast in Echtzeit nach QR-Codes scannen kann.

Das Ziel der App war es, 60 fps in der Benutzeroberfläche zu halten und fast sofort den QR-Code zu erkennen. Das bedeutete, dass ich den Erkennungscode in einen Web-Worker stecken musste (ziemlich normales Zeug). In diesem Post wollte ich nur schnell mitteilen, wie ich comlink benutzt habe, um die Logik im Worker massiv zu vereinfachen.

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 (Web-Arbeiter)

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);

Ich liebe wirklich Comlink, ich denke, es ist ein Game Changer einer Bibliothek, besonders wenn es darum geht, idiomatisches JavaScript zu erstellen, das über Threads hinweg funktioniert. Schließlich ist es eine nette Sache, dass die native Barcode-Erkennungs-API in einem Worker ausgeführt werden kann, sodass die gesamte Logik außerhalb der Benutzeroberfläche gekapselt ist.

Ganzen Beitrag lesen.

Running FFMPEG with WASM in a Web Worker

Paul Kinlan

Ich liebe FFMPEG.js, es ist ein nettes Tool, das mit asm.js` zusammengestellt wurde und ich kann JS Web-Apps erstellen, die Videos schnell bearbeiten können. FFMPEG.js funktioniert auch mit Web Worker, sodass Sie Videos codieren können, ohne den Hauptthread zu blockieren.

Ich liebe auch Comlink. Mit Comlink kann ich leicht mit Web-Arbeitern interagieren, indem ich Funktionen und Klassen offen lege, ohne mich mit einem komplexen `postMessage’-Zustandsautomaten auseinandersetzen zu müssen.

Ich habe vor kurzem die beiden zusammen zu kombinieren. Ich habe experimentiert FFMPEG in Web Assembly exportieren (es funktioniert - yay) und ich wollte alle PostMessage Arbeit im aktuellen FFMPEG.js Projekt aufräumen. Unten ist, wie der Code jetzt aussieht - ich denke, es ist ziemlich ordentlich. Wir haben einen Worker, der ffmpeg.js und comlink importiert und einfach die ffmpeg-Schnittstelle verfügbar macht. Dann haben wir die Webseite, die den Worker lädt und anschließend mithilfe von comlink einen Proxy für die ffmpeg-API erstellt.

Ordentlich.

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);
   }),
});

Ich mag es wirklich, wie Comlink, Workers und WASM kompilierte Module zusammen spielen können. Ich erhalte idiomatisches JavaScript, das direkt mit dem WASM-Modul interagiert und vom Hauptthread abläuft.

Ganzen Beitrag lesen.

Translating a blog using Google Cloud Translate and Hugo

Paul Kinlan

Ich bin vor kurzem von einer Reise nach Indien zurückgekommen, um an der Google4India Veranstaltung teilzunehmen (Bericht bald) und mich mit vielen Unternehmen und Entwicklern zu treffen. Eine der interessantesten diskutierten Änderungen war die Forderung nach mehr Inhalten in der Sprache der Nutzer in dem Land, und es wurde besonders offensichtlich bei allen Google-Produkten, die von der Erleichterung der Suche in der Benutzersprache, der Suche nach Inhalten, und es auch an die Benutzer in Text- oder Sprachform zurückzulesen.

Die ganze Reise hat mich zum Nachdenken gebracht. Mein Blog ist mit Hugo gebaut. Hugo unterstützt nun Inhalte in mehreren Sprachen. Hugo ist komplett statisch, also ist das Erstellen neuer Inhalte eine Angelegenheit, die nur eine neue Datei erstellt und das Build-System magisch macht. Vielleicht kann ich etwas aufbauen, das meinen Inhalt für mehr Leute verfügbar macht, indem ich meinen statischen Inhalt durch ein Übersetzungstool leite, weil die menschliche Übersetzung von Inhalten sehr teuer ist.

Ein paar Stunden vor meinem Flug zurück nach Großbritannien habe ich ein kleines Skript erstellt, das meine Markdown-Dateien aufnimmt und sie über Google Cloud Translate durchsucht, um schnell zu erstellen Übersetzung der Seite, die ich dann schnell hosten kann. Die gesamte Lösung wird im Folgenden vorgestellt. Es ist ein relativ grundlegender Prozessor, es ignoriert die Hugo-Präambel, es ignoriert “Code” und es ignoriert Pull-Zitate - meine Annahme war, dass diese immer so belassen werden sollen, wie sie geschrieben wurden.

Hinweis: Es sieht so aus, als ob unsere Lernsoftware für Übersetzungen verwendet wird. Daher ist es wichtig, Ihre Seite so zu markieren, dass die Google Übersetzer-Inhalte nicht als Eingabe für die Algorithmen verwendet werden.

// 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);

Insgesamt bin ich sehr zufrieden mit dem Prozess. Ich verstehe, dass die maschinelle Übersetzung nicht perfekt ist, aber ich denke, dass ich die Reichweite meiner Inhalte für Menschen erhöhen kann, die möglicherweise in ihren eigenen Sprachen und nicht in Englisch suchen. Ich kann die Suchoberfläche meiner Inhalte vergrößern und hoffentlich mehr helfen Menschen.

Es wird eine Weile dauern, um zu sehen, ob dies den Leuten tatsächlich hilft, also werde ich zurück berichten, wenn ich mehr Daten habe …. Nun, um mein Skript über mehr von meiner Seite laufen zu lassen :)

Apple - Web apps - All Categories

Paul Kinlan

Erinnern Sie sich daran, wann Web Apps eine empfohlene Methode zur Verwendung von Apps auf dem iPhone waren?

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

Vollständigen Beitrag lesen.

Um 2013 herum begann Apple, das Verzeichnis / webapps / top-level nach / iphone / umzuleiten.

Die Sache ist, das Verzeichnis war eigentlich ziemlich gut, viele der Apps dort funktionieren noch heute. Mit Blick auf den AppStore löste es jedoch viel mehr Probleme, die Entwickler hatten: Bessere Entdeckung und Suche speziell, weil der AppStore direkt auf dem Gerät war. Der AppStore begann auch damit, die Reibung zwischen Benutzern und Entwicklern speziell im Hinblick auf Zahlungen zu reduzieren.

Gears API

Paul Kinlan

Ich schreibe einen Blogpost über die frühen Mobile Web APIs und Alex Russell erinnert mich an 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

Vollständigen Beitrag lesen.

Ich denke, es ist interessant zu sehen, dass AppCache und WebSQL, Geolocation und WebWorker aus den Ideen in Google Gears herauskamen und nur die letzten beiden wirklich überlebten. WebSQL wurde nie allgemein unterstützt und durch IndexedDB ersetzt. und AppCache durch ServiceWorker ersetzt

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

Paul Kinlan

Wir verwenden Google Chat intern sehr oft, um über unser Team zu kommunizieren - es ist ein bisschen wie unser Durchhang; Wir erstellen auch eine Menge Inhalte, die über RSS-Feeds zugänglich sind. Wir haben sogar einen Team-Feed, den Sie alle ansehen können. Erst vor kurzem habe ich herausgefunden, dass es ziemlich einfach ist, einen einfachen Post-Only-Bot über WebHooks und das zu erstellen gab mir die Idee, ich kann einen einfachen Dienst erstellen, der RSS-Feeds abfragt und diese dann an unseren Webhook sendet, der direkt in unserem Team-Chat posten kann.

Es war am Ende ziemlich einfach, und ich habe den ganzen Code unten eingeschlossen. Ich habe Firebase-Funktionen verwendet - ich vermute, dass dies auf anderen Function-as-a-Service-Sites genauso einfach ist - und Superfeedr. Superfeedr ist ein Dienst, der Pubsubhubbub-Pings (jetzt WebSub) hören kann und auch RSS-Feeds abfragt, für die Pubsub nicht eingerichtet ist. Wenn dann ein Feed gefunden wird, pingt er eine konfigurierte URL (in meinem Fall meine Cloud-Funktion in Firebase) mit einer XML- oder JSON-Darstellung der neu gefundenen Feed-Daten - alles, was Sie tun müssen, ist die Daten analysieren und etwas damit machen.

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);

Ganzen Beitrag lesen.

Ich war überrascht und erfreut darüber, wie einfach es war, sich einzurichten.

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 wechselte vorübergehend zu Chrome OS:

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

Ganzen Beitrag lesen.

Ruth hat einen tollen Artikel darüber geschrieben, dass sie auf Chrome OS umgestiegen ist, weil ihre Hauptmaschine kaputt gegangen ist.

Ich habe vor 4 Monaten (vor Google I / O) Vollzeit zu Chrome OS gewechselt und bin nur auf den Mac gewechselt, weil ich mein PixelBook (jetzt behoben) gebrochen habe.

Für mich ist es eine der besten Webentwicklungsmaschinen, die es heute gibt. Es ist das einzige Gerät, das ich “True Mobile” testen kann - Sie können Chrome auf Mobile, Firefox Mobile, Samsung Browser, Brave usw. über die ARC-Plattform installieren. Crostini ist auch ein großer Fortschritt für Chrome OS, da es eine Menge des Linux-App-Ökosystems zu Chrome OS bringt und es wirklich eine riesige App-Lücke für mich auf Chrome OS füllt; Ich habe Firefox, vim, git, VS-Code, Node, npm, all meine Build-Tools, GIMP und Inkscape … Das heißt nicht, dass es perfekt war, Crostini könnte schneller sein, es ist noch nicht GPU-beschleunigt und es könnte mehr in den Filemanager usw. integriert sein, und schließlich benötigt das PixelBook wirklich mehr physische Ports - ich kann zwei 4k-Bildschirme daran anschließen, aber ich kann nicht gleichzeitig aufladen.

Ich denke, Ruths Abschluss ist auch ziemlich genau, das PixelBook ist eine teure Maschine, aber ich bin sehr sehr gespannt darauf, dass dies zu immer mehr Geräten kommt (besonders zu solchen mit wesentlich niedrigeren Preisen).

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.

Jep.

PWA: Progressive Web All-the-things

Paul Kinlan

PWA. Progressive Web Apps. Frances Berriman und Alex Russell prägten den Begriff “progressive Web Apps” im Jahr 2015 mit einem meiner Meinung nach bahnbrechenden Beitrag “Progressive Web Apps: Entkommene Tabs ohne unsere Seele zu verlieren”. 3 Jahre später haben wir einen langen Weg zurückgelegt. Aus einer losen Sammlung von Technologien - Service Worker, Manifest, Add to Homescreen, Web Push -, die ursprünglich nur in einer Browser-Engine implementiert wurden, bis hin zu einer Marke, die branchenübergreifend mit Unternehmen und Entwicklern und allen großen Unternehmen zusammenhängt Browser-Anbieter, die den Großteil des “PWA” Stacks implementieren.

Read More

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

Paul Kinlan

Mustafa schreibt:

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.

Ganzen Beitrag lesen.

Ich fand das ein sehr interessanter Post, der auch eine Ergänzung zu einem Post ist, den ich über die [Herausforderungen für Webentwickler] geschrieben habe (0). Es ist nicht verwunderlich, dass Browser-Kompatibilität ein Problem ist, aber was immer noch ein Problem ist, ist, dass das Bauen für IE11 immer noch etwas ist, das die Industrie zurückhält. Gleichermaßen weist Mustafa darauf hin, dass es immer noch ein Problem mit den Tools rund um Responsive Design gibt und die Betonung auf einer einzigen responsiven Lösung führt immer zu folgendem (das ist in Mustafas Post):

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

Das ist ein Problem, mit dem wir alle noch zu kämpfen haben. Auf der einen Seite möchten wir, dass jeder eine reaktionsfähige Lösung entwickelt, die jedem auf jedem Geräte-Formfaktor zur Verfügung steht, andererseits ist der Benutzerkontext wichtig und der Benutzer ist oft nur bereit bestimmte Aktionen zu bestimmten Zeiten auszuführen; Das sehen wir in der Handels- und Handelsbranche: Menschen werden auf Mobilgeräten surfen und auf dem Desktop arbeiten, und dann stellt sich die Frage, ob Sie für dieses multimodale Modell mehr sorgen oder ein konsistentes Erlebnis auf allen Geräten schaffen … I Ich vermute, die Antwort lautet: “Es kommt darauf an”, aber so oder so, es ist ein hartes Problem für alle, von den Produktteams bis zu den Entwicklungsteams.

Page Lifecycle API - Philip Walton

Paul Kinlan

Philip Walton hat einen tiefen Einblick in eine neue API, an der das Chrome-Team gearbeitet hat, um Ihnen (dem Entwickler) die Kontrolle darüber zu geben, wie Sie reagieren müssen, wenn der Browser Ihre Tabs auslädt.

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.

Vollständigen Beitrag lesen.

Mein erster Kommentar ist, dass Sie Philips Post lesen sollten. Es ist unglaublich.

Auf Mobilgeräten kann Chrome beim Hintergrund (Einfrieren oder Verwerfen) der Seite ziemlich aggressiv sein, um Ressourcen zu schonen, wenn der Benutzer sie nicht verwendet (z. B. wenn Sie Tabs austauschen oder aus der Chrome-App auf Android wechseln), wenn der Browser Hintergrund hat Seite als Entwickler Sie haben traditionell keine Kenntnis davon, wenn dies passiert, so dass Sie nicht einfach Zustand beibehalten oder sogar offene Ressourcen schließen können und genauso wichtig, wenn Sie App sind, wieder den Zustand sauber zu hydratisieren. Wenn Entwickler die Kontrolle haben, können sie fundiertere Entscheidungen treffen, was auch bedeutet, dass der Browser aggressiver Ressourcen schonen kann, ohne die Benutzer- oder Entwicklererfahrung ernsthaft zu beeinträchtigen.

Schließlich erklärt das folgende Diagramm alles sehr gut.

Seitenlebenszyklus-API

Add to homescreen changes in Chrome 68 - Pete LePage

Paul Kinlan

Pete LePage schreibt über wichtige Änderungen an Add to Homescreen in 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.

Vollständigen Beitrag lesen.

Ich hatte ursprünglich gemischte Gefühle, weil so viele Leute nicht mit dem `beofinstallprompt’-Ereignis umgehen, was bedeutete, dass plötzlich die Anzahl der Installationen von Web-APKs erheblich sinken würde, aber ich denke, es ist tatsächlich das Richtige.

Das Ziel ist es, die Anzahl der lästigen Aufforderungen im Web zu reduzieren, und das letzte, was wir in der Branche brauchen, ist eine relativ große Eingabeaufforderung, wenn wir denken, dass der Benutzer vielleicht eine PWA installieren möchte Denken Sie darüber nach, wo und wann ** Sie ** eine Installation anfordern möchten und Sie dies als Reaktion auf eine Benutzergeste tun müssen.

Das Schöne daran ist, dass wir (Chrome) mehr Ambient-Möglichkeiten einführen, um den Benutzer wissen zu lassen, dass eine Erfahrung installiert werden kann. Jetzt ist es die kleine untere Leiste, die beim ersten Laden erscheint und hoffentlich in der Zukunft erkundet werden kann subtilere Möglichkeiten, den Benutzer wissen zu lassen, dass er Maßnahmen ergreifen kann.