Skip to content

本地iframe运行无法查看源码 #87

@jerrychan7

Description

@jerrychan7

[email protected]

我采用 blob+iframe 的形式在本地运行,但无法查看网页源代码。

报错
common.js:1 Uncaught (in promise) SecurityError: Failed to construct 'Worker': Script at 'https://cdn.jsdelivr.net/npm/chii/public/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.js' cannot be accessed from origin 'http://localhost:3000'.
    at common.js:1:95943
    at new Promise (<anonymous>)
    at new pr (common.js:1:95918)
    at pr.fromURL (common.js:1:96079)
    at s.createWorker (formatter.js:1:328)
    at s.processNextTask (formatter.js:1:689)
    at formatter.js:1:1541
    at new Promise (<anonymous>)
    at s.runTask (formatter.js:1:1472)
    at s.format (formatter.js:1:1634)
(anonymous)	@	common.js:1
pr	@	common.js:1
fromURL	@	common.js:1
createWorker	@	formatter.js:1
processNextTask	@	formatter.js:1
(anonymous)	@	formatter.js:1
runTask	@	formatter.js:1
format	@	formatter.js:1
h	@	formatter.js:1
setPretty	@	source_frame.js:1
setDeferredContent	@	source_frame.js:1
await in setDeferredContent		
ensureContentLoaded	@	source_frame.js:1
wasShown	@	source_frame.js:1
wasShown	@	sources.js:1
notify	@	legacy.js:1
processWasShown	@	legacy.js:1
showWidgetInternal	@	legacy.js:1
show	@	legacy.js:1
showTab	@	legacy.js:1
selectTab	@	legacy.js:1
innerShowFile	@	sources.js:1
showFile	@	sources.js:1
showSourceLocation	@	sources.js:1
showUISourceCode	@	sources.js:1
reveal	@	sources.js:1
(anonymous)	@	common.js:1
jt	@	common.js:1
await in jt		
sourceSelected	@	sources.js:1
onclick	@	sources.js:1

报错说是因为安全问题无法在 localhost 中创建 cdn 的 worker?是否可以通过 blob 的方式创建 worker?

源码
<body>
  <script src="https://cdn.jsdelivr.net/npm/chobitsu"></script>
  <script>太长 写在下面</script>
  <script src="/src/index.jsx" type="module"></script>
               ↑ vite 出来的带 source map 的代码
</body>
// 参考:
// https://github.com/solidjs/solid-playground/blob/master/packages/solid-repl/src/components/preview.tsx
// https://github.com/liriliri/chii/blob/master/src/target/DevtoolsFrame.ts

function devToolsSrc(targetOrigin = location.origin) {
  const version = '';
  const cdn = `https://cdn.jsdelivr.net/npm/chii${version? '@' + version: ''}/public`;
  const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
  const html = `
    <!DOCTYPE html>
    <html lang="en">
    <meta charset="utf-8">
    <title>DevTools</title>
    <style>
      @media (prefers-color-scheme: dark) {
        body {
          background-color: #292a2d;
        }
      }
      body .screencast-viewport {
        max-width: 100%;
        flex: 1;
      }
    </style>
    ${isSafari? `<script src="${cdn}/front_end/third_party/polyfill/customElement.js"></scr`+`ipt>`: ''}
    ${!window.requestIdleCallback? `<script src="${cdn}/front_end/third_party/polyfill/requestIdleCallback.js"></scr`+`ipt>`: ''}
    <meta name="referrer" content="no-referrer">
    <script src="https://unpkg.com/@ungap/custom-elements/es.js"></scr`+`ipt>
    <script type="module" src="${cdn}/front_end/entrypoints/chii_app/chii_app.js"></scr`+`ipt>
    <body class="undocked" id="-blink-dev-tools">
  `;
  const devtoolsRawUrl = URL.createObjectURL(new Blob([html], { type: 'text/html' }));
  // URL.revokeObjectURL(devtoolsRawUrl);
  return `${devtoolsRawUrl}#?embedded=${encodeURIComponent(targetOrigin)}`;
}

const windowLoaded = new Promise((s) => window.addEventListener('load', s));

async function openDevTools() {
  const targetOrigin = location.origin;

  const devtoolsIframe = document.createElement('iframe');
  devtoolsIframe.setAttribute('title', 'DevTools');
  devtoolsIframe.style.border = "none";
  devtoolsIframe.style.height = '50vh';
  devtoolsIframe.style.width = '100vw';
  devtoolsIframe.style.position = 'fixed';
  devtoolsIframe.style.bottom = '0';
  devtoolsIframe.style.left = '0';
  devtoolsIframe.style.zIndex = 9e20 + '';
  devtoolsIframe.src = devToolsSrc(targetOrigin);
  document.body.appendChild(devtoolsIframe);

  let devtoolsLoaded = false;
  const runtimeExeCtxCreated = Promise.withResolvers();

  // 这里等待 devtools 加载完毕再输出,才能保证输出的信息不会丢失
  // 而目前观察到的只有接受到frameTree之后才能正常输出
  // 故而这里缓存所有的控台输出,等待frameTree之后再输出
  const msgBuffer = [];
  const sendToDevtools = (msg, force = false) => {
    if (typeof msg !== 'string') msg = JSON.stringify(msg);
    if (!devtoolsLoaded && msg.includes('frameTree')) {
      runtimeExeCtxCreated.resolve();
    }
    if (!force && !devtoolsLoaded && (
         msg.includes('Runtime.consoleAPICalled')
      || msg.includes('Runtime.exceptionRevoked')
      || msg.includes('Runtime.exceptionThrown')
      // || msg.includes('Runtime.executionContextCreated')
      // || msg.includes('Runtime.executionContextDestroyed')
      // || msg.includes('Runtime.executionContextsCleared')
      // || msg.includes('Runtime.inspectRequested')
      // || msg.includes('Runtime.bindingCalled')
    ))
      msgBuffer.push(msg);
    else devtoolsIframe.contentWindow.postMessage(msg, targetOrigin);
  };
  let id = 0;
  const sendToChobitsu = (msg) => {
    msg.id = 'tmp' + ++id;
    chobitsu.sendRawMessage(JSON.stringify(msg));
  };
  chobitsu.setOnMessage((message) => {
    if (message.includes('"id":"tmp')) return;
    sendToDevtools(message);
  });

  runtimeExeCtxCreated.promise.then(async () => {
    for (let i = 0; i < msgBuffer.length; ++i)
      sendToDevtools(msgBuffer[i], true);
    devtoolsLoaded = true;
    msgBuffer.length = 0;
  });

  sendToDevtools({
    method: 'Page.frameNavigated',
    params: {
      frame: {
        id: '1',
        mimeType: 'text/html',
        securityOrigin: location.origin,
        url: location.href,
      },
      type: 'Navigation',
    },
  });
  sendToChobitsu({ method: 'Network.enable' });
  sendToDevtools({ method: 'Runtime.executionContextsCleared' });
  sendToChobitsu({ method: 'Runtime.enable' });
  sendToChobitsu({ method: 'Debugger.enable' });
  sendToChobitsu({ method: 'DOMStorage.enable' });
  sendToChobitsu({ method: 'DOM.enable' });
  sendToChobitsu({ method: 'CSS.enable' });
  sendToChobitsu({ method: 'Overlay.enable' });
  sendToChobitsu({ method: 'Console.enable' });
  sendToDevtools({ method: 'DOM.documentUpdated' });

  window.addEventListener('message', ({ source, data }) => {
    if (source === devtoolsIframe.contentWindow) {
      chobitsu.sendRawMessage(data);
    }
  });
}

openDevTools();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions