UNPKG

@tomjs/vscode-extension-webview

Version:

When using 'webview.html' in vscode extension development, 'HMR' of vue/react is supported.

197 lines (176 loc) 5.36 kB
// src/template.html var template_default = `<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <style> html, body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } #webview-patch-iframe { width: 100%; height: 100%; border: none; } .outer { width: 100%; height: 100%; overflow: hidden; } </style> <script type="module" id="webview-patch"> const TAG = '[@tomjs:vscode:extension] '; function onDomReady(callback, doc) { const _doc = doc || document; if (_doc.readyState === 'interactive' || _doc.readyState === 'complete') { callback(); } else { _doc.addEventListener('DOMContentLoaded', callback); } } let vsCodeApi; function getApi() { if (vsCodeApi) return vsCodeApi; return (vsCodeApi = acquireVsCodeApi()); } function sendInitData(iframe) { console.log(TAG + 'init data'); const dataset = {}; Object.keys(document.body.dataset).forEach(key => { dataset[key] = document.body.dataset[key]; }); iframe.contentWindow.postMessage( { type: '[vscode:extension]:init', data: { state: getApi().getState(), style: document.getElementById('_defaultStyles').innerHTML, root: { cssText: document.documentElement.style.cssText, }, body: { dataset: dataset, className: document.body.className, role: document.body.getAttribute('role'), }, }, }, '*', ); } function observeAttributeChanges(element, attributeName, callback) { const observer = new MutationObserver(function (mutationsList) { for (let mutation of mutationsList) { if (mutation.type === 'attributes' && mutation.attributeName === attributeName) { callback(mutation.target.getAttribute(attributeName)); } } }); observer.observe(element, { attributes: true }); return observer; } // message handler let iframeLoaded = false; const cacheMessages = []; function handleMessage(e) { const iframe = document.getElementById('webview-patch-iframe'); if (!iframeLoaded || !iframe) { return; } if (e.origin.startsWith('vscode-webview://')) { iframe.contentWindow.postMessage(e.data, '*'); } else if ('{{serverUrl}}'.startsWith(e.origin)) { const { type, data } = e.data; console.log(TAG + ' received:', e.data); if (type === '[vscode:client]:postMessage') { getApi().postMessage(data); } } } window.addEventListener('message', function (event) { if (event.origin.startsWith('vscode-webview://')) { cacheMessages.push(event); return; } handleMessage(event); }); let isCacheWorking = false; setInterval(() => { if (isCacheWorking) { return; } isCacheWorking = true; if (iframeLoaded) { let event = cacheMessages.shift(); while (event) { handleMessage(event); event = cacheMessages.shift(); } } isCacheWorking = false; }, 50); onDomReady(function () { /** @type {HTMLIFrameElement} */ const iframe = document.getElementById('webview-patch-iframe'); observeAttributeChanges(document.body, 'class', function (className) { sendInitData(iframe); }); onDomReady(function () { iframeLoaded = true; sendInitData(iframe); }, iframe.contentDocument); iframe.addEventListener('load', function (e) { iframeLoaded = true; let interval = setInterval(() => { try { if (document.getElementById('_defaultStyles')) { sendInitData(iframe); clearInterval(interval); return; } } catch (e) { clearInterval(interval); console.error(e); } }, 10); }); }); </script> </head> <body> <div class="outer"> <iframe id="webview-patch-iframe" frameborder="0" sandbox="allow-scripts allow-same-origin allow-forms allow-pointer-lock allow-downloads" allow="cross-origin-isolated; autoplay; clipboard-read; clipboard-write" src="{{serverUrl}}" ></iframe> </div> </body> </html> `; // src/index.ts function getHtml(options) { const opts = { serverUrl: "" }; if (typeof options === "string") { opts.serverUrl = options; } else { Object.assign(opts, options); } return template_default.replace(new RegExp("{{serverUrl}}", "g"), opts.serverUrl); } var src_default = getHtml; export { src_default as default, getHtml };