Код предварительной обработки для приложения React, которое запускается только во время компиляции - PullRequest
0 голосов
/ 07 марта 2020

Я использую response-stati c, чтобы скомпилировать группу страниц блога, каждая из которых написана в отдельном файле .tsx, в сайт c. Однако я хочу иметь специальную функцию, которая заключается в автоматической генерации определенного c содержимого (например, списка ссылок, ссылочного текста) на основе дерева DOM другой страницы, но моя текущая реализация работает очень неэффективно с поток реакции c:

Например, для автоматического извлечения заголовков разделов страниц и ссылки на них:

Metadata.tsx

export type SectionMetadata = {
  label: string;
  title: React.ReactNode;
};

export default class Metadata {
  static context = React.createContext(new Metadata());

  static Provider: React.FC<{ metadata?: Metadata }> = props => (
    <Metadata.context.Provider value={props.metadata || new Metadata()}>
      {props.children}
    </Metadata.context.Provider>
  );

  static extract(content: React.ReactNode) {
    const metadata = new Metadata();
    ReactDOMServer.renderToString(
      <Metadata.Provider metadata={metadata}>{content}</Metadata.Provider>
    );
    return metadata;
  }

  sections: SectionMetadata[] = [];

  registerSection = (label: string, title: React.ReactNode) => {
    this.sections.push({ label, title, subsections: [] });
  };
}

Section.tsx

export const Section: React.FC<{
  label: string;
  title: React.ReactNode;
}> = props => {
  const metadata = React.useContext(Metadata.context);
  const index = metadata.registerSection(props.label, props.title);
  return (
    <>
      <h1 id={props.label}>{props.title}</h1>
      {props.children}
    </>
  );
};

Index.tsx

type SectionData = { page: string; label: string; title: React.ReactNode };
const contents: SectionData[] = [];
const contentContext = require.context("/pages", true, /\.tsx$/, "lazy");
for (const name of contentContext.keys()) {
  const label = path.basename(name, ".tsx");
  contentContext(name).then(({ default: Page }: { default: any }) => {
    const metadata = Metadata.extract(<Page />);
    for (const sec of metadata.sections) {
      contents.push({ page: label, label: sec.label, title: sec.title });
    }
  });
}

// Omitted some delaying mechanism that allows `contents` to be
// initialized before rendering
export default class Index extends React.Component {
  render = () => (
    <ul>
      {contents.map((sec: SectionData, index: number) => (
        <li key={index}>
          <Link to={`/pages/${sec.page}#${sec.label}`}>{sec.title}</Link>
        </li>
      ))}
    </ul>
  );
}

Таким образом все теги Section, присутствующие на всех страницах, будут перехвачены и переданы в Index.tsx для генерации списка ссылок.

Однако в настоящее время реагировать-стати c обрабатывает это как часть поведения приложения и упаковывает его в экспортируемое веб-приложение. Это означает, что каждый раз, когда клиент открывает страницу Index, веб-приложение будет пытаться загрузить все страницы и повторно запустить логи предварительной обработки c. sh Чтобы изменить это так, чтобы в экспортированном веб-приложении динамически генерируемая часть заменялась ссылками * stati c.

Страницы моего блога состоят из специальных макетов и сред, использующих компоненты React, поэтому я приходится придерживаться одного компонента React на страницу, и будет очень сложно перейти на Markdown / plain HTML с языком шаблонов и т. д. c. Но я в порядке с переключением на Гэтсби или Далее. js, если эта функция может быть реализована там.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...