w3c / w3c/FileAPI

Proposal: `Blob.from()` for creating virtual Blobs with custom backing storage

オープン
#209 コメント 4 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

主要言語
HTML
スター
118
フォーク
52
平均マージ
9日 16時間
マージ済み PR(30日)
1

説明

I'd like to propose an addition to the Blob API to enable the creation of virtual Blob or File instances backed by custom-defined storage logic. This would allow SDKs and libraries to expose file-like objects without requiring the developer to manage low-level data fetching or streaming themselves.

✨ Proposed API
const virtualBlob = Blob.from({
  size: 1024,
  async stream(start, end) {
    return customStreamOrAsyncIterable(start, end)
  }
})
  • size: Total size of the blob (required).

  • stream(start, end): Required method that returns a ReadableStream or AsyncIterable for the requested byte range. it may or may not be async

This API is synchronous to create, but lazy in that no data is fetched until actually needed. The internal Blob machinery would take care of slicing and offsetting, so the developers only need to focus on implement the backing source logic.

🧩 Example Usage with SDK

This enables a clean integration pattern with APIs like Dropbox, Google Drive, or internal systems:

import Client from 'dropbox/sdk.js'

const dropbox = new Client(apiKey)

const fileHandle = await dropbox.getFileHandle(user, path)

const file = fileHandle.openAsFile()
const url = URL.createObjectURL(file)

What dropbox sdk then actually dose:

function openAsFile() {
  const blobPart = Blob.from({
    size: this.#size,
    async stream(start, end) {
      // makes a partial request for the requested range
      const res = await fetch(url, { 
        headers: { range: `bytes=${start}-${end}` }
      })
      return res.body
    }
  })
  
  return new File([ blobPart ], this.#filename, {
    type: this.#type,
    lastModified: this.#lastModified
  })
}

In this model:

  • fileHandle contains only metadata (filename, type, size, lastModified).
  • openAsFile() constructs a File backed by virtual Blob part.
  • No actual data is fetched until the Blob is consumed — for example, when writing to disk or calling .arrayBuffer().
✅ Benefits
  • Enables SDKs to expose virtual File/Blob objects without requiring developers to build ad-hoc wrappers.
  • Avoids early data fetching and defers I/O until absolutely needed.
  • Keeps the interface clean, idiomatic, and interoperable with existing Blob consumers.
  • Great fit for use cases like remote file systems, zip file introspection, lazy file generation, and more.
🔧 Comparison to Today

Without this feature, developers must manually wrap streams, manage slicing, and emulate Blob behavior — often with duplicated effort and edge-case bugs. This addition would make such patterns first-class citizens in the platform.

🔍 Real-World Problem This Solves

A common pattern on the web is to trigger file downloads using a Blob URL and a programmatically clicked <a> tag:

const blob = new Blob([fileData], { type: 'application/pdf' })
const url = URL.createObjectURL(blob)

const a = document.createElement('a')
a.href = url
a.download = 'report.pdf'
a.click()

However, to use this pattern today, you must already have all the file data in memory.

If you're working with a remote file (e.g. from cloud storage or an SDK), you can't delay the download until after the click — because:

Once the click handler ends, isTrusted becomes false.

Any async operation (like fetching the file) that happens after the click ends is now treated as not user-initiated.

Browsers will block the download, thinking it's an automatic or malicious attempt.

⛔️ This effectively means: if you want to allow the user to download a file, you must download the entire file first, even if they never end up clicking “Download.”

With Blob.from(), we could instead return a virtual Blob that doesn't require any data until it's needed:

const blob = Blob.from({
  size: 10_000_000,
  async stream(start, end) {
    return fetchRangeStream(start, end)
  }
})

const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'report.pdf'
a.click()

In this model, the download is triggered immediately within the click event — but data is only fetched as it's needed, safely within the user gesture's trusted scope.

✅ This allows you to:

  • Keep memory usage low (no preloading needed).
  • Allow user-triggered downloads of remote/virtual files.
  • Preserve compatibility with browser download restrictions.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、Blob、File、slicing、streaming、object URLs に関する既存の File API 定義を確認します。この issue ではファイルもテストも指定されていません。完了には、size と stream(start, end) の契約、lazy fetching の動作、既存の Blob コンシューマーとの互換性を含む、Blob.from() の解決済み仕様が必要です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
javascript
領域
api, web-dev
issue の種類
機能追加
難易度
5/5
見積もり時間
1週間以上
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
32/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。