Skip to content

logging

logging controls the package-owned logs emitted by createDocsIslands() and the public logger helpers exposed by this package. It does not change rendering; it only decides which @docs-islands/* messages stay visible in Node and in the browser.

Each createDocsIslands() instance owns an isolated logger scope. VitePress injects that scope into the build graph, and the shared @docs-islands/logger runtime reads it when no explicit scope is passed. Parallel VitePress instances or test runs therefore do not overwrite each other's logging config. Use @docs-islands/logger for framework-agnostic direct logger usage.

When to Use It

Use logging when the integration works but the console is too noisy, or when you need focused diagnostics for one docs-islands subsystem. During normal setup you may only keep warn and error; during investigation you can enable debug to see which rule allowed a visible log and how long the logger has been active.

Minimal Example

.vitepress/config.ts
ts
import { createDocsIslands } from '@docs-islands/vitepress';
import { react } from '@docs-islands/vitepress/adapters/react';
import { hmr } from '@docs-islands/vitepress/logger/presets';

const islands = createDocsIslands({
  adapters: [react()],
  logging: {
    levels: ['warn', 'error'],
    plugins: { hmr },
    rules: {
      'hmr/markdownUpdate': 'off',
      'hmr/viteAfterUpdate': {},
    },
  },
});

islands.apply(vitepressConfig);

This keeps only warn and error output from the selected docs-islands HMR stream. hmr/viteAfterUpdate uses the preset default matcher, while hmr/markdownUpdate is disabled explicitly. 'off' is shorthand for { enabled: false }.

Mental Model

When logging.rules is not configured, the logger uses the default visibility set:

  • debug: false: error, warn, info, and success are visible.
  • debug: true: error, warn, info, success, and debug are visible.

When logging.rules is configured, the logger switches to rule mode after any plugin rules are expanded:

  1. Rules with enabled: false are filtered out first. They do not match scope, do not allow levels, and do not appear in debug labels.
  2. Every active rule is checked against the log's main, group, and message. Declared fields use AND semantics.
  3. A matching rule uses rule.levels ?? logging.levels as its effective levels. If both are omitted, the default non-debug set is used.
  4. A log is visible when at least one matching active rule allows the current level.
  5. If rule mode is active but no active rule matches, nothing is printed. There is no fallback to root levels.

Multiple rules can contribute to the same log. Their allowed levels form a union, and debug labels keep the declaration order from logging.rules.

Root Options

OptionMeaning
debugEnables diagnostic output. Visible error, warn, info, and success logs include matching labels and a relative elapsed-time suffix such as 12.34ms.
levelsRoot visibility set. In rule mode, it is the default effective levels for rules that do not define rule.levels; it is not a maximum that narrows rules.
pluginsOptional preset-plugin registry. The object key becomes the namespace used by logging.rules["<plugin>/<rule>"].
rulesEither a focused rule array or a plugin-rule object. When present and non-empty after normalization, logging is decided only by active matching rules.

Plugin Rules

logging.plugins is the recommended entrypoint when you only want to filter docs-islands internal logs.

ts
import { hmr, runtime } from '@docs-islands/vitepress/logger/presets';

const logging = {
  debug: true,
  levels: ['warn'],
  plugins: { hmr, runtime },
  rules: {
    'hmr/viteAfterUpdate': {},
    'runtime/reactDevRender': {
      levels: ['warn', 'error'],
    },
    'runtime/renderValidation': 'off',
  },
};
  • plugins registers logging preset plugins under a namespace key such as hmr.
  • rules["<plugin>/<rule>"] = {} enables the preset rule with its default matcher.
  • rules["<plugin>/<rule>"] = 'off' disables that preset rule and is equivalent to { enabled: false }.
  • The override object can only override enabled, message, or levels. group and main always inherit from the preset rule.

Built-in Presets and Coverage

The presets exported by @docs-islands/vitepress/logger/presets are predefined main/group matchers for built-in docs-islands log streams. The catalog below lists every preset, every rule, and the default range each one constrains.

Preset Coverage

Built-in logging presets and rule catalog

Read presets as grouped matcher bundles: presets describe a subsystem, while rules pin the exact built-in log stream.

9 presets · 33 rules

This catalog is organized from the current exported preset definitions. Click any preset name, rule id, or main/group matcher to copy it. The summary table gives you the preset-level map first, and each grouped detail table shows the exact default main/group matcher used by every rule.

Preset

Preset summary

PresetPurposeCoverageRules
Build-stage logs around framework bundling, SSR output, and final integration work.Constrained to VitePress-side build groups such as browser bundle, SSR bundle, MPA integration, shared runtime metafile, and final HTML processing.7 rules
Configuration-stage logs for environment checks before the feature pipeline starts.Currently scoped to the VitePress-side Node version validation flow.1 rules
Development-time hot-update logs for Markdown containers and React runtime follow-up work.Covers Markdown HMR reparse flow, React runtime preparation, SSR-only re-rendering, and the render steps that follow Vite updates.5 rules
Parsing logs for Markdown pages, framework script blocks, and React-specific reference analysis.Constrained to the parser groups that scan page structure and resolve React imports and component references.2 rules
Plugin-layer logs for the VitePress integration that wires rendering strategies into the site.Currently scoped to the rendering-strategy plugin flow on the VitePress side.1 rules
Resolution logs for page and module references that are derived from VitePress context.Currently scoped to inline page resolution on the VitePress side.1 rules
Runtime logs for browser loading, render orchestration, and part of the shared core runtime validation path.Spans both VitePress-side runtime groups and core-side runtime validation / React manager groups.11 rules
Site DevTools logs for AI services and build-report generation.Constrained to the Site DevTools AI server and AI build report groups on the VitePress side.2 rules
Core-side transform logs for Markdown component processing and SSR integration.Constrained to core transform groups for Markdown component tags, SSR container integration, and SSR CSS injection.3 rules

Rule details

7 rules

Constrained to VitePress-side build groups such as browser bundle, SSR bundle, MPA integration, shared runtime metafile, and final HTML processing.

main
RulePurposemaingroup
Tracks browser-side framework bundle generation and output shaping.
Tracks the final build cleanup and result consolidation stage.
Tracks framework integration work when the site builds in MPA mode.
Tracks shared client runtime metafile collection and inspection.
Tracks SSR bundle generation and related build output layout.
Tracks SSR integration artifacts and the build step that wires them together.
Tracks final HTML injection and framework-specific HTML transforms.

Rule details

1 rules

Currently scoped to the VitePress-side Node version validation flow.

main
RulePurposemaingroup
Tracks Node version checks and related environment guardrails.

Rule details

5 rules

Covers Markdown HMR reparse flow, React runtime preparation, SSR-only re-rendering, and the render steps that follow Vite updates.

main
RulePurposemaingroup
Tracks Markdown file changes that trigger container script reparsing.
Tracks React runtime preparation work before HMR continues.
Tracks SSR-only container re-rendering during development updates.
Tracks docs-islands follow-up handling after Vite finishes an update.
Tracks the render phase that runs after Vite update handling completes.

Rule details

2 rules

Constrained to the parser groups that scan page structure and resolve React imports and component references.

main
RulePurposemaingroup
Tracks framework-agnostic page parsing and script block discovery.
Tracks React-specific import resolution, component binding, and reference validation.

Rule details

1 rules

Currently scoped to the rendering-strategy plugin flow on the VitePress side.

main
RulePurposemaingroup
Tracks plugin setup and runtime status for rendering strategy integration.

Rule details

1 rules

Currently scoped to inline page resolution on the VitePress side.

main
RulePurposemaingroup
Tracks inline-page lookup and resolution decisions.

Rule details

11 rules

Spans both VitePress-side runtime groups and core-side runtime validation / React manager groups.

mainmain
RulePurposemaingroup
Tracks the core-side React component manager lifecycle.
Tracks the core-side React render strategy resolution flow.
Tracks runtime CSS preload and CSS load-state management.
Tracks browser-side loading of React client entry modules.
Tracks the VitePress-side React component manager lifecycle.
Tracks the runtime response after development content updates land.
Tracks fallback paths when development-time mount work cannot use the primary path.
Tracks the render branch used while development-time mount work runs.
Tracks development-time React render execution.
Tracks the bootstrapping path for the development runtime loader.
Tracks core-side validation for resolved render results.

Rule details

2 rules

Constrained to the Site DevTools AI server and AI build report groups on the VitePress side.

main
RulePurposemaingroup
Tracks AI build report generation, caching, and report reads.
Tracks Site DevTools AI server requests and server-side integration work.

Rule details

3 rules

Constrained to core transform groups for Markdown component tags, SSR container integration, and SSR CSS injection.

main
RulePurposemaingroup
Tracks Markdown component-tag transformation before runtime output is emitted.
Tracks SSR container integration into page output.
Tracks CSS injection work performed during SSR-oriented transforms.

Public Logger Usage

@docs-islands/vitepress/logger is the VitePress logger facade. It exposes createLogger and formatDebugMessage; generic direct runtime configuration lives in @docs-islands/logger.

logging defines the runtime visibility policy. It decides whether a log is emitted at runtime, and in debug mode it also controls which rule labels and elapsed-time metadata are attached to visible logs.

@docs-islands/logger stays framework-agnostic. Inside docs-islands, @docs-islands/utils/logger bridges the bundler-injected __DOCS_ISLANDS_LOGGER_SCOPE_ID__ to the base logger, and @docs-islands/vitepress/logger.createLogger(...) only works when that injected scope is present.

Runtime Policy vs Build-Time Optimization

The logger tree-shaking plugin is a build-time optimization layer. It reuses the resolved logging rules to prune statically analyzable logger calls during build.

These two layers are related, but they are not the same thing:

  • logging always defines runtime behavior.
  • The tree-shaking plugin only handles the static subset it can prove safely.
  • If a log cannot be analyzed statically, it stays in the output and is still filtered by the runtime logger.

So a runtime-suppressed log is not automatically a pruned log.

Dimensionlogginglogger tree-shaking plugin
StageRuntimeBuild
Controls final console outputYesNo, runtime stays canonical
Removes static message text from the bundleNoYes, for the supported static subset
Reuses the resolved logging rulesYesYes
CoverageFull runtime modelStatic, provable subset only
Fallback when analysis is not possibleRuntime matchingKeep the call and defer to runtime
.vitepress/config.ts
ts
import { createDocsIslands } from '@docs-islands/vitepress';
import { createLogger } from '@docs-islands/vitepress/logger';

const logger = createLogger({
  main: '@acme/custom-docs',
}).getLoggerByGroup('userland.metrics');
const hiddenLogger = createLogger({
  main: '@acme/custom-docs',
}).getLoggerByGroup('userland.hidden');

const islands = createDocsIslands({
  logging: {
    debug: true,
    rules: [
      {
        label: 'userland-metrics',
        main: '@acme/custom-docs',
        group: 'userland.metrics',
        levels: ['info'],
      },
    ],
  },
});

islands.apply(vitepressConfig);

logger.info('visible userland info');
hiddenLogger.info('suppressed userland info');

With this setup, userland.metrics stays visible, while userland.hidden is suppressed. If you later change createLogger({ main: ... }), update your rules to match that main or remove the main filter.

Logger Tree-Shaking Plugin

In createDocsIslands() managed builds, docs-islands already installs the logger tree-shaking transform automatically.

If you only want the public logger in a VitePress site and still want production pruning, install the public plugin explicitly:

.vitepress/config.ts
ts
import { defineConfig } from 'vitepress';
import { loggerTreeShaking } from '@docs-islands/logger/plugin';

export default defineConfig({
  vite: {
    plugins: [
      loggerTreeShaking.vite({
        logging: {
          levels: ['warn', 'error'],
        },
      }),
    ],
  },
});

If logging is omitted, the plugin falls back to the default logger visibility policy, which still prunes statically analyzable debug logs. If you want dynamic logs outside the createDocsIslands() graph to follow the same policy, configure the runtime logger separately as well.

Production Tree-Shaking

When the tree-shaking transform is active, a static user-authored log that is provably suppressed by the resolved logging rules is removed from the generated JavaScript, so its static message text does not stay in the bundle.

Use this direct shape when you want pruning coverage:

ts
import { createLogger } from '@docs-islands/vitepress/logger';

const logger = createLogger({
  main: '@acme/custom-docs',
}).getLoggerByGroup('userland.metrics');

logger.info('static metric ready');
logger.success('static metric uploaded');
logger.warn('static metric delayed');
logger.error('static metric failed');
logger.debug('static metric details');

The optimizer only analyzes this constrained static form:

  • createLogger must be a named import from @docs-islands/vitepress/logger.
  • main, getLoggerByGroup(...), and the log message must all be string literals.
  • The log call must be a standalone statement such as logger.info('message').
PatternIncluded in pruning
const logger = createLogger({ main: 'x' }).getLoggerByGroup('y')Yes
logger.info('msg') / warn / error / success / debugYes
Template strings, concatenation, variables, dynamic main, dynamic groupNo
Aliasing, destructuring, reassignment, dynamic method accessNo
Non-standalone expressions such as const result = logger.info('msg')No

Dynamic logs still work, but they are intentionally left for runtime filtering:

ts
logger.info(`metric ${name}`);
logger.info(`metric ${name}`);
logger.info(message);
createLogger({ main }).getLoggerByGroup(group).info('dynamic binding');

Those forms remain compatible, but docs-islands does not guarantee that their message text disappears from production output. Pruning coverage is a static subset of runtime logging coverage, not a replacement for it.

Generic Logger Usage

For direct logger usage outside VitePress managed builds, import from the framework-agnostic package:

ts
import { createLogger, setLoggerConfig } from '@docs-islands/logger';

setLoggerConfig({
  levels: ['warn', 'error'],
});

const logger = createLogger({
  main: '@acme/custom-docs',
}).getLoggerByGroup('userland.metrics');

logger.warn('visible generic warning');

@docs-islands/vitepress/logger should not be used as a generic logger entry. It is reserved for the VitePress build graph established by createDocsIslands().

Interactive Scope Probe

The playground below runs the VitePress logger facade from inside this docs site:

  • A normal @docs-islands/vitepress/logger import uses the current createDocsIslands() logger scope through runtime injection.
  • The framework-agnostic @docs-islands/logger runtime demo lives on the standalone logger package page.
Scope validation

Logger scope playground

The VitePress import reads the current docs-islands logger scope from runtime injection and follows the active createDocsIslands({ logging }) policy.

This playground runs a real VitePress logger probe on the page and captures its console output back into the UI. It is meant to validate the injected logger-scope behavior from inside the docs site itself.

Scope validationRunning probe...

Injected scope import

This card uses the VitePress logger import inside the docs-islands build graph. The logger runtime reads the scope injected by createDocsIslands() and does not expose generic runtime configuration.

Import path
Status
Running probe...
setLoggerConfig(...) behavior
Managed by createDocsIslands({ logging })
Visible message emitted
No
Hidden message emitted
No
Captured warning
No
Captured console lines
No

Reusing Built-in main/group

If your user-authored logs intentionally or accidentally reuse the same main / group values as built-in docs-islands logs, they may also match the same preset rules or direct logging.rules entries:

  • Your user logs may become visible or suppressed together with built-in logs.
  • In debug mode, they may show the same rule labels as built-in logs, which makes diagnosis noisier.
  • Later tuning of built-in preset coverage can unintentionally affect your user logs too.

Unless you explicitly want both streams to share the same filtering space, prefer a dedicated namespace such as @acme/custom-docs with userland.*.

Direct Rule Fields

Array-form logging.rules is still supported when you need raw low-level matching outside preset plugins.

FieldMeaning
labelRequired stable identifier. When debug is enabled, visible logs show contributing labels as [LabelA][LabelB].
enabledOptional pre-filter switch. false makes the rule completely inactive; it is not a lower-priority deny rule.
mainOptional exact package match, for example @docs-islands/vitepress. Glob patterns are not applied to main.
groupOptional logger group matcher. Plain strings are exact; patterns with glob magic use picomatch, for example runtime.react.* or test.case.?1.
messageOptional message matcher. Plain strings are exact; patterns with glob magic use picomatch, for example *timeout*, request *, or task-[ab].
levelsOptional effective levels for this rule. It replaces the root levels for this rule and participates in the union with other matching rules.

Matching Examples

Direct rule arrays remain useful when you want broad wildcards or message-text filtering that is not tied to one preset label.

ts
const islands = createDocsIslands({
  adapters: [react()],
  logging: {
    debug: true,
    levels: ['warn'],
    rules: [
      {
        label: 'react-runtime-warnings',
        main: '@docs-islands/vitepress',
        group: 'runtime.react.*',
      },
      {
        label: 'runtime-timeouts',
        group: 'runtime.*',
        message: '*timeout*',
        levels: ['error'],
      },
    ],
  },
});

A warn from runtime.react.component-manager is visible through react-runtime-warnings. An error message containing timeout is visible through runtime-timeouts. If one log matches both rules and its level is allowed by both, debug mode prints both labels in declaration order.

Debug output looks like this:

bash
[react-runtime-warnings][runtime-timeouts] @docs-islands/vitepress[runtime.react.component-manager]: request timeout 12.34ms

Common Patterns

Keep Only Warnings and Errors for React Runtime Logs

ts
const islands = createDocsIslands({
  adapters: [react()],
  logging: {
    levels: ['warn', 'error'],
    rules: [
      {
        label: 'react-runtime-warn-error',
        main: '@docs-islands/vitepress',
        group: 'runtime.react.*',
      },
    ],
  },
});

Combine a Broad Rule with a Specific Message Rule

ts
const islands = createDocsIslands({
  adapters: [react()],
  logging: {
    levels: ['warn'],
    rules: [
      {
        label: 'runtime-warnings',
        group: 'runtime.*',
      },
      {
        label: 'timeout-errors',
        message: '*timeout*',
        levels: ['error'],
      },
    ],
  },
});

This keeps runtime warnings while also allowing timeout errors anywhere. The two rules do not override each other; they contribute together.

Temporarily Disable One Rule

ts
const islands = createDocsIslands({
  adapters: [react()],
  logging: {
    rules: [
      {
        label: 'runtime-react',
        group: 'runtime.react.*',
        levels: ['warn'],
      },
      {
        label: 'runtime-react-disabled',
        enabled: false,
        group: 'runtime.react.component-manager',
        levels: ['error'],
      },
    ],
  },
});

The disabled rule is ignored completely. It does not silence or override the active runtime-react rule, and it never appears in debug labels.

Filter by Message Text

ts
const islands = createDocsIslands({
  adapters: [react()],
  logging: {
    rules: [
      {
        label: 'hydration-timeouts',
        message: '*hydration*timeout*',
        levels: ['warn', 'error'],
      },
    ],
  },
});

Use message rules for short investigation windows, especially when a noisy group contains only a few messages you care about.

Released under the MIT License. (0826c60)

Global Debug Console

docs-islands Runtime Globals

Browse the runtime globals injected by @docs-islands/vitepress and inspect their current live values.

Console helper: window.__DOCS_ISLANDS_SITE_DEVTOOLS__.getGlobal('__PAGE_METAFILE__')

Injected Globals

VitePress runtime site data. Hidden in dev and MPA mode.