Hello.

I am Paul Kinlan.

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

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

Paul Kinlan

あなたは、ブラウザでウェブだけを使ってビデオを作成し編集することができます。 Screenflowに似たユーザーインターフェイスを提供することで、複数のビデオ、画像、およびオーディオを1つのビデオにまとめて、YouTubeなどのサービスにアップロードできる出力ビデオを作成できるようにする必要があります。 私の前の投稿からビデオエディタの要件を簡単に説明した後、この記事ではスクリーンキャストでウェブカメラレコーダーをどのように作成したか、そしてスクリーンキャストを構築する方法レコーダー:) それはすべてき​​ちんとしていて、新しい navigator.getDisplayMedia APIを使用します。これにより、ユーザーは画面コンテンツへのアクセスを許可することができます。以下のコードは、私がこのビデオを作成するために使用したすべてのものです。 ビデオは非常に非常に生であり、現時点で私はビデオを編集することができないので、多くの間違いがあります:)私の目標は、このプロジェクトの終わりに、私は良いビデオをエンドツーエンドで作ることができるということです。 このビデオのコードデモ window.onload = () => { if('getDisplayMedia' in navigator) warning.style.display = 'none'; let blobs; let blob; let rec; let stream; let voiceStream; let desktopStream; captureBtn.onclick = async () => { download.style.display = 'none'; desktopStream = await navigator.getDisplayMedia({video:true}); voiceStream = await navigator.mediaDevices.getUserMedia({video: false, audio: true}); let tracks = [...desktopStream.getTracks(), ...voiceStream.getAudioTracks()] console.log('Tracks to add to stream', tracks); stream = new MediaStream(tracks); videoElement.srcObject = stream; blobs = []; rec = new MediaRecorder(stream, {mimeType: 'video/webm; codecs=vp9,opus'}); rec.

Read More

Paul Kinlan

Trying to make the web and developers better.

RSS Github Medium

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

Paul Kinlan

最初の問題は、ウェブ上でビデオエディタを作成するです。

私は複数のビデオストリーム(デスクトップとウェブカム)を持っています。私はワンビデオ要素のビデオストリームを切り替えることができるようにしたいので、Webカメラとデスクトップを素早く切り替えることができ、 MediaRecorderを破ることはできません。

あなたが videoTracksオブジェクトのselectedプロパティを <video>要素が含まれていますが、トラックの配列に含まれる要素は1つだけです(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.

全文を読む

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

あなたは、ブラウザでウェブだけを使ってビデオを作成し編集することができます。 Screenflowに似たユーザーインターフェイスを提供することで、複数のビデオ、画像、およびオーディオを1つのビデオにまとめて、YouTubeなどのサービスにアップロードできる出力ビデオを作成できるようにする必要があります。 この投稿は本当に単なる声明です。私はプラットフォーム上で利用できるものと利用できないものを整理し、今日までにどのくらい得ることができるかを見るための長いプロセスを開始するつもりです。 このプロジェクトのいくつかの考えの中で、私はカール・セイガンの瞬間を持っていました。つまり、リンゴ・パイを作るために宇宙を発明する代わりに、少なくともビデオ・エディタを構築するのに必要なすべてのツールを作成する必要があります。それを行うプロセス。この記事が存在するという事実は、私がいくつかの作品を用意して準備ができていることを知っているからです。 私は、他の誰かのためのビジネスでもある大規模なモノリシックな「ビデオエディタ」を作り出すつもりはないと思っていますが、私はそれを簡単にするために必要なすべての部分を工夫するつもりですウェブ上で素晴らしい動画を作成し、多くの人にウェブ上で可能なことを見せてもらいましょう。 以下は私の大まかな1ページプロジェクト計画です: 私が持っている使用例: *私は通常、Google I / OとChrome DevSummitのすべてのデバイスデモを記録し、オーバーレイなどを追加する必要があります。チームの全員がこれを行うことができます。 *チームはしばしばスクリーンキャストを記録し、シンプルなウェブサイトからすぐにそれを行い、最終的な出力をクリーンアップできるようにしたいと考えています。 *私は鋭く保つためにいくつかの製品を作る必要があります。 ;) 入力: [p0]マイクから音声を録音する [p0]ウェブカメラからビデオを録画する[完了 - 下記参照] [p0]ウェブ上にホストされている外部動画を埋め込む [p0]デスクトップを記録する [p1]リモートストリームを記録する [p1]&lt; canvas&gt;を記録します。素子 [p0]ローカルデバイスからファイルをロードする [p1]ローカルデバイスからファイルを共有する(android share intent) 操作: [p1]ウォーターマークを追加する [p1]フィルター効果を画像に追加する [p0]カスタム画像をレイヤーとして追加する [p0]ビデオとオーバーレイをキューに入れる [p0]オーディオとビデオの別々のトラックをオーバーレイする [p1]特定の時間にテキストを重ねる [p0]ビデオをサイズに切り抜く [p0]ビデオの位置決めとサイズ変更を有効にする [p0]ビデオ/オーディオのトリム [p0]スプライスビデオ/オーディオ 出力: [p0] webm形式のビデオファイル [p1] MTB情報 [p1] xyz形式のビデオファイル このビデオのコードデモ const init = () => { let blobs; let rec; let stream; captureBtn.onclick = async () => { stream = await navigator.

Read More

Barcode detection in a Web Worker using Comlink

Paul Kinlan

私はQRコードの大ファンです。実世界とデジタル世界の間でデータを交換するための非常にシンプルできれいな方法です。数年前から、私はQRSnapperと呼ばれる小さなプロジェクトを持っていました。まあそれはいくつかの名前を持っていますが、これは私が解決したものです&mdash;これは getUserMedia APIを使用してユーザのカメラからライブデータを取得し、ほぼリアルタイムでQRコードをスキャンすることができます。

このアプリの目標は、UIで60fpsを維持し、QRコードをすぐに検出できるようにすることでした。これは、検出コードをWebワーカー(かなり標準的なもの)に入れなければならないことを意味しました。この記事では、comlinkを使ってワーカーのロジックを大幅に単純化する方法を簡単に共有したいと思っていました。

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(ウェブワーカー)

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

私は本当にComlinkが大好きです。特に、スレッド間で動作する慣用JavaScriptを作成する場合、ライブラリのゲームチェンジャーだと思います。最後にここでうまくいくのは、ネイティブのバーコード検出APIをワーカー内で実行できるため、すべてのロジックがUIからカプセル化されているからです。

全文を読む

Running FFMPEG with WASM in a Web Worker

Paul Kinlan

私はFFMPEG.jsが大好きです。これは、asm.jsでコンパイルされた素敵なツールです。そして、私はビデオをすばやく編集できるJS Webアプリケーションを作成しましょう。 FFMPEG.jsもWebワーカーと連携して、メインスレッドをブロックせずにビデオをエンコードすることができます。

私はComlinkも大好きです。 Comlinkでは、複雑な postMessageステートマシンを扱わなくても、関数やクラスを公開することで、Webワーカーと簡単にやりとりすることができます。

私は最近、この2つを組み合わせる必要があります。私はFFMPEGをWebアセンブリにエクスポートして実験しました(これはうまくいきます)、現在のFFMPEG.jsプロジェクトでpostMessageの作業をすべてクリーンアップしたかったのです。以下は、コードが今のように見えるものです - 私はそれがかなりきちんとしていると思います。私たちにはffmpeg.jsとcomlinkをインポートするワーカーがいて、単にffmpegインターフェイスを公開するだけです。次に、workerを読み込んだ後、comlinkを使ってffmpeg APIへのプロキシを作成するWebページがあります。

きちんとした

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

私はComlink、Workers、WASMのコンパイルされたモジュールが一緒に演奏できる方法が本当に好きです。私はWASMモジュールと直接対話する慣用的なJavaScriptを取得し、それはメインスレッドから実行されます。

全文を読む

Translating a blog using Google Cloud Translate and Hugo

Paul Kinlan

私は最近、Google4Indiaイベント(近いうちに報告)に出席し、多くの企業や開発者と出会うためにインドへの旅行から帰ってきました。議論された最も興味深い変更の1つは、国のユーザーの言語でより多くのコンテンツを求めていたことでした。特に、ユーザーの言語で検索しやすくすること、コンテンツを見つけること、テキストまたは音声形式でユーザにそれを読み戻すことができます。

旅行全体が私に考えさせてくれました。私のブログはHugoで構築されています。 Hugoは現在、複数の言語で書かれたコンテンツをサポートしています。 Hugoは完全に静的なので、新しいコンテンツを作成することは、新しいファイルを作成してビルドシステムに魔法をかけることの問題です。翻訳ツールを使用して静的コンテンツを実行することで、より多くの人がコンテンツを利用できるようにすることができます。なぜなら、コンテンツの翻訳者は非常に高額なためです。

私の飛行前にイギリスに帰国する数時間前に、自分のマークダウンファイルを取得し、Google Cloud Translateで実行してクイック検索を作成するスクリプトを作成しました私はすぐにホストすることができますページの翻訳。ソリューション全体を以下に示します。これは比較的基本的なプロセッサーで、「コード」を無視したHugoプリアンブルを無視し、プル・クォートを無視しています。これらは常に書かれたままにしておくことを前提としていました。

注:翻訳用のラーニングソフトウェアのように見えるので、学習ツールでGoogle Translatedコンテンツをアルゴリズムの入力として使用しないようにページをマークアップすることが重要です(https://cloud.google.com/translate/マークアップ)。

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

全体として、私はそのプロセスに非常に満足しています。機械翻訳は完璧ではないと私は考えていますが、英語ではなく自分の言語で検索している可能性のあるユーザーにコンテンツのリーチを広げることができると私は思っています。人。

これが実際に人々に役立つかどうかを確認するにはしばらく時間がかかりますので、データが増えたときに報告します。

Apple - Web apps - All Categories

Paul Kinlan

Web AppsがiPhoneでアプリを使用するために推奨される方法を覚えていますか?

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

全文を読む

2013年頃、Appleは/ webapps /トップレベルのディレクトリを/ iphone /

ことは、ディレクトリは実際にはかなり良かった、そこのアプリの多くは今日も動作しています。しかし、AppStoreを見ると、開発者が持っていたより多くの問題が解決されました。 AppStoreはまた、支払いに関してユーザーや開発者から取り除かれた摩擦を具体的に紹介し始めました。

Gears API

Paul Kinlan

私は初期のモバイルWeb APIに関するブログ記事を書いているし、Alex Russellは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

全文を読む

AppCacheとWebSQL、GeolocationとWebWorkersはGoogle Gearsのアイデアから出てきて、実際に生き残ったのは後者の2つだけです。 WebSQLは決して広くサポートされておらず、IndexedDBに置き換えられました。 ServiceWorkerに置き換えられたAppCache

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

Paul Kinlan

私たちはGoogleチャットを内部的に使用してチーム全体でコミュニケーションを取っています。また、RSSフィードを介してアクセスできる多くのコンテンツを作成し、すべて見ることができるチームフィードを持っています。最近まで、WebHooks(https://developers.google.com/hangouts/chat/how-tos/webhooks)経由で単純なポストオンリーボットを作成することはかなり簡単であることがわかりました。私にはアイデアが与えられました。私はRSSフィードをポーリングして、私たちのチームチャットに直接投稿できるWebhookに送信する簡単なサービスを作成できます。

最後はかなりシンプルで、以下のコードをすべて含めました。私はFirebaseの機能を使用しました - これは他のサービス機能サイトやSuperfeedrと同じように簡単だと思われます。 SuperfeedrはPubsubhubbub ping(現在WebSub)を聞くことができるサービスで、Pubsubが設定されていないRSSフィードもポーリングします。フィードが見つかると、新しく見つかったフィードデータをXMLまたはJSON形式で構成されたURL(私の場合、FirebaseのCloud機能)にpingを実行します。データを解析して何かをするだけです。

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

完全な記事を読む

私は驚いて、セットアップがいかに簡単かについて喜んでいました。

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が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

全文を読む

彼女の主なマシンが壊れたので、ルースはChrome OSに移行するという大きな記事を書いています。

私は4ヶ月前(Google I / Oの前)にChrome OSにフルタイムで移行し、PixelBookを壊したためにMacに移行しました(現在は修正済み)。

私のために、それは今日そこにある最高のウェブ開発機の一つです。それは私が ‘真のモバイル’をテストできる唯一のデバイスです - あなたはそれにARCプラットフォームを介して、モバイル、サムスンのブラウザ、ブレイブなど、モバイル上のモバイルをインストールすることができます。 CrostiniはChrome OSのゲームチェンジャーでもあります.Chrome OSにLinux Appエコシステムの多くをもたらし、Chrome OS上で私にとって巨大なアプリケーションギャップを埋めるようになります。私はFirefox、vim、git、VSコード、ノード、npm、すべてのビルドツール、GIMP、Inkscapeを持っています…それは完璧だとは言えませんが、Crostiniはもっと速くて、GPUはまだ加速していません。 Filemanagerなどとの統合がさらに進んでいき、最終的にPixelBookには物理的なポートがさらに必要になります.2つの4kスクリーンを接続することはできますが、同時に充電することはできません。

私はルースのまとめも非常に正確だと思うが、PixelBookは高価なマシンだが、これはますます多くのデバイス(特に低価格帯のデバイス)になることを非常に喜んでいる。

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.

うん。

PWA: Progressive Web All-the-things

Paul Kinlan

PWA。プログレッシブウェブアプリ。 Frances BerrimanとAlex Russellは、2015年に「プログレッシブウェブアプリ:私たちの魂を失うことなくタブを逃れる」(0)という、「プログレッシブウェブアプリ」という言葉を主張しています。 3年後、我々は長い道のりを歩んだ。当初は1つのブラウザエンジンでしか実装されていなかったサービスワーカー、マニフェスト、ホーム画面に追加、Web Pushというゆるやかな技術の集まりから、企業や開発者と業界全体に密着し始めたブランド、ブラウザベンダーは大多数の ‘PWA’スタックを実装しています。 野生のPWAの数を大まかに把握するのに役立つappディレクトリ、toolsがあります。 PWA](3)。しかし、PWAは何を定義していますか?フランシスとアレックスはこの特徴のリストを思いついた: Responsive: to fit any form factor Connectivity independent: Progressively-enhanced with Service Workers to let them work offline App-like-interactions: Adopt a Shell + Content application model to create appy navigations & interactions Fresh: Transparently always up-to-date thanks to the Service Worker update process Safe: Served via TLS (a Service Worker requirement) to prevent snooping Discoverable: Are identifiable as “applications” thanks to W3C Manifests and Service Worker registration scope allowing search engines to find them

Read More

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

Paul Kinlan

ムスタファは次のように書いている。

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.

全文を読む

私はこれを非常に興味深い投稿と見なしました。これは、ウェブ開発者の課題について書いた記事の補足でもあります。ブラウザの互換性が問題であることは驚くべきことではありませんが、まだ懸念されるのは、IE11を構築することはまだ業界を後押ししていることです。同様に、Mustafa氏は、レスポンシブデザインのツールにはまだ問題が残っていると指摘しています。また、単一のレスポンシブルなソリューションに重点を置くと、常にムスタファのポストにあります。

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

これは私たちがまだ苦労していると思う問題です。一方では、誰もがすべてのデバイスのフォームファクターで誰にでも役立つことができる応答性の高いソリューションを構築したいと考えています。一方、ユーザーコンテキストは重要であり、しばしば特定の時間に特定のアクションを実行するだけです。小売業や商工業では多くの人々が見ています。人々はモバイルでブラウジングしてデスクトップで完成し、このマルチモーダルモデルをより多くの人に提供したり、すべてのデバイスで一貫した体験を構築したりできます。その答えは「それは依存している」と疑われますが、製品チームからエンジニアリングチームまで、誰にとっても難しい問題のいずれかです。

Page Lifecycle API - Philip Walton

Paul Kinlan

Philip Walton氏は、ブラウザがタブをアンロードしたときの対応方法をChrome開発者がコントロールするために、Chromeチームが取り組んでいる新しいAPIについて深く掘り下げています。

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.

完全な記事を読む

私の最初のコメントは、あなたがフィリップスの記事を読むべきだということです。それは信じられないです。

モバイルでは、ユーザーがブラウザを使用していないときにリソースを節約するために、ページをバックグラウンド(フリーズまたは破棄)するときにかなり攻撃的になる可能性があります(タブを入れ替えたり、AndroidのChromeアプリから移動するなど)あなたは伝統的にこれがいつ起こるのかを知らない開発者としてページを開いて、簡単に状態を保持したり、開いているリソースを閉じたりすることができず、アプリケーションが重要なときに状態をきれいに再水和します。開発者がコントロールできるようになると、情報に基づいた選択を行うことができ、ユーザーや開発者のエクスペリエンスに深刻な影響を与えることなく、ブラウザをより積極的に使用してリソースを節約できます。

最後に、下の図はそれをすべてうまく説明しています。

ページライフサイクルAPI

Add to homescreen changes in Chrome 68 - Pete LePage

Paul Kinlan

Pete LePageは、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.

全文を読む

多くの人が beforeinstallpromptイベントを処理していないので、Web APKのインストール数が急激に減少することを意味していたため、これは元々気になりましたが、実際には正しいことだと思います。

目標はWeb上で起こっている迷惑なプロンプトの数を減らすことです。業界で最後に必要となるのは、ユーザーがPWAをインストールしたいと思ったときに表示される比較的大きなプロンプトです。あなたがいつどこで**あなたがインストールを促すかを考えて、あなたはユーザージェスチャーに応じてそれをしなければなりません。

きちんとしたことは、私たち(Chrome)が、体験をインストールできることをユーザーに知らせるためのより多くの周囲の方法を導入していることです。最初の負荷に現れる小さなボトムバーです。ユーザーに行動を起こせることを知らせるより微妙な方法。

A one year PWA retrospective - Pinterest Engineering

Paul Kinlan

PinterestのPWAの概要

The verdict

Now for the part you’ve all been waiting for: the numbers. Weekly active users on mobile web have increased 103 percent year-over-year overall, with a 156 percent increase in Brazil and 312 percent increase in India. On the engagement side, session length increased by 296 percent, the number of Pins seen increased by 401 percent and people were 295 percent more likely to save a Pin to a board. Those are amazing in and of themselves, but the growth front is where things really shined. Logins increased by 370 percent and new signups increased by 843 percent year-over-year. Since we shipped the new experience, mobile web has become the top platform for new signups. And for fun, in less than 6 months since fully shipping, we already have 800 thousand weekly users using our PWA like a native app (from their homescreen).

Looking back over one full year since we started rebuilding our mobile web, we’re so proud of the experience we’ve created for our users. Not only is it significantly faster, it’s also our first platform to support right-to-left languages and “night mode.” Investing in a full-featured PWA has exceeded our expectations. And we’re just getting started.

全文を読む

これは本当に素晴らしいポストショーで、質の高い、迅速で魅力的なサイトを構築する利点があります。 PWAの ‘App’部分、具体的には ‘Add to Homescreen’のインストール可能性が多くのユーザーによって使用されていることもわかります。より広範な記事を読んだことは、彼らが素晴らしいウェブサイトの経験に焦点を当てていたことを知っていることです。つまり、コード分割による繰り返し可能で予測可能なパフォーマンスを持つ高速ロードサイトに焦点を当てています。チーム。その後、ベースエクスペリエンスがあれば、プッシュ通知などの機能を必要とするユーザーに重ねることができます。

Configuring hugo server to serve 'mjs' ES modules

Paul Kinlan

デフォルトでは、Hugoは正しいコンテンツタイプの.mjsファイルを提供しません。実際、最近までhugoはMIMEタイプごとに複数のファイル拡張子を提供することはできませんでした。これは修正されたv0.43のように見えます。

[mediaTypes] [mediaTypes.“text/javascript”] suffixes = [“js”, “mjs”]

全文を読む

上記のコードでは、正しいMIMEタイプのESモジュール用のmjsファイルを提供できます(メモモジュールは ‘text / javascript’で提供する必要があります)。これはローカルテストにのみ必要です。ホスティングは別の問題です:)

Thoughts on importing npm modules to the web as JavaScript modules

Paul Kinlan

私はESモジュールについて昨日投稿した投稿を考えています

I needed a quick way import a simple module get-urls into my project. The module is well tested and it does what I needed … ignore the fact that it’s pretty easy to implement in a couple of lines of JavaScript. The problem I had is that my project is built in ES6, uses modules and I didn’t want to have to bundle up using CommonJS (require).

I couldn’t find a lot of guidance on what to do here, so I went to experiement and this solution is the solution I came across:

  1. Create a file that imports the npm module I needed. module.exports = require(‘get-urls’); This module will be what’s converted to ES6 style.
  2. Create a rollup config that
    1. Imports the node globals, and builtins.
    2. Resolves all npm modules required for my usage of this module.
    3. Pass the results through the commonjs plugin so that it’s now in JavaScript module format.
    4. Compress the output, because it’s huge :
  3. Include the bundled file in your project and rejoice.

全文を読む

私が元の記事で試してみたかったことの一つだが、私が取り上げることにしたのは、ノードのエコシステムには膨大な量のコードがあり、それは実際にはノードそのものに固有のコードではないが、 Common JSや他の非常に特殊なNode API(バッファ、古いURLなど)を介してNodeを起動すると、ESモジュールをユビキタスにするために必要な変更が必要になる可能性がありますさまざまなプラットフォーム(Web /サーバー)でコードをきれいに共有できるようにするために、多くの変換ツールとバンドルを使用する必要があるエコシステムが変わります。

私たちはどこにいるのですか、Web上での話がありませんでした.Nodeが導入したプリミティブのヒープがなかったので、実際には多くのプラットフォームの要件が考慮されるようになりました。状況の批判よりも多くの肯定的な評価。

また、ノードとウェブの両方で標準的なファイル拡張子として ‘.mjs’を使用する動きもあります。しかし、私はこれを完全に快適に感じていますが、.msjはインフラストラクチャがまだ「text / javascript」と認識しているファイルではなく、これをソートして惑星上のすべてのWebサーバーによって自動的に推測されることを楽しみにしています。私は、サービングインフラストラクチャにさらに多くの構成変更を展開する必要はありません。

楽しい時間がたくさんあります。私は1つはWebにもっと多くの機能をもたらすことを楽しみにしています。

Importing npm modules to the web as JavaScript modules

Paul Kinlan

私は静的なサイトにコンテンツをプッシュするのを簡単にする方法に取り組んできました。もう1つのポストでもっと共有することは楽しい小さなエクササイズでした。この記事では、ほぼすべてのnpmモジュールをJavaScriptモジュールを使用してフロントエンドプロジェクトにインポートするために使用した rollup設定を共有したいと思います。 私はプロジェクトに簡単なモジュール get-urlsを簡単にインポートする必要がありました。モジュールは十分にテストされていて、私が必要なことをしてくれます… JavaScriptの2行で実装するのはかなり簡単だという事実を無視してください。私が持っていた問題は、私のプロジェクトがES6でビルドされ、モジュールを使用していて、CommonJS( require)を使ってバンドルしたくないということでした。 私はここで何をすべきかについて多くの指針を見つけることができませんでしたので、私は実験に行きました。このソリューションは私が遭遇した解決策です: 1.必要なnpmモジュールをインポートするファイルを作成します。 module.exports = require( 'get-urls');このモジュールはES6スタイルに変換されます。 2.ロールアップ設定を作成します。1.ノードのグローバルと組み込み関数をインポートします。 1.このモジュールの使用に必要なすべてのnpmモジュールを解決します。 1.結果を commonjsプラグインに渡して、JavaScriptモジュール形式になるようにします。 1.巨大なので、出力を圧縮します:\ 3.あなたのプロジェクトに同梱のファイルを含めて喜んでください。 import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import builtins from 'rollup-plugin-node-builtins'; import globals from 'rollup-plugin-node-globals'; import closure from 'rollup-plugin-closure-compiler-js'; export default { input: 'static/javascripts/get-urls.js', output: { file: 'static/javascripts/get-urls.bundle.mjs', format: 'es', browser: true }, plugins: [ globals(), builtins(), resolve({ preferBuiltins: false, browser: true, // pass custom options to the resolve plugin customResolveOptions: { moduleDirectory: 'node_modules' } }), commonjs(), closure({ compilationLevel: 'WHITESPACE', languageIn: 'ES6', languageOut: 'ES6' }) ] }; おそらくこれよりも良い方法があると思いますが、比較的シンプルな関数(70kb)の出力は出力されますが、ここでは自分のページにnpmのモジュールを直接使用できます。

Read More