mirror of
https://github.com/jakejarvis/hugo-extended.git
synced 2026-07-29 19:55:21 -04:00
docs: update AGENTS.md and README.md for clarity and accuracy
This commit is contained in:
@@ -85,7 +85,7 @@ npm run test:coverage # coverage via v8
|
||||
- Example: `tests/unit/args.test.ts` covers argv building behavior driven by `flags.json`.
|
||||
- Example: `tests/unit/types.test.ts` uses `expectTypeOf` to validate type surfaces.
|
||||
- Example: `tests/unit/utils.test.ts` covers platform package detection and binary path resolution.
|
||||
- Example: `tests/unit/binary-packages.test.ts` covers generated package manifests, checksum parsing, and archive type detection.
|
||||
- Example: `tests/unit/platform.test.ts` covers generated package manifests, checksum parsing, and archive type detection.
|
||||
|
||||
- `tests/integration/*`
|
||||
- Executes real Hugo commands and does real filesystem work in temp dirs.
|
||||
|
||||
@@ -4,41 +4,39 @@
|
||||
[](https://www.npmjs.com/package/hugo-extended)
|
||||
[](https://github.com/jakejarvis/hugo-extended/actions)
|
||||
|
||||
> Plug-and-play binary wrapper for [Hugo Extended](https://gohugo.io/), the awesomest static-site generator. Now with full TypeScript support and type-safe APIs!
|
||||
A plug-and-play NPM wrapper for the [Hugo](https://gohugo.io/) static-site generator.
|
||||
|
||||
## Features
|
||||
|
||||
- 🚀 **Zero configuration** — Hugo binary is provided by a platform-specific optional package
|
||||
- 📦 **Version-locked** — Package version matches Hugo version (e.g., `hugo-extended@0.140.0` = Hugo v0.140.0)
|
||||
- 🔒 **Type-safe API** — Full TypeScript support with autocomplete for all Hugo commands and flags
|
||||
- ⚡ **Multiple APIs** — Use CLI, function-based, or builder-style APIs
|
||||
- 🎯 **Extended by default** — Automatically uses Hugo Extended on supported platforms
|
||||
- **CLI passthrough** – Run Hugo with `hugo` (or `hugo-extended`) from `package.json` scripts.
|
||||
- **Predictable versioning** – `hugo-extended`'s version in `package.json` will always match the version of Hugo invoked by your package manager.
|
||||
- **Type-safe API** – Generated command and option types for the Hugo version in this package.
|
||||
- **Builder API** – Call common commands as methods such as `hugo.server()` and `hugo.new.project()` programmatically.
|
||||
- **No install-time scripts** – Runtime resolution uses optional platform and architecture-specific NPM packages.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js `>=22.12.0`
|
||||
- A package manager that installs optional dependencies (unless you set `HUGO_BIN_PATH`; see [Binary Resolution](#binary-resolution) below)
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install hugo-extended --save-dev
|
||||
# or
|
||||
yarn add hugo-extended --dev
|
||||
# or
|
||||
# or...
|
||||
pnpm add hugo-extended --save-dev
|
||||
# or...
|
||||
bun add hugo-extended --dev
|
||||
# or...
|
||||
yarn add hugo-extended --dev
|
||||
```
|
||||
|
||||
### SCSS/PostCSS Support
|
||||
> [!IMPORTANT]
|
||||
> **Recommended:** Use `--save-exact` to ensure your team is developing against the same Hugo version.
|
||||
|
||||
If you're using Hugo's SCSS features, you'll also want:
|
||||
## CLI Usage
|
||||
|
||||
```sh
|
||||
npm install postcss postcss-cli autoprefixer --save-dev
|
||||
```
|
||||
|
||||
These integrate seamlessly with Hugo's [built-in PostCSS pipes](https://gohugo.io/functions/css/postcss/).
|
||||
|
||||
## Usage
|
||||
|
||||
### CLI Usage
|
||||
|
||||
The simplest way — just run `hugo` commands directly:
|
||||
Call the `hugo` binary from NPM scripts just like you would with a system-wide Hugo installation:
|
||||
|
||||
```jsonc
|
||||
// package.json
|
||||
@@ -55,184 +53,259 @@ The simplest way — just run `hugo` commands directly:
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Programmatic API
|
||||
The wrapper resolves the binary, forwards all arguments to Hugo, and exits with Hugo's exit code.
|
||||
|
||||
#### Builder-style API
|
||||
## TypeScript API
|
||||
|
||||
A fluent interface where each Hugo command is a method:
|
||||
### Builder API
|
||||
|
||||
```typescript
|
||||
The default export is callable and also has builder methods attached:
|
||||
|
||||
```ts
|
||||
import hugo from "hugo-extended";
|
||||
|
||||
// Start server
|
||||
await hugo.server({
|
||||
port: 1313,
|
||||
buildDrafts: true,
|
||||
});
|
||||
|
||||
// Build site
|
||||
await hugo.build({
|
||||
minify: true,
|
||||
environment: "production",
|
||||
});
|
||||
|
||||
// Module commands
|
||||
await hugo.mod.get();
|
||||
await hugo.mod.tidy();
|
||||
await hugo.mod.clean({ all: true });
|
||||
|
||||
// Generate shell completions
|
||||
await hugo.completion.zsh();
|
||||
```
|
||||
|
||||
#### Function-based API
|
||||
|
||||
Use `exec()` for commands that output to the console, or `execWithOutput()` to capture the output:
|
||||
|
||||
```typescript
|
||||
import { exec, execWithOutput } from "hugo-extended";
|
||||
|
||||
// Start development server with full type safety
|
||||
await exec("server", {
|
||||
source: "site",
|
||||
port: 1313,
|
||||
buildDrafts: true,
|
||||
navigateToChanged: true,
|
||||
});
|
||||
|
||||
// Build for production
|
||||
await exec("build", {
|
||||
await hugo.build({
|
||||
source: "site",
|
||||
minify: true,
|
||||
cleanDestinationDir: true,
|
||||
baseURL: "https://example.com",
|
||||
baseURL: "https://example.com/",
|
||||
});
|
||||
|
||||
// Capture command output
|
||||
const { stdout } = await execWithOutput("version");
|
||||
console.log(stdout); // "hugo v0.140.0+extended darwin/arm64 ..."
|
||||
|
||||
// List all content pages
|
||||
const { stdout: pages } = await execWithOutput("list all");
|
||||
await hugo.new.project("site", { format: "yaml" });
|
||||
await hugo.new.content("posts/hello.md", {
|
||||
source: "site",
|
||||
kind: "post",
|
||||
});
|
||||
await hugo.mod.tidy({ source: "site" });
|
||||
```
|
||||
|
||||
#### Direct Binary Access
|
||||
> [!NOTE]
|
||||
> Builder methods inherit stdio, so Hugo output is printed directly to the current process. Use `execWithOutput()` when you need to capture output.
|
||||
|
||||
For advanced use cases, get the Hugo binary path directly:
|
||||
### Function API
|
||||
|
||||
```typescript
|
||||
import hugo from "hugo-extended";
|
||||
import { spawn } from "child_process";
|
||||
Use `exec()` when you want inherited stdio:
|
||||
|
||||
const binPath = await hugo();
|
||||
console.log(binPath); // "/usr/local/bin/hugo" or similar
|
||||
```ts
|
||||
import { exec } from "hugo-extended";
|
||||
|
||||
// Use with spawn, exec, or any process library
|
||||
spawn(binPath, ["version"], { stdio: "inherit" });
|
||||
```
|
||||
|
||||
### Type Imports
|
||||
|
||||
Import Hugo types for use in your own code:
|
||||
|
||||
```typescript
|
||||
import type { HugoCommand, HugoOptionsFor, HugoServerOptions } from "hugo-extended";
|
||||
|
||||
// Type-safe option objects
|
||||
const serverOpts: HugoServerOptions = {
|
||||
await exec("server", {
|
||||
source: "site",
|
||||
port: 1313,
|
||||
buildDrafts: true,
|
||||
disableLiveReload: false,
|
||||
};
|
||||
});
|
||||
|
||||
// Generic helper
|
||||
function runHugo<C extends HugoCommand>(cmd: C, opts: HugoOptionsFor<C>) {
|
||||
// ...
|
||||
await exec("new project", ["site"], {
|
||||
format: "yaml",
|
||||
});
|
||||
```
|
||||
|
||||
Use `execWithOutput()` when you need stdout and stderr:
|
||||
|
||||
```ts
|
||||
import { execWithOutput } from "hugo-extended";
|
||||
|
||||
const { stdout } = await execWithOutput("version");
|
||||
console.log(stdout);
|
||||
|
||||
const { stdout: pages } = await execWithOutput("list all", {
|
||||
source: "site",
|
||||
});
|
||||
console.log(pages);
|
||||
```
|
||||
|
||||
### Binary Path Access
|
||||
|
||||
Call the default export or `getHugoBinary()` to resolve the executable:
|
||||
|
||||
```ts
|
||||
import { spawn } from "node:child_process";
|
||||
import hugo, { getHugoBinary } from "hugo-extended";
|
||||
|
||||
const binFromDefault = await hugo();
|
||||
const binFromNamedExport = await getHugoBinary();
|
||||
|
||||
spawn(binFromDefault, ["version"], { stdio: "inherit" });
|
||||
console.log(binFromNamedExport);
|
||||
```
|
||||
|
||||
### Types
|
||||
|
||||
The main entry exports the generic command helpers:
|
||||
|
||||
```ts
|
||||
import type { HugoCommand, HugoOptionsFor } from "hugo-extended";
|
||||
|
||||
function run<C extends HugoCommand>(command: C, options: HugoOptionsFor<C>) {
|
||||
return { command, options };
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
Generated command-specific interfaces are available from `hugo-extended/types`:
|
||||
|
||||
### `exec(command, options?)`
|
||||
```ts
|
||||
import type { HugoServerOptions } from "hugo-extended/types";
|
||||
|
||||
Execute a Hugo command with inherited stdio (output goes to console).
|
||||
|
||||
- **command** — Hugo command string (e.g., `"server"`, `"build"`, `"mod clean"`)
|
||||
- **options** — Type-safe options object (optional)
|
||||
- **Returns** — `Promise<void>`
|
||||
|
||||
### `execWithOutput(command, options?)`
|
||||
|
||||
Execute a Hugo command and capture output.
|
||||
|
||||
- **command** — Hugo command string
|
||||
- **options** — Type-safe options object (optional)
|
||||
- **Returns** — `Promise<{ stdout: string; stderr: string }>`
|
||||
|
||||
### `hugo` (default export)
|
||||
|
||||
The default export is both callable (returns binary path) and has builder methods:
|
||||
|
||||
```typescript
|
||||
// Get binary path (backward compatible)
|
||||
const binPath = await hugo();
|
||||
|
||||
// Builder methods
|
||||
await hugo.build({ minify: true });
|
||||
await hugo.server({ port: 3000 });
|
||||
const options: HugoServerOptions = {
|
||||
source: "site",
|
||||
port: 1313,
|
||||
buildDrafts: true,
|
||||
};
|
||||
```
|
||||
|
||||
### Available Commands
|
||||
## Commands and Options
|
||||
|
||||
All Hugo commands are fully typed with autocomplete:
|
||||
Command and option types are generated from `hugo help` output for the Hugo version locked to this package. Regenerate them when bumping the Hugo version.
|
||||
|
||||
| Command | Builder Method | Description |
|
||||
| ------------- | -------------------- | ---------------------------------------------------------- |
|
||||
| `build` | `hugo.build()` | Build your site |
|
||||
| `server` | `hugo.server()` | Start dev server |
|
||||
| `new` | `hugo.new()` | Create new content |
|
||||
| `mod get` | `hugo.mod.get()` | Download modules |
|
||||
| `mod tidy` | `hugo.mod.tidy()` | Clean go.mod/go.sum |
|
||||
| `mod clean` | `hugo.mod.clean()` | Clean module cache |
|
||||
| `mod vendor` | `hugo.mod.vendor()` | Vendor dependencies |
|
||||
| `list all` | `hugo.list.all()` | List all content |
|
||||
| `list drafts` | `hugo.list.drafts()` | List draft content |
|
||||
| `config` | `hugo.config()` | Print configuration |
|
||||
| `version` | `hugo.version()` | Print version |
|
||||
| `env` | `hugo.env()` | Print environment |
|
||||
| ... | ... | [All Hugo commands supported](https://gohugo.io/commands/) |
|
||||
Options use camelCase property names:
|
||||
|
||||
## Platform Support
|
||||
```ts
|
||||
await hugo.build({
|
||||
baseURL: "https://example.com/",
|
||||
buildDrafts: true,
|
||||
cleanDestinationDir: true,
|
||||
});
|
||||
```
|
||||
|
||||
Hugo Extended is automatically used on supported platforms:
|
||||
When an option exists in the generated flag spec, the wrapper preserves Hugo's canonical long flag exactly, including mixed-case flags such as `--baseURL` and `--buildDrafts`. Unknown camelCase properties fall back to kebab-case.
|
||||
|
||||
| Platform | Architecture | Hugo Extended |
|
||||
| -------- | ------------ | ----------------- |
|
||||
| macOS | x64, ARM64 | ✅ |
|
||||
| Linux | x64, ARM64 | ✅ |
|
||||
| Windows | x64 | ✅ |
|
||||
| Windows | ARM64 | ❌ (vanilla Hugo) |
|
||||
Value handling:
|
||||
|
||||
- Boolean options are emitted only when `true`.
|
||||
- String and number options are emitted as `--flag value`.
|
||||
- Array options repeat the flag once per value.
|
||||
- `undefined` and `null` options are skipped.
|
||||
|
||||
If a command is not exposed as a builder method, use `exec("command name", ...)` or `execWithOutput("command name", ...)`.
|
||||
|
||||
## Binary Resolution
|
||||
|
||||
At runtime, `hugo-extended` resolves the binary in this order:
|
||||
|
||||
1. `HUGO_BIN_PATH`, when set.
|
||||
2. The platform-specific optional dependency for the current OS and CPU.
|
||||
|
||||
Runtime code never downloads, installs, or extracts Hugo.
|
||||
|
||||
| Platform | Architecture | Package | Edition |
|
||||
| -------- | ------------ | -------------------------------------------- | ------------ |
|
||||
| macOS | x64, arm64 | `@jakejarvis/hugo-extended-darwin-universal` | Extended |
|
||||
| Linux | x64 | `@jakejarvis/hugo-extended-linux-amd64` | Extended |
|
||||
| Linux | arm64 | `@jakejarvis/hugo-extended-linux-arm64` | Extended |
|
||||
| Windows | x64 | `@jakejarvis/hugo-extended-windows-amd64` | Extended |
|
||||
| Windows | arm64 | `@jakejarvis/hugo-windows-arm64` | Vanilla Hugo |
|
||||
|
||||
Unsupported platforms can still use this package by setting `HUGO_BIN_PATH` to a compatible Hugo executable.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Customize runtime binary resolution with this environment variable:
|
||||
|
||||
| Variable | Description |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| `HUGO_BIN_PATH` | Use a pre-existing Hugo binary instead of the platform package binary. Example: `HUGO_BIN_PATH=/usr/local/bin/hugo` |
|
||||
|
||||
### Examples
|
||||
| Variable | Type | Description |
|
||||
| --------------- | ------ | -------------------------------------------- |
|
||||
| `HUGO_BIN_PATH` | string | Absolute path to a pre-existing Hugo binary. |
|
||||
|
||||
```sh
|
||||
# Use a system-installed Hugo binary
|
||||
HUGO_BIN_PATH=/usr/local/bin/hugo npm run build
|
||||
```
|
||||
|
||||
For programmatic access, import `getEnvConfig()` or `ENV_VAR_DOCS`:
|
||||
|
||||
```ts
|
||||
import { ENV_VAR_DOCS, getEnvConfig } from "hugo-extended";
|
||||
|
||||
console.log(getEnvConfig());
|
||||
console.log(ENV_VAR_DOCS);
|
||||
```
|
||||
|
||||
## SCSS and PostCSS
|
||||
|
||||
Hugo's SCSS support is provided by Hugo Extended. If your site uses Hugo's PostCSS integration, install the Node tools your Hugo pipeline expects:
|
||||
|
||||
```sh
|
||||
npm install postcss postcss-cli autoprefixer --save-dev
|
||||
```
|
||||
|
||||
See Hugo's [PostCSS documentation](https://gohugo.io/functions/css/postcss/) for pipeline configuration.
|
||||
|
||||
## Development
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
Common commands:
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
npm run check-types
|
||||
npm run lint
|
||||
npm run fmt:check
|
||||
npm test
|
||||
```
|
||||
|
||||
Test targets:
|
||||
|
||||
```sh
|
||||
npm run test:unit
|
||||
npm run test:integration
|
||||
npm run test:e2e
|
||||
npm run test:coverage
|
||||
```
|
||||
|
||||
Integration and e2e tests run the resolved Hugo binary. In tests that operate on a site directory, prefer passing Hugo's global `source` option over changing `process.cwd()`.
|
||||
|
||||
### Regenerating Types
|
||||
|
||||
[`generate-types.ts`](scripts/generate-types.ts) traverses Hugo help output and writes:
|
||||
|
||||
- `src/generated/types.ts`
|
||||
- `src/generated/flags.json`
|
||||
|
||||
Run it after bumping the package/Hugo version:
|
||||
|
||||
```sh
|
||||
npm run generate-types
|
||||
```
|
||||
|
||||
Expect generated type changes when Hugo adds, removes, renames, or recases commands and flags upstream.
|
||||
|
||||
### Generating Platform Packages
|
||||
|
||||
[`generate-packages.ts`](scripts/generate-packages.ts) downloads Hugo release assets, verifies SHA-256 checksums, extracts the binary, and writes publishable packages to `dist-platforms/`.
|
||||
|
||||
Generate the package for the current platform:
|
||||
|
||||
```sh
|
||||
npm run generate-packages
|
||||
```
|
||||
|
||||
Generate one package by name:
|
||||
|
||||
```sh
|
||||
npm run generate-packages -- --package @jakejarvis/hugo-extended-linux-amd64
|
||||
```
|
||||
|
||||
Generate all packages:
|
||||
|
||||
```sh
|
||||
npm run generate-packages -- --all
|
||||
```
|
||||
|
||||
macOS Hugo v0.153.0 and newer ships as a `.pkg`. Generating the macOS package requires macOS because extraction uses `pkgutil --expand-full`. `.tar.gz` and `.zip` assets can be generated on Linux or macOS.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hugo binary not found
|
||||
### Hugo binary package not found
|
||||
|
||||
`hugo-extended` depends on platform-specific optional packages such as `@jakejarvis/hugo-extended-linux-amd64`. If you install with optional dependencies omitted, the wrapper cannot find its bundled Hugo binary.
|
||||
|
||||
Reinstall with optional dependencies explicitly enabled. A plain install will not fix this if your environment or package-manager config is still omitting optional dependencies.
|
||||
This usually means optional dependencies were not installed. Reinstall with optional dependencies enabled:
|
||||
|
||||
```sh
|
||||
npm install --include=optional
|
||||
@@ -240,11 +313,19 @@ pnpm install --config.optional=true
|
||||
yarn config set ignore-optional false && yarn install
|
||||
```
|
||||
|
||||
If your environment intentionally omits optional dependencies, set `HUGO_BIN_PATH` to a compatible Hugo binary instead.
|
||||
If your environment intentionally omits optional dependencies, set `HUGO_BIN_PATH` instead.
|
||||
|
||||
### macOS installation
|
||||
### Unsupported platform
|
||||
|
||||
As of [v0.153.0](https://github.com/gohugoio/hugo/releases/tag/v0.153.0), Hugo is distributed as a `.pkg` installer for macOS. The macOS binary package is built from that `.pkg` during release packaging, so **no sudo, global installation, or install-time script is required** for consumers.
|
||||
Set `HUGO_BIN_PATH` to a Hugo binary built for your platform:
|
||||
|
||||
```sh
|
||||
HUGO_BIN_PATH=/opt/bin/hugo npx hugo version
|
||||
```
|
||||
|
||||
### macOS packaging
|
||||
|
||||
The macOS platform package is created during release packaging from Hugo's upstream `.pkg` asset. Consumers do not need sudo access, global installation, or install-time scripts.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user