CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-astrojs--node

Node.js adapter for Astro framework enabling server-side rendering and standalone server deployments

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

preview.mddocs/

Preview Server

Development preview server functionality for testing built applications locally with configurable host and port options.

Capabilities

Create Preview Server

Creates a preview server for testing built Astro applications in development with automatic server management and networking features.

/**
 * Creates preview server for development testing of built applications
 * @param preview - Preview configuration including server entrypoint and networking
 * @returns Promise resolving to PreviewServer instance with control methods
 * @throws AstroError if server entrypoint is missing or invalid
 */
function createPreviewServer(preview: PreviewParams): Promise<PreviewServer>;

interface PreviewParams {
  /** Path to built server entrypoint module */
  serverEntrypoint: URL;
  /** Host to bind server to - defaults based on CLI arguments */
  host?: string;
  /** Port to bind server to - defaults to 4321 */
  port?: number;
  /** Custom headers to add to responses */
  headers?: Record<string, string>;
  /** Astro logger instance for output */
  logger: AstroIntegrationLogger;
}

interface PreviewServer {
  /** Resolved host server is bound to */
  host: string;
  /** Port server is listening on */
  port: number;
  /** Promise that resolves when server is closed */
  closed(): Promise<void>;
  /** Gracefully stop the server */
  stop(): Promise<void>;
}

Usage Examples:

import createPreviewServer from "@astrojs/node/preview.js";

// Basic preview server
const server = await createPreviewServer({
  serverEntrypoint: new URL("./dist/server.js", import.meta.url),
  logger: astroLogger
});

console.log(`Preview server running at http://${server.host}:${server.port}`);

// Stop server when done
await server.stop();
// Preview server with custom configuration
const server = await createPreviewServer({
  serverEntrypoint: new URL("./dist/server.js", import.meta.url),
  host: "0.0.0.0", // Listen on all interfaces
  port: 3000,
  headers: {
    "X-Frame-Options": "DENY",
    "X-Content-Type-Options": "nosniff"
  },
  logger: astroLogger
});

Host Resolution

The preview server uses sophisticated host resolution logic to handle different CLI argument patterns:

/**
 * Resolves host configuration for preview server binding
 * @param configuredHost - Host value from configuration or CLI
 * @returns Resolved host string for server binding
 */
function getResolvedHostForHttpServer(host: string | boolean | undefined): string | undefined;

Host Resolution Logic:

  • false: Returns 'localhost' (secure default)
  • true: Returns undefined (listen on all IPs - 0.0.0.0 or ::)
  • undefined: Uses environment or default to '0.0.0.0'
  • string: Uses provided host value directly

Environment Variables:

  • HOST: Override host binding from environment
  • PORT: Override port from environment (preview default: 4321)

Server Management

Auto-Start Prevention

The preview server prevents auto-start of the server entrypoint to avoid conflicts:

// Disables auto-start before importing server module
process.env.ASTRO_NODE_AUTOSTART = 'disabled';

Server Entrypoint Validation

Validates that the server entrypoint exists and exports the required handler:

interface ServerModule {
  /** Request handler function from server entrypoint */
  handler: (
    req: IncomingMessage,
    res: ServerResponse,
    next?: (err?: unknown) => void,
    locals?: object
  ) => void | Promise<void>;
}

Error Conditions:

  • Module Not Found: Throws AstroError suggesting to run build first
  • Missing Handler: Throws AstroError indicating incorrect entrypoint file
  • Import Errors: Re-throws original error for debugging

Custom Headers Support

Automatically adds custom headers to successful responses (status 200):

if (preview.headers) {
  server.server.addListener('request', (_, res) => {
    if (res.statusCode === 200) {
      for (const [name, value] of Object.entries(preview.headers ?? {})) {
        if (value) res.setHeader(name, value);
      }
    }
  });
}

Header Application:

  • Only applied to responses with 200 status code
  • Empty/falsy header values are skipped
  • Headers are set before response is sent to client

Network Address Logging

The preview server provides detailed network information including local and network addresses:

/**
 * Logs server listening information with local and network addresses
 * @param logger - Astro integration logger for formatted output
 * @param server - HTTP/HTTPS server instance
 * @param configuredHost - Host configuration for address resolution
 * @returns Promise that resolves when logging is complete
 */
function logListeningOn(
  logger: AstroIntegrationLogger,
  server: http.Server | https.Server,
  configuredHost: string | boolean | undefined
): Promise<void>;

Address Detection:

  • Local Addresses: 127.0.0.1 mapped to localhost
  • Network Addresses: All network interfaces with IPv4 addresses
  • Wildcard Hosts: Show both local and network addresses
  • Specific Hosts: Show only the configured host

Example Output:

Server listening on 
  local: http://localhost:4321 	
  network: http://192.168.1.100:4321

HTTPS Support

Preview server supports HTTPS via environment variables (same as standalone mode):

// Environment variables for HTTPS
SERVER_CERT_PATH="/path/to/certificate.pem"
SERVER_KEY_PATH="/path/to/private-key.pem"

HTTPS Configuration:

  • Both certificate and key paths must be provided
  • Certificates are read synchronously at server startup
  • Invalid certificates will cause server startup to fail

Error Handling

Server Startup Errors

The preview server handles various startup error conditions:

await new Promise<void>((resolve, reject) => {
  server.server.once('listening', resolve);
  server.server.once('error', reject);
  server.server.listen(port, host);
});

Common Error Scenarios:

  • Port In Use: EADDRINUSE error with port number
  • Permission Denied: EACCES for privileged ports (< 1024)
  • Invalid Host: ENOTFOUND for invalid host addresses
  • Network Unavailable: ENETUNREACH for unreachable networks

Module Import Errors

Provides helpful error messages for common preview issues:

if (
  (err as any).code === 'ERR_MODULE_NOT_FOUND' &&
  (err as any).url === preview.serverEntrypoint.href
) {
  throw new AstroError(
    `The server entrypoint ${fileURLToPath(
      preview.serverEntrypoint,
    )} does not exist. Have you ran a build yet?`,
  );
}

Graceful Shutdown

The preview server supports graceful shutdown with cleanup:

async stop() {
  await new Promise((resolve, reject) => {
    httpServer.destroy((err) => (err ? reject(err) : resolve(undefined)));
  });
}

Shutdown Process:

  1. Stop accepting new connections
  2. Close existing connections gracefully
  3. Clean up server resources
  4. Resolve shutdown promise

Integration with Astro CLI

The preview server integrates with Astro's preview command:

# Basic preview
astro preview

# Custom host and port
astro preview --host 0.0.0.0 --port 3000

# With custom headers (via astro.config.mjs)
astro preview

CLI Argument Mapping:

  • --host without value: host = true (listen on all interfaces)
  • --host <value>: host = <value> (listen on specific interface)
  • --port <number>: port = <number> (use specific port)
  • No arguments: Uses defaults and environment variables

docs

handlers.md

index.md

integration.md

preview.md

server-management.md

server-runtime.md

tile.json