Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ node_modules
*.d.ts

packages/cli/src/lib/live-server/*
packages/cli/test/**/pagefind/**/*.js


# Docs
docs/_site/

# --- packages/core ---

Expand Down
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ packages/core/template/*/_site
# Generated site (MarkBind)
packages/cli/test/functional/*/_site

# Generated pagefind directories for sites and in expected
packages/cli/test/functional/**/pagefind

# Ignore .page-vue-render.js files in functional test and subdirectories on update
packages/cli/test/functional/**/*.page-vue-render.js

Expand Down Expand Up @@ -107,6 +110,8 @@ packages/core/index.js
packages/core/src/lib/progress/*.js
# --- packages/core end ---

# Nx for Lerna
.nx/cache
.nx/workspace-data
.nx/workspace-data

# Pagefind fragments
*.pf_fragment
29 changes: 29 additions & 0 deletions docs/userGuide/makingTheSiteSearchable.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,35 @@ You can add a search bar component to your website to allow users to search the
<include src="syntax/keywords.md" />
<include src="syntax/indexing.md" />



## Using Pagefind (Beta)

MarkBind now supports [Pagefind](https://pagefind.app/), a static low-bandwidth search library, as a built-in feature. This provides full-text search capabilities without external services.

<box type="info">
This is a <strong>beta</strong> feature and will be refined in future updates. To use it, you must have <code>enableSearch: true</code> in your <code>site.json</code> (this is the default).
</box>

<box type="warning">
The Pagefind index is currently only generated during a full site build (e.g., <code>markbind build</code>). It will <strong>not</strong> repeatedly update during live reload (<code>markbind serve</code>) when you modify pages. You must restart the server (re-run <code>markbind serve</code>) or rebuild to refresh the search index.
</box>

To add the Pagefind search bar to your page, simply insert the following `div` where you want it to appear:

```html
<div id="pagefind-search-input"></div>
```

MarkBind will automatically inject the necessary scripts and styles to render the search UI.

The following UI will be rendered, which is provided by Pagefind:

<div id="pagefind-search-input"></div>


<br>

## Using External Search Services

MarkBind sites can use Algolia Doc Search services easily via the Algolia plugin. Unlike the built-in search, Algolia provides full-text search. See the panel below for more info.
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

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

The documentation states that Pagefind provides "full-text search capabilities without external services" (line 44), but then on line 71, it says "Unlike the built-in search, Algolia provides full-text search." This creates confusion about whether the built-in Pagefind feature provides full-text search or not. The messaging should be clarified for consistency.

Suggested change
MarkBind sites can use Algolia Doc Search services easily via the Algolia plugin. Unlike the built-in search, Algolia provides full-text search. See the panel below for more info.
MarkBind sites can use Algolia Doc Search services easily via the Algolia plugin. Algolia is a hosted service that also provides full-text search and advanced search features. See the panel below for more info.

Copilot uses AI. Check for mistakes.
Expand Down
146 changes: 146 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions packages/cli/test/functional/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ expectedErrors.forEach((error, index) => {
logger.info(`${index + 1}: ${error}`);
});

const GENERATED_DIRECTORIES_TO_IGNORE = ['pagefind'];

testSites.forEach((siteName) => {
console.log(`Running ${siteName} tests`);
try {
execSync(`node ../../index.js build ${siteName}`, execOptions);
const siteIgnoredFiles = plantumlGeneratedFilesForTestSites[siteName];
compare(siteName, 'expected', '_site', siteIgnoredFiles);
compare(siteName, 'expected', '_site', siteIgnoredFiles, GENERATED_DIRECTORIES_TO_IGNORE);
} catch (err) {
printFailedMessage(err, siteName);
process.exit(1);
Expand All @@ -63,7 +65,8 @@ testConvertSites.forEach((sitePath) => {
execSync(`node ../../index.js init ${nonMarkBindSitePath} -c`, execOptions);
execSync(`node ../../index.js build ${nonMarkBindSitePath}`, execOptions);
const siteIgnoredFiles = plantumlGeneratedFilesForConvertSites[siteName];
compare(sitePath, 'expected', 'non_markbind_site/_site', siteIgnoredFiles);
compare(sitePath, 'expected', 'non_markbind_site/_site', siteIgnoredFiles,
GENERATED_DIRECTORIES_TO_IGNORE);
} catch (err) {
printFailedMessage(err, sitePath);
cleanupConvert(path.resolve(__dirname, sitePath));
Expand All @@ -83,7 +86,7 @@ testTemplateSites.forEach((templateAndSitePath) => {
execSync(`node ../../index.js init ${siteCreationTempPath} --template ${flag}`, execOptions);
execSync(`node ../../index.js build ${siteCreationTempPath}`, execOptions);
const siteIgnoredFiles = plantumlGeneratedFilesForTemplateSites[siteName];
compare(sitePath, 'expected', 'tmp/_site', siteIgnoredFiles);
compare(sitePath, 'expected', 'tmp/_site', siteIgnoredFiles, GENERATED_DIRECTORIES_TO_IGNORE);
} catch (err) {
printFailedMessage(err, sitePath);
fs.removeSync(path.resolve(__dirname, siteCreationTempPath));
Expand Down
12 changes: 9 additions & 3 deletions packages/cli/test/functional/testUtil/compare.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,19 @@ function filterPageVueRenderFiles(filePaths) {
* @param {string} expectedSiteRelativePath - Relative path to expected site output (default: "expected")
* @param {string} siteRelativePath - Relative path to actual generated site output (default: "_site")
* @param {string} ignoredPaths - Specify any paths to ignore for comparison, but still check for existence.
* @param {string[]} ignoredDirectories - Specify any directories to ignore for comparison (e.g. 'pagefind')
*/
function compare(root, expectedSiteRelativePath = 'expected', siteRelativePath = '_site', ignoredPaths = []) {
function compare(root,
expectedSiteRelativePath = 'expected',
siteRelativePath = '_site',
ignoredPaths = [],
ignoredDirectories = []) {
const expectedDirectory = path.join(root, expectedSiteRelativePath);
const actualDirectory = path.join(root, siteRelativePath);

let expectedPaths = walkSync(expectedDirectory, { directories: false });
let actualPaths = walkSync(actualDirectory, { directories: false });
const walkSyncOptions = { directories: false, ignore: ignoredDirectories };
let expectedPaths = walkSync(expectedDirectory, walkSyncOptions);
let actualPaths = walkSync(actualDirectory, walkSyncOptions);

// Vue render JS files (*.page-vue-render.js) are not committed to version control,
// so we exclude them from the comparison to avoid false positive diffs.
Expand Down
17 changes: 17 additions & 0 deletions packages/cli/test/functional/test_site/expected/bugs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<link rel="stylesheet" href="/test_site/markbind/glyphicons/css/bootstrap-glyphicons.min.css">
<link rel="stylesheet" href="/test_site/markbind/css/codeblock-dark.min.css">
<link rel="stylesheet" href="/test_site/markbind/css/markbind.min.css">
<link rel="stylesheet" href="/test_site/pagefind/pagefind-ui.css">
<link rel="stylesheet" href="/test_site/plugins/testMarkbindPlugin/testMarkbindPluginStylesheet.css">
<link rel="stylesheet" href="/test_site/plugins/web3Form/web-3-form.css">
<link rel="stylesheet" href="/test_site/plugins/markbind-plugin-anchors/markbind-plugin-anchors.css">
Expand Down Expand Up @@ -359,5 +360,21 @@ <h1 id="heading-in-footer-should-not-be-indexed">Heading in footer should not be
});

</script>
<script src="/test_site/pagefind/pagefind-ui.js"></script>

<script>
window.addEventListener('DOMContentLoaded', (event) => {
const searchContainers = document.querySelectorAll('#pagefind-search-input');
if (searchContainers.length) {
searchContainers.forEach((container) => {
new window.PagefindUI({
element: container,
showSubResults: true,
showImages: false,
});
});
}
});
</script>

</html>
17 changes: 17 additions & 0 deletions packages/cli/test/functional/test_site/expected/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<link rel="stylesheet" href="/test_site/markbind/glyphicons/css/bootstrap-glyphicons.min.css">
<link rel="stylesheet" href="/test_site/markbind/css/codeblock-dark.min.css">
<link rel="stylesheet" href="/test_site/markbind/css/markbind.min.css">
<link rel="stylesheet" href="/test_site/pagefind/pagefind-ui.css">
<link rel="stylesheet" href="/test_site/plugins/testMarkbindPlugin/testMarkbindPluginStylesheet.css">
<link rel="stylesheet" href="/test_site/plugins/web3Form/web-3-form.css">
<link rel="stylesheet" href="/test_site/plugins/markbind-plugin-anchors/markbind-plugin-anchors.css">
Expand Down Expand Up @@ -1025,5 +1026,21 @@ <h1 id="heading-in-footer-should-not-be-indexed">Heading in footer should not be
});

</script>
<script src="/test_site/pagefind/pagefind-ui.js"></script>

<script>
window.addEventListener('DOMContentLoaded', (event) => {
const searchContainers = document.querySelectorAll('#pagefind-search-input');
if (searchContainers.length) {
searchContainers.forEach((container) => {
new window.PagefindUI({
element: container,
showSubResults: true,
showImages: false,
});
});
}
});
</script>

</html>
Loading