Start · Sprachen · JavaScript · Referenz · GPUCompilationMessage.length

GPUCompilationMessage.length

Eigenschaft

Schreibgeschützte Zahl mit der Länge (in UTF-16-Codeeinheiten) des Abschnitts im WGSL-Shader-Quelltext, auf den sich eine Compiler-Meldung bezieht.

seit JavaScript WebGPU – Chrome/Edge 113+, Firefox 141+ (Windows), Kategorie: webapi

Signatur

get GPUCompilationMessage.length

Beschreibung

Die Eigenschaft length einer GPUCompilationMessage gibt an, wie lang der Teil des Shader-Quelltexts ist, auf den sich eine Fehlermeldung, Warnung oder Info des WGSL-Compilers bezieht. Zusammen mit offset ergibt sich daraus genau der betroffene Abschnitt: code.slice(offset, offset + length).

An Meldungen kommt man über GPUShaderModule.getCompilationInfo(). Die Methode liefert ein Promise mit einem GPUCompilationInfo-Objekt, dessen Array messages die einzelnen GPUCompilationMessage-Objekte enthält. Mit length kann man die fehlerhafte Stelle zum Beispiel in einem Code-Editor markieren oder in der Konsole mit Tilden unterstreichen.

Der Wert wird in UTF-16-Codeeinheiten gezählt, also genauso wie JavaScript-Strings. Deshalb passt er direkt zu String.prototype.slice() und substring(). Bezieht sich eine Meldung auf keinen bestimmten Abschnitt im Quelltext, ist length gleich 0.

Rückgabewert

Typ
number
Beschreibung
Eine nicht-negative ganze Zahl mit der Länge des betroffenen Quelltext-Abschnitts in UTF-16-Codeeinheiten. Der Wert ist 0, wenn die Meldung keinem bestimmten Abschnitt zugeordnet ist.

Beispiele

Betroffenen Quelltext-Abschnitt ausgeben

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();

const code = `
@fragment
fn main() -> @location(0) vec4f {
  return vec4f(1.0, 0.0, 0.0, undefinedVar);
}`;

const module = device.createShaderModule({ code });
const info = await module.getCompilationInfo();

for (const msg of info.messages) {
  const snippet = code.slice(msg.offset, msg.offset + msg.length);
  console.log(`${msg.type}: ${msg.message}`);
  console.log(`Betroffen (${msg.length} Zeichen): "${snippet}"`);
}
error: unresolved value 'undefinedVar' Betroffen (12 Zeichen): "undefinedVar"

Fehlerstelle wie ein Compiler unterstreichen

const formatMessage = (code, msg) => {
  if (msg.lineNum === 0) return `${msg.type}: ${msg.message}`;
  const line = code.split('\n')[msg.lineNum - 1];
  // linePos ist 1-basiert; mindestens ein Marker, auch bei length 0
  const marker = ' '.repeat(msg.linePos - 1) + '~'.repeat(Math.max(msg.length, 1));
  return `${msg.type} [${msg.lineNum}:${msg.linePos}]: ${msg.message}\n${line}\n${marker}`;
};

const checkShader = async (device, code) => {
  const module = device.createShaderModule({ code });
  const { messages } = await module.getCompilationInfo();
  messages.forEach((msg) => console.warn(formatMessage(code, msg)));
  return messages.every((m) => m.type !== 'error');
};

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const ok = await checkShader(device, 'fn f() -> i32 { return 1.5; }');
console.log('Kompilierbar:', ok);
error [1:24]: return statement type must match its function return type ... fn f() -> i32 { return 1.5; } ~~~~~~~~~~~ Kompilierbar: false

Markierungen für einen Code-Editor erzeugen

const toEditorMarkers = (messages) =>
  messages
    .filter((m) => m.length > 0) // Meldungen ohne Quelltext-Bezug überspringen
    .map((m) => ({
      from: m.offset,
      to: m.offset + m.length,
      severity: m.type, // 'error' | 'warning' | 'info'
      text: m.message,
    }));

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const module = device.createShaderModule({ code: 'fn f() { let x = y; }' });
const { messages } = await module.getCompilationInfo();
console.log(toEditorMarkers(messages));
[{ from: 17, to: 18, severity: 'error', text: "unresolved value 'y'" }]

// Wichtig · Fallstricke

  • Einheit UTF-16: length und offset zählen UTF-16-Codeeinheiten, keine Bytes und keine Unicode-Codepoints. Enthält der Shader-Quelltext Emojis oder andere Zeichen außerhalb der BMP (etwa in Kommentaren), passen die Werte zu String.prototype.slice(), aber nicht zu Byte-Positionen aus TextEncoder.
  • Wert 0: Meldungen ohne Bezug zum Quelltext haben length === 0 (meist auch lineNum === 0). Vor dem Markieren sollte man das prüfen, sonst entstehen leere Bereiche.
  • Uneinheitliche Meldungen: Wie lang ein markierter Bereich ist und wie die Meldung formuliert ist, hängt von der Implementierung ab (Tint in Chromium, Naga in Firefox, WebKit). Programmlogik sollte sich deshalb nicht auf bestimmte Werte oder Texte verlassen.
  • Schreibgeschützt: Eine Zuweisung an length wird ignoriert, im Strict Mode löst sie einen TypeError aus.
  • Kompatibilität: WebGPU steht nur in sicheren Kontexten (HTTPS) zur Verfügung, auch in Web Workern. Firefox unterstützt es bisher nur teilweise. Vorher mit if (!navigator.gpu) prüfen, ob die API vorhanden ist.