Skip to content

FAQ

WXT를 사용하는 방법이나 동작 방식에 대해 자주 묻는 질문들입니다.

왜 콘텐츠 스크립트가 매니페스트에 추가되지 않나요?

개발 중에는 WXT가 콘텐츠 스크립트를 동적으로 등록합니다. 이렇게 하면 파일을 저장할 때 전체 확장 프로그램을 다시 로드하지 않고도 개별적으로 스크립트를 다시 로드할 수 있습니다.

개발 중에 등록된 콘텐츠 스크립트 목록을 확인하려면 서비스 워커의 콘솔을 열고 다음 명령을 실행하세요:

js
await chrome.scripting.getRegisteredContentScripts();

개발 중 브라우저 자동 열림을 비활성화하려면 어떻게 해야 하나요?

자세한 내용은 https://wxt.dev/guide/essentials/config/browser-startup.html#disable-opening-browser 를 참고하세요.

개발 중에 웹사이트에 로그인 상태를 유지하려면 어떻게 해야 하나요?

자세한 내용은 https://wxt.dev/guide/essentials/config/browser-startup.html#persist-data 를 참고하세요.

내 컴포넌트 라이브러리가 콘텐츠 스크립트에서 작동하지 않아요!

createShadowRootUi를 사용할 때 주로 두 가지 문제(또는 둘 다)로 인해 발생합니다:

  1. 스타일이 ShadowRoot 외부에 추가됨

    Details

    일부 컴포넌트 라이브러리는 <style> 또는 <link> 엘리먼트를 추가해 CSS를 페이지에 직접 삽입합니다. 이 엘리먼트는 기본적으로 문서의 <head>에 배치됩니다. 이로 인해 스타일이 ShadowRoot 외부에 위치하게 되고, ShadowRoot의 격리로 인해 스타일이 UI에 적용되지 않습니다.

    라이브러리가 이렇게 동작한다면, 스타일을 배치할 위치를 라이브러리에 알려줘야 합니다. 다음은 인기 있는 컴포넌트 라이브러리의 문서입니다:

    위에 나열되지 않은 라이브러리를 사용한다면, 문서나 이슈에서 "shadow root", "shadow dom", "css container"를 검색해 보세요. 모든 라이브러리가 shadow DOM을 지원하는 것은 아니므로, 이 기능을 요청하기 위해 이슈를 열어야 할 수도 있습니다.

    Antd 스타일을 설정하는 예제입니다:

    tsx
    import { StyleProvider } from '@ant-design/cssinjs';
    import ReactDOM from 'react-dom/client';
    import App from './App.tsx';
    
    const ui = await create`ShadowRoot`Ui(ctx, {
      // ...
      onMount: (container, shadow) => {
        const cssContainer = shadow.querySelector('head')!;
        const root = ReactDOM.createRoot(container);
        root.render(
          <StyleProvider container={cssContainer}>
            <App />
          </StyleProvider>,
        );
        return root;
      },
    });
  2. UI 엘리먼트가 ShadowRoot 외부에 추가됨

    Details

    이 문제는 주로 TeleportPortal 컴포넌트가 DOM의 다른 위치(보통 문서의 <body>)에 엘리먼트를 렌더링할 때 발생합니다. 이는 주로 다이얼로그나 팝오버 컴포넌트에서 사용됩니다. 이렇게 하면 엘리먼트가 ShadowRoot 외부에 렌더링되므로 스타일이 적용되지 않습니다.

    이 문제를 해결하려면, 앱에 타겟을 제공하고 Teleport/Portal에 타겟을 전달해야 합니다.

    먼저, ShadowRoot<body> 엘리먼트(문서의 <body>가 아님)에 대한 참조를 저장합니다:

    ts
    import { createApp } from 'vue';
    import App from './App.vue';
    
    const ui = await create`ShadowRoot`Ui(ctx, {
      // ...
      onMount: (container, shadow) => {
        const teleportTarget = shadow.querySelector('body')!;
        const app = createApp(App)
          .provide('TeleportTarget', teleportTarget)
          .mount(container);
        return app;
      },
    });
    ui.mount();
    tsx
    // hooks/PortalTargetContext.ts
    import { createContext } from 'react';
    
    export const PortalTargetContext = createContext<HTMLElement>();
    
    // entrypoints/example.content.ts
    import ReactDOM from 'react-dom/client';
    import App from './App.tsx';
    import PortalTargetContext from '~/hooks/PortalTargetContext';
    
    const ui = await create`ShadowRoot`Ui(ctx, {
      // ...
      onMount: (container, shadow) => {
        const portalTarget = shadow.querySelector('body')!;
        const root = ReactDOM.createRoot(container);
        root.render(
          <PortalTargetContext.Provider value={portalTarget}>
            <App />
          </PortalTargetContext.Provider>,
        );
        return root;
      },
    });
    ui.mount();

    그런 다음, UI의 일부를 DOM의 다른 위치로 이동시킬 때 이 참조를 사용합니다:

    vue
    <script lang="ts" setup>
    import { Teleport } from 'vue';
    
    const teleportTarget = inject('TeleportTarget');
    </script>
    
    <template>
      <div>
        <Teleport :to="teleportTarget">
          <dialog>My dialog</dialog>
        </Teleport>
      </div>
    </template>
    tsx
    import { useContext } from 'react';
    import { createPortal } from 'react-dom';
    import PortalTargetContext from '~/hooks/PortalTargetContext';
    
    const MyComponent = () => {
      const portalTarget = useContext(PortalTargetContext);
    
      return <div>{createPortal(<dialog>My dialog</dialog>, portalTarget)}</div>;
    };

두 문제는 동일한 원인에서 비롯됩니다: 라이브러리가 무언가를 ShadowRoot 외부에 배치하고, ShadowRoot의 격리로 인해 CSS가 UI에 적용되지 않습니다.

두 문제는 동일한 해결책이 있습니다: 라이브러리가 엘리먼트를 ShadowRoot 외부가 아닌 내부에 배치하도록 지시하세요. 각 문제에 대한 자세한 정보와 예제 해결책은 위의 내용을 참고하세요.