diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 5d1c9e9..277d423 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -43,10 +43,10 @@ const context = await esbuild.context({ logLevel: "info", sourcemap: prod ? false : "inline", treeShaking: true, - minifyWhitespace: prod, - minifyIdentifiers: prod, - minifySyntax: prod, - legalComments: 'inline', + // Production builds must be minified (Obsidian dev docs: Optimize plugin load time) + minify: prod, + // Remove all other comments; banner remains + legalComments: 'none', outfile: path.join(outDir, "main.js"), }); diff --git a/src/core/audio/AudioWorkletSource.ts b/src/core/audio/AudioWorkletSource.ts index 4d2cfa6..cca8b6f 100644 --- a/src/core/audio/AudioWorkletSource.ts +++ b/src/core/audio/AudioWorkletSource.ts @@ -1,111 +1,9 @@ /** - * AudioWorklet source code as a string - * This allows us to create a blob URL for loading in restricted environments + * AudioWorklet source code as a single-line string with comments stripped + * to keep bundled output comment-free (except the esbuild banner). */ - -export const AUDIO_WORKLET_SOURCE = ` -// AudioWorkletProcessor for real-time audio processing -class AudioProcessorWorklet extends AudioWorkletProcessor { - constructor() { - super(); - - this.bufferSize = 4096; - this.audioBuffer = []; - this.isRecording = false; - - // Listen for messages from main thread - this.port.onmessage = (event) => { - this.handleMessage(event.data); - }; - } - - /** - * Handle messages from main thread - */ - handleMessage(data) { - switch (data.type) { - case 'start': - this.isRecording = true; - this.audioBuffer = []; - break; - - case 'stop': - this.isRecording = false; - // Send any remaining buffered audio - if (this.audioBuffer.length > 0) { - this.sendAudioData(); - } - break; - - case 'configure': - if (data.bufferSize) { - this.bufferSize = data.bufferSize; - } - break; - } - } - - /** - * Process audio - called for each render quantum (128 samples) - */ - process(inputs, outputs, parameters) { - const input = inputs[0]; - - if (!this.isRecording || !input || input.length === 0) { - return true; // Keep processor alive - } - - // Get the first channel - const channelData = input[0]; - if (!channelData || channelData.length === 0) { - return true; - } - - // Buffer the audio data - this.audioBuffer.push(new Float32Array(channelData)); - - // Check if we've accumulated enough data - const totalSamples = this.audioBuffer.reduce((sum, buffer) => sum + buffer.length, 0); - if (totalSamples >= this.bufferSize) { - this.sendAudioData(); - } - - return true; // Keep processor alive - } - - /** - * Send accumulated audio data to main thread - */ - sendAudioData() { - if (this.audioBuffer.length === 0) { - return; - } - - // Combine all buffers into one - const totalLength = this.audioBuffer.reduce((sum, buffer) => sum + buffer.length, 0); - const combinedBuffer = new Float32Array(totalLength); - - let offset = 0; - for (const buffer of this.audioBuffer) { - combinedBuffer.set(buffer, offset); - offset += buffer.length; - } - - // Send to main thread - this.port.postMessage({ - type: 'audio', - data: combinedBuffer, - timestamp: currentTime - }); - - // Clear the buffer - this.audioBuffer = []; - } -} - -// Register the processor -registerProcessor('audio-processor-worklet', AudioProcessorWorklet); -`; +export const AUDIO_WORKLET_SOURCE = +`class AudioProcessorWorklet extends AudioWorkletProcessor{constructor(){super();this.bufferSize=4096;this.audioBuffer=[];this.isRecording=!1;this.port.onmessage=e=>{this.handleMessage(e.data)}}handleMessage(e){switch(e.type){case\"start\":this.isRecording=!0,this.audioBuffer=[];break;case\"stop\":this.isRecording=!1,this.audioBuffer.length>0&&this.sendAudioData();break;case\"configure\":e.bufferSize&&(this.bufferSize=e.bufferSize);break}}process(e){const t=e[0];if(!this.isRecording||!t||t.length===0)return!0;const s=t[0];if(!s||s.length===0)return!0;this.audioBuffer.push(new Float32Array(s));const r=this.audioBuffer.reduce((n,o)=>n+o.length,0);return r>=this.bufferSize&&this.sendAudioData(),!0}sendAudioData(){if(this.audioBuffer.length===0)return;const e=this.audioBuffer.reduce((t,s)=>t+s.length,0),t=new Float32Array(e);let s=0;for(const r of this.audioBuffer)t.set(r,s),s+=r.length;this.port.postMessage({type:\"audio\",data:t,timestamp:currentTime}),this.audioBuffer=[]}}registerProcessor(\"audio-processor-worklet\",AudioProcessorWorklet);`; /** * Create a blob URL for the AudioWorklet diff --git a/src/core/audio/VADProcessor.ts b/src/core/audio/VADProcessor.ts index fb9b47f..911442c 100644 --- a/src/core/audio/VADProcessor.ts +++ b/src/core/audio/VADProcessor.ts @@ -114,22 +114,21 @@ export class VADProcessor extends Disposable { // fvad.js の内容を読み込んで評価(プラグインルートから) const fvadJsPath = this.getPluginAssetPath('fvad.js'); const fvadJsContent = await this.readPluginTextAsset('fvad.js'); + const sanitizedFvadJsContent = fvadJsContent + // Remove block comments + .replace(/\/\*[\s\S]*?\*\//g, '') + // Remove line comments + .replace(/^\s*\/\/.*$/gm, ''); // モジュールを評価するための一時的な環境を作成 return new Promise((resolve, reject) => { // スクリプトタグを作成 const script = document.createElement('script'); script.type = 'module'; - script.textContent = ` - // import.meta.url のポリフィル - const importMeta = { url: 'file:///${fvadJsPath}' }; - - // fvad モジュールを定義 - ${fvadJsContent} - - // グローバルに公開 - window.__fvadModule = fvad; - `; + script.textContent = + `const importMeta={url:'file:///${fvadJsPath}'};` + + `${sanitizedFvadJsContent}` + + `window.__fvadModule=fvad;`; // エラーハンドリング script.onerror = (error) => {