File structure in Docmost, an open-source alternative to Confluence and Notion
In this article, we will review the Docmost client file structure. This project’s frontend is built using React + Vite and has a monorepo architecture setup using NX.
We will be focusing on the client:
client
client folder contains the frontend code for the Docmost. It uses Mantine components.
Let’s pick a route and study how the files are organized in order to render that page in react.
We will focus on:
-
Components structure
-
API Layer
Page.tsx
I picked page route, this is the page that renders the editor as shown in the below image. I logged in Docmost cloud version and was on free trial at the time of writing this article.
How to locate this page in the client? I would start at the URL — https://myworkspace-665.docmost.com/s/general/p/home-page-t7i4wXav8l and check the routes configured in the client.
I found this in App.tsx L54 — L68.
<Route path={"/p/:pageSlug"} element={<PageRedirect />} /> <Route element={<Layout />}> <Route path={"/home"} element={<Home />} /> <Route path={"/s/:spaceSlug"} element={<SpaceHome />} /> <Route path={"/s/:spaceSlug/p/:pageSlug"} element={ <ErrorBoundary fallback={<>{t("Failed to load page. An error occurred.")}</>} > <Page /> </ErrorBoundary> } />
The route — /s/general/p/home-page-t7i4wXav8l this translates to s/:spaceSlug/p/:pageSlug.
I am suprised there is no lazy loading in App.tsx, I did create an issue suggesting this — Issue #1037
Page is imported from page/page.tsx.
Components structure
<div> <Helmet> <title>{`${page?.icon || ""} ${page?.title || t("untitled")}`}</title> </Helmet> <PageHeader readOnly={spaceAbility.cannot( SpaceCaslAction.Manage, SpaceCaslSubject.Page, )} /> <FullEditor key={page.id} pageId={page.id} title={page.title} content={page.content} slugId={page.slugId} spaceSlug={page?.space?.slug} editable={spaceAbility.can( SpaceCaslAction.Manage, SpaceCaslSubject.Page, )} /> <HistoryModal pageId={page.id} /> </div>
These are the components rendered in the page.tsx
Helmet
Helmet is imported as shown below:
import { Helmet } from "react-helmet-async"
PageHeader
PageHeader is imported as shown below:
import PageHeader from "@/features/page/components/header/page-header.tsx";
FullEditor
FullEditor is imported as shown below:
import { FullEditor } from "@/features/editor/full-editor";
HistoryModal
HistoryModal is imported as shown below:
import HistoryModal from "@/features/page-history/components/history-modal";
API Layer
In this page.tsx, the following code snippet is found at L17–28
const { t } = useTranslation(); const { pageSlug } = useParams(); const { data: page, isLoading, isError, error, } = usePageQuery({ pageId: extractPageSlugId(pageSlug) }); const { data: space } = useGetSpaceBySlugQuery(page?.space?.slug); const spaceRules = space?.membership?.permissions; const spaceAbility = useSpaceAbility(spaceRules);
usePageQuery
usePageQuery
is imported as shown below:
import { usePageQuery } from "@/features/page/queries/page-query";
useGetSpaceBySlugQuery
useGetSpaceBySlugQuery
is imported as shown below:
import { useGetSpaceBySlugQuery } from "@/features/space/queries/space-query.ts";
About me:
Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.
I am open to work on interesting projects. Send me an email at ramu.narasinga@gmail.com
My Github — https://github.com/ramu-narasinga
My website — https://ramunarasinga.com
My Youtube channel — https://www.youtube.com/@ramu-narasinga
Learning platform — https://thinkthroo.com
Codebase Architecture — https://app.thinkthroo.com/architecture
Best practices — https://app.thinkthroo.com/best-practices
Production-grade projects — https://app.thinkthroo.com/production-grade-projects