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

Tôi đã ở Trung Quốc vài tuần trước cho Ngày nhà phát triển của Google và tôi đã hiển thị cho mọi người [Trình quét QRCode] của tôi (0), nó hoạt động tốt cho đến khi tôi ngoại tuyến. Khi người dùng ngoại tuyến (hoặc được kết nối một phần) máy ảnh sẽ không khởi động, điều đó có nghĩa là bạn không thể chụp mã QR. Nó đã cho tôi một tuổi để làm việc ra những gì đang xảy ra, và nó chỉ ra tôi đã nhầm lẫn bắt đầu máy ảnh trong sự kiện onload của tôi và yêu cầu Google Analytics sẽ treo và không giải quyết một cách kịp thời. Đó là cam kết cố định nó.

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.

Đọc toàn bộ bài đăng.

Tôi khuyến khích bạn đọc bài đăng vì có rất nhiều thông tin chi tiết tuyệt vời.

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

Paul Kinlan

Vào cuối tuần, tôi đã chơi với bộ mã hóa video hiệu ứng Boomerang, bạn có thể làm cho nó hoạt động gần thời gian thực (tôi sẽ giải thích sau). Tôi đã làm việc trên Chrome trên máy tính để bàn, nhưng nó sẽ không bao giờ hoạt động bình thường trên Chrome trên Android. Xem mã ở đây.

Có vẻ như khi bạn sử dụng captureStream () trên một <canvas>có độ phân giải tương đối lớn (1280x720 trong trường hợp của tôi) API MediaRecorder sẽ không thể mã hóa video và nó sẽ không lỗi và bạn không thể phát hiện ra rằng nó không thể mã hóa video trước thời hạ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.

Đọc toàn bộ bài đăng.

Nếu bạn muốn chơi xung quanh với bản demo hoạt động trên cả hai thì nhấp vào đây

Why Microsoft and Google love progressive web apps | Computerworld

Paul Kinlan

Một bài đăng hay về PWA từ Mike Elgan. Tôi không chắc chắn về mục tiêu của Microsoft với PWA, nhưng tôi nghĩ rằng chúng tôi khá đơn giản: chúng tôi muốn người dùng có quyền truy cập vào nội dung và chức năng ngay lập tức và theo cách họ mong đợi để có thể tương tác với nó trên thiết bị của họ. Web sẽ tiếp cận mọi người trên mọi thiết bị được kết nối và người dùng có thể truy cập vào phương thức ưa thích của họ, dưới dạng ứng dụng nếu đó là cách họ mong đợi (di động, có thể) hoặc giọng nói trên trợ lý, v.v.

Chúng tôi vẫn còn là một cách xa web không đầu, tuy nhiên, có một điều thực sự khiến tôi trong bài viết:

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

Đọc toàn bộ bài đăng.

Các trang web và ứng dụng trên web không được phân tách, web là liên kết, có thể lập chỉ mục, tạm thời, nhưng chúng tôi đang nhận được nhiều thông tin hơn với từng trang web mà chúng tôi xây dựng. Chúng tôi đang tạo ra các silo không mong muốn vì nền tảng không dễ dàng cho phép người dùng nhận * dữ liệu của họ trong và ngoài các trang web dễ dàng. Tôi không nói về RDF hay bất cứ thứ gì như vậy, các thao tác cơ bản như sao chép và dán, kéo và thả, chia sẻ lên trang web và chia sẻ từ trang web bị hỏng trên web ngày hôm nay, và đó là trước khi chúng tôi truy cập IPC giữa các khung, công nhân và cửa sổ.

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

Paul Kinlan

Bạn sẽ có thể tạo và chỉnh sửa video chỉ bằng cách sử dụng web trong trình duyệt. Bạn có thể cung cấp giao diện người dùng giống như Luồng màn hình cho phép bạn tạo video đầu ra kết hợp nhiều video, hình ảnh và âm thanh thành một video có thể tải lên các dịch vụ như YouTube. Tiếp theo từ [bài viết trước] của tôi (0) mô tả ngắn gọn các yêu cầu của trình chỉnh sửa video, trong bài viết này tôi chỉ muốn nhanh chóng hiển thị trên màn hình cách tôi đã xây dựng máy ghi web cam và cách xây dựng một màn hình máy ghi âm :)

Read More

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

Paul Kinlan

Vấn đề đầu tiên tôi tìm thấy là cố gắng xây dựng trình chỉnh sửa video trên web.

Tôi có nhiều luồng video (máy tính để bàn và web cam) và tôi muốn có thể chuyển đổi giữa các luồng video trên một phần tử video để tôi có thể nhanh chóng chuyển đổi giữa web cam và màn hình nền và không phá vỡ MediaRecorder.

Có vẻ như bạn có thể làm điều đó thông qua việc chuyển đổi thuộc tính selected trên đối tượngvideoTracks trên <video>phần tử, nhưng bạn không thể, mảng các bản nhạc chỉ chứa 1 phần tử (đoạn video đầu tiên trên 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.

Đọc toàn bộ bài đăng.

Repro case.

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

Bạn sẽ có thể tạo và chỉnh sửa video chỉ bằng cách sử dụng web trong trình duyệt. Bạn có thể cung cấp giao diện người dùng giống như Luồng màn hình cho phép bạn tạo video đầu ra kết hợp nhiều video, hình ảnh và âm thanh thành một video có thể tải lên các dịch vụ như YouTube. Bài đăng này thực sự chỉ là một tuyên bố về ý định.

Read More

Barcode detection in a Web Worker using Comlink

Paul Kinlan

Tôi là một fan hâm mộ lớn của QRCodes, họ rất đơn giản và gọn gàng để trao đổi dữ liệu giữa thế giới thực và thế giới kỹ thuật số. Trong một vài năm nay tôi đã có một dự án nhỏ bên gọi là QRSnapper & mdash; nó cũng có một vài cái tên, nhưng đây là cái tôi đã giải quyết trên & mdash; sử dụng API getUserMedia để lấy dữ liệu trực tiếp từ máy ảnh của người dùng để nó có thể quét mã QR trong thời gian thực gần.

Mục tiêu của ứng dụng là duy trì 60 khung hình / giây trong giao diện người dùng và gần ngay lập tức phát hiện Mã QR, điều này có nghĩa là tôi phải đặt mã phát hiện vào một Công nhân Web (những thứ khá chuẩn). Trong bài viết này, tôi chỉ muốn chia sẻ nhanh cách tôi sử dụng comlink để đơn giản hóa logic trong 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 (nhân viên 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);

Tôi thực sự yêu Comlink, tôi nghĩ rằng đó là một sự thay đổi trò chơi của một thư viện đặc biệt là khi nói đến việc tạo JavaScript thành ngữ hoạt động trên các chủ đề. Cuối cùng là một điều gọn gàng ở đây, đó là API phát hiện mã vạch gốc có thể được chạy bên trong một nhân viên để tất cả logic được gói gọn khỏi giao diện người dùng.

Đọc toàn bộ bài đăng.

Running FFMPEG with WASM in a Web Worker

Paul Kinlan

Tôi yêu FFMPEG.js, nó là một công cụ gọn gàng được biên dịch với asm.js` và nó cho phép tôi xây dựng các ứng dụng web JS có thể chỉnh sửa video nhanh chóng. FFMPEG.js cũng hoạt động với các nhân viên web để bạn có thể mã hóa video mà không chặn luồng chính.

Tôi cũng yêu Comlink. Comlink cho phép tôi dễ dàng tương tác với các nhân viên web bằng cách trưng ra các hàm và các lớp mà không cần phải xử lý một máy trạng thái postMessage phức tạp.

Gần đây tôi đã kết hợp cả hai. Tôi đã thử nghiệm lấy FFMPEG xuất ra Web Assembly (nó hoạt động - yay) và tôi muốn dọn sạch tất cả công việc postMessage trong dự án FFMPEG.js hiện tại. Dưới đây là những gì mã bây giờ trông giống như - Tôi nghĩ rằng nó khá gọn gàng. Chúng tôi có một công nhân nhập khẩu ffmpeg.js và comlink và nó đơn giản cho thấy giao diện ffmpeg, và sau đó chúng tôi có trang web tải nhân viên và sau đó sử dụng comlink để tạo proxy cho API ffmpeg.

Khéo léo.

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

Tôi thực sự thích cách Comlink, Worker và WASM biên dịch các mô-đun có thể chơi cùng nhau. Tôi nhận được JavaScript thành ngữ tương tác trực tiếp với mô-đun WASM và nó chạy ra khỏi luồng chính.

Đọc toàn bộ bài đăng.

Translating a blog using Google Cloud Translate and Hugo

Paul Kinlan

Gần đây tôi đã trở về từ một chuyến đi đến Ấn Độ để tham dự sự kiện Google4India (báo cáo sớm) và gặp gỡ nhiều doanh nghiệp và nhà phát triển. Một trong những thay đổi thú vị nhất được thảo luận là thúc đẩy nhiều nội dung hơn bằng ngôn ngữ của người dùng trong nước và đặc biệt rõ ràng trên tất cả các sản phẩm của Google, giúp tìm kiếm bằng ngôn ngữ người dùng dễ dàng hơn, để tìm nội dung, và cũng có thể đọc lại cho người dùng dưới dạng văn bản hoặc giọng nói.

Toàn bộ chuyến đi khiến tôi suy nghĩ. Blog của tôi được xây dựng với Hugo. Hugo hiện hỗ trợ nội dung bằng nhiều ngôn ngữ. Hugo hoàn toàn tĩnh, vì vậy việc tạo nội dung mới là vấn đề chỉ tạo một tệp mới và cho phép hệ thống xây dựng thực hiện phép thuật của nó. Vì vậy, có lẽ tôi có thể xây dựng thứ gì đó sẽ làm cho nội dung của tôi có sẵn cho nhiều người hơn bằng cách chạy nội dung tĩnh của tôi thông qua một công cụ dịch vì bản dịch nội dung của con người rất tốn kém.

Một vài giờ trước khi chuyến bay của tôi trở lại Vương quốc Anh, tôi đã tạo một tập lệnh nhỏ sẽ lấy các tệp đánh dấu và chạy chúng thông qua Google Cloud Translate để tạo nhanh dịch của trang mà tôi có thể nhanh chóng lưu trữ. Toàn bộ giải pháp được trình bày dưới đây. Đó là một bộ xử lý tương đối cơ bản, nó bỏ qua phần mở đầu của Hugo nó bỏ qua ‘mã’ và nó bỏ qua các trích dẫn kéo - giả định của tôi là ở chỗ chúng luôn được để lại như cách chúng được viết.

Lưu ý: Có vẻ như phần mềm học tập của chúng tôi dành cho bản dịch sử dụng nên điều quan trọng là đánh dấu trang của bạn để công cụ học tập không sử dụng nội dung được dịch của Google làm đầu vào cho thuật toán của nó.

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

Nói chung, tôi rất hài lòng với quy trình này. Tôi hiểu rằng bản dịch máy không hoàn hảo nhưng suy nghĩ của tôi là tôi có thể tăng khả năng tiếp cận nội dung của mình với những người có thể đang tìm kiếm bằng ngôn ngữ của riêng họ và không phải bằng tiếng Anh tôi có thể tăng diện tích bề mặt khám phá nội dung của mình và những người.

Nó sẽ mất một lúc để xem nếu điều này thực sự giúp mọi người, vì vậy tôi sẽ báo cáo lại khi tôi có thêm dữ liệu …. Bây giờ để chạy kịch bản của tôi trên nhiều trang web của tôi :)

Apple - Web apps - All Categories

Paul Kinlan

Hãy nhớ rằng khi các ứng dụng web được * a * đề xuất cách sử dụng các ứng dụng trên iPhone?

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

Đọc toàn bộ bài đăng.

Vào khoảng năm 2013, Apple bắt đầu chuyển hướng / webapps / thư mục cấp cao nhất đến / iphone /

Vấn đề là, thư mục thực sự khá tốt, rất nhiều ứng dụng trong đó vẫn hoạt động hiện nay. Tuy nhiên, nhìn vào AppStore, nó giải quyết được nhiều vấn đề hơn mà các nhà phát triển đã có: Phát hiện và tìm kiếm tốt hơn cụ thể vì AppStore đã trực tiếp trên thiết bị. AppStore cũng bắt đầu giới thiệu rằng ma sát bị loại bỏ khỏi người dùng và nhà phát triển cụ thể liên quan đến thanh toán.

Gears API

Paul Kinlan

Tôi đang viết một bài đăng trên blog về API Web di động sớm và Alex Russell đã nhắc tôi về 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

Đọc toàn bộ bài đăng.

Tôi nghĩ thật thú vị khi thấy rằng AppCache và WebSQL, Geolocation và WebWorkers xuất hiện từ những ý tưởng trong Google Gears và nó chỉ là hai ý tưởng sau đó thực sự tồn tại. WebSQL không bao giờ được hỗ trợ rộng rãi và được thay thế bởi IndexedDB; và AppCache được thay thế bởi ServiceWorker

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

Paul Kinlan

Chúng tôi sử dụng Google Trò chuyện trong nội bộ rất nhiều để giao tiếp trong nhóm của chúng tôi - nó giống như chùng của chúng tôi; Chúng tôi cũng tạo nhiều nội dung có thể truy cập thông qua nguồn cấp dữ liệu RSS, thậm chí chúng tôi có feed nhóm mà tất cả các bạn có thể xem. Cho đến gần đây tôi mới phát hiện ra rằng việc tạo [bot đơn giản chỉ sau qua WebHooks] thật đơn giản (https://developers.google.com/hangouts/chat/how-tos/webhooks) và rằng đã cho tôi ý tưởng, tôi có thể tạo ra một dịch vụ đơn giản để thăm dò nguồn cấp dữ liệu RSS và sau đó gửi chúng đến webhook của chúng tôi có thể đăng trực tiếp vào cuộc trò chuyện nhóm của chúng tôi.

Nó đã được khá đơn giản cuối cùng, và tôi đã bao gồm tất cả các mã dưới đây. Tôi đã sử dụng các chức năng Firebase - Tôi nghi ngờ rằng điều này cũng dễ dàng trên các trang web chức năng như một dịch vụ khác - và Superfeedr. Superfeedr là một dịch vụ có thể nghe các ping Pubsubhubbub (nay là WebSub) và nó cũng sẽ thăm dò các nguồn cấp dữ liệu RSS không có Pubsub được thiết lập. Sau đó, khi tìm thấy nguồn cấp dữ liệu, nó sẽ ping một URL được cấu hình (trong trường hợp của tôi là Cloud Function của tôi trong Firebase) với một biểu diễn XML hoặc JSON của dữ liệu nguồn cấp dữ liệu mới được tìm thấy - tất cả những gì bạn phải làm là phân tích cú pháp dữ liệu và thực hiện điều gì đó với nó.

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

Đọc toàn bộ bài đăng.

Tôi đã rất ngạc nhiên và vui mừng về cách dễ dàng để thiết lập.

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 đã chuyển sang Chrome OS (tạm thời):

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

Đọc toàn bộ bài đăng.

Ruth có một bản ghi tuyệt vời để chuyển sang Chrome OS vì máy chính của cô đã bị hỏng.

Tôi đã chuyển sang Chrome OS toàn thời gian cách đây 4 tháng (trước Google I / O) và chỉ chuyển sang Mac vì tôi đã phá vỡ PixelBook của mình (hiện đã được sửa).

Đối với tôi, đây là một trong những máy phát triển web tốt nhất hiện nay. Đó là thiết bị duy nhất mà tôi có thể thử nghiệm ‘thiết bị di động thực sự’ - bạn có thể cài đặt Chrome trên thiết bị di động, Firefox Mobile, Samsung Browser, Brave, v.v. qua nền tảng ARC. Crostini cũng là một thay đổi trò chơi cho Chrome OS vì nó mang lại rất nhiều hệ sinh thái ứng dụng Linux cho Chrome OS và nó thực sự bắt đầu lấp đầy một khoảng trống lớn cho tôi trên Chrome OS; Tôi đã có Firefox, vim, git, VS Code, Node, npm, tất cả các công cụ xây dựng của tôi, GIMP và Inkscape … Điều đó không có nghĩa là nó hoàn hảo, Crostini có thể nhanh hơn, không phải GPU tăng tốc và nó có thể được tích hợp nhiều hơn với Filemanager vv, và cuối cùng PixelBook thực sự cần nhiều cổng vật lý hơn - tôi có thể đính kèm hai màn hình 4k vào nó, nhưng tôi không thể sạc cùng một lúc.

Tôi nghĩ rằng sự quấn của Ruth cũng khá chính xác, PixelBook là một chiếc máy đắt tiền, nhưng tôi rất vui mừng khi thấy điều này đến với nhiều thiết bị hơn (đặc biệt là ở những điểm giá thấp hơn nhiều).

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.

Yup.

PWA: Progressive Web All-the-things

Paul Kinlan

PWA. Ứng dụng web nâng cao. Frances Berriman và Alex Russell đặt ra thuật ngữ “ứng dụng web tiến bộ” vào năm 2015 với những gì tôi nghĩ là một bài đăng chủ đề “Progressive Web Apps: Escaping Tabs mà không làm mất linh hồn của chúng tôi”. 3 năm sau, chúng tôi đã đi một chặng đường dài. Từ một bộ sưu tập công nghệ lỏng lẻo - Service Worker, Manifest, Add to Homescreen, Web Push - ban đầu chỉ được triển khai trong một trình duyệt, đến một thương hiệu đã bắt đầu gắn bó với ngành công nghiệp và các nhà phát triển, và tất cả các nhà cung cấp trình duyệt thực hiện phần lớn ngăn xếp ‘PWA’.

Read More

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

Paul Kinlan

Mustafa viết:

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.

Đọc toàn bộ bài đăng.

Tôi thấy đây là một bài rất thú vị cũng là một bổ sung cho một bài viết tôi đã viết về thách thức đối với các nhà phát triển web. Không có gì đáng ngạc nhiên khi trình duyệt compat là một vấn đề, nhưng những gì vẫn còn là một mối quan tâm là xây dựng cho IE11 vẫn là một cái gì đó mà đang nắm giữ ngành công nghiệp trở lại. Tương tự như vậy, Mustafa chỉ ra rằng vẫn còn một vấn đề với các công cụ xung quanh thiết kế Responsive và nhấn mạnh vào một giải pháp đáp ứng duy nhất luôn dẫn đến những điều sau đây (đó là trong bài Mustafa):

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

Đây là một vấn đề mà tôi nghĩ rằng tất cả chúng ta vẫn vật lộn với. Một mặt, chúng tôi muốn mọi người xây dựng một giải pháp đáp ứng có thể phục vụ mọi người trên mọi yếu tố hình thức thiết bị, ngữ cảnh người dùng khác là quan trọng và thường người dùng sẽ chỉ sẵn sàng thực hiện một số hành động nhất định tại một số thời điểm nhất định; chúng ta thấy điều này rất nhiều trong ngành bán lẻ và thương mại: mọi người sẽ duyệt trên thiết bị di động và hoàn thành trên máy tính để bàn và câu hỏi sau đó trở thành bạn phục vụ cho mô hình đa phương thức này nhiều hơn hoặc xây dựng trải nghiệm nhất quán trên tất cả các thiết bị … nghi ngờ câu trả lời là ‘nó phụ thuộc’, nhưng dù bằng cách nào thì đó cũng là một vấn đề khó khăn đối với mọi người từ các nhóm sản phẩm đến các đội kỹ thuật.

Page Lifecycle API - Philip Walton

Paul Kinlan

Philip Walton có một cái nhìn sâu sắc tuyệt vời vào một API mới mà nhóm Chrome đã làm việc để cung cấp cho bạn (nhà phát triển) kiểm soát cách phản hồi khi trình duyệt tải các tab của bạn xuống.

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.

Đọc toàn bộ bài đăng.

Nhận xét đầu tiên của tôi là bạn nên đọc bài đăng của Philips. Không thể tin được.

Trên thiết bị di động, Chrome có thể khá tích cực khi chạy nền (đóng băng hoặc hủy) trang để tiết kiệm tài nguyên khi người dùng không sử dụng (ví dụ: khi bạn trao đổi tab hoặc di chuyển từ ứng dụng Chrome trên Android), khi trình duyệt khởi động trang như một nhà phát triển bạn theo truyền thống không có kiến ​​thức về thời điểm điều này xảy ra, do đó bạn không thể dễ dàng duy trì trạng thái hoặc thậm chí đóng tài nguyên mở và cũng quan trọng khi ứng dụng của bạn trở lại trạng thái sạch sẽ. Khi nhà phát triển có quyền kiểm soát họ có thể đưa ra nhiều lựa chọn sáng suốt hơn, điều này cũng có nghĩa là trình duyệt có thể tích cực hơn trong việc bảo tồn tài nguyên trong tương lai mà không ảnh hưởng nghiêm trọng đến trải nghiệm người dùng hoặc nhà phát triển.

Cuối cùng, sơ đồ dưới đây giải thích tất cả đều khá tốt.

API vòng đời trang

Add to homescreen changes in Chrome 68 - Pete LePage

Paul Kinlan

Pete LePage viết về những thay đổi quan trọng đối với Thêm vào màn hình chính trong 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.

Đọc toàn bộ bài đăng.

Tôi có cảm giác lẫn lộn về điều này ban đầu bởi vì rất nhiều người không xử lý sự kiện ‘beforeinstallprompt`, điều đó có nghĩa là số lượt cài đặt APK trên web sẽ giảm đáng kể, nhưng tôi nghĩ đó thực sự là điều đúng đắn.

Mục tiêu là giảm số lượng lời nhắc gây phiền nhiễu xảy ra trên web và điều cuối cùng chúng tôi cần trong ngành là một dấu nhắc tương đối lớn xuất hiện khi chúng tôi nghĩ rằng người dùng có thể muốn cài đặt PWA, thay vào đó bạn cần suy nghĩ về nơi và khi nào ** bạn ** muốn nhắc cài đặt và bạn phải thực hiện nó để đáp lại cử chỉ của người dùng.

Điều gọn gàng là chúng tôi (Chrome) đang giới thiệu nhiều cách khác để cho người dùng biết rằng trải nghiệm có thể được cài đặt, ngay bây giờ đó là thanh đáy nhỏ xuất hiện trong lần tải đầu tiên và hy vọng trong tương lai chúng tôi có thể khám phá những cách tinh tế hơn để cho người dùng biết rằng họ có thể hành động.