Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Добавить версию в PDF #182

Merged
merged 20 commits into from
Jun 9, 2022

Conversation

bkoshelev
Copy link
Contributor

#140

Описание

PR добавляет логику создания PDF на основе уже имеющихся данных из *.mdx файлов.

Данные конвертируются следующим образом: mdx -> md -> pdf

Основная идея была в том, чтобы не менять mdx файлы.

Фичи

  • Добавлено оглавление
  • Внутренние ссылки 1-го уровня глубины заменены на якоря
  • Тесты с вопросами удалены из текста
  • Аннотации перенесены в конец книги в раздел "Словарь"
  • В футер сайта добавлена кнопка для скачивания книги в PDF

Что не получилось сделать:

  • Приложения для просмотра pdf не видят содержание (во многих приложениях есть боковая панель в которой можно выводить Table Of Contents
  • Внутренние ссылки второго уровня глубины сломаны (например, /lsp/in-real-life)
    Нужно описать объект вида [ссылка]: [якорь, ведущий к нужному подразделу книги] и добавить якоря в нужные места
  • Не работает разрыв страницы

Особенности

Из-за того что remark-плагины отдают только esm-модули, а в next.js падает сборка при установке type: module в -package.json, решено пока что собирать скрипт отдельно с помощью esbuild. (В дальнейшем можно перейти на ts-node, так как он уже поддерживает esm-модули)

Пример получившегося файла:

solid_book.pdf

Скриншоты

Верстка

Screenshot 2022-05-08 at 20 39 46

Screenshot 2022-05-08 at 20 39 02

Структура классов

image

@vercel
Copy link

vercel bot commented May 8, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
ota-solid ✅ Ready (Inspect) Visit Preview Jun 5, 2022 at 4:21PM (UTC)

Copy link
Owner

@bespoyasov bespoyasov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Офигенно, работает 🥳
Спасибо!

Я попробовал предложить идеи, как можно упростить код генератора. Посмотри, пожалуйста, что думаешь об этом?

Возможно, эти идеи уже приходили в голову, и были причины, чтобы их отмести? Тогда расскажи, пожалуйста, что именно вызвало проблемы — чтобы это сохранилось в истории репозитория. Возможно, это понадобится в будущем.

let markdown = ''
const keys = Object.keys(glossary.terms).sort()

keys.forEach((definite) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А мы можем сделать ненумерованный список? Будет и семантичнее, шаблон «склейки» будет выглядеть лучше, и результат рендера будет больше похож на список.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если у PDF какие-то проблемы с отображением списков, то пофиг.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Теперь глоссарий - это unordered list. Также добавил проверку на наличие аббревиатур. Если ни одна не будет найдена, то глоссарий не будет добавлен в книгу.

solid_book.pdf

.eslintignore Outdated
@@ -1,2 +1,3 @@
node_modules
*.d.ts
services/BookBuilder/*.ts
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мне кажется, лучше подправить линтер, если там есть какие-то ошибки. Потому что этот код мы пишем сами, и с одной стороны у нас полный контроль над ним, а с другой лучше все ограничения автоматизировать.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ага, пришлось так сделать из-за того что многие зависимости начали использовать конструкцию "import type {}", которая появилась только в TS 3.8.

Тогда лучше дождусь момента, когда будет вмержен PR и тогда эти игноры больше не понадобятся.

@@ -0,0 +1,54 @@
import { readFileSync } from 'fs'

import { Markdown } from './md'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кажется, тут есть циклические зависимости? Можно попробовать распилить интерфейс и реализацию, как вариант.

Возможно, стоит подумать в сторону концептуального разделения «работы с файловой системой» и «работой с текстовым содержимым». Тогда можно будет упростить API «сервиса файловой системы», сделав его более универсальным.

Сейчас легко запутаться между “mdx” и “md”, потому что структура и иерархия похожи и реализация во многом повторяется. Разделение, вероятно, может помочь урезать количество кода.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это же, кстати, может помочь избавиться от чрезмерной детализации в index.ts, где мы руками создаём классы для разделов и подразделов.

Вероятно, может помочь тип данных, в котором будет описываться раздел с соответствующими для него подразделами. (Ну, или если отдаться в пуризм, то два типа, один для работы с FS, другой для работы с данными.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отрефакторил код.

  • Теперь mdx и md наследуются от общего класса.

  • Теперь мы заранее описываем отдельную структуру-объект, и на ее основе наполняем книгу контентом из .mdx-файлов в отдельной функции.

// удаляем лишние элементы из markdown
const changeNode: Test = (el, index, parent) => {
if (invalidTypes.includes(el.type)) {
// исключаем все не-markdown элементы
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я бы, наверное, комментарии заменил на функции, в названиях которых бы выразил намерение:

function isForbiddenElement(el) {
  return invalidTypes.includes(el.type)
}

// ...

if (isForibddenElement(el)) { /* ... */ }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ок, заменил на функции

}

addTableOfContents = (markdown: Markdown) => {
const treeRoot4 = unified().use(remarkToc, { heading: 'Содержание' }).runSync(this.parse(markdown))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

treeRoot4: почему 4? :–)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

убрал, спасибо

services/BookBuilder/mdToPdf.ts Outdated Show resolved Hide resolved
@bespoyasov
Copy link
Owner

Я там, кстати, ещё зависимости обновляю, и это может затронуть глоссарий :–(

@bkoshelev
Copy link
Contributor Author

Я там, кстати, ещё зависимости обновляю, и это может затронуть глоссарий :–(

Судя по коммитам, глоссарий теперь больше не нужен. И контент, на основе которого он собирался будет удален. Хорошо, тогда уберу логику сборки глоссария из PR.

Co-authored-by: Alex <bespoyasov@me.com>
Copy link
Owner

@bespoyasov bespoyasov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Офигенно! Спасибо большое, от меня жирный лайк :—)

P.S. Я вмёржил PR с обновлением зависимостей, который блокировал линтер, останется только конфликты порезолвить.

}
}

export abstract class MarkdownTreeMarkdownAdapter {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Единственное только, вероятно, лучше вынести адаптер в отдельный модуль, из-за него сейчас markdown и markdownTree в циклической зависимости друг от друга.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Готово! Оказалось что в eslint не было настроено правило для поиска циклических зависимостей в *.ts-файлах, поэтому я их не видел.

Если нужно, могу добавить это правило в этом или в отдельном PR.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Каеф, спасибо!
Можно в отдельном PR, да.

Я на неделе ещё раз пробегусь по коду, если что-то найду, поправлю и где-то ближе к выходным вмёржу :—)

@bespoyasov
Copy link
Owner

Мёржу! 🎉

@bespoyasov bespoyasov merged commit 3746c69 into bespoyasov:master Jun 9, 2022
@bkoshelev
Copy link
Contributor Author

Ура!

@bespoyasov
Copy link
Owner

Спасибо за помощь и участие ^_^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Создать читабельную версию в PDF
2 participants