Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

231 Commits

Repository files navigation

@ebuildy/docusaurus-plugin-gitlab

OpenSSF Scorecard

NPM Version

Embed GitLab resources � project info, README, releases, issues, and any file or code snippet � directly in your Docusaurus 3 documentation using MDX components.

Screenshot

All data is fetched at build time and baked into your static site. No API tokens or network calls ever reach the browser, and pages stay fast.

  • â�� Works with gitlab.com and self-hosted GitLab (configurable host)
  • â�� Authenticated (private projects) or public, via a build-time token
  • â�� Five ready-to-use JSX components
  • â�� README images and badges are downloaded and localized (offline-safe, frozen at build time)
  • â�� On-disk caching, theme-aware (Infima) styling, graceful error fallbacks

Requires Docusaurus 3.x and Node 22.13+ or 24.

Installation

npm install @ebuildy/docusaurus-plugin-gitlab

ESM-only. This package ships as ES modules (all of its remark/rehype dependencies are ESM). Load it from an ESM config — docusaurus.config.ts or docusaurus.config.mjs (the examples below use import). CommonJS configs work too on the supported Node versions (22.13+), since Node can require() ES modules natively.

Setup

Two one-time steps in your Docusaurus site.

1. Register the remark plugin

In docusaurus.config.js (or .ts), add the remark plugin to your docs/blog preset:

import{remarkGitlab}from"@ebuildy/docusaurus-plugin-gitlab";exportdefault{presets: [["classic",{docs: {remarkPlugins: [[remarkGitlab,{host: "https://gitlab.com",token: process.env.GITLAB_TOKEN,// optional for public projects},],],},},],],};

2. Register the components

Make the components available in every .mdx page by swizzling MDXComponents. Create src/theme/MDXComponents.js:

importMDXComponentsfrom"@theme-original/MDXComponents";import*asGitlabfrom"@ebuildy/docusaurus-plugin-gitlab/components";exportdefault{ ...MDXComponents, ...Gitlab};

Now write the components in any .mdx page � no per-page imports needed.

Components

The project prop accepts either a numeric ID (project={12345}) or the full namespace path (project="group/subgroup/repo").

<GitlabProjectInfo>

A card with name, description, topics, stars/forks, and last activity. It can also embed compact releases, commits, and issues sections � each is opt-in and only fetched when its count prop is a positive number.

<GitlabProjectInfoproject="group/repo" />
<GitlabProjectInfoproject="group/repo"showStats={false} />
<GitlabProjectInfoproject="group/app"releases={3}commits={5}issues={5} />
<GitlabProjectInfoproject="group/app"releases={3}releasesLayout="cards"link="https://example.com/app" />
PropTypeDefaultDescription
projectstring | number�Required. Project path or ID
showStatsbooleantrueShow the stars / forks / created / last-activity row
showLinksbooleantrueLink the release / commit / issue items. Set false to render them as plain text (the card title stays a link)
linkstringproject's web_urlOverride the card title's link target
releasesnumber�Embed the latest N releases. Absent or � 0 � not fetched, not rendered
commitsnumber�Embed the latest N commits. Absent or � 0 � not fetched, not rendered
issuesnumber�Embed the latest N issues. Absent or � 0 � not fetched, not rendered
releasesLayout"list" | "cards""list"Layout for the releases section. An invalid value fails the build
commitsLayout"list" | "cards""list"Layout for the commits section. An invalid value fails the build
issuesLayout"list" | "cards""list"Layout for the issues section. An invalid value fails the build

Each section's list layout renders one compact line per item � release: tag and name; commit: linked short SHA, title, and author; issue: linked #iid and title. Every item shows its date (absolute, e.g. May 1, 2020) pinned to the right. cards renders a richer variant of the same data.

The showStats row can also show extra pills � total commit count, contributor count, open issue count, repository size � automatically, whenever that data is available; there's no attribute to request them. Set showStats={false} to hide the whole row (pills included). Commit count and repository size come from the project's statistics, which GitLab only returns to tokens with Reporter role or higher; on anonymous/public builds those two pills are simply omitted. Contributor count also depends on the API returning a total count header, and is omitted if it isn't.

<GitlabReadme>

Renders a project's README as themed HTML. Images and badges are downloaded and localized; links resolve back to GitLab.

<GitlabReadmeproject="group/repo" />
<GitlabReadmeproject="group/repo"ref="develop" />
PropTypeDefaultDescription
projectstring | number�Required.
refstringdefault branchBranch, tag, or commit SHA
toc"hidden" | "inline" | "sidebar"autoWhere to render the table of contents

Table of contents: if the README contains a GitLab [[_TOC_]] marker on its own line, it is replaced at build time with a generated table of contents linking to the document's h2�h5 headings (which receive slug ids). This also works for markdown embedded via <GitlabFile> and for release notes. The toc prop overrides this default: toc="inline" always renders the inline TOC (even without a marker); toc="sidebar" renders the README's headings in the page's native right-hand sidebar instead (merged with the page's own headings) and suppresses the inline TOC; toc="hidden" renders no TOC and strips any marker. Omitting toc keeps today's marker-driven behavior.

<GitlabReadmeproject="group/repo"toc="sidebar" />

Note: in sidebar mode the README is injected as pre-rendered HTML, so Docusaurus' broken-anchor checker can't see its heading anchors � harmless at the default onBrokenAnchors: "warn" (build succeeds, links work), but would fail a build configured with onBrokenAnchors: "throw".

Alerts: GitLab alert blockquotes are rendered as themed callouts. A blockquote whose first line is > [!note], > [!tip], > [!important], > [!caution], or > [!warning] becomes a <div> carrying both gitlab-md-alert* hook classes and the Docusaurus/Infima alert alert--<variant> classes (so it inherits theme colors). Type matching is case-insensitive; add text after the marker for a custom title, e.g. > [!warning] Data deletion. This also works for <GitlabFile> markdown and release notes.

<GitlabReleases>

A list of releases with notes, dates, and asset links.

<GitlabReleasesproject="group/repo"limit={5} />
<GitlabReleasesproject="group/repo"includePrereleases={true} />
PropTypeDefaultDescription
projectstring | number�Required.
limitnumber10Max releases to show
includePrereleasesbooleanfalseInclude upcoming/pre-releases

<GitlabIssues>

A filtered list of issues.

<GitlabIssuesproject="group/repo"labels="bug"state="opened"limit={10} />
PropTypeDefaultDescription
projectstring | number�Required.
statestringopenedopened, closed, or all
labelsstring�Comma-separated label filter
milestonestring�Milestone title filter
limitnumber20Max issues to show

<GitlabFile>

Embed any file from a repository. Markdown files (.md/.mdx) render as HTML (with image localization, like the README); any other file renders as a syntax-highlighted code block (via prism-react-renderer).

<GitlabFileproject="group/repo"path="docs/architecture.md" />
<GitlabFileproject="group/repo"path="src/main.ts" />
<GitlabFileproject="group/repo"path="src/main.ts"lines="10-25" />
PropTypeDefaultDescription
projectstring | number�Required.
pathstring�Required. File path within the repo
refstringdefault branchBranch, tag, or commit SHA
linesstringwhole fileLine range for code files, e.g. "10-25" (1-based, inclusive)

<GitlabTopics>

The instance topic catalog as links, each with a project-count bubble.

<GitlabTopicsfilter="^data"order="name:desc"limit={10} />
PropTypeDefaultDescription
filterstring�Case-insensitive regex on the topic title
orderstringnamename, name:asc, or name:desc
limitnumberallMax topics to show

<GitlabLabels>

A project's or group's labels as links to the filtered issues list. list or cards layout.

<GitlabLabelsproject="group/repo"layout="cards"filter="^team::"limit={20} />
PropTypeDefaultDescription
projectstring | number�Provide either project or group
groupstring | number�Provide either project or group
layoutstringlistlist or cards
filterstring�Case-insensitive regex on the label name
orderstringnamename, name:asc, or name:desc
limitnumberallMax labels to show

The cards layout accepts grid props: cardColumns (fixed column count), cardMinWidth (responsive min width, ignored when cardColumns is set), gap, maxWidth, and align (start/center).

Both components render scoped labels/topics (scope::value, e.g. Abilities::Performance) as a two-part badge � the scope keeps its color and the value gets a dark-gray background. The split is on the last ::.

<GitlabUser>

A user profile as a small card: photo, display name, linked @username, and configurable profile sections from the public user API.

<GitlabUsername="jdoe" />
<GitlabUsername="jdoe"show="org,bio,counts" />
PropTypeDefaultDescription
namestringrequiredGitLab username
showstringorg,location,bio,counts,sinceCard sections: org, location, bio, counts (followers/following), since (member since)

<GitlabUsers>

The members of a group or project (inherited included) as a grid of user cards.

<GitlabUsersgroup="my-group"role="developer" />
<GitlabUsersproject="group/repo"show="role,org,counts"cardColumns={3}gap="1rem" />
PropTypeDefaultDescription
groupstring | numberProvide either group or project
projectstring | numberProvide either group or project
rolestringExact-match filter: guest, reporter, developer, maintainer, owner, …
showstringrole<GitlabUser> tokens plus role (role badge)
limitnumberallMax members to show (fetch capped at 500)

The grid accepts the shared card-grid props: cardColumns, cardMinWidth (default 260px), gap, maxWidth, align. The default show="role" costs a single members call; profile tokens add one cached profile lookup per member at build time (two API requests per member on a cold build, deduplicated across pages and builds).

<GitlabRoadmap>

Renders a timeline of GitLab epics (Premium/Ultimate, group-level) or milestones (free; project or group). All data is fetched at build time.

<GitlabRoadmapsource="milestones"project="group/repo"layout="gantt"showLabels />
<GitlabRoadmapsource="milestones"project="group/repo"layout="timeline" />
PropValuesDefaultNotes
sourceepics | milestonesepicsFetch path
groupgroup path/idRequired for epics; one of group/project for milestones
projectproject path/idMilestones only
layoutgantt | timelineganttHorizontal bars vs. vertical spine
layoutFitpage | contentpageGantt only: page pins to the page width (ticks reduced to quarters/years by span, year rules bolded); content expands with a horizontal scrollbar
scalequarters | months | weeksautoAuto from span; prop overrides
stateopened | closed | allopened
labelscomma-separatedLabel filter
from / toYYYY-MM-DDderivedExplicit window
limitnumber50Max items (≤ 500)
orderstart | due | titlestartSort key
groupBynone | label | parentnoneSection headings. In the timeline layout, none groups by year → quarter
colorBysource | label | statesourceBar/card tint
showProgressbooleantrueEpics only
showLabelsbooleanfalseInline label chips

Generating pages from a group

Instead of writing one page per project by hand, drop a single directive on a folder's index page and let the plugin generate a child page per project in a GitLab group at build time. The generated pages become children of the declaring page in the sidebar.

Put the directive on the folder's index doc � index.mdx, README.mdx, or a doc named after its folder (Docusaurus's category index convention):

---title: Group projects---# docs/team/index.mdx# Our GitLab projects{@generateGitlabPagesgroup="my-group"sections="info,readme"includeSubgroups=false}
AttributeTypeDefaultDescription
groupstring | number�Required. Group path or ID
sectionsstring"readme"Comma-separated list of info, readme, releases, issues � becomes the components rendered on each generated project page
topicsstring�Comma-separated topic filter; only projects with all listed topics are included
includeSubgroupsbooleanfalseInclude projects from subgroups
includeArchivedbooleanfalseInclude archived projects

The plugin writes one <project-slug>.mdx per project as a sibling of the declaring page (subgroups become nested folders with their own _category_.json), so the autogenerated sidebar nests them under the declaring page:

docs/team/
index.mdx <- the declaring page (parent)
acme-web.mdx <- generated child
acme-api.mdx <- generated child
frontend/ <- generated subgroup
_category_.json
web-app.mdx

Generated files are git-ignored (the plugin writes a scoped .gitignore in the folder that ignores only what it generated � never your index page) and are regenerated on every build, tracked via a .gitlab-generated manifest so stale pages are removed on regeneration. Never hand-edit or commit them. Generation runs once at plugin init, before the docs plugin scans the filesystem, so the generated pages feed the autogenerated sidebar like any other doc. Keep the declaring page's folder dedicated to this generation.

You can also (re)generate the pages without a full build:

npx docusaurus gitlab:generate

During docusaurus start, generation runs once per process at startup. Editing the {@generateGitlabPages �} attributes (group, sections, topics, �) requires restarting docusaurus start to regenerate � it is not re-evaluated on hot reload.

On the declaring page itself, the directive is replaced with a <GitlabProjectGrid> card grid � one card per project, linking to its generated child page. Because the declaring page is a folder index, it is served at a directory URL with a trailing slash (e.g. /team/), so each card links to the child with a bare relative slug (<slug> � /team/<slug>). If your site sets trailingSlash: false, adjust routing accordingly.

::include directives inside included markdown

When a fetched GitLab README or markdown file contains a GitLab ::include directive, the plugin expands it at build time, splicing the referenced file in as raw markdown:

::include{file=docs/chapter1.md}
  • Relative paths resolve to a file in the same GitLab project and ref as the enclosing include, fetched through the same cached client.

  • Remote URLs (::include{file=https://â�¦}) are fetched only when their host is listed in the includeAllowedHosts plugin option (empty by default, so remote includes are off until you opt in).

  • Markdown targets (.md/.mdx/.markdown) are spliced inline and expanded recursively (max depth 8) with cycle detection. Any other file (e.g. .yaml, .json) is inserted as a fenced, syntax-highlighted code block.

  • Put the directive inside a fenced code block to insert a file's content verbatim into that block (GitLab: includes in code blocks):

    ```yaml
    ::include{file=config/profiles.yaml}
    ```
    

    The directive is replaced by the file content in place � no extra fence, no markdown processing.

  • A failed include aborts the build in strict mode, or renders an inline warning otherwise.

Plugin options

OptionTypeDefaultDescription
hoststring�Required. GitLab base URL (e.g. https://gitlab.com)
tokenstring�Personal/Project Access Token. Optional for public reads. Build-time only
strictbooleantrue in prod, false in devOn a failed fetch: true aborts the build; false renders a fallback
cache{ ttl: number } | false{ ttl: 3600 }On-disk cache TTL (seconds), or false to disable
assetDirstringstatic/gitlab-assetsWhere README images/badges are downloaded
assetBaseUrlstring/gitlab-assetsURL path the downloaded assets are served from
fixAutolinksbooleantrueRewrite CommonMark autolinks in included markdown to MDX-safe links (include placeholders only)
fixVoidTagsbooleantrueSelf-close HTML void elements (<br> � <br/>) in included markdown (include placeholders only)
fixInlineStylesbooleantrueConvert HTML string style="�" attributes to JSX style objects in included markdown
convertAlertsbooleantrueTranslate GitLab alert blockquotes (> [!note]) to Docusaurus admonitions (:::note) in included markdown
stripTocbooleanfalseRemove a redundant "Table of Contents" section (and [[_TOC_]] marker) from included markdown
outProcessorsArray<(md: string) => string | Promise<string>>[]Extra post-processors for included markdown, run after the built-in fixes
includeAllowedHostsstring[][]Hostnames allowed as remote ::include{file=https://�} targets
debugbooleanfalseEmit build-time debug traces for the include pipeline (resolved placeholders and ::include directives) via @docusaurus/logger
markdownRenderChainPluggableListdefault chainOverride the markdown�sanitized-HTML plugin chain (see below)

The token is read at build time only. Provide it via an environment variable (GITLAB_TOKEN) � never commit it.

Customizing the markdown render chain

Fetched GitLab markdown (project descriptions, release notes, READMEs, and markdown files) is rendered at build time by a unified plugin chain. By default it is:

remarkParse → remarkEmoji → remarkGfm → remarkRehype({ allowDangerousHtml })
→ rehypeRaw → rehypeSanitize

Override or extend it with the markdownRenderChain option. Spread the exported default to add plugins:

import{defaultMarkdownRenderChain}from"@ebuildy/docusaurus-plugin-gitlab";importrehypeHighlightfrom"rehype-highlight";// docusaurus.config.ts � plugin options{host: "https://gitlab.com",markdownRenderChain: [...defaultMarkdownRenderChain,rehypeHighlight],}

Internal stages (heading anchors/TOC, GitLab alert admonitions, asset localization, HTML serialization) always run after your chain and are not configurable.

Security: GitLab content is untrusted. The default chain runs rehype-sanitize. If your custom markdownRenderChain omits it, that content is rendered without sanitization (XSS risk); the plugin emits a build-time warning when this is detected. Keep rehype-sanitize in the chain unless you fully control the GitLab source.

How it works

A remark plugin walks the MDX syntax tree during docusaurus build, finds the <Gitlab*> elements, fetches the needed data from GitLab's REST API (via @gitbeaker/rest), downloads any README images/badges into your static assets, and injects the result as a prop. The React components are pure presentational renderers of that prop. Results are cached on disk so local docusaurus start hot-reloads don't hammer the API.

Because everything happens at build time, your published HTML is self-contained: no tokens shipped, no client-side API calls, no CORS.

For a deeper tour of the internals � the three build-time pipelines, the module map, and data-flow diagrams � see docs/ARCHITECTURE.md.

Styling

The components ship without any bundled CSS � they render plain, stable class names so you stay in full control of the look. The package includes an optional, light/dark-aware theme (theme.css) you can apply as-is or use as a starting point. It's built on Infima variables, so it tracks your site's active theme automatically.

Apply it from your classic preset's theme.customCss:

// docusaurus.config.ts (ESM)import{createRequire}from"node:module";constrequire=createRequire(import.meta.url);// ...inside the classic preset options:theme: {customCss: require.resolve("@ebuildy/docusaurus-plugin-gitlab/theme.css"),},

Prefer to own the CSS? Copy theme.css into your src/css/custom.css and edit freely. The class names you can target:

ClassElement
gitlab-card<GitlabProjectInfo> container
gitlab-card-headeravatar + title row
gitlab-avatarproject avatar image
gitlab-titleproject / release title
gitlab-mutedsecondary text (dates, authors, descriptions)
gitlab-badgetopics, tags, labels, release assets
gitlab-statsstars / forks / updated row
gitlab-issues / gitlab-issueissues list + each issue row
gitlab-issue-state / gitlab-issue-titleissue state badge (data-state) + title link
gitlab-releases / gitlab-releasereleases list + each release card
gitlab-release-notes / gitlab-release-assetsrelease body + asset links
gitlab-readmerendered README / markdown file
gitlab-md-tocgenerated [[_TOC_]] table of contents (<nav>)
gitlab-md-alert / gitlab-md-alert--<type>alert callout container + per-type modifier (also gets Infima alert alert--<variant>)
gitlab-md-alert-titlealert title row
gitlab-fallbackerror fallback box
gitlab-code / gitlab-code-title / gitlab-code-precode file embed

Development

pnpm install # whole workspace (package + example sites)
pnpm run build # compile with tsc (ESM-only + types)
pnpm test# unit tests (Vitest)
pnpm run typecheck # tsc --noEmit

The examples/site/ directory contains a minimal Docusaurus 3 site used by the end-to-end test (test/e2e/build.test.ts), which builds the site against a mocked GitLab API and asserts the embeds are baked into the HTML.

License

MIT

About

Embed GitLab resources — project info, README, releases, issues, and any file/code snippet — in your Docusaurus 3 docs at build time.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages