Signatur
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
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}"`);
}
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);
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));
// Wichtig · Fallstricke
- Einheit UTF-16:
lengthundoffsetzä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 zuString.prototype.slice(), aber nicht zu Byte-Positionen ausTextEncoder. - Wert 0: Meldungen ohne Bezug zum Quelltext haben
length === 0(meist auchlineNum === 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
lengthwird ignoriert, im Strict Mode löst sie einenTypeErroraus. - 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.