Skip to content

commonformhq/trawl

Repository files navigation

Trawl

PHP-native build-time full-text search indexer with a dependency-free JavaScript query runtime. No Node, no server-side query API, no Elasticsearch — index at build time, query in the browser.

Why Trawl?

Trawl fills a specific gap: PHP shops that want client-side full-text search without adding Node to their toolchain.

Trawl Pagefind Hosted (Algolia, etc.)
Indexer runtime PHP (Composer) Node/npx SaaS
Search runtime Browser-only JS Browser-only JS Server API
Node dependency None Required for indexing None
Composer install composer require --dev N/A N/A
Chunked index Yes (CRC32 shards) Yes N/A
On-premise Fully self-contained Fully self-contained Third-party

If you already have Node in your build pipeline, Pagefind is excellent and more mature. If you don't, or you want your entire dev dependency tree in Composer, Trawl is your option.

Quickstart

composer require --dev commonform/trawl
trawl init
trawl build --source=dist/ --output=dist/trawl/

Then in your HTML:

<script type="module">
import { Trawl } from '/trawl.js';

const trawl = await Trawl.init({ baseUrl: '/trawl/' });
const results = await trawl.search('reverse proxy');
// [{ url, title, score, excerpt: '...<mark>reverse proxy</mark>...' }]
</script>

Copy runtime/trawl.js from the package into your public directory, or use it directly from vendor/commonform/trawl/runtime/trawl.js.

CLI Commands

trawl build   Build the search index
trawl verify  Validate manifest + shard + doc consistency
trawl watch   Watch for file changes and rebuild incrementally
trawl init    Scaffold a trawl.json configuration file

Build

trawl build --source=dist/ --output=dist/trawl/
trawl build --adapter=markdown --source=content/ --output=dist/trawl/
trawl build --incremental                          # skip unchanged docs
trawl build --config=trawl.json                    # use config file

Verify

trawl verify --index=dist/trawl/

Configuration (trawl.json)

{
    "source": "dist/",
    "output": "dist/trawl/",
    "adapter": "filesystem",
    "include": ["**/*.html"],
    "exclude": ["**/404.html", "drafts/**"],
    "selectors": {
        "title": "title",
        "heading": "h1, h2, h3",
        "body": "main",
        "ignore": "[data-trawl-ignore], nav, footer"
    },
    "field_weights": { "title": 10, "heading": 5, "body": 1 },
    "facets": ["tags", "category"],
    "language": "en",
    "stemmer": "porter2",
    "stopwords": "default",
    "incremental": true,
    "cache_file": ".trawl-cache.json"
}

Adapters

Adapter Input Description
filesystem .html files Walks a directory of rendered HTML, extracts content via CSS selectors
markdown .md / .mdx files Parses YAML frontmatter + Markdown body via league/commonmark
array iterable<Document> Programmatic input from CMS integrations

JS Runtime API

import { Trawl } from './trawl.js';

const trawl = await Trawl.init({ baseUrl: '/trawl/' });

const results = await trawl.search('query', {
    limit: 10,
    filters: { tags: 'docs' },
    mode: 'and'               // 'and' (default) or 'or'
});

// results: [{ url, title, score, excerpt, meta }]

Requirements

  • Indexer: PHP 8.3+, Composer
  • Runtime: Any browser with native fetch, ES modules, and URL

License

MPL-2.0

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages