検索
ホームページウェブフロントエンドjsチュートリアルサイトブロッキングのクロスブラウザ拡張機能を構築する

この記事では、Web サイトをブロックするためのブラウザー拡張機能を構築する私のプロセスを段階的に説明し、私が遭遇した課題と私が思いついた解決策について説明します。これは包括的なガイドを意図したものではありません。私は何かの専門家であるとは主張しません。このプロジェクトを構築する背後にある私の思考プロセスを共有したいだけです。したがって、ここでのすべてを割り引いて考えてください。すべての行を説明するのではなく、プロジェクトのキーポイント、苦労、興味深いケース、プロジェクトの癖に焦点を当てます。ご自身でソース コードをさらに詳しく調べてみてください。


目次:

  • 序文
  • プロジェクトのセットアップ
  • メイン入力フォームの作成
  • URL ブロックの処理
  • オプションページの作成
  • 厳密モードの実装
  • 結論

序文

多くの人と同じように、私もさまざまなタスクに集中するのに苦労しています。特にインターネットが気を散らすものであることが多いためです。幸いなことに、私はプログラマーとして優れた問題作成スキルを身につけてきたので、より優れた既存のソリューションを探すのではなく、ユーザーがアクセスを制限したい Web サイトをブロックする独自のブラウザー拡張機能を作成することにしました。
まず、要件と主な機能の概要を説明します。拡張機能は次のことを行う必要があります:

  • クロスブラウザであること。
  • Web サイトをブラックリストからブロックします。
  • ブロック オプションを選択できます。サブドメインを含むドメイン全体をブロックするか、選択した URL のみをブロックします。
  • ブロックされた Web サイトをブラックリストから削除せずに無効にする機能を提供します。
  • ユーザーが無効になった URL を再発したり、再度有効にするのを忘れたりした場合に、自動的にアクセスを制限するオプションを提供します (ADHD の人に役立ちます)。

プロジェクトのセットアップ

まず、私が選んだメインスタックは次のとおりです。

  • TypeScript: オートコンプリート機能を使用しない拡張機能には見慣れない API が多数あるため、JS よりも TS を選択しました。
  • Webpack: TS コンパイル用の tsc と比較して、このコンテキストでの使用が簡単です。さらに、tsc.
  • を使用してブラウザ準拠の JS を生成するときに問題が発生しました。
  • CSS: Vanilla CSS は、シンプルさ、より小さいバンドル サイズ、最小限の依存関係という私の目標に一致しました。また、わずか数ページの拡張機能としては、それ以外のものはやりすぎになると感じました。これらの理由から、私は React や特定の拡張機能構築フレームワーク
  • などのツールを使用しないことにしました。

拡張機能開発と通常の Web 開発との主な違いは、拡張機能がほとんどのイベント、コンテンツ スクリプト、およびそれらの間のメッセージングを処理する Service Worker に依存していることです。

マニフェストの作成

クロスブラウザー機能をサポートするために、2 つのマニフェスト ファイルを作成しました。

  • manifest.chrome.json: Chrome の Manifest v3 要件用。
  • manifest.firefox.json: Firefox の場合、Manifest v2 をより適切にサポートします。 2 つのファイルの主な違いは次のとおりです:

manifest.chrome.json:

{
  "manifest_version": 3,
  "action": {
    "default_title": "Click to show the form"
  },
  "incognito": "split",
  "permissions": [
    "activeTab",
    "declarativeNetRequestWithHostAccess",
    "scripting",
    "storage",
    "tabs"
  ],
  "host_permissions": ["*://*/"], // get access to all URLs
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"]
  }],
  "web_accessible_resources": [
    {
      "resources": ["blocked.html", "options.html", "about.html", "icons/*.svg"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
}
</all_urls></all_urls>

manifest.firefox.json:

{
  "manifest_version": 2,
  "browser_action": {
    "default_title": "Click to show the form"
  },
  "permissions": [
    "activeTab",
    "declarativeNetRequest",
    "declarativeNetRequestWithHostAccess",
    "scripting", 
    "storage",
    "tabs",
    "*://*/"
  ],
  "background": {
    "scripts": [
      "background.js"
    ],
    "persistent": false
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": [
      "options.js",
      "blocked.js",
      "about.js"
    ]
  }],
  "web_accessible_resources": [
    "blocked.html",
    "options.html", 
    "icons/*.svg"
  ],
  "content_security_policy": "script-src 'self'; object-src 'self'",
}
</all_urls>

ここで興味深い点の 1 つは、Chrome には "incognito": "split" が必要であるということです。これは、Firefox がシークレット モードなしで正常に動作するのに対し、シークレット モードで適切に動作するように指定されたプロパティです。

拡張機能の基本的なファイル構造は次のとおりです:

dist/
node_modules/
src/
|-- background.tsc
|-- content.ts
static/
|-- manifest.chrome.json
|-- manifest.firefox.json
package.json
tsconfig.json
webpack.config.js

ここで、拡張機能がどのように機能するかについて説明しましょう。ユーザーは、ブロックしたい URL を送信するために、ある種のフォームをトリガーできる必要があります。ユーザーが URL にアクセスすると、拡張機能がリクエストをインターセプトし、リクエストをブロックするか許可するかをチェックします。また、ユーザーがブロックされたすべての URL のリストを表示し、リストから URL を追加、編集、無効化、または削除できる、ある種のオプション ページも必要です。

メイン入力フォームの作成

ユーザーが拡張機能アイコンをクリックするかキーボード ショートカットを入力すると、HTML と CSS が現在のページに挿入されてフォームが表示されます。ポップアップを呼び出すなど、フォームを表示するにはさまざまな方法がありますが、私の好みに合わせたカスタマイズ オプションは限られています。バックグラウンド スクリプトは次のようになります:

background.ts:

import browser, { DeclarativeNetRequest } from 'webextension-polyfill';

// on icon click
const action = chrome.action ?? browser.browserAction; // Manifest v2 only has browserAction method
action.onClicked.addListener(tab => {
  triggerPopup(tab as browser.Tabs.Tab);
});

// on shortcut key press 
browser.commands.onCommand.addListener(command => {
  if (command === 'trigger_form') {
    browser.tabs.query({ active: true, currentWindow: true })
      .then((tabs) => {
        const tab = tabs[0];
        if (tab) {
          triggerPopup(tab);
        }
      })
      .catch(error => console.error(error));
  }
});

function triggerPopup(tab: browser.Tabs.Tab) {
  if (tab.id) {
    const tabId = tab.id;
    browser.scripting.insertCSS(({
      target: { tabId },
      files: ['global.css', './popup.css'],
    }))
      .then(() => {
        browser.scripting.executeScript
          ? browser.scripting.executeScript({
            target: { tabId },
            files: ['./content.js'], // refer to the compiled JS files, not the original TS ones 
          })
          : browser.tabs.executeScript({
            file: './content.js',
          });
      })
      .catch(error => console.error(error));
  }
}

Web ページのさまざまなスタイルがフォームにどのような影響を与えるかを予測するのは難しいため、HTML をすべてのページに挿入すると、予測できない結果が生じる可能性があります。より良い代替案は、スタイルの独自のスコープを作成する Shadow DOM を使用することのようです。潜在的な改善であることは間違いなく、今後取り組んでいきたいと思っています。

ブラウザの互換性のために webextension-polyfill を使用しました。これを使用することで、マニフェストのバージョンごとに個別の拡張機能を作成する必要がなくなりました。機能の詳細については、こちらをご覧ください。これを機能させるために、マニフェスト ファイル内の他のスクリプトの前に、browser-polyfill.js ファイルを含めました。

manifest.chrome.json:

{
  "content_scripts": [{
    "js": ["browser-polyfill.js"]
  }],
}

manifest.firefox.json:

{
  "background": {
    "scripts": [
      "browser-polyfill.js",
      // other scripts
    ],
  },
  "content_scripts": [{
    "js": [
      "browser-polyfill.js",
      // other scripts
    ]
  }],
}

フォームを挿入するプロセスは簡単な DOM 操作ですが、1 つのテンプレート リテラルを要素に適用するのではなく、各要素を個別に作成する必要があることに注意してください。より冗長で退屈ですが、このメソッドは、ブラウザでコンパイルされたコードを実行しようとしたときに表示される安全でない HTML インジェクションの警告を回避します。

content.ts:

import browser from 'webextension-polyfill';
import { maxUrlLength, minUrlLength } from "./globals";
import { GetCurrentUrl, ResToSend } from "./types";
import { handleFormSubmission } from './helpers';

async function showPopup() {
  const body = document.body;
  const formExists = document.getElementById('extension-popup-form');
  if (!formExists) {
    const msg: GetCurrentUrl = { action: 'getCurrentUrl' };

    try {
      const res: ResToSend = await browser.runtime.sendMessage(msg);

      if (res.success && res.url) {
        const currUrl: string = res.url;
        const popupForm = document.createElement('form');
        popupForm.classList.add('extension-popup-form');
        popupForm.id = 'extension-popup-form';

        /* Create every child element the same way as above */

        body.appendChild(popupForm);
        popupForm.addEventListener('submit', (e) => {
          e.preventDefault();
          handleFormSubmission(popupForm, handleSuccessfulSubmission); // we'll discuss form submission later
        });
        document.addEventListener('keydown', (e) => {
          if (e.key === 'Escape') {
            if (popupForm) {
              body.removeChild(popupForm);
            }
          }
        });
      }
    } catch (error) {
      console.error(error);
      alert('Something went wrong. Please try again.');
    }
  }
}

function handleSuccessfulSubmission() {
  hidePopup();
  setTimeout(() => {
    window.location.reload();
  }, 100); // need to wait a little bit in order to see the changes
}

function hidePopup() {
  const popup = document.getElementById('extension-popup-form');
  popup && document.body.removeChild(popup);
}

次に、フォームがブラウザに表示されることを確認します。必要なコンパイル手順を実行するために、Webpack を次のように構成しました:

webpack.config.ts:

{
  "manifest_version": 3,
  "action": {
    "default_title": "Click to show the form"
  },
  "incognito": "split",
  "permissions": [
    "activeTab",
    "declarativeNetRequestWithHostAccess",
    "scripting",
    "storage",
    "tabs"
  ],
  "host_permissions": ["*://*/"], // get access to all URLs
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"]
  }],
  "web_accessible_resources": [
    {
      "resources": ["blocked.html", "options.html", "about.html", "icons/*.svg"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
}
</all_urls></all_urls>

基本的に、実行したコマンドの環境変数からブラウザ名を取得して 2 つのマニフェスト ファイルから選択し、TypeScript コードを dist/ ディレクトリにコンパイルします。

拡張機能の適切なテストを作成するつもりでしたが、Puppeteer がコンテンツ スクリプトのテストをサポートしていないため、ほとんどの機能をテストできないことがわかりました。コンテンツ スクリプトのテストに関する回避策についてご存知の場合は、ぜひコメント欄でお知らせください。

package.json のビルド コマンドは次のとおりです:

{
  "manifest_version": 2,
  "browser_action": {
    "default_title": "Click to show the form"
  },
  "permissions": [
    "activeTab",
    "declarativeNetRequest",
    "declarativeNetRequestWithHostAccess",
    "scripting", 
    "storage",
    "tabs",
    "*://*/"
  ],
  "background": {
    "scripts": [
      "background.js"
    ],
    "persistent": false
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": [
      "options.js",
      "blocked.js",
      "about.js"
    ]
  }],
  "web_accessible_resources": [
    "blocked.html",
    "options.html", 
    "icons/*.svg"
  ],
  "content_security_policy": "script-src 'self'; object-src 'self'",
}
</all_urls>

それで、たとえば、私が走るときはいつでも

dist/
node_modules/
src/
|-- background.tsc
|-- content.ts
static/
|-- manifest.chrome.json
|-- manifest.firefox.json
package.json
tsconfig.json
webpack.config.js

Chrome のファイルは dist/ ディレクトリにコンパイルされます。アクション アイコンをクリックするかショートカットを押して、任意のサイトでフォームをトリガーすると、フォームは次のようになります:

Main form display

URLブロックの処理

メイン フォームの準備ができたので、次のタスクはそれを送信することです。ブロック機能を実装するために、declarativeNetRequest API と動的ルールを活用しました。ルールは拡張機能のストレージに保存されます。動的ルールの操作は Service Worker ファイル内でのみ可能であるため、Service Worker とコンテンツ スクリプトの間でデータを交換するには、必要なデータを含むメッセージをそれらの間で送信します。この拡張機能にはかなりの種類の操作が必要なので、アクションごとにタイプを作成しました。操作タイプの例を次に示します:

types.ts:

import browser, { DeclarativeNetRequest } from 'webextension-polyfill';

// on icon click
const action = chrome.action ?? browser.browserAction; // Manifest v2 only has browserAction method
action.onClicked.addListener(tab => {
  triggerPopup(tab as browser.Tabs.Tab);
});

// on shortcut key press 
browser.commands.onCommand.addListener(command => {
  if (command === 'trigger_form') {
    browser.tabs.query({ active: true, currentWindow: true })
      .then((tabs) => {
        const tab = tabs[0];
        if (tab) {
          triggerPopup(tab);
        }
      })
      .catch(error => console.error(error));
  }
});

function triggerPopup(tab: browser.Tabs.Tab) {
  if (tab.id) {
    const tabId = tab.id;
    browser.scripting.insertCSS(({
      target: { tabId },
      files: ['global.css', './popup.css'],
    }))
      .then(() => {
        browser.scripting.executeScript
          ? browser.scripting.executeScript({
            target: { tabId },
            files: ['./content.js'], // refer to the compiled JS files, not the original TS ones 
          })
          : browser.tabs.executeScript({
            file: './content.js',
          });
      })
      .catch(error => console.error(error));
  }
}

メイン フォームとオプション ページの両方から新しい URL を追加できるのは合理的であるため、送信は新しいファイル内の再利用可能な関数によって実行されました。

helpers.ts:

{
  "content_scripts": [{
    "js": ["browser-polyfill.js"]
  }],
}

content.ts で handleFormSubmission() を呼び出しています。これは、提供された URL を検証し、それを Service Worker に送信してブラックリストに追加します。

動的ルールには、考慮する必要がある最大サイズが設定されています。長すぎる URL 文字列を渡すと、動的ルールを保存しようとしたときに予期しない動作が発生します。私の場合、ルールの最大長は 75 文字の URL が適切であることがわかりました。

Service Worker が受信したメッセージを処理する方法は次のとおりです。

background.ts:

{
  "background": {
    "scripts": [
      "browser-polyfill.js",
      // other scripts
    ],
  },
  "content_scripts": [{
    "js": [
      "browser-polyfill.js",
      // other scripts
    ]
  }],
}

送信のために、新しいルール オブジェクトを作成し、それを含めるように動的ルールを更新します。単純な条件付き正規表現を使用すると、ドメイン全体をブロックするか、指定された URL のみをブロックするかを選択できます。

完了後、コンテンツスクリプトに応答メッセージを返します。このスニペットで最も興味深いのは、nanoid の使用です。試行錯誤の結果、動的ルールの量には制限があることがわかりました。古いブラウザでは 5000、新しいブラウザでは 30000 です。 5000 を超えるルールに ID を割り当てようとしたときに、バグによってこの問題が発生したことがわかりました。ID を 4999 未満に制限することはできなかったので、ID を 3 桁の数字に制限する必要がありました ( 0 ~ 999、つまり合計 1000 個の一意の ID)。これは、拡張機能のルールの総量を 5000 から 1000 に削減したことを意味します。これは、一方では非常に重要ですが、他方では、ユーザーがブロックする URL をそれほど多く持つ可能性は非常に低いため、私たちは、このあまり優雅ではない解決策で妥協することにしました。

これで、ユーザーは新しい URL をブラックリストに追加し、それらに割り当てるブロックの種類を選択できるようになりました。ブロックされたリソースにアクセスしようとすると、ブロック ページにリダイレクトされます:

Block page

ただし、対処する必要がある特殊なケースが 1 つあります。ユーザーが直接アクセスした場合、拡張機能は不要な URL をブロックします。ただし、Web サイトがクライアント側リダイレクトを備えた SPA である場合、拡張機能はそこで禁止されている URL をキャッチしません。このケースに対処するために、現在のタブをリッスンして URL が変更されたかどうかを確認するために、background.ts を更新しました。この問題が発生した場合、URL がブラックリストに含まれているかどうかを手動で確認し、含まれている場合はユーザーをリダイレクトします。

background.ts:

{
  "manifest_version": 3,
  "action": {
    "default_title": "Click to show the form"
  },
  "incognito": "split",
  "permissions": [
    "activeTab",
    "declarativeNetRequestWithHostAccess",
    "scripting",
    "storage",
    "tabs"
  ],
  "host_permissions": ["*://*/"], // get access to all URLs
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"]
  }],
  "web_accessible_resources": [
    {
      "resources": ["blocked.html", "options.html", "about.html", "icons/*.svg"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
}
</all_urls></all_urls>

getRules() は、declarativeNetRequest.getDynamicRules() メソッドを利用して、より読みやすい形式に変換するすべての動的ルールのリストを取得する関数です。

拡張機能は、直接および SPA 経由でアクセスされた URL を正しくブロックするようになりました。

オプションページの作成

オプション ページには、以下に示すようなシンプルなインターフェイスがあります:

Options page

これは、編集、削除、無効化、厳密モードの適用などの主要な機能が含まれるページです。配線方法は次のとおりです。

編集と削除機能

編集はおそらく最も複雑な作業でした。ユーザーは、文字列を変更するか、ブロック タイプを変更する (ドメイン全体または特定のドメインのみをブロックする) ことによって URL を編集できます。編集するときは、編集した URL の ID を配列に収集します。保存時に、変更を適用するために Service Worker に渡す更新された動的ルールを作成します。変更を保存するかリロードするたびに、動的ルールを再フェッチしてテーブルにレンダリングします。以下はその簡略版です:

options.ts:

{
  "manifest_version": 3,
  "action": {
    "default_title": "Click to show the form"
  },
  "incognito": "split",
  "permissions": [
    "activeTab",
    "declarativeNetRequestWithHostAccess",
    "scripting",
    "storage",
    "tabs"
  ],
  "host_permissions": ["*://*/"], // get access to all URLs
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"]
  }],
  "web_accessible_resources": [
    {
      "resources": ["blocked.html", "options.html", "about.html", "icons/*.svg"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
}
</all_urls></all_urls>

特定のルールをブロックするか許可するかを決定する方法は、その isActive プロパティを条件付きでチェックするだけです。ルールの更新とルールの取得 - これらはバックグラウンド リスナーに追加する 2 つの操作です:

background.ts:

{
  "manifest_version": 2,
  "browser_action": {
    "default_title": "Click to show the form"
  },
  "permissions": [
    "activeTab",
    "declarativeNetRequest",
    "declarativeNetRequestWithHostAccess",
    "scripting", 
    "storage",
    "tabs",
    "*://*/"
  ],
  "background": {
    "scripts": [
      "background.js"
    ],
    "persistent": false
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": [
      "options.js",
      "blocked.js",
      "about.js"
    ]
  }],
  "web_accessible_resources": [
    "blocked.html",
    "options.html", 
    "icons/*.svg"
  ],
  "content_security_policy": "script-src 'self'; object-src 'self'",
}
</all_urls>

編集された URL が既存のルールの複製になるという特殊なケースがあるため、更新機能を正しく理解するのは少し困難でした。それ以外は同じです。動的ルールを更新し、完了時に適切なメッセージを送信します。

URL の削除はおそらく最も簡単な作業です。この拡張機能には、特定のルールの削除とすべてのルールの削除の 2 種類の削除があります。

options.ts:

dist/
node_modules/
src/
|-- background.tsc
|-- content.ts
static/
|-- manifest.chrome.json
|-- manifest.firefox.json
package.json
tsconfig.json
webpack.config.js

そして、前と同じように、Service Worker リスナーにさらに 2 つのアクションを追加しました。

background.ts:

import browser, { DeclarativeNetRequest } from 'webextension-polyfill';

// on icon click
const action = chrome.action ?? browser.browserAction; // Manifest v2 only has browserAction method
action.onClicked.addListener(tab => {
  triggerPopup(tab as browser.Tabs.Tab);
});

// on shortcut key press 
browser.commands.onCommand.addListener(command => {
  if (command === 'trigger_form') {
    browser.tabs.query({ active: true, currentWindow: true })
      .then((tabs) => {
        const tab = tabs[0];
        if (tab) {
          triggerPopup(tab);
        }
      })
      .catch(error => console.error(error));
  }
});

function triggerPopup(tab: browser.Tabs.Tab) {
  if (tab.id) {
    const tabId = tab.id;
    browser.scripting.insertCSS(({
      target: { tabId },
      files: ['global.css', './popup.css'],
    }))
      .then(() => {
        browser.scripting.executeScript
          ? browser.scripting.executeScript({
            target: { tabId },
            files: ['./content.js'], // refer to the compiled JS files, not the original TS ones 
          })
          : browser.tabs.executeScript({
            file: './content.js',
          });
      })
      .catch(error => console.error(error));
  }
}

厳密モードの実装

おそらく、この拡張機能の主な機能は、ブラウジング習慣をより厳密に制御する必要があるユーザーに対して、無効化された (アクセスを許可された) ルールのブロックを自動的に強制する機能です。これは、厳密モードがオフになると、ユーザーによって無効にされた URL は、ユーザーが変更するまで無効のままになるという考えです。厳密モードをオンにすると、無効になったルールは 1 時間後に自動的に再び有効になります。このような機能を実装するために、拡張機能のローカル ストレージを使用して、無効になっている各ルールを表すオブジェクトの配列を保存しました。すべてのオブジェクトには、ルール ID、ブロック解除日、および URL 自体が含まれます。ユーザーが新しいリソースにアクセスするか、ブラックリストを更新するたびに、拡張機能はまずストレージに期限切れのルールがないかチェックし、それに応じてルールを更新します。

options.ts:

{
  "content_scripts": [{
    "js": ["browser-polyfill.js"]
  }],
}

isStrictModeOn ブール値もストレージに保存されます。それが true の場合、すべてのルールをループし、新しく作成されたブロック解除時間を使用して無効になっているルールをストレージに追加します。次に、応答ごとに、無効なルールがないかストレージを確認し、期限切れのルールが存在する場合は削除して、更新します。

background.ts:

{
  "background": {
    "scripts": [
      "browser-polyfill.js",
      // other scripts
    ],
  },
  "content_scripts": [{
    "js": [
      "browser-polyfill.js",
      // other scripts
    ]
  }],
}

これでウェブサイトブロック拡張機能は完成です。ユーザーは、必要な URL を追加、編集、削除、無効化したり、部分的または全体のドメイン ブロックを適用したり、厳密モードを使用してブラウジングの規律を維持したりできます。

Extension work example


結論

これが、私のサイトブロック拡張機能の基本的な概要です。これは私にとって初めての拡張機能であり、特に Web 開発の世界が時々平凡になり得ることを考えると、興味深い経験でした。改善と新機能の余地は間違いなくあります。ブラックリスト内の URL の検索バー、適切なテストの追加、厳密モードのカスタム期間、一度に複数の URL を送信する - これらは、いつかこのプロジェクトに追加したいと考えている、私の頭の中にあるもののほんの一部です。また、当初は拡張機能をクロスプラットフォームにすることを計画していましたが、私の携帯電話では実行できませんでした。
このウォークスルーを読んで面白かった場合、何か新しいことを学んだ場合、またはその他のフィードバックがある場合は、コメントをいただければ幸いです。読んでいただきありがとうございます。

ソースコード
ライブバージョン

以上がサイトブロッキングのクロスブラウザ拡張機能を構築するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Python vs. Javascript:どの言語を学ぶべきですか?Python vs. Javascript:どの言語を学ぶべきですか?May 03, 2025 am 12:10 AM

PythonまたはJavaScriptの選択は、キャリア開発、学習曲線、エコシステムに基づいている必要があります。1)キャリア開発:Pythonはデータサイエンスとバックエンド開発に適していますが、JavaScriptはフロントエンドおよびフルスタック開発に適しています。 2)学習曲線:Python構文は簡潔で初心者に適しています。 JavaScriptの構文は柔軟です。 3)エコシステム:Pythonには豊富な科学コンピューティングライブラリがあり、JavaScriptには強力なフロントエンドフレームワークがあります。

JavaScriptフレームワーク:最新のWeb開発のパワーJavaScriptフレームワーク:最新のWeb開発のパワーMay 02, 2025 am 12:04 AM

JavaScriptフレームワークのパワーは、開発を簡素化し、ユーザーエクスペリエンスとアプリケーションのパフォーマンスを向上させることにあります。フレームワークを選択するときは、次のことを検討してください。1。プロジェクトのサイズと複雑さ、2。チームエクスペリエンス、3。エコシステムとコミュニティサポート。

JavaScript、C、およびブラウザの関係JavaScript、C、およびブラウザの関係May 01, 2025 am 12:06 AM

はじめに私はあなたがそれを奇妙に思うかもしれないことを知っています、JavaScript、C、およびブラウザは正確に何をしなければなりませんか?彼らは無関係であるように見えますが、実際、彼らは現代のウェブ開発において非常に重要な役割を果たしています。今日は、これら3つの間の密接なつながりについて説明します。この記事を通して、JavaScriptがブラウザでどのように実行されるか、ブラウザエンジンでのCの役割、およびそれらが協力してWebページのレンダリングと相互作用を駆動する方法を学びます。私たちは皆、JavaScriptとブラウザの関係を知っています。 JavaScriptは、フロントエンド開発のコア言語です。ブラウザで直接実行され、Webページが鮮明で興味深いものになります。なぜJavascrを疑問に思ったことがありますか

node.jsは、型を使用してストリーミングしますnode.jsは、型を使用してストリーミングしますApr 30, 2025 am 08:22 AM

node.jsは、主にストリームのおかげで、効率的なI/Oで優れています。 ストリームはデータを段階的に処理し、メモリの過負荷を回避します。大きなファイル、ネットワークタスク、リアルタイムアプリケーションの場合。ストリームとTypeScriptのタイプの安全性を組み合わせることで、パワーが作成されます

Python vs. JavaScript:パフォーマンスと効率の考慮事項Python vs. JavaScript:パフォーマンスと効率の考慮事項Apr 30, 2025 am 12:08 AM

PythonとJavaScriptのパフォーマンスと効率の違いは、主に以下に反映されています。1)解釈された言語として、Pythonはゆっくりと実行されますが、開発効率が高く、迅速なプロトタイプ開発に適しています。 2)JavaScriptはブラウザ内の単一のスレッドに限定されていますが、マルチスレッドおよび非同期I/Oを使用してnode.jsのパフォーマンスを改善でき、両方とも実際のプロジェクトで利点があります。

JavaScriptの起源:その実装言語の調査JavaScriptの起源:その実装言語の調査Apr 29, 2025 am 12:51 AM

JavaScriptは1995年に発信され、Brandon Ikeによって作成され、言語をCに実現しました。 2。JavaScriptのメモリ管理とパフォーマンスの最適化は、C言語に依存しています。 3. C言語のクロスプラットフォーム機能は、さまざまなオペレーティングシステムでJavaScriptを効率的に実行するのに役立ちます。

舞台裏:JavaScriptをパワーする言語は何ですか?舞台裏:JavaScriptをパワーする言語は何ですか?Apr 28, 2025 am 12:01 AM

JavaScriptはブラウザとnode.js環境で実行され、JavaScriptエンジンに依存してコードを解析および実行します。 1)解析段階で抽象的構文ツリー(AST)を生成します。 2)ASTをコンパイル段階のバイトコードまたはマシンコードに変換します。 3)実行段階でコンパイルされたコードを実行します。

PythonとJavaScriptの未来:傾向と予測PythonとJavaScriptの未来:傾向と予測Apr 27, 2025 am 12:21 AM

PythonとJavaScriptの将来の傾向には、1。Pythonが科学コンピューティングの分野での位置を統合し、AI、2。JavaScriptはWebテクノロジーの開発を促進します。どちらもそれぞれのフィールドでアプリケーションシナリオを拡大し続け、パフォーマンスをより多くのブレークスルーを行います。

See all articles

ホット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 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

SublimeText3 Mac版

SublimeText3 Mac版

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

SublimeText3 Linux 新バージョン

SublimeText3 Linux 新バージョン

SublimeText3 Linux 最新バージョン

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール