메인 컨텐츠로 이동
Version: 2.0.0-beta.17

Client architecture

테마 별칭

A theme works by exporting a set of components, e.g. Navbar, Layout, Footer, to render the data passed down from plugins. Docusaurus and users use these components by importing them using the @theme webpack alias:

import Navbar from '@theme/Navbar';

@theme 별칭은 아래와 같은 우선순위에 따라 몇 개의 디렉터리를 참조할 수 있습니다.

  1. 사용자의 website/src/theme 디렉터리가 가장 높은 우선순위를 가집니다.
  2. A Docusaurus theme package's theme directory.
  3. 도큐사우루스 코어에서 제공하는 대체 컴포넌트(거의 사용할 일은 없습니다)

This is called a layered architecture: a higher-priority layer providing the component would shadow a lower-priority layer, making swizzling possible. Given the following structure:

website
├── node_modules
│ └── @docusaurus/theme-classic
│ └── theme
│ └── Navbar.js
└── src
└── theme
└── Navbar.js

@theme/Navbar 가져오기를 하게 되면 website/src/theme/Navbar.js 파일이 언제나 우선순위를 가집니다. 이런 동작을 컴포넌트 바꾸기(swizzling)이라고 합니다. If you are familiar with Objective C where a function's implementation can be swapped during runtime, it's the exact same concept here with changing the target @theme/Navbar is pointing to!

We already talked about how the "userland theme" in src/theme can re-use a theme component through the @theme-original alias. One theme package can also wrap a component from another theme, by importing the component from the initial theme, using the @theme-init import.

아래 예제는 기본 테마의 CodeBlock 컴포넌트를 react-live 코드 연습 페이지 기능으로 확장하는 방법을 보여줍니다.

import InitialCodeBlock from '@theme-init/CodeBlock';
import React from 'react';

export default function CodeBlock(props) {
return props.live ? (
<ReactLivePlayground {...props} />
) : (
<InitialCodeBlock {...props} />
);
}

Check the code of @docusaurus/theme-live-codeblock for details.

caution

Unless you want to publish a re-usable "theme enhancer" (like @docusaurus/theme-live-codeblock), you likely don't need @theme-init.

이런 별칭을 이해하는 건 상당히 어려울 수 있습니다. Let's imagine the following case with a super convoluted setup with three themes/plugins and the site itself all trying to define the same component. 내부적으로 도큐사우루스는 이런 테마를 "스택" 형태로 로드합니다.

+-------------------------------------------------+
| `website/src/theme/CodeBlock.js` | <-- `@theme/CodeBlock`은 언제나 최상위를 가리킵니다always points to the top
+-------------------------------------------------+
| `theme-live-codeblock/theme/CodeBlock/index.js` | <-- `@theme-original/CodeBlock`는 바뀌지 않은 최상위 컴포넌트를 가리킵니다
+-------------------------------------------------+
| `plugin-awesome-codeblock/theme/CodeBlock.js` |
+-------------------------------------------------+
| `theme-classic/theme/CodeBlock/index.js` | <-- `@theme-init/CodeBlock`은 언제나 최하위를 가리킵니다
+-------------------------------------------------+

"스택" 형태에서 컴포넌트는 preset plugins > preset themes > plugins > themes > site의 순서로 추가됩니다. 그래서 website/src/theme에서 바뀐 컴포넌트는 맨 마지막에 로드되기 때문에 항상 맨 위에 나옵니다.

@theme/* always points to the topmost component—when CodeBlock is swizzled, all other components requesting @theme/CodeBlock receive the swizzled version.

@theme-original/*는 항상 최상위 바뀌지 않은 컴포넌트를 가리킵니다. 때문에 바뀐 컴포넌트에서 @theme-original/CodeBlock를 가져올 수 있습니다. "컴포넌트 스택"에서 테마에서 제공하는 다음 항목을 가리키게 됩니다. 플러그인 작성자는 컴포넌트가 최상위 컴포넌트일 수 있고 자신을 가져오려고 할 수도 있기 때문에 이를 사용하지 말아야 합니다.

@theme-init/* always points to the bottommost component—usually, this comes from the theme or plugin that first provides this component. 코드 블록을 향상하고자 하는 개별 플러그인/테마는 @theme-init/CodeBlock를 사용해 기본 버전을 안전하게 가져올 수 있습니다. 사이트 작성자는 일반적으로 최하위 컴포넌트 대신 최상위 컴포넌트를 수정하기 때문에 이를 사용하지 말아야 합니다. @theme-init/CodeBlock 별칭이 없을 수도 있습니다. 도큐사우루스에서는 @theme-original/CodeBlock과 다른 별칭을 가리킬 때 다시 말하면 두 개 이상의 테마에서 제공하는 경우에만 별칭을 만듭니다. 우리는 별칭을 낭비하지 않습니다!

Client modules

Client modules are part of your site's bundle, just like theme components. However, they are usually side-effect-ful. Client modules are anything that can be imported by Webpack—CSS, JS, etc. JS scripts usually work on the global context, like registering event listeners, creating global variables...

리액트에서 초기 UI를 렌더링 처리하기 전에 전역으로 모듈을 가져옵니다.

App.tsx
// How it works under the hood
import '@generated/client-modules';

Plugins and sites can both declare client modules, through getClientModules and siteConfig.clientModules, respectively.

Client modules are called during server-side rendering as well, so remember to check the execution environment before accessing client-side globals.

mySiteGlobalJs.js
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';

if (ExecutionEnvironment.canUseDOM) {
// As soon as the site loads in the browser, register a global event listener
window.addEventListener('keydown', (e) => {
if (e.code === 'Period') {
location.assign(location.href.replace('.com', '.dev'));
}
});
}

CSS stylesheets imported as client modules are global.

mySiteGlobalCss.css
/* This stylesheet is global. */
.globalSelector {
color: red;
}