目次
Google Lighthouseとは何ですか?
設定
node.jsでクロムを開く
プログラムで灯台を実行します
Lighthouseのレポートを節約します
ディレクトリの作成
レポートを保存します
Lighthouseレポートの比較
前のレポートに対して新しいレポートを比較してください
2つのレポートを比較します
比較ロジック
Complete source code
Next steps
ホームページ ウェブフロントエンド CSSチュートリアル node.jsツールを作成して、Google Lighthouseレポートを記録および比較する

node.jsツールを作成して、Google Lighthouseレポートを記録および比較する

Apr 09, 2025 am 09:18 AM

node.jsツールを作成して、Google Lighthouseレポートを記録および比較する

このチュートリアルでは、node.jsにシンプルなツールを作成してコマンドラインを介してGoogle灯台監査を実行し、JSON形式で生成するレポートを保存して、Webサイトを成長および開発するにつれてWebパフォーマンスを監視できるようにして、それらを比較する方法を段階的に紹介します。

これがプログラムでGoogle Lighthouseで働く方法について学ぶことに関心のある開発者にとって、良い紹介として役立つことを願っています。

しかし、最初に、初心者のために…

Google Lighthouseとは何ですか?

Google Lighthouseは、Web開発者のユーティリティベルトで利用できる最も自動化されたツールの1つです。これにより、全体的な品質の尺度を形成できる多くの重要な領域でWebサイトをすばやく監査することができます。これらは:

  • パフォーマンス
  • アクセシビリティ
  • ベストプラクティス
  • SEO
  • プログレッシブWebアプリ

監査が完了すると、ウェブサイトがうまく機能することについてレポートが生成されます。後者は、ページを改善するための次のステップの指標として機能することを意図しています。

これが完全なレポートの外観です。

他の一般的な診断およびWebパフォーマンスメトリックに加えて、レポートの非常に便利な機能は、各重要な領域が0〜100の間のカラーコーディングスコアに集約されていることです。

これにより、開発者はさらなる分析なしでWebサイトの品質を迅速に評価できるだけでなく、利害関係者やクライアントなどの技術者以外の人々も理解することができます。

たとえば、これは、灯台のアクセシビリティスコアが50ポイント上昇してグリーンに上昇した後、ウェブサイトのアクセシビリティを改善するために時間を費やした後、マーケティングのヘザーとの勝利を共有する方がはるかに簡単です。

しかし、同様に、プロジェクトマネージャーのサイモンは、スピードインデックスまたは最初のコンテンツペイントの意味を理解していないかもしれませんが、灯台レポートが赤の深い膝を示す灯台レポートを見たとき、彼はあなたがまだやるべきことを知っています。

ChromeまたはEdgeの最新バージョンにいる場合は、DevToolsを使用して現在自分で灯台監査を実行できます。方法は次のとおりです。

また、PageSpeed InsightsまたはWebPagetestなどの人気のあるパフォーマンスツールを介して、オンラインで灯台監査を実行することもできます。

ただし、今日では、ノードモジュールとしての灯台のみに関心があります。これにより、プログラムでツールを使用してWebパフォーマンスメトリックを監査、記録、比較することができます。

その方法を見つけましょう。

設定

まず、まだ持っていない場合は、node.jsが必要になります。それをインストールするには、数百万の異なる方法があります。 HomeBrewパッケージマネージャーを使用しますが、必要に応じてnode.js Webサイトからインストーラーを直接ダウンロードすることもできます。このチュートリアルはnode.js v10.17.0を念頭に置いて書かれていますが、過去数年間にリリースされたほとんどのバージョンではうまく機能する可能性が非常に高いです。

また、灯台監査を実行する方法であるため、Chromeがインストールされる必要があります。

次に、プロジェクトの新しいディレクトリを作成し、コンソールでCDにCDに作成します。次に、NPM initを実行して、package.jsonファイルの作成を開始します。この時点で、ファイルが作成されるまで、できるだけ多くのこのスキップをスキップするために、Enterキーを何度もバッシングすることをお勧めします。

次に、プロジェクトディレクトリに新しいファイルを作成しましょう。私は私のlh.jsに電話しましたが、あなたが望むものは何でも自由に電話してください。これには、ツールのすべてのJavaScriptが含まれます。選択したテキストエディターでそれを開き、今のところ、Console.logステートメントを書きます。

 console.log( 'hello world');
ログイン後にコピー

次に、コンソールで、CWD(現在のワーキングディレクトリ)がプロジェクトディレクトリとノードLH.JSを実行し、使用したものを何でも置き換えます。

あなたは見るべきです:

 $ node lh.js
こんにちは世界
ログイン後にコピー

そうでない場合は、ノードのインストールが機能していることを確認すると、間違いなく正しいプロジェクトディレクトリにいます。

これが邪魔にならないように、私たちはツール自体の開発に進むことができます。

node.jsでクロムを開く

プロジェクトの最初の依存関係である灯台自体をインストールしましょう。

 npmインストール灯台 -  save-dev
ログイン後にコピー

これにより、すべてのパッケージのファイルを含むnode_modulesディレクトリが作成されます。 GITを使用している場合、これでやりたいことは、.gitignoreファイルに追加することだけです。

LH.JSでは、次にTest Console.log()を削除し、灯台モジュールをインポートして、コードで使用できるようにする必要があります。そうするように:

 const lighthouse = require( 'lighthouse');
ログイン後にコピー

その下では、灯台の依存関係の1つであるChrome-Launcherというモジュールをインポートする必要があり、監査を実行できるようにノードを単独でChromeを起動できるようにします。

 const lighthouse = require( 'lighthouse');
const chromelauncher = require( 'chrome-launcher');
ログイン後にコピー

これらの2つのモジュールにアクセスできるようになったので、Chromeを開き、Lighthouse監査を実行し、レポートをコンソールに印刷する単純なスクリプトを作成しましょう。

URLをパラメーターとして受け入れる新しい関数を作成します。 node.jsを使用してこれを実行するため、厄介なインターネットエクスプローラーユーザーを心配する必要がないため、ES6構文を安全に使用できます。

 const launchchrome =(url)=> {

}
ログイン後にコピー

関数内で、最初に行う必要があるのは、インポートしたChrome-Launcherモジュールを使用してChromeを開くことで、URLパラメーターを介して渡される引数に送信します。

launch()メソッドとstartingurlオプションを使用してこれを行うことができます。

 const launchchrome = url => {
  chromeLauncher.launch({
    startingurl:url
  });
};
ログイン後にコピー

以下の関数を呼び出し、選択したURLを渡すと、ノードスクリプトが実行されると、URLでChromeが開かれます。

 LaunchChrome( 'https://www.lukeharrison.dev');
ログイン後にコピー

起動関数は実際に約束を返します。これにより、いくつかの便利な方法とプロパティを含むオブジェクトにアクセスできます。

たとえば、以下のコードを使用して、Chromeを開き、オブジェクトをコンソールに印刷し、3秒後にKill()メソッドを使用してChromeを閉じることができます。

 const launchchrome = url => {
  ChromeLauncher
    。打ち上げ({
      startingurl:url
    })
    .then(chrome => {
      console.log(chrome);
      setimeout(()=> chrome.kill()、3000);
    });
};

LaunchChrome( "https://www.lukeharrison.dev");
ログイン後にコピー

Chromeが把握したので、Lighthouseに移りましょう。

プログラムで灯台を実行します

まず、LaunchChrome()関数を最終的な機能をより反映したものに変更してみましょう。邪魔にならないように、チュートリアルで前半でインポートした灯台モジュールを使用できるようになりました。

Chrome LauncherのThen機能では、ブラウザが開いてからのみ実行される場合にのみ、灯台のURL引数を渡し、このWebサイトの監査をトリガーします。

 const launchchromeandrunlighthouse = url => {
  ChromeLauncher
    。打ち上げ({
      startingurl:url
    })
    .then(chrome => {
      const opts = {
        ポート:Chrome.port
      };
      Lighthouse(url、opts);
    });
};

LaunchChromeandrunlighthouse( "https://www.lukeharrison.dev");
ログイン後にコピー

LighthouseインスタンスをChromeブラウザウィンドウにリンクするには、URLとともにポートを通過する必要があります。

このスクリプトを今すぐ実行する場合、コンソールでエラーが発生します。

 (ノード:47714)unhandledpromiserejectionwarning:エラー:おそらく、同じオリジンに複数のタブが開いているでしょう。
ログイン後にコピー

これを修正するには、Chrome Launcherからstartingurlオプションを削除し、LighthouseをここからURLナビゲーションを処理させるだけです。

 const launchchromeandrunlighthouse = url => {
  chromeLauncher.launch()。then(chrome => {
    const opts = {
      ポート:Chrome.port
    };
    Lighthouse(url、opts);
  });
};
ログイン後にコピー

このコードを実行する場合、何かが間違いなく起こっているように見えることに気付くでしょう。灯台の監査が間違いなく実行されていることを確認するために、コンソールでフィードバックを受け取っていないだけでなく、以前のようにChromeインスタンス自体も閉鎖されていません。

ありがたいことに、Lighthouse()Functionは、監査結果にアクセスできる約束を返します。

Chromeを殺してから、結果オブジェクトのレポートプロパティを介してJSON形式の端末にそれらの結果を印刷しましょう。

 const launchchromeandrunlighthouse = url => {
  chromeLauncher.launch()。then(chrome => {
    const opts = {
      ポート:Chrome.port
    };
    lighthouse(url、opts).then(result => {
      Chrome.kill();
      console.log(results.report);
    });
  });
};
ログイン後にコピー

コンソールはこれらの結果を表示する最良の方法ではありませんが、クリップボードにコピーして灯台レポートビューアーにアクセスする場合、ここに貼り付けると、その栄光のすべてのレポートが表示されます。

この時点で、laintChromeandrunlighthouse()機能を実行して、実行が終了したらレポートを返すために、コードを少し整理することが重要です。これにより、JavaScriptの乱雑なピラミッドをもたらすことなく、後でレポートを処理できます。

 const lighthouse = require( "lighthouse");
const chromelauncher = require( "Chrome-Launcher");

const launchchromeandrunlighthouse = url => {
  return chromelauncher.launch()。then(chrome => {{
    const opts = {
      ポート:Chrome.port
    };
    lighthouse(url、opts)を返します。
      chrome.kill()。then(()=> results.report);
    });
  });
};

LaunchChromeanDrunlighthouse( "https://www.lukeharrison.dev").then(result => {{
  console.log(results);
});
ログイン後にコピー

気づいたかもしれないことの1つは、私たちのツールが現時点で1つのウェブサイトのみを監査できることです。これを変更して、コマンドラインを介してURLを引数として渡すことができます。

コマンドラインの引数を扱うことで痛みを取り除くために、Yargsというパッケージでそれらを処理します。

 npmインストール -  save-dev yargs
ログイン後にコピー

次に、ChromeランチャーとLighthouseとともにスクリプトの上部にインポートします。ここではそのargv関数のみが必要です。

 const lighthouse = require( 'lighthouse');
const chromelauncher = require( 'chrome-launcher');
const argv = require( 'yargs')。argv;
ログイン後にコピー

これは、そうするような端末でコマンドライン引数を渡す場合を意味します。

 node lh.js -url https://www.google.co.uk
ログイン後にコピー

…次のように、スクリプトの引数にアクセスできます。

 const url = argv.url // https://www.google.co.uk
ログイン後にコピー

スクリプトを編集して、コマンドラインURL引数を関数のURLパラメーターに渡しましょう。引数が渡されなかった場合に備えて、IFステートメントとエラーメッセージを介して少しセーフティネットを追加することが重要です。

 if(argv.url){
  LaunchChromeanDrunlighthouse(argv.url).then(result => {{
    console.log(results);
  });
} それ以外 {
  「あなたは灯台にURLを渡していない」を投げます。
}
ログイン後にコピー

田田! Chromeを起動し、JSON形式のターミナルにレポートを印刷する前に、プログラムで灯台監査を実行するツールがあります。

Lighthouseのレポートを節約します

レポートをコンソールに印刷することは、その内容を簡単に読み取ることができず、将来の使用のために保存されないため、あまり役に立ちません。チュートリアルのこのセクションでは、この動作を変更して、各レポートが独自のJSONファイルに保存されます。

さまざまなWebサイトからのレポートを停止するために、そのように整理します。

  • lukeharrison.dev
    • 2020-01-31T18:18:12.648Z.JSON
    • 2020-01-31T19:10:24.110Z.JSON
  • CNN.com
    • 2020-01-14T22:15:10.396z.json
  • LH.JS

レポートには、レポートがいつ生成されたかを示すタイムスタンプでレポートに名前を付けます。これは、2つのレポートファイル名が同じではないことを意味し、レポートを簡単に区別するのに役立ちます。

私たちの注意を必要とするWindowsには1つの問題があります。コロン(:)はファイル名の違法な性格です。この問題を軽減するために、任意のコロンをアンダースコア(_)に置き換えるため、典型的なレポートファイル名は次のようになります。

  • 2020-01-31T18_18_12.648Z.JSON

ディレクトリの作成

まず、コマンドラインURL引数を操作して、ディレクトリ名に使用できるようにする必要があります。

これには、wwwを削除するだけではありません。これは、www(例:www.foo.com/bar)に座っていないWebページで実行される監査を説明する必要があるためです。

これらのURLについては、無効な文字を再度アンダースコアに置き換えます。そうすれば、https://www.foo.com/barで監査を実行した場合、レポートを含む結果のディレクトリ名はfoo.com_barになります。

URLの処理を容易にするために、URLと呼ばれるネイティブNode.jsモジュールを使用します。これは、他のパッケージと同様にインポートでき、package.jsonに追加してnpm経由でプルすることはできません。

 const lighthouse = require( 'lighthouse');
const chromelauncher = require( 'chrome-launcher');
const argv = require( 'yargs')。argv;
const url = require( 'url');
ログイン後にコピー

次に、新しいURLオブジェクトをインスタンス化するために使用しましょう。

 if(argv.url){
  const urlobj = new url(argv.url);

  LaunchChromeanDrunlighthouse(argv.url).then(result => {{
    console.log(results);
  });
}
ログイン後にコピー

urlobjをコンソールに印刷する場合、使用できる有用なURLデータがたくさん表示されます。

 $ node lh.js -url https://www.foo.com/bar
url {
  href: 'https://www.foo.com/bar'、
  起源: 'https://www.foo.com'、
  プロトコル: 'https:'、
  ユーザー名: ''、
  パスワード: ''、
  ホスト: 'www.foo.com'、
  ホスト名: 'www.foo.com'、
  ポート: ''、
  パス名: '/bar'、
  検索: ''、
  SearchParams:urlsearchparams {}、
  ハッシュ: ''
}
ログイン後にコピー

dirNameという新しい変数を作成し、HTTPSプロトコルに加えてWWWを削除するために、URLのホストプロパティで文字列置換()メソッドを使用します。

 const urlobj = new url(argv.url);
let dirname = urlobj.host.replace( 'www。'、 '');
ログイン後にコピー

ここでletを使用しました。これは、constを再割り当てすることができます。これは、URLにパス名がある場合はリファレンスを更新する必要があるため、スラッシュをアンダースコアに置き換える必要があります。これは正規表現パターンで実行でき、次のようになります。

 const urlobj = new url(argv.url);
let dirname = urlobj.host.replace( "www。"、 "");
if(urlobj.pathname!== "/"){
  dirname = dirname urlobj.pathname.replace(/\ // g、 "_");
}
ログイン後にコピー

これで、ディレクトリ自体を作成できます。これは、FS(「ファイルシステム」の略)と呼ばれる別のネイティブnode.jsモジュールを使用することで実行できます。

 const lighthouse = require( 'lighthouse');
const chromelauncher = require( 'chrome-launcher');
const argv = require( 'yargs')。argv;
const url = require( 'url');
const fs = require( 'fs');
ログイン後にコピー

mkdir()メソッドを使用してディレクトリを作成できますが、最初にexistssync()メソッドを使用して、node.jsがエラーをスローするため、ディレクトリが既に存在するかどうかを確認する必要があります。

 const urlobj = new url(argv.url);
let dirname = urlobj.host.replace( "www。"、 "");
if(urlobj.pathname!== "/"){
  dirname = dirname urlobj.pathname.replace(/\ // g、 "_");
}
if(!fs.existsync(dirname)){
  fs.mkdirsync(dirname);
}
ログイン後にコピー

ポイントでスクリプトをテストすると、新しいディレクトリが作成されます。 https://www.bbc.co.uk/newsをURL引数として渡すと、bbc.co.uk_newsという名前のディレクトリが得られます。

レポートを保存します

LaunchChromeanDrunlighthouse()のその後の関数では、既存のConsole.logをロジックに置き換えて、レポートをディスクに書き込みます。これは、FSモジュールのWriteFile()メソッドを使用して実行できます。

 LaunchChromeanDrunlighthouse(argv.url).then(result => {{
  fs.WriteFile( "Report.json"、result、err => {
    (err)スローERR;
  });
});
ログイン後にコピー

最初のパラメーターはファイル名を表し、2番目はファイルのコンテンツ、3番目は書き込みプロセス中に何か問題が発生した場合にエラーオブジェクトを含むコールバックです。これにより、Report.jsonと呼ばれる新しいファイルが作成されます。

ファイル名としてタイムスタンプを使用して、正しいディレクトリに送信する必要があります。前者は簡単です。

 LaunchChromeanDrunlighthouse(argv.url).then(result => {{
  fs.writefile( `$ {dirname}/report.json`、result、err => {
    (err)スローERR;
  });
});
ログイン後にコピー

ただし、後者は、レポートが生成されたときのタイムスタンプを何らかの形で取得する必要があります。ありがたいことに、レポート自体はこれをデータポイントとしてキャプチャし、Fetchtimeプロパティとして保存されます。

Windowsファイルシステムでうまく機能するように、アンダースコア(_)のコロン(:)を交換することを忘れないでください。

 LaunchChromeanDrunlighthouse(argv.url).then(result => {{
  fs.writefile(
    `$ {dirname}/$ {results [" fetchtime "]。置き換え(/:/g、" _ ")}。json`、
    結果、
    err => {
      (err)スローERR;
    }
  );
});
ログイン後にコピー

Timestamed.jsonのファイル名ではなく、これを今すぐ実行する場合、代わりに次のようなエラーが表示される可能性があります。

 unhandledpromiserejectionwarning:typeRror:未定義のプロパティ「置き換え」を読み取ることができません
ログイン後にコピー

これは、LighthouseがJavaScriptが消費できるオブジェクトではなく、JSON形式でレポートを返しているためです。

ありがたいことに、JSONを自分で解析する代わりに、灯台に代わりに通常のJavaScriptオブジェクトとしてレポートを返すように頼むことができます。

これには、以下の行を編集する必要があります。

 chrome.kill()。then(()=> results.report);
ログイン後にコピー

…に:

 return chrome.kill()。then(()=> results.lhr);
ログイン後にコピー

これで、スクリプトを再実行すると、ファイルは正しく命名されます。ただし、開いた場合、残念ながらコンテンツだけが…

 [オブジェクトオブジェクト]
ログイン後にコピー

これは、以前と同じように反対の問題があるからです。最初にJSONオブジェクトに接続することなく、JavaScriptオブジェクトをレンダリングしようとしています。

ソリューションは簡単です。この巨大なオブジェクトの解析や弦楽器にリソースを無駄にしないようにするために、灯台から両方のタイプを返すことができます。

 lighthouse(url、opts)を返します。
  return chrome.kill()。then(()=> {
    戻る {
      JS:results.lhr、
      JSON:results.report
    };
  });
});
ログイン後にコピー

次に、WriteFileインスタンスをこれに変更できます。

 fs.writefile(
  `$ {dirname}/$ {results.js [" fetchtime "]。置換(/:/g、" _ ")}。
  results.json、
  err => {
    (err)スローERR;
  }
);
ログイン後にコピー

ソート! Lighthouse監査が完了すると、当社のツールは、WebサイトURLにちなんで名付けられたディレクトリに、一意のタイムスタンプ付きファイル名を含むファイルにレポートを保存する必要があります。

これは、レポートがより効率的に整理されていることを意味し、レポートがどれだけ保存されても、お互いを無効にしません。

Lighthouseレポートの比較

日常開発中、パフォーマンスの向上に焦点を当てたとき、コンソール内のレポートを非常に迅速に比較し、正しい方向に向かっているかどうかを確認する能力が非常に有用である可能性があります。これを念頭に置いて、この比較機能の要件は次のはずです。

  1. 灯台監査が完了したときに同じWebサイトに以前のレポートが既に存在する場合、それに対して自動的に比較を実行し、主要なパフォーマンスメトリックの変更を示します。
  2. また、必要ないかもしれない新しい灯台レポートを生成することなく、2つのWebサイトからの2つのレポートの主要なパフォーマンスメトリックを比較できるはずです。

レポートのどの部分を比較する必要がありますか?これらは、灯台レポートの一部として収集された数値キーパフォーマンスメトリックです。彼らは、ウェブサイトの目的と知覚されたパフォーマンスに関する洞察を提供します。

さらに、Lighthouseは、レポートのこの部分にリストされていないが、比較に含まれる適切な形式である他のメトリックも収集しています。これらは:

  • 最初のバイトまでの時間 -最初のバイトまでの時間は、サーバーが応答を送信する時間を識別します。
  • 総ブロッキング時間 -タスクの長さが50msを超えてミリ秒で表された場合、FCPからインタラクティブまでのすべての期間の合計。
  • 推定入力レイテンシ -推定入力レイテンシは、ページロードの最も忙しい5Sウィンドウ中に、ミリ秒単位でユーザー入力に応答するためにアプリがどれだけ時間がかかるかの推定値です。レイテンシが50ミリ秒を超える場合、ユーザーはアプリを遅れていると認識する場合があります。

メトリック比較はコンソールにどのように出力する必要がありますか?古いメトリックと新しいメトリックを使用して、レポートからレポートにどのように変更されたかを確認する単純なパーセンテージベースの比較を作成します。

迅速なスキャンを可能にするために、個々のメトリックがより速く、遅く、または変化していないかに応じて、個々のメトリックをカラーコードします。

この出力を目指してください。

前のレポートに対して新しいレポートを比較してください

LaunchChromeanDrunlighthouse()関数のすぐ下にComparePorts()という新しい関数を作成することから始めましょう。これには、すべての比較ロジックが含まれます。比較に使用される2つのレポートを受け入れるために、2つのパラメーターを提供します。

今のところ、プレースホルダーとして、各レポートのデータをコンソールに印刷するだけで、正しく受信していることを検証します。

 const compareports =(from、to)=> {
  console.log(from ["finalurl"] "" from ["fetchtime"]);
  console.log(to ["finalurl"] "" to ["fetchtime"]);
};
ログイン後にコピー

この比較は、新しいレポートの作成後に開始されるため、この関数を実行するロジックは、LaunchChromeanDrunlighthouseのThen関数に配置する必要があります。

たとえば、30のレポートがディレクトリにある場合、どのレポートが最新かを決定し、新しいレポートが比較される前のレポートとして設定する必要があります。ありがたいことに、私たちはすでにレポートのファイル名としてタイムスタンプを使用することにしたので、これは私たちに仕事をするものを与えてくれます。

まず、既存のレポートを収集する必要があります。このプロセスを簡単にするために、ファイルを検索するときにパターンマッチングが可能になるGLOWと呼ばれる新しい依存関係をインストールします。これは、存在するレポートの数またはそれらが何と呼ばれるかを予測できないため、これは重要です。

他の依存関係と同じようにインストールします:

 npmインストールグローブ -  save-dev
ログイン後にコピー

次に、通常と同じようにファイルの上部にインポートします。

 const lighthouse = require( 'lighthouse');
const chromelauncher = require( 'chrome-launcher');
const argv = require( 'yargs')。argv;
const url = require( 'url');
const fs = require( 'fs');
const glob = require( 'glob');
ログイン後にコピー

GLOWを使用して、ディレクトリ内のすべてのレポートを収集します。これは、DirName変数を介して既に知られています。 JavaScriptの実行を継続したくないため、同期オプションをTrueに設定することが重要です。

 LaunchChromeanDrunlighthouse(argv.url).then(result => {{
  const prevreports = glob( `$ {dirname}/*。json`、{
    同期:true
  });

  // et al

});
ログイン後にコピー

このプロセスは、パスの配列を返します。したがって、レポートディレクトリが次のようになった場合:

  • lukeharrison.dev
    • 2020-01-31T10_18_12.648Z.JSON
    • 2020-01-31T10_18_24.110Z.JSON

…その後、結果の配列は次のようになります。

 [
 'lukeharrison.dev/2020-01-31t10_18_12.648z.json'、
 'lukeharrison.dev/2020-01-31t10_18_24.110z.json'
]
ログイン後にコピー

以前のレポートが存在する場合にのみ比較を実行できるため、この配列を比較ロジックの条件として使用しましょう。

 const prevreports = glob( `$ {dirname}/*。json`、{
  同期:true
});

if(prevreports.length){
}
ログイン後にコピー

レポートファイルパスのリストがあり、それらのタイムスタンプ付きファイル名を比較して、最新のファイル名を決定する必要があります。

これは、最初にすべてのファイル名のリストを収集し、ディレクトリ名などの無関係なデータをトリミングし、アンダースコア(_)をコロン(:)を再び有効な日付に戻すように注意する必要があることを意味します。これを行う最も簡単な方法は、別のnode.jsネイティブモジュールを使用することです。

 const path = require( 'path');
ログイン後にコピー

そのように、そのように、その解析方法への引数としてのパスを渡す

Path.Parse( 'lukeharrison.dev/2020-01-31t10_18_24.110Z.json');
ログイン後にコピー

この便利なオブジェクトを返します:

 {
  根: ''、
  dir: 'lukeharrison.dev'、
  ベース: '2020-01-31T10_18_24.110Z.JSON'、
  ext: '.json'、
  名前: '2020-01-31T10_18_24.110Z'
}
ログイン後にコピー

したがって、すべてのタイムスタンプファイル名のリストを取得するには、これを行うことができます。

 if(prevreports.length){
  日付= [];
  for(prevreportsのレポート){
    dates.push(
      新しい日付(path.parse(prevreports [Report])。name.replace(/_/g、 ":"))
    );
  }
}
ログイン後にコピー

私たちのディレクトリが次のように見えた場合、これもまた次のように見えます

  • lukeharrison.dev
    • 2020-01-31T10_18_12.648Z.JSON
    • 2020-01-31T10_18_24.110Z.JSON

結果:

 [
 '2020-01-31T10:18:12.648Z'、
 '2020-01-31T10:18:24.110Z'
]
ログイン後にコピー

日付の便利なことは、デフォルトで本質的に匹敵することです。

 const alpha = new Date( '2020-01-31');
const bravo = new Date( '2020-02-15');

console.log(alpha> bravo); // 間違い
console.log(bravo> alpha); // 真実
ログイン後にコピー

したがって、還元関数を使用することにより、最新のものだけが残るまで日付の配列を減らすことができます。

日付= [];
for(prevreportsのレポート){
  dates.push(new date(path.parse(pretreports [Report])。name.replace(/_/g、 ":")));
}
const max = dates.reduce(function(a、b){
  return math.max(a、b);
});
ログイン後にコピー

マックスの内容をコンソールに印刷する場合、UNIXタイムスタンプを投げるので、最新の日付を正しいISO形式に戻すために別のラインを追加する必要があります。

 const max = dates.reduce(function(a、b){
 return math.max(a、b);
});
const retryReport = new Date(max).toIsString();
ログイン後にコピー

これらがレポートのリストであると仮定します。

  • 2020-01-31T23_24_41.786Z.JSON
  • 2020-01-31T23_25_36.827Z.JSON
  • 2020-01-31T23_37_56.856Z.JSON
  • 2020-01-31T23_39_20.459Z.JSON
  • 2020-01-31T23_56_50.959Z.JSON

最近のレポートの値は、2020-01-31T23:56:50.959zです。

最新のレポートがわかったので、次にその内容を抽出する必要があります。最近のレポート変数の下に最近のReportContentsと呼ばれる新しい変数を作成し、空の関数を割り当てます。

この関数は、手動で呼び出すのではなく、常に実行する必要があることがわかっているため、JavaScriptパーサーが到達したときにそれ自体で実行されるIFFE(すぐに呼び出された関数式)に変えることは理にかなっています。これは、余分な括弧によって表されます。

 const restryReportContents =(()=> {

})();
ログイン後にコピー

この関数では、ネイティブFSモジュールのreadfilesync()メソッドを使用して、最新のレポートの内容を返すことができます。これはJSON形式であるため、通常のJavaScriptオブジェクトに解析することが重要です。

 const restryReportContents =(()=> {
  const output = fs.readfilesync(
    dirname "/" starterreport.replace(/:/g、 "_") ".json"、
    「UTF8」、
    (err、results)=> {
      結果を返します。
    }
  );
  return json.parse(output);
})();
ログイン後にコピー

そして、それはComparePorts()関数を呼び出し、現在のレポートと最新のレポートの両方を引数として渡す問題です。

 ComparePorts(最近のReportContents、results.js);
ログイン後にコピー

現時点では、これはコンソールにいくつかの詳細を印刷するだけで、レポートデータをテストできるようになります。

 https://www.lukeharrison.dev/ 2020-02-01T00:25:06.918Z
https://www.lukeharrison.dev/ 2020-02-01T00:25:42.169z
ログイン後にコピー

この時点でエラーが発生した場合は、チュートリアルの前半から有効なコンテンツなしでレポートを削除してください。JSONファイルまたはレポートを試してください。

2つのレポートを比較します

残りの重要な要件は、2つのWebサイトからの任意の2つのレポートを比較する機能でした。これを実装する最も簡単な方法は、ユーザーがコマンドライン引数として完全なレポートファイルパスを渡すことができることです。

コマンドラインでは、これは次のようになります。

 Node LH.JS  -  From LukeHarrison.dev/2020-02-01t00:25:06.918z-to-to CNN.com/2019-12-16T15:12:07.169z
ログイン後にコピー

これを達成するには、URLコマンドライン引数の存在をチェックする条件付きIFステートメントを編集する必要があります。追加のチェックを追加して、ユーザーがFromとPathに渡されたばかりであるかどうかを確認します。それ以外の場合は、以前のようにURLをチェックします。これにより、新しい灯台監査を防ぎます。

 if(argv.from && argv.to){

} else if(argv.url){
 // et al
}
ログイン後にコピー

これらのJSONファイルの内容を抽出し、それらをJavaScriptオブジェクトに解析してから、それらをComparePorts()関数に渡しましょう。

最新のレポートを取得する前に、すでにJSONを解析しました。この機能を独自のヘルパー関数に外挿して、両方の場所で使用できます。

最近のReportContents()関数をベースとして使用して、引数としてファイルパスを受け入れるgetContents()と呼ばれる新しい関数を作成します。 JavaScriptパーサーが見つけたらすぐに実行したくないので、これはIFFEではなく通常の機能であることを確認してください。

 const getContents = pathstr => {
  const output = fs.readfilesync(pathstr、 "utf8"、(err、results)=> {
    結果を返します。
  });
  return json.parse(output);
};

const compareports =(from、to)=> {
  console.log(from ["finalurl"] "" from ["fetchtime"]);
  console.log(to ["finalurl"] "" to ["fetchtime"]);
};
ログイン後にコピー

次に、最近のReportContents()関数を更新して、代わりにこの外挿されたヘルパー関数を使用します。

 const restryReportContents = getContents(dirname '/' stromageReport.Replace(/:/g、 '_') '.json');
ログイン後にコピー

新しい条件に戻って、比較レポートの内容をComparePorts()関数に渡す必要があります。

 if(argv.from && argv.to){
  ComparEReports(
    getContents(argv.from ".json")、
    getContents(argv.to ".json")
  );
}
ログイン後にコピー

以前のように、これはコンソールのレポートに関する基本的な情報を印刷して、すべて正常に機能していることを知らせる必要があります。

 node lh.js  -  from lukeharrison.dev/2020-01-31t23_24_41.786z-to to lukeharrison.dev/2020-02-01t11_16_25.25.221z
ログイン後にコピー

につながる:

 https://www.lukeharrison.dev/ 2020-01-31t23_24_41.786z
https://www.lukeharrison.dev/ 2020-02-01t11_16_25.221z
ログイン後にコピー

比較ロジック

開発のこの部分では、比較ロジックを構築して、ComparePorts()関数によって受信された2つのレポートを比較します。

灯台が返されるオブジェクト内には、パフォーマンスメトリック、機会、情報をリストする別のオブジェクトを含む監査と呼ばれるプロパティがあります。ここには多くの情報がありますが、その多くはこのツールの目的のために興味がありません。

これは、比較したい9つのパフォーマンスメトリックの1つであるFirst Contentful Paintのエントリです。

 「ファーストコンテンツペイント」:{
  「ID」:「FirstContentful-Paint」、
  「タイトル」:「最初のコンテンツフルペイント」、
  「説明」:「最初のテキストまたは画像がペイントされる時間を最初のコンテンツペイントマーク。[詳細](https://web.dev/first-contentful-paint)。」
  「スコア」:1
  「ScoredisPlayMode」:「数値」、
  「numericValue」:1081.661、
  「DisplayValue」:「1.1 s」
}
ログイン後にコピー

これらの9つのパフォーマンスメトリックのキーをリストする配列を作成します。これを使用して監査オブジェクトをフィルタリングできます。

 const compareports =(from、to)=> {
  const metricfilter = [
    「ファーストコンテンツペイント」、
    「最初のことを意味するペイント」、
    「スピードインデックス」、
    「推定入力遅延」、
    「ブロッキングタイム全体」、
    「マックスポテンシャルフィッド」、
    「時間からの時間」、
    「First-CPU-Idle」、
    "相互の作用"
  ];
};
ログイン後にコピー

次に、レポートの監査オブジェクトのいずれかをループし、その名前をフィルターリストに対して相互参照します。 (どちらの監査オブジェクトが同じコンテンツ構造を持っているため、どの監査オブジェクトは関係ありません。)

それがそこにある場合、それから素晴らしい、私たちはそれを使いたいです。

 const metricfilter = [
  「ファーストコンテンツペイント」、
  「最初のことを意味するペイント」、
  「スピードインデックス」、
  「推定入力遅延」、
  「ブロッキングタイム全体」、
  「マックスポテンシャルフィッド」、
  「時間からの時間」、
  「First-CPU-Idle」、
  "相互の作用"
];

for(["audits"]からauditobjを入れてください){
  if(metricfilter.includes(auditobj)){
    console.log(auditobj);
  }
}
ログイン後にコピー

このConsole.log()は、以下のキーをコンソールに印刷します。

ファーストコンテンツペイント
最初のことを意味するペイント
Speed-Index
推定入力遅延
総ブロッキング時間
最大値 -  fid
最初の時間まで
First-CPU-Idle
相互の作用
ログイン後にコピー

つまり、['audits]] [auditobj] .numericvalueおよび[' audits '] [auditobj] [auditobj] .numericvalueにそれぞれ使用して、メトリック自体にアクセスすることを意味します。

これらをキーを使用してコンソールに印刷する場合、次のような出力になります。

 FirstContentful-Paint 1081.661 890.774
First-Minedful-Paint 1081.661 954.774
Speed-Index 15576.7031351777 1098.622294504341
推定入力遅延12.8 12.8
総ブロッキング時間59 31.5
Max-Potential-FID 153 102
16.8599999999985 16.09600000000000004
First-CPU-Idle 1704.8490000000002 1918.774
インタラクティブ2266.2835 2374.3615
ログイン後にコピー

必要なすべてのデータがあります。これら2つの値の割合の差を計算し、以前に概説したカラーコード形式の形式を使用してコンソールにログに記録するだけです。

2つの値間の変化率を計算する方法を知っていますか?私も。ありがたいことに、みんなのお気に入りのモノリス検索エンジンが救助に来ました。

式は次のとおりです。

 ((from -to) / from)x 100
ログイン後にコピー

したがって、最初のレポート(from)には5.7の速度インデックスがあり、次に2番目のレポート(to)で2.1秒の速度インデックスがあるとしましょう。計算は次のとおりです。

 5.7-2.1 = 3.6
3.6 / 5.7 = 0.63157895
0.63157895 * 100 = 63.157895
ログイン後にコピー

小数点以下の2つの場所に丸めると、速度指数が63.16%減少します。

これをMetricFilterアレイの下のComparEerports()関数内のヘルパー関数に入れましょう。

 const calcpercentagediff =(from、to)=> {
  const per =((to --from) / from) * 100;
  return Math.round(per * 100) / 100;
};
ログイン後にコピー

Back in our auditObj conditional, we can begin to put together the final report comparison output.

First off, use the helper function to generate the percentage difference for each metric.

 for (let auditObj in from["audits"]) {
  if (metricFilter.includes(auditObj)) {
    const percentageDiff = calcPercentageDiff(
      from["audits"][auditObj].numericValue,
      to["audits"][auditObj].numericValue
    );
  }
}
ログイン後にコピー

Next, we need to output values in this format to the console:

This requires adding color to the console output. In Node.js, this can be done by passing a color code as an argument to the console.log() function like so:

 console.log('\x1b[36m', 'hello') // Would print 'hello' in cyan
ログイン後にコピー

You can get a full reference of color codes in this Stackoverflow question. We need green and red, so that's \x1b[32m and \x1b[31m respectively. For metrics where the value remains unchanged, we'll just use white. This would be \x1b[37m.

Depending on if the percentage increase is a positive or negative number, the following things need to happen:

  • Log color needs to change (Green for negative, red for positive, white for unchanged)
  • Log text contents change.
    • '[Name] is X% slower for positive numbers
    • '[Name] is X% faster' for negative numbers
    • '[Name] is unchanged' for numbers with no percentage difference.
  • If the number is negative, we want to remove the minus/negative symbol, as otherwise, you'd have a sentence like 'Speed Index is -92.95% faster' which doesn't make sense.

There are many ways this could be done. Here, we'll use theMath.sign() function, which returns 1 if its argument is positive, 0 if well… 0, and -1 if the number is negative. That'll do.

 for (let auditObj in from["audits"]) {
  if (metricFilter.includes(auditObj)) {
    const percentageDiff = calcPercentageDiff(
      from["audits"][auditObj].numericValue,
      to["audits"][auditObj].numericValue
    );

    let logColor = "\x1b[37m";
    const log = (() => {
      if (Math.sign(percentageDiff) === 1) {
        logColor = "\x1b[31m";
        return `${percentageDiff "%"} slower`;
      } else if (Math.sign(percentageDiff) === 0) {
        return "unchanged";
      } それ以外 {
        logColor = "\x1b[32m";
        return `${percentageDiff "%"} faster`;
      }
    })();
    console.log(logColor, `${from["audits"][auditObj].title} is ${log}`);
  }
}
ログイン後にコピー

So, there we have it.

You can create new Lighthouse reports, and if a previous one exists, a comparison is made.

And you can also compare any two reports from any two sites.

Complete source code

Here's the completed source code for the tool, which you can also view in a Gist via the link below.

 const lighthouse = require("lighthouse");
const chromeLauncher = require("chrome-launcher");
const argv = require("yargs").argv;
const url = require("url");
const fs = require("fs");
const glob = require("glob");
const path = require("path");

const launchChromeAndRunLighthouse = url => {
  return chromeLauncher.launch().then(chrome => {
    const opts = {
      port: chrome.port
    };
    return lighthouse(url, opts).then(results => {
      return chrome.kill().then(() => {
        戻る {
          js: results.lhr,
          json: results.report
        };
      });
    });
  });
};

const getContents = pathStr => {
  const output = fs.readFileSync(pathStr, "utf8", (err, results) => {
    return results;
  });
  return JSON.parse(output);
};

const compareReports = (from, to) => {
  const metricFilter = [
    "first-contentful-paint",
    "first-meaningful-paint",
    "speed-index",
    "estimated-input-latency",
    "total-blocking-time",
    "max-potential-fid",
    "time-to-first-byte",
    "first-cpu-idle",
    "相互の作用"
  ];

  const calcPercentageDiff = (from, to) => {
    const per = ((to - from) / from) * 100;
    return Math.round(per * 100) / 100;
  };

  for (let auditObj in from["audits"]) {
    if (metricFilter.includes(auditObj)) {
      const percentageDiff = calcPercentageDiff(
        from["audits"][auditObj].numericValue,
        to["audits"][auditObj].numericValue
      );

      let logColor = "\x1b[37m";
      const log = (() => {
        if (Math.sign(percentageDiff) === 1) {
          logColor = "\x1b[31m";
          return `${percentageDiff.toString().replace("-", "") "%"} slower`;
        } else if (Math.sign(percentageDiff) === 0) {
          return "unchanged";
        } それ以外 {
          logColor = "\x1b[32m";
          return `${percentageDiff.toString().replace("-", "") "%"} faster`;
        }
      })();
      console.log(logColor, `${from["audits"][auditObj].title} is ${log}`);
    }
  }
};

if (argv.from && argv.to) {
  compareReports(
    getContents(argv.from ".json"),
    getContents(argv.to ".json")
  );
} else if (argv.url) {
  const urlObj = new URL(argv.url);
  let dirName = urlObj.host.replace("www.", "");
  if (urlObj.pathname !== "/") {
    dirName = dirName urlObj.pathname.replace(/\//g, "_");
  }

  if (!fs.existsSync(dirName)) {
    fs.mkdirSync(dirName);
  }

  launchChromeAndRunLighthouse(argv.url).then(results => {
    const prevReports = glob(`${dirName}/*.json`, {
      sync: true
    });

    if (prevReports.length) {
      dates = [];
      for (report in prevReports) {
        dates.push(
          new Date(path.parse(prevReports[report]).name.replace(/_/g, ":"))
        );
      }
      const max = dates.reduce(function(a, b) {
        return Math.max(a, b);
      });
      const recentReport = new Date(max).toISOString();

      const recentReportContents = getContents(
        dirName "/" recentReport.replace(/:/g, "_") ".json"
      );

      compareReports(recentReportContents, results.js);
    }

    fs.writeFile(
      `${dirName}/${results.js["fetchTime"].replace(/:/g, "_")}.json`,
      results.json,
      err => {
        (err)スローERR;
      }
    );
  });
} それ以外 {
  throw "You haven't passed a URL to Lighthouse";
}
ログイン後にコピー

View Gist

Next steps

With the completion of this basic Google Lighthouse tool, there's plenty of ways to develop it further.例えば:

  • Some kind of simple online dashboard that allows non-technical users to run Lighthouse audits and view metrics develop over time. Getting stakeholders behind web performance can be challenging, so something tangible they can interest with themselves could pique their interest.
  • Build support for performance budgets, so if a report is generated and performance metrics are slower than they should be, then the tool outputs useful advice on how to improve them (or calls you names).

幸運を!

以上がnode.jsツールを作成して、Google Lighthouseレポートを記録および比較するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Vue 3 Vue 3 Apr 02, 2025 pm 06:32 PM

それは' Vueチームにそれを成し遂げてくれておめでとうございます。それは大規模な努力であり、長い時間がかかったことを知っています。すべての新しいドキュメントも同様です。

ブラウザから有効なCSSプロパティ値を取得できますか? ブラウザから有効なCSSプロパティ値を取得できますか? Apr 02, 2025 pm 06:17 PM

私はこの非常に正当な質問で誰かに書いてもらいました。 Leaは、ブラウザから有効なCSSプロパティ自体を取得する方法についてブログを書いています。それはこのようなものです。

CI/CDで少し CI/CDで少し Apr 02, 2025 pm 06:21 PM

「ウェブサイト」は「モバイルアプリ」よりも適していると言いますが、Max Lynchからのこのフレーミングが好きです。

粘着性のあるポジショニングとサスのダッシュを備えた積み重ねられたカード 粘着性のあるポジショニングとサスのダッシュを備えた積み重ねられたカード Apr 03, 2025 am 10:30 AM

先日、Corey Ginnivanのウェブサイトから、この特に素敵なビットを見つけました。そこでは、スクロール中にカードのコレクションが互いに積み重ねられていました。

WordPressブロックエディターでのマークダウンとローカリゼーションを使用します WordPressブロックエディターでのマークダウンとローカリゼーションを使用します Apr 02, 2025 am 04:27 AM

WordPressエディターでユーザーに直接ドキュメントを表示する必要がある場合、それを行うための最良の方法は何ですか?

レスポンシブデザインのブラウザを比較します レスポンシブデザインのブラウザを比較します Apr 02, 2025 pm 06:25 PM

これらのデスクトップアプリがいくつかあり、目標があなたのサイトをさまざまな次元ですべて同時に表示しています。たとえば、書くことができます

スティッキーヘッダーとフッターにCSSグリッドを使用する方法 スティッキーヘッダーとフッターにCSSグリッドを使用する方法 Apr 02, 2025 pm 06:29 PM

CSS Gridは、レイアウトをこれまで以上に簡単にするように設計されたプロパティのコレクションです。何でもするように、少し学習曲線がありますが、グリッドは

Googleフォント変数フォント Googleフォント変数フォント Apr 09, 2025 am 10:42 AM

Google Fontsが新しいデザイン(ツイート)を展開したようです。最後の大きな再設計と比較して、これははるかに反復的です。違いをほとんど伝えることができません

See all articles