From 979b09cd1c4172265eae87608629470d444de36f Mon Sep 17 00:00:00 2001 From: ematipico Date: Wed, 18 Feb 2026 13:08:38 +0000 Subject: [PATCH 1/9] fix(core): logging overhaul --- .changeset/big-jobs-make.md | 5 + .changeset/green-zebras-lick.md | 5 + benchmark/packages/adapter/src/server.ts | 4 +- packages/astro/package.json | 2 +- packages/astro/src/cli/flags.ts | 6 +- packages/astro/src/config/index.ts | 2 +- packages/astro/src/core/app/app.ts | 5 +- packages/astro/src/core/app/base.ts | 63 ++++++++- packages/astro/src/core/app/dev/app.ts | 24 +++- .../astro/src/core/app/entrypoints/index.ts | 7 +- packages/astro/src/core/build/app.ts | 3 + packages/astro/src/core/build/index.ts | 2 +- packages/astro/src/core/config/logging.ts | 12 -- packages/astro/src/core/dev/restart.ts | 2 +- packages/astro/src/core/logger/node.ts | 130 ++++++++++++++++-- packages/astro/src/core/messages.ts | 26 ++++ packages/astro/src/core/preview/index.ts | 2 +- packages/astro/src/core/sync/index.ts | 2 +- packages/astro/src/vite-plugin-app/app.ts | 19 ++- .../test/astro-dev-platform.test.js | 11 ++ .../src/pages/code-test.astro | 12 ++ packages/telemetry/package.json | 3 +- packages/telemetry/src/index.ts | 33 +++-- pnpm-lock.yaml | 15 +- 24 files changed, 337 insertions(+), 58 deletions(-) create mode 100644 .changeset/big-jobs-make.md create mode 100644 .changeset/green-zebras-lick.md delete mode 100644 packages/astro/src/core/config/logging.ts create mode 100644 packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/code-test.astro diff --git a/.changeset/big-jobs-make.md b/.changeset/big-jobs-make.md new file mode 100644 index 000000000000..8e1201a4183e --- /dev/null +++ b/.changeset/big-jobs-make.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes an issue where the use of the Astro internal logger couldn't work with Cloudflare Vite plugin. diff --git a/.changeset/green-zebras-lick.md b/.changeset/green-zebras-lick.md new file mode 100644 index 000000000000..c433004b1e1d --- /dev/null +++ b/.changeset/green-zebras-lick.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes an issue where the new Astro v6 development server didn't log anything when navigating the pages. diff --git a/benchmark/packages/adapter/src/server.ts b/benchmark/packages/adapter/src/server.ts index 727444e06cd4..2a4d45f443d1 100644 --- a/benchmark/packages/adapter/src/server.ts +++ b/benchmark/packages/adapter/src/server.ts @@ -1,6 +1,6 @@ import * as fs from 'node:fs'; import type { SSRManifest } from 'astro'; -import { AppPipeline, BaseApp } from 'astro/app'; +import { AppPipeline, BaseApp, type LogRequestPayload } from 'astro/app'; class MyApp extends BaseApp { #manifest: SSRManifest | undefined; @@ -30,6 +30,8 @@ class MyApp extends BaseApp { streaming, }); } + + logRequest(_options: LogRequestPayload) {} } export function createExports(manifest: SSRManifest) { diff --git a/packages/astro/package.json b/packages/astro/package.json index a3bc99b85fe6..a6a06697e348 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -129,9 +129,9 @@ "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", + "consola": "^3.2.3", "cookie": "^1.1.1", "cssesc": "^3.0.0", - "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", "devalue": "^5.6.2", "diff": "^8.0.3", diff --git a/packages/astro/src/cli/flags.ts b/packages/astro/src/cli/flags.ts index 5e1ea2f9258f..b73c18c669ee 100644 --- a/packages/astro/src/cli/flags.ts +++ b/packages/astro/src/cli/flags.ts @@ -1,6 +1,6 @@ import type { Arguments } from 'yargs-parser'; -import { Logger, type LogOptions } from '../core/logger/core.js'; -import { nodeLogDestination } from '../core/logger/node.js'; +import type { Logger, LogOptions } from '../core/logger/core.js'; +import { createNodeLogger, nodeLogDestination } from '../core/logger/node.js'; import type { AstroInlineConfig } from '../types/public/config.js'; // Alias for now, but allows easier migration to node's `parseArgs` in the future. @@ -52,5 +52,5 @@ export function createLoggerFromFlags(flags: Flags): Logger { logging.level = 'silent'; } - return new Logger(logging); + return createNodeLogger({ logLevel: logging.level }); } diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index a7d3c324df0b..0f7eba7c3ac0 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -37,7 +37,7 @@ export function getViteConfig( { runHookConfigSetup, runHookConfigDone }, ] = await Promise.all([ import('vite'), - import('../core/config/logging.js'), + import('../core/logger/node.js'), import('../core/config/index.js'), import('../core/create-vite.js'), import('../integrations/hooks.js'), diff --git a/packages/astro/src/core/app/app.ts b/packages/astro/src/core/app/app.ts index 0b6e6ac468f2..e672de736ffa 100644 --- a/packages/astro/src/core/app/app.ts +++ b/packages/astro/src/core/app/app.ts @@ -1,4 +1,4 @@ -import { BaseApp } from './base.js'; +import { BaseApp, type LogRequestPayload } from './base.js'; import { AppPipeline } from './pipeline.js'; export class App extends BaseApp { @@ -12,4 +12,7 @@ export class App extends BaseApp { isDev(): boolean { return false; } + + // Should we log something for our users? + logRequest(_options: LogRequestPayload) {} } diff --git a/packages/astro/src/core/app/base.ts b/packages/astro/src/core/app/base.ts index fae8bbf8a6bc..3169e359b7e5 100644 --- a/packages/astro/src/core/app/base.ts +++ b/packages/astro/src/core/app/base.ts @@ -18,6 +18,7 @@ import { REROUTABLE_STATUS_CODES, REROUTE_DIRECTIVE_HEADER, responseSentSymbol, + REWRITE_DIRECTIVE_HEADER_KEY, } from '../constants.js'; import { getSetCookiesFromResponse } from '../cookies/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; @@ -342,6 +343,7 @@ export abstract class BaseApp

{ } public async render(request: Request, renderOptions?: RenderOptions): Promise { + const timeStart = performance.now(); let routeData: RouteData | undefined = renderOptions?.routeData; let locals: object | undefined; let clientAddress: string | undefined; @@ -379,7 +381,8 @@ export abstract class BaseApp

{ 'The adapter ' + this.manifest.adapterName + ' provided a custom RouteData for ', request.url, ); - this.logger.debug('router', 'RouteData:\n' + routeData); + this.logger.debug('router', 'RouteData'); + this.logger.debug('router', routeData); } if (locals) { if (typeof locals !== 'object') { @@ -443,6 +446,16 @@ export abstract class BaseApp

{ }); session = renderContext.session; response = await renderContext.render(componentInstance); + + const isRewrite = response.headers.has(REWRITE_DIRECTIVE_HEADER_KEY); + + this.logThisRequest({ + pathname, + method: request.method, + statusCode: response.status, + isRewrite, + timeStart, + }); } catch (err: any) { this.logger.error(null, err.stack || err.message || String(err)); return this.renderError(request, { @@ -672,4 +685,52 @@ export abstract class BaseApp

{ public getManifest() { return this.pipeline.manifest; } + + logThisRequest({ + pathname, + method, + statusCode, + isRewrite, + timeStart, + }: { + pathname: string; + method: string; + statusCode: number; + isRewrite: boolean; + timeStart: number; + }) { + const timeEnd = performance.now(); + this.logRequest({ + pathname, + method, + statusCode, + isRewrite, + reqTime: timeEnd - timeStart, + }); + } + + public abstract logRequest(_options: LogRequestPayload): void; } + +export type LogRequestPayload = { + /** + * The current path being rendered + */ + pathname: string; + /** + * The method of the request + */ + method: string; + /** + * The status code of the request + */ + statusCode: number; + /** + * If the current request is a rewrite + */ + isRewrite: boolean; + /** + * How long it took to render the request + */ + reqTime: number; +}; diff --git a/packages/astro/src/core/app/dev/app.ts b/packages/astro/src/core/app/dev/app.ts index b36119646fac..10378c848a02 100644 --- a/packages/astro/src/core/app/dev/app.ts +++ b/packages/astro/src/core/app/dev/app.ts @@ -3,7 +3,12 @@ import { MiddlewareNoDataOrNextCalled, MiddlewareNotAResponse } from '../../erro import { type AstroError, isAstroError } from '../../errors/index.js'; import type { Logger } from '../../logger/core.js'; import type { CreateRenderContext, RenderContext } from '../../render-context.js'; -import { BaseApp, type DevMatch, type RenderErrorOptions } from '../base.js'; +import { + BaseApp, + type DevMatch, + type LogRequestPayload, + type RenderErrorOptions, +} from '../base.js'; import type { SSRManifest } from '../types.js'; import { NonRunnablePipeline } from './pipeline.js'; import { getCustom404Route, getCustom500Route } from '../../routing/helpers.js'; @@ -11,6 +16,7 @@ import { ensure404Route } from '../../routing/astro-designed-error-pages.js'; import { matchRoute } from '../../routing/dev.js'; import type { RunnablePipeline } from '../../../vite-plugin-app/pipeline.js'; import type { RoutesList } from '../../../types/astro.js'; +import { req } from '../../messages.js'; export class DevApp extends BaseApp { logger: Logger; @@ -134,4 +140,20 @@ export class DevApp extends BaseApp { return renderRoute(custom500); } } + + logRequest({ pathname, method, statusCode, isRewrite, reqTime }: LogRequestPayload) { + if (pathname === '/favicon.ico') { + return; + } + this.logger.info( + null, + req({ + url: pathname, + method, + statusCode, + isRewrite, + reqTime, + }), + ); + } } diff --git a/packages/astro/src/core/app/entrypoints/index.ts b/packages/astro/src/core/app/entrypoints/index.ts index 63fdafd87d91..2730ce8395f6 100644 --- a/packages/astro/src/core/app/entrypoints/index.ts +++ b/packages/astro/src/core/app/entrypoints/index.ts @@ -1,6 +1,11 @@ export type { RoutesList } from '../../../types/astro.js'; export { App } from '../app.js'; -export { BaseApp, type RenderErrorOptions, type RenderOptions } from '../base.js'; +export { + BaseApp, + type RenderErrorOptions, + type RenderOptions, + type LogRequestPayload, +} from '../base.js'; export { fromRoutingStrategy, toRoutingStrategy } from '../common.js'; export { createConsoleLogger } from '../logging.js'; export { diff --git a/packages/astro/src/core/build/app.ts b/packages/astro/src/core/build/app.ts index 92900bbc80fd..aae4c30af6d9 100644 --- a/packages/astro/src/core/build/app.ts +++ b/packages/astro/src/core/build/app.ts @@ -4,6 +4,7 @@ import type { BuildInternals } from './internal.js'; import { BuildPipeline } from './pipeline.js'; import type { StaticBuildOptions } from './types.js'; import type { CreateRenderContext, RenderContext } from '../render-context.js'; +import type { LogRequestPayload } from '../app/base.js'; export class BuildApp extends BaseApp { createPipeline(_streaming: boolean, manifest: SSRManifest, ..._args: any[]): BuildPipeline { @@ -52,4 +53,6 @@ export class BuildApp extends BaseApp { }); } } + + logRequest(_options: LogRequestPayload) {} } diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 069f63651903..8842c4bbaee5 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -14,7 +14,7 @@ import { import type { AstroSettings, RoutesList } from '../../types/astro.js'; import type { AstroInlineConfig, RuntimeMode } from '../../types/public/config.js'; import { resolveConfig } from '../config/config.js'; -import { createNodeLogger } from '../config/logging.js'; +import { createNodeLogger } from '../logger/node.js'; import { createSettings } from '../config/settings.js'; import { createVite } from '../create-vite.js'; import { createKey, getEnvironmentKey, hasEnvironmentKey } from '../encryption.js'; diff --git a/packages/astro/src/core/config/logging.ts b/packages/astro/src/core/config/logging.ts deleted file mode 100644 index bd72f8b5e978..000000000000 --- a/packages/astro/src/core/config/logging.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { AstroInlineConfig } from '../../types/public/config.js'; -import { Logger } from '../logger/core.js'; -import { nodeLogDestination } from '../logger/node.js'; - -export function createNodeLogger(inlineConfig: AstroInlineConfig): Logger { - if (inlineConfig.logger) return inlineConfig.logger; - - return new Logger({ - dest: nodeLogDestination, - level: inlineConfig.logLevel ?? 'info', - }); -} diff --git a/packages/astro/src/core/dev/restart.ts b/packages/astro/src/core/dev/restart.ts index d6165c50364b..e7eb667fec83 100644 --- a/packages/astro/src/core/dev/restart.ts +++ b/packages/astro/src/core/dev/restart.ts @@ -8,7 +8,7 @@ import { SETTINGS_FILE } from '../../preferences/constants.js'; import type { AstroSettings } from '../../types/astro.js'; import type { AstroInlineConfig } from '../../types/public/config.js'; import { createSettings, resolveConfig } from '../config/index.js'; -import { createNodeLogger } from '../config/logging.js'; +import { createNodeLogger } from '../logger/node.js'; import { collectErrorMetadata } from '../errors/dev/utils.js'; import { isAstroConfigZodError } from '../errors/errors.js'; import { createSafeError } from '../errors/index.js'; diff --git a/packages/astro/src/core/logger/node.ts b/packages/astro/src/core/logger/node.ts index aa5df6225d62..fe4405152f77 100644 --- a/packages/astro/src/core/logger/node.ts +++ b/packages/astro/src/core/logger/node.ts @@ -1,5 +1,8 @@ import type { Writable } from 'node:stream'; -import debugPackage from 'debug'; +import { inspect } from 'node:util'; +import colors from 'piccolore'; +import type { AstroInlineConfig } from '../../types/public/config.js'; +import { Logger } from './core.js'; import { getEventPrefix, type LogMessage, type LogWritable, levels } from './core.js'; type ConsoleStream = Writable & { @@ -22,28 +25,135 @@ export const nodeLogDestination: LogWritable = { }, }; -const debuggers: Record = {}; +interface DebugLogger { + lastTime: number; + namespace: string; + color: (text: string) => string; +} + +const debuggers: Record = {}; + +// Color functions array for namespace coloring (similar to debug package) +const colorFunctions = [ + colors.cyan, + colors.magenta, + colors.blue, + colors.yellow, + colors.green, + colors.red, + colors.gray, +]; + +function selectColorFunction(namespace: string): (text: string) => string { + let hash = 0; + for (let i = 0; i < namespace.length; i++) { + hash = (hash << 5) - hash + namespace.charCodeAt(i); + hash |= 0; + } + return colorFunctions[Math.abs(hash) % colorFunctions.length]; +} + +function humanizeTime(ms: number): string { + if (ms >= 1000) { + return `${(ms / 1000).toFixed(1)}s`; + } + return `${ms}ms`; +} /** * Emit a message only shown in debug mode. - * Astro (along with many of its dependencies) uses the `debug` package for debug logging. + * Mimics the debug package's behavior and format. * You can enable these logs with the `DEBUG=astro:*` environment variable. - * More info https://github.com/debug-js/debug#environment-variables */ -function debug(type: string, ...messages: Array) { +function debug(type: string, ...messages: any[]) { const namespace = `astro:${type}`; - debuggers[namespace] = debuggers[namespace] || debugPackage(namespace); - return debuggers[namespace](...messages); + + // Check if debug is enabled for this namespace before doing anything + if (!isDebugEnabled(namespace)) { + return; + } + + // Initialize logger for this namespace if needed + if (!debuggers[namespace]) { + debuggers[namespace] = { + lastTime: Date.now(), + namespace, + color: selectColorFunction(namespace), + }; + } + + const logger = debuggers[namespace]; + const now = Date.now(); + const delta = now - logger.lastTime; + logger.lastTime = now; + + const prefix = logger.color(namespace); + const diff = logger.color(`+${humanizeTime(delta)}`); + + // Format each message + for (const message of messages) { + let formatted: string; + if (typeof message === 'string') { + formatted = message; + } else { + // Use util.inspect for objects (similar to debug package) + formatted = inspect(message, { colors: true, depth: null }); + } + + // Add prefix to each line (like debug package does) + const lines = formatted.split('\n'); + for (let i = 0; i < lines.length; i++) { + if (i === 0) { + process.stderr.write(` ${prefix} ${lines[i]} ${diff}\n`); + } else { + process.stderr.write(` ${prefix} ${lines[i]}\n`); + } + } + } } -// This is gross, but necessary since we are depending on globals. -(globalThis as any)._astroGlobalDebug = debug; +/** + * Check if debug logging is enabled for a namespace based on DEBUG env var. + * Supports patterns like: DEBUG=astro:*, DEBUG=astro:cli, DEBUG=* + */ +function isDebugEnabled(namespace: string): boolean { + const envDebug = process.env.DEBUG; + if (!envDebug) return false; + const patterns = envDebug.split(',').map((p) => p.trim()); + return patterns.some((pattern) => { + if (pattern === '*') return true; + if (pattern.endsWith(':*')) { + const prefix = pattern.slice(0, -2); + return namespace === prefix || namespace.startsWith(prefix + ':'); + } + return namespace === pattern; + }); +} + +/** + * Enable verbose debug logging for Astro and Vite. + * This updates the DEBUG environment variable. + * Since debug() now checks isDebugEnabled() on every call, we don't need to recreate loggers. + */ export function enableVerboseLogging() { - debugPackage.enable('astro:*,vite:*'); + process.env.DEBUG = 'astro:*,vite:*'; + debug('cli', '--verbose flag enabled! Enabling: DEBUG="astro:*,vite:*"'); debug( 'cli', 'Tip: Set the DEBUG env variable directly for more control. Example: "DEBUG=astro:*,vite:* astro build".', ); } + +// This is gross, but necessary since we are depending on globals. +(globalThis as any)._astroGlobalDebug = debug; + +export function createNodeLogger(inlineConfig: AstroInlineConfig): Logger { + if (inlineConfig.logger) return inlineConfig.logger; + + return new Logger({ + dest: nodeLogDestination, + level: inlineConfig.logLevel ?? 'info', + }); +} diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index c151b7f56477..2b1a97358194 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -31,6 +31,32 @@ const { * Prestyled messages for the CLI. Used by astro CLI commands. */ +/** Display each request being served with the path and the status code. */ +export function req({ + url, + method, + statusCode, + reqTime, + isRewrite, +}: { + url: string; + statusCode: number; + method?: string; + reqTime?: number; + isRewrite?: boolean; +}): string { + const color = statusCode >= 500 ? red : statusCode >= 300 ? yellow : blue; + return ( + color(`[${statusCode}]`) + + ` ` + + `${isRewrite ? color('(rewrite) ') : ''}` + + (method && method !== 'GET' ? color(method) + ' ' : '') + + url + + ` ` + + (reqTime ? dim(Math.round(reqTime) + 'ms') : '') + ); +} + /** Display server host and startup time */ export function serverStart({ startupTime, diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts index 03826ce31ded..c572510e80fe 100644 --- a/packages/astro/src/core/preview/index.ts +++ b/packages/astro/src/core/preview/index.ts @@ -8,7 +8,7 @@ import { runHookConfigDone, runHookConfigSetup } from '../../integrations/hooks. import type { AstroInlineConfig } from '../../types/public/config.js'; import type { PreviewModule, PreviewServer } from '../../types/public/preview.js'; import { resolveConfig } from '../config/config.js'; -import { createNodeLogger } from '../config/logging.js'; +import { createNodeLogger } from '../logger/node.js'; import { createSettings } from '../config/settings.js'; import { createRoutesList } from '../routing/manifest/create.js'; import { ensureProcessNodeEnv } from '../util.js'; diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index c17a6a630d98..8ca64d9ce8a7 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -18,7 +18,7 @@ import type { AstroSettings } from '../../types/astro.js'; import type { AstroInlineConfig } from '../../types/public/config.js'; import { getTimeStat } from '../build/util.js'; import { resolveConfig } from '../config/config.js'; -import { createNodeLogger } from '../config/logging.js'; +import { createNodeLogger } from '../logger/node.js'; import { createSettings } from '../config/settings.js'; import { createVite } from '../create-vite.js'; import { diff --git a/packages/astro/src/vite-plugin-app/app.ts b/packages/astro/src/vite-plugin-app/app.ts index bb2258ddcd4a..c63a774a2886 100644 --- a/packages/astro/src/vite-plugin-app/app.ts +++ b/packages/astro/src/vite-plugin-app/app.ts @@ -22,7 +22,8 @@ import { RunnablePipeline } from './pipeline.js'; import { getCustom404Route, getCustom500Route } from '../core/routing/helpers.js'; import { ensure404Route } from '../core/routing/astro-designed-error-pages.js'; import { matchRoute } from '../core/routing/dev.js'; -import type { DevMatch } from '../core/app/base.js'; +import type { DevMatch, LogRequestPayload } from '../core/app/base.js'; +import { req } from '../core/messages.js'; export class AstroServerApp extends BaseApp { settings: AstroSettings; @@ -289,6 +290,22 @@ export class AstroServerApp extends BaseApp { return renderRoute(custom500); } } + + logRequest({ pathname, method, statusCode, isRewrite, reqTime }: LogRequestPayload) { + if (pathname === '/favicon.ico') { + return; + } + this.logger.info( + null, + req({ + url: pathname, + method, + statusCode, + isRewrite, + reqTime, + }), + ); + } } type HandleRequest = { diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.js b/packages/integrations/cloudflare/test/astro-dev-platform.test.js index d33edfdd54a8..779d2a1b2a25 100644 --- a/packages/integrations/cloudflare/test/astro-dev-platform.test.js +++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.js @@ -59,4 +59,15 @@ describe('AstroDevPlatform', () => { assert.equal($('#hasPRODKV').text(), 'true'); assert.equal($('#hasACCESS').text(), 'true'); }); + + it('Code component works in dev mode (no CommonJS module errors)', async () => { + const res = await fixture.fetch('/code-test'); + assert.equal(res.status, 200); + const html = await res.text(); + const $ = cheerio.load(html); + // Verify the page rendered successfully with Code component + assert.equal($('h1').text(), 'Testing Code Component'); + // Verify the code block was rendered + assert.ok($('pre').length > 0, 'Code block should be rendered'); + }); }); diff --git a/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/code-test.astro b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/code-test.astro new file mode 100644 index 000000000000..34993e471c5d --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/code-test.astro @@ -0,0 +1,12 @@ +--- +import { Code } from 'astro:components'; +--- + + + Code Component Test + + +

Testing Code Component

+ + + diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json index daad1d3843d3..435719aa96fd 100644 --- a/packages/telemetry/package.json +++ b/packages/telemetry/package.json @@ -30,7 +30,7 @@ ], "dependencies": { "ci-info": "^4.4.0", - "debug": "^4.4.3", + "consola": "^3.2.3", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^4.0.0", @@ -38,7 +38,6 @@ "which-pm-runs": "^1.1.0" }, "devDependencies": { - "@types/debug": "^4.1.12", "@types/dlv": "^1.1.5", "@types/node": "^18.17.8", "@types/which-pm-runs": "^1.0.2", diff --git a/packages/telemetry/src/index.ts b/packages/telemetry/src/index.ts index 4662e598f5ac..c53bf4d73eaf 100644 --- a/packages/telemetry/src/index.ts +++ b/packages/telemetry/src/index.ts @@ -1,6 +1,5 @@ import { randomBytes } from 'node:crypto'; import { isCI } from 'ci-info'; -import debug from 'debug'; import { GlobalConfig } from './config.js'; import * as KEY from './config-keys.js'; import { post } from './post.js'; @@ -13,6 +12,13 @@ export type TelemetryEvent = { eventName: string; payload: Record } // In the event of significant policy changes, update this! const VALID_TELEMETRY_NOTICE_DATE = '2023-08-25'; +/** + * Get the debug function from global (set by astro's logger) + */ +function getDebug(): ((type: string, ...args: any[]) => void) | undefined { + return (globalThis as any)._astroGlobalDebug; +} + type EventMeta = SystemInfo; interface EventContext extends ProjectInfo { anonymousId: string; @@ -22,7 +28,6 @@ export class AstroTelemetry { private _anonymousSessionId: string | undefined; private _anonymousProjectInfo: ProjectInfo | undefined; private config = new GlobalConfig({ name: 'astro' }); - private debug = debug('astro:telemetry'); private isCI = isCI; private env = process.env; @@ -108,20 +113,21 @@ export class AstroTelemetry { } async notify(callback: () => boolean | Promise) { + const debug = getDebug(); if (this.isDisabled || this.isCI) { - this.debug(`[notify] telemetry has been disabled`); + debug?.('telemetry', `[notify] telemetry has been disabled`); return; } // The end-user has already been notified about our telemetry integration! // Don't bother them about it again. if (this.isValidNotice()) { - this.debug(`[notify] last notified on ${this.notifyDate}`); + debug?.('telemetry', `[notify] last notified on ${this.notifyDate}`); return; } const enabled = await callback(); this.config.set(KEY.TELEMETRY_NOTIFY_DATE, new Date().valueOf().toString()); this.config.set(KEY.TELEMETRY_ENABLED, enabled); - this.debug(`[notify] telemetry has been ${enabled ? 'enabled' : 'disabled'}`); + debug?.('telemetry', `[notify] telemetry has been ${enabled ? 'enabled' : 'disabled'}`); } async record(event: TelemetryEvent | TelemetryEvent[] = []) { @@ -130,9 +136,11 @@ export class AstroTelemetry { return Promise.resolve(); } + const debug = getDebug(); + // Skip recording telemetry if the feature is disabled if (this.isDisabled) { - this.debug('[record] telemetry has been disabled'); + debug?.('telemetry', '[record] telemetry has been disabled'); return Promise.resolve(); } @@ -152,10 +160,15 @@ export class AstroTelemetry { context.anonymousId = `CI.${meta.ciName || 'UNKNOWN'}`; } - if (this.debug.enabled) { + // Check if debug is enabled by trying to call it - if DEBUG is not set, nothing happens + const debugOutput = + process.env.DEBUG?.includes('astro:telemetry') || + process.env.DEBUG?.includes('astro:*') || + process.env.DEBUG === '*'; + if (debugOutput && debug) { // Print to standard error to simplify selecting the output - this.debug({ context, meta }); - this.debug(JSON.stringify(events, null, 2)); + debug('telemetry', { context, meta }); + debug('telemetry', JSON.stringify(events, null, 2)); // Do not send the telemetry data if debugging. Users may use this feature // to preview what data would be sent. return Promise.resolve(); @@ -166,7 +179,7 @@ export class AstroTelemetry { events, }).catch((err) => { // Log the error to the debugger, but otherwise do nothing. - this.debug(`Error sending event: ${err.message}`); + debug?.('telemetry', `Error sending event: ${err.message}`); }); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e39dc12b60d5..d52a74b3bd50 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -541,15 +541,15 @@ importers: common-ancestor-path: specifier: ^2.0.0 version: 2.0.0 + consola: + specifier: ^3.2.3 + version: 3.4.2 cookie: specifier: ^1.1.1 version: 1.1.1 cssesc: specifier: ^3.0.0 version: 3.0.0 - debug: - specifier: ^4.4.3 - version: 4.4.3(supports-color@8.1.1) deterministic-object-hash: specifier: ^2.0.2 version: 2.0.2 @@ -6986,9 +6986,9 @@ importers: ci-info: specifier: ^4.4.0 version: 4.4.0 - debug: - specifier: ^4.4.3 - version: 4.4.3(supports-color@8.1.1) + consola: + specifier: ^3.2.3 + version: 3.4.2 dlv: specifier: ^1.1.3 version: 1.1.3 @@ -7005,9 +7005,6 @@ importers: specifier: ^1.1.0 version: 1.1.0 devDependencies: - '@types/debug': - specifier: ^4.1.12 - version: 4.1.12 '@types/dlv': specifier: ^1.1.5 version: 1.1.5 From 7e073a71c024910eb0c84e170b25e1818f61cfc5 Mon Sep 17 00:00:00 2001 From: ematipico Date: Wed, 18 Feb 2026 14:25:18 +0000 Subject: [PATCH 2/9] remove consola --- packages/astro/package.json | 2 -- packages/telemetry/package.json | 1 - packages/telemetry/test/index.test.js | 46 +++++++++++++++++++++------ pnpm-lock.yaml | 9 ------ 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/packages/astro/package.json b/packages/astro/package.json index a6a06697e348..7598ff47fb0d 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -129,7 +129,6 @@ "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", - "consola": "^3.2.3", "cookie": "^1.1.1", "cssesc": "^3.0.0", "deterministic-object-hash": "^2.0.2", @@ -181,7 +180,6 @@ "@playwright/test": "1.58.2", "@types/aria-query": "^5.0.4", "@types/cssesc": "^3.0.2", - "@types/debug": "^4.1.12", "@types/dlv": "^1.1.5", "@types/hast": "^3.0.4", "@types/html-escaper": "3.0.4", diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json index 435719aa96fd..e68ce7e50783 100644 --- a/packages/telemetry/package.json +++ b/packages/telemetry/package.json @@ -30,7 +30,6 @@ ], "dependencies": { "ci-info": "^4.4.0", - "consola": "^3.2.3", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^4.0.0", diff --git a/packages/telemetry/test/index.test.js b/packages/telemetry/test/index.test.js index 47d64198c282..2bfc353614de 100644 --- a/packages/telemetry/test/index.test.js +++ b/packages/telemetry/test/index.test.js @@ -4,7 +4,7 @@ import { AstroTelemetry } from '../dist/index.js'; function setup() { const config = new Map(); - const telemetry = new AstroTelemetry({ version: '0.0.0-test.1' }); + const telemetry = new AstroTelemetry({ astroVersion: '0.0.0-test.1', viteVersion: '0.0.0' }); const logs = []; // Stub isCI to false so we can test user-facing behavior telemetry.isCI = false; @@ -12,11 +12,32 @@ function setup() { telemetry.env = {}; // Override config so we can inspect it telemetry.config = config; - // Override debug so we can inspect it - telemetry.debug.enabled = true; - telemetry.debug.log = (...args) => logs.push(args); - return { telemetry, config, logs }; + // Mock the global debug function to capture logs + const originalDebug = globalThis._astroGlobalDebug; + globalThis._astroGlobalDebug = (type, ...args) => { + if (type === 'telemetry') { + logs.push(args); + } + // Call original if it exists (for other namespaces) + if (originalDebug) { + originalDebug(type, ...args); + } + }; + + // Enable debug for telemetry + const oldDebug = process.env.DEBUG; + process.env.DEBUG = 'astro:telemetry'; + + return { + telemetry, + config, + logs, + cleanup: () => { + globalThis._astroGlobalDebug = originalDebug; + process.env.DEBUG = oldDebug; + }, + }; } describe('AstroTelemetry', () => { let oldCI; @@ -29,11 +50,12 @@ describe('AstroTelemetry', () => { process.env.CI = oldCI; }); it('initializes when expected arguments are given', () => { - const { telemetry } = setup(); + const { telemetry, cleanup } = setup(); assert(telemetry instanceof AstroTelemetry); + cleanup(); }); it('does not record event if disabled', async () => { - const { telemetry, config, logs } = setup(); + const { telemetry, config, logs, cleanup } = setup(); telemetry.setEnabled(false); const [key] = Array.from(config.keys()); assert.notEqual(key, undefined); @@ -45,9 +67,10 @@ describe('AstroTelemetry', () => { const [log] = logs; assert.notEqual(log, undefined); assert.match(logs.join(''), /disabled/); + cleanup(); }); it('records event if enabled', async () => { - const { telemetry, config, logs } = setup(); + const { telemetry, config, logs, cleanup } = setup(); telemetry.setEnabled(true); const [key] = Array.from(config.keys()); assert.notEqual(key, undefined); @@ -56,9 +79,10 @@ describe('AstroTelemetry', () => { assert.equal(telemetry.isDisabled, false); await telemetry.record(['TEST']); assert.equal(logs.length, 2); + cleanup(); }); it('respects disable from notify', async () => { - const { telemetry, config, logs } = setup(); + const { telemetry, config, logs, cleanup } = setup(); await telemetry.notify(() => false); const [key] = Array.from(config.keys()); assert.notEqual(key, undefined); @@ -68,9 +92,10 @@ describe('AstroTelemetry', () => { const [log] = logs; assert.notEqual(log, undefined); assert.match(logs.join(''), /disabled/); + cleanup(); }); it('respects enable from notify', async () => { - const { telemetry, config, logs } = setup(); + const { telemetry, config, logs, cleanup } = setup(); await telemetry.notify(() => true); const [key] = Array.from(config.keys()); assert.notEqual(key, undefined); @@ -80,5 +105,6 @@ describe('AstroTelemetry', () => { const [log] = logs; assert.notEqual(log, undefined); assert.match(logs.join(''), /enabled/); + cleanup(); }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d52a74b3bd50..8f8974bd11ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -541,9 +541,6 @@ importers: common-ancestor-path: specifier: ^2.0.0 version: 2.0.0 - consola: - specifier: ^3.2.3 - version: 3.4.2 cookie: specifier: ^1.1.1 version: 1.1.1 @@ -683,9 +680,6 @@ importers: '@types/cssesc': specifier: ^3.0.2 version: 3.0.2 - '@types/debug': - specifier: ^4.1.12 - version: 4.1.12 '@types/dlv': specifier: ^1.1.5 version: 1.1.5 @@ -6986,9 +6980,6 @@ importers: ci-info: specifier: ^4.4.0 version: 4.4.0 - consola: - specifier: ^3.2.3 - version: 3.4.2 dlv: specifier: ^1.1.3 version: 1.1.3 From 2c79511a46c2ff26d59235c635323e14a1c674c8 Mon Sep 17 00:00:00 2001 From: ematipico Date: Thu, 19 Feb 2026 14:35:26 +0000 Subject: [PATCH 3/9] a bunch of fixes eheh --- biome.jsonc | 2 +- packages/astro/components/Code.astro | 22 ++++++++++++----- .../src/assets/fonts/vite-plugin-fonts.ts | 2 +- packages/astro/src/cli/add/index.ts | 4 ++-- packages/astro/src/cli/build/index.ts | 2 +- packages/astro/src/cli/dev/index.ts | 2 +- packages/astro/src/cli/preferences/index.ts | 2 +- packages/astro/src/cli/preview/index.ts | 2 +- packages/astro/src/cli/sync/index.ts | 2 +- packages/astro/src/cli/telemetry/index.ts | 2 +- packages/astro/src/cli/throw-and-exit.ts | 2 +- packages/astro/src/core/app/dev/app.ts | 2 +- packages/astro/src/core/config/config.ts | 2 +- packages/astro/src/core/dev/dev.ts | 5 ++-- packages/astro/src/core/dev/restart.ts | 2 +- packages/astro/src/core/logger/vite.ts | 2 +- packages/astro/src/core/messages/node.ts | 21 ++++++++++++++++ .../core/{messages.ts => messages/runtime.ts} | 20 +++------------- .../src/core/preview/static-preview-server.ts | 2 +- packages/astro/src/core/util-runtime.ts | 24 +++++++++++++++++++ packages/astro/src/vite-plugin-app/app.ts | 2 +- .../src/vite-plugin-astro-server/error.ts | 2 +- .../test/units/config/config-validate.test.js | 2 +- packages/integrations/cloudflare/package.json | 1 + packages/integrations/cloudflare/src/index.ts | 2 ++ .../test/astro-dev-platform.test.js | 2 ++ packages/markdown/remark/package.json | 5 +++- packages/markdown/remark/src/shiki.ts | 10 ++++++++ pnpm-lock.yaml | 3 +++ 29 files changed, 108 insertions(+), 45 deletions(-) create mode 100644 packages/astro/src/core/messages/node.ts rename packages/astro/src/core/{messages.ts => messages/runtime.ts} (92%) create mode 100644 packages/astro/src/core/util-runtime.ts diff --git a/biome.jsonc b/biome.jsonc index 2251f5e4db13..5d842c8e8096 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -137,7 +137,7 @@ // We don't want to have node modules in code that should be runtime agnostic "includes": [ "**/packages/astro/src/**/runtime/**/*.ts", - "**/packages/astro/src/**/runtime.ts" + "**/packages/astro/src/**/*runtime*.ts" ], "linter": { "rules": { diff --git a/packages/astro/components/Code.astro b/packages/astro/components/Code.astro index 860ea9ceea2e..d3f380863461 100644 --- a/packages/astro/components/Code.astro +++ b/packages/astro/components/Code.astro @@ -1,10 +1,7 @@ --- -import { - type ThemePresets, - createShikiHighlighter, - globalShikiStyleCollector, - transformerStyleToClass, -} from '@astrojs/markdown-remark'; +import { createShikiHighlighter, type ThemePresets } from '@astrojs/markdown-remark/shiki'; +import { globalShikiStyleCollector } from '@astrojs/markdown-remark/shiki-style-collector'; +import { transformerStyleToClass } from '@astrojs/markdown-remark/transformers/style-to-class'; import type { ShikiTransformer, ThemeRegistration, ThemeRegistrationRaw } from 'shiki'; import { bundledLanguages } from 'shiki/langs'; import type { CodeLanguage } from '../dist/types/public/common.js'; @@ -13,6 +10,10 @@ import type { HTMLAttributes } from '../types.js'; // Code.astro always uses Shiki, so import the virtual CSS module import 'virtual:astro:shiki-styles.css'; +// Import JavaScript engine for Cloudflare Workers +// Workers can't load WASM files from filesystem, so use JS engine instead +import { createJavaScriptRegexEngine } from 'shiki/engine/javascript'; + interface Props extends Omit, 'lang'> { /** The code to highlight. Required. */ code: string; @@ -111,6 +112,14 @@ if (typeof lang === 'object') { } } +// Detect Cloudflare Workers environment +// Workers can't load WASM files from filesystem, so use JavaScript RegExp engine +// Check for Cloudflare context that's injected by @astrojs/cloudflare adapter +const isCloudflareWorkers = + ('cf' in Astro.request) || // Cloudflare request object + ('cfContext' in Astro.locals) || // Cloudflare context in locals + ('cloudflare' in Astro.locals); // Alternative location + const highlighter = await createShikiHighlighter({ langs: [ typeof lang === 'string' @@ -122,6 +131,7 @@ const highlighter = await createShikiHighlighter({ ], theme, themes, + ...(isCloudflareWorkers ? { engine: createJavaScriptRegexEngine() } : {}), }); // Combine style-to-class transformer with user-provided transformers diff --git a/packages/astro/src/assets/fonts/vite-plugin-fonts.ts b/packages/astro/src/assets/fonts/vite-plugin-fonts.ts index 58a533a6a8a4..ed890f0ea443 100644 --- a/packages/astro/src/assets/fonts/vite-plugin-fonts.ts +++ b/packages/astro/src/assets/fonts/vite-plugin-fonts.ts @@ -8,7 +8,7 @@ import { generateCspDigest } from '../../core/encryption.js'; import { collectErrorMetadata } from '../../core/errors/dev/utils.js'; import { AstroError, AstroErrorData, isAstroError } from '../../core/errors/index.js'; import type { Logger } from '../../core/logger/core.js'; -import { formatErrorMessage } from '../../core/messages.js'; +import { formatErrorMessage } from '../../core/messages/runtime.js'; import { appendForwardSlash, joinPaths, prependForwardSlash } from '../../core/path.js'; import { getClientOutputDirectory } from '../../prerender/utils.js'; import type { AstroSettings } from '../../types/astro.js'; diff --git a/packages/astro/src/cli/add/index.ts b/packages/astro/src/cli/add/index.ts index 8fa02854031d..ae1dcc62a83a 100644 --- a/packages/astro/src/cli/add/index.ts +++ b/packages/astro/src/cli/add/index.ts @@ -24,8 +24,8 @@ import { updateTSConfigForFramework, } from '../../core/config/tsconfig.js'; import type { Logger } from '../../core/logger/core.js'; -import * as msg from '../../core/messages.js'; -import { printHelp } from '../../core/messages.js'; +import * as msg from '../../core/messages/runtime.js'; +import { printHelp } from '../../core/messages/runtime.js'; import { appendForwardSlash } from '../../core/path.js'; import { ensureProcessNodeEnv, parseNpmName } from '../../core/util.js'; import { eventCliSession, telemetry } from '../../events/index.js'; diff --git a/packages/astro/src/cli/build/index.ts b/packages/astro/src/cli/build/index.ts index 30f19bdccaab..c5e23ac5816c 100644 --- a/packages/astro/src/cli/build/index.ts +++ b/packages/astro/src/cli/build/index.ts @@ -1,5 +1,5 @@ import _build from '../../core/build/index.js'; -import { printHelp } from '../../core/messages.js'; +import { printHelp } from '../../core/messages/runtime.js'; import { type Flags, flagsToAstroInlineConfig } from '../flags.js'; interface BuildOptions { diff --git a/packages/astro/src/cli/dev/index.ts b/packages/astro/src/cli/dev/index.ts index f5ddba717c7b..60bc5c2b9264 100644 --- a/packages/astro/src/cli/dev/index.ts +++ b/packages/astro/src/cli/dev/index.ts @@ -1,6 +1,6 @@ import colors from 'piccolore'; import devServer from '../../core/dev/index.js'; -import { printHelp } from '../../core/messages.js'; +import { printHelp } from '../../core/messages/runtime.js'; import { type Flags, flagsToAstroInlineConfig } from '../flags.js'; interface DevOptions { diff --git a/packages/astro/src/cli/preferences/index.ts b/packages/astro/src/cli/preferences/index.ts index 0be869e02083..7b8f5953048a 100644 --- a/packages/astro/src/cli/preferences/index.ts +++ b/packages/astro/src/cli/preferences/index.ts @@ -6,7 +6,7 @@ import colors from 'piccolore'; import { resolveConfig } from '../../core/config/config.js'; import { createSettings } from '../../core/config/settings.js'; import { collectErrorMetadata } from '../../core/errors/dev/utils.js'; -import * as msg from '../../core/messages.js'; +import * as msg from '../../core/messages/runtime.js'; import { DEFAULT_PREFERENCES } from '../../preferences/defaults.js'; import { coerce, isValidKey, type PreferenceKey } from '../../preferences/index.js'; import type { AstroSettings } from '../../types/astro.js'; diff --git a/packages/astro/src/cli/preview/index.ts b/packages/astro/src/cli/preview/index.ts index 9607d0bf1ef9..5c6a08f097e2 100644 --- a/packages/astro/src/cli/preview/index.ts +++ b/packages/astro/src/cli/preview/index.ts @@ -1,5 +1,5 @@ import colors from 'piccolore'; -import { printHelp } from '../../core/messages.js'; +import { printHelp } from '../../core/messages/runtime.js'; import previewServer from '../../core/preview/index.js'; import { type Flags, flagsToAstroInlineConfig } from '../flags.js'; diff --git a/packages/astro/src/cli/sync/index.ts b/packages/astro/src/cli/sync/index.ts index 7f488836d6cf..c50742b4b8ad 100644 --- a/packages/astro/src/cli/sync/index.ts +++ b/packages/astro/src/cli/sync/index.ts @@ -1,4 +1,4 @@ -import { printHelp } from '../../core/messages.js'; +import { printHelp } from '../../core/messages/runtime.js'; import _sync from '../../core/sync/index.js'; import { type Flags, flagsToAstroInlineConfig } from '../flags.js'; diff --git a/packages/astro/src/cli/telemetry/index.ts b/packages/astro/src/cli/telemetry/index.ts index 13d12af562cc..4fa0defcb026 100644 --- a/packages/astro/src/cli/telemetry/index.ts +++ b/packages/astro/src/cli/telemetry/index.ts @@ -1,4 +1,4 @@ -import * as msg from '../../core/messages.js'; +import * as msg from '../../core/messages/runtime.js'; import { telemetry } from '../../events/index.js'; import { createLoggerFromFlags, type Flags } from '../flags.js'; diff --git a/packages/astro/src/cli/throw-and-exit.ts b/packages/astro/src/cli/throw-and-exit.ts index 239dab18091a..d66db31d8e11 100644 --- a/packages/astro/src/cli/throw-and-exit.ts +++ b/packages/astro/src/cli/throw-and-exit.ts @@ -2,7 +2,7 @@ import { collectErrorMetadata } from '../core/errors/dev/index.js'; import { isAstroConfigZodError } from '../core/errors/errors.js'; import { createSafeError } from '../core/errors/index.js'; import { debug } from '../core/logger/core.js'; -import { formatErrorMessage } from '../core/messages.js'; +import { formatErrorMessage } from '../core/messages/runtime.js'; import { eventError, telemetry } from '../events/index.js'; /** Display error and exit */ diff --git a/packages/astro/src/core/app/dev/app.ts b/packages/astro/src/core/app/dev/app.ts index 10378c848a02..ff64f5994eaa 100644 --- a/packages/astro/src/core/app/dev/app.ts +++ b/packages/astro/src/core/app/dev/app.ts @@ -16,7 +16,7 @@ import { ensure404Route } from '../../routing/astro-designed-error-pages.js'; import { matchRoute } from '../../routing/dev.js'; import type { RunnablePipeline } from '../../../vite-plugin-app/pipeline.js'; import type { RoutesList } from '../../../types/astro.js'; -import { req } from '../../messages.js'; +import { req } from '../../messages/runtime.js'; export class DevApp extends BaseApp { logger: Logger; diff --git a/packages/astro/src/core/config/config.ts b/packages/astro/src/core/config/config.ts index dce4bccf3876..08d48e430c54 100644 --- a/packages/astro/src/core/config/config.ts +++ b/packages/astro/src/core/config/config.ts @@ -12,7 +12,7 @@ import type { } from '../../types/public/config.js'; import { trackAstroConfigZodError } from '../errors/errors.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import { formatConfigErrorMessage } from '../messages.js'; +import { formatConfigErrorMessage } from '../messages/runtime.js'; import { mergeConfig } from './merge.js'; import { validateConfig } from './validate.js'; import { loadConfigWithVite } from './vite-load.js'; diff --git a/packages/astro/src/core/dev/dev.ts b/packages/astro/src/core/dev/dev.ts index 1b6fb8abd930..fa3bbd8f6624 100644 --- a/packages/astro/src/core/dev/dev.ts +++ b/packages/astro/src/core/dev/dev.ts @@ -11,7 +11,8 @@ import { MutableDataStore } from '../../content/mutable-data-store.js'; import { globalContentConfigObserver } from '../../content/utils.js'; import { telemetry } from '../../events/index.js'; import type { AstroInlineConfig } from '../../types/public/config.js'; -import * as msg from '../messages.js'; +import * as msg from '../messages/runtime.js'; +import { newVersionAvailable } from '../messages/node.js'; import { ensureProcessNodeEnv } from '../util.js'; import { startContainer } from './container.js'; import { createContainerWithAutomaticRestart } from './restart.js'; @@ -71,7 +72,7 @@ export default async function dev(inlineConfig: AstroInlineConfig): Promise { + return typeof value === 'object' && value != null; +} + +/** Cross-realm compatible URL */ +export function isURL(value: unknown): value is URL { + return Object.prototype.toString.call(value) === '[object URL]'; +} + +/** Wraps an object in an array. If an array is passed, ignore it. */ +export function arraify(target: T | T[]): T[] { + return Array.isArray(target) ? target : [target]; +} + +export function padMultilineString(source: string, n = 2) { + const lines = source.split(/\r?\n/); + return lines.map((l) => ` `.repeat(n) + l).join(`\n`); +} diff --git a/packages/astro/src/vite-plugin-app/app.ts b/packages/astro/src/vite-plugin-app/app.ts index c63a774a2886..66971e6179bc 100644 --- a/packages/astro/src/vite-plugin-app/app.ts +++ b/packages/astro/src/vite-plugin-app/app.ts @@ -23,7 +23,7 @@ import { getCustom404Route, getCustom500Route } from '../core/routing/helpers.js import { ensure404Route } from '../core/routing/astro-designed-error-pages.js'; import { matchRoute } from '../core/routing/dev.js'; import type { DevMatch, LogRequestPayload } from '../core/app/base.js'; -import { req } from '../core/messages.js'; +import { req } from '../core/messages/runtime.js'; export class AstroServerApp extends BaseApp { settings: AstroSettings; diff --git a/packages/astro/src/vite-plugin-astro-server/error.ts b/packages/astro/src/vite-plugin-astro-server/error.ts index 3cb04e914da4..ca726d852e98 100644 --- a/packages/astro/src/vite-plugin-astro-server/error.ts +++ b/packages/astro/src/vite-plugin-astro-server/error.ts @@ -1,7 +1,7 @@ import type { SSRManifest } from '../core/app/types.js'; import { collectErrorMetadata } from '../core/errors/dev/index.js'; import type { Logger } from '../core/logger/core.js'; -import { formatErrorMessage } from '../core/messages.js'; +import { formatErrorMessage } from '../core/messages/runtime.js'; import type { ModuleLoader } from '../core/module-loader/index.js'; export function recordServerError( diff --git a/packages/astro/test/units/config/config-validate.test.js b/packages/astro/test/units/config/config-validate.test.js index 04ab328eb77d..d3755dcf5f68 100644 --- a/packages/astro/test/units/config/config-validate.test.js +++ b/packages/astro/test/units/config/config-validate.test.js @@ -6,7 +6,7 @@ import * as z from 'zod/v4'; import { fontProviders } from '../../../dist/assets/fonts/providers/index.js'; import { LocalFontProvider } from '../../../dist/assets/fonts/providers/local.js'; import { validateConfig as _validateConfig } from '../../../dist/core/config/validate.js'; -import { formatConfigErrorMessage } from '../../../dist/core/messages.js'; +import { formatConfigErrorMessage } from '../../../dist/core/messages/runtime.js'; import { envField } from '../../../dist/env/config.js'; /** diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index 45916614b135..eb3167e25ea8 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -44,6 +44,7 @@ "@astrojs/internal-helpers": "workspace:*", "@astrojs/underscore-redirects": "workspace:*", "@cloudflare/vite-plugin": "^1.25.0", + "obug": "^2.1.1", "piccolore": "^0.1.3", "tinyglobby": "^0.2.15", "vite": "^7.3.1" diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index 71048175ce1e..096c3e4290d5 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -9,6 +9,7 @@ import { astroFrontmatterScanPlugin } from './esbuild-plugin-astro-frontmatter.j import { getParts } from './utils/generate-routes-json.js'; import { type ImageService, setImageConfig } from './utils/image-config.js'; import { createConfigPlugin } from './vite-plugin-config.js'; +import { createWasmUrlPlugin } from './vite-plugin-wasm-url.js'; import { cloudflareConfigCustomizer, DEFAULT_SESSION_KV_BINDING_NAME, @@ -190,6 +191,7 @@ export default function createIntegration(args?: Options): AstroIntegration { createConfigPlugin({ sessionKVBindingName, }), + createWasmUrlPlugin(), ], }, image: setImageConfig(args?.imageService ?? 'compile', config.image, command, logger), diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.js b/packages/integrations/cloudflare/test/astro-dev-platform.test.js index 779d2a1b2a25..e03d9689f45d 100644 --- a/packages/integrations/cloudflare/test/astro-dev-platform.test.js +++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.js @@ -64,10 +64,12 @@ describe('AstroDevPlatform', () => { const res = await fixture.fetch('/code-test'); assert.equal(res.status, 200); const html = await res.text(); + console.log('HTML output:', html); const $ = cheerio.load(html); // Verify the page rendered successfully with Code component assert.equal($('h1').text(), 'Testing Code Component'); // Verify the code block was rendered + console.log('Pre elements found:', $('pre').length); assert.ok($('pre').length > 0, 'Code block should be rendered'); }); }); diff --git a/packages/markdown/remark/package.json b/packages/markdown/remark/package.json index f77c4d6624ba..e8e1a03f88b5 100644 --- a/packages/markdown/remark/package.json +++ b/packages/markdown/remark/package.json @@ -13,7 +13,10 @@ "homepage": "https://astro.build", "main": "./dist/index.js", "exports": { - ".": "./dist/index.js" + ".": "./dist/index.js", + "./shiki": "./dist/shiki.js", + "./shiki-style-collector": "./dist/shiki-style-collector.js", + "./transformers/style-to-class": "./dist/transformers/style-to-class.js" }, "imports": { "#import-plugin": { diff --git a/packages/markdown/remark/src/shiki.ts b/packages/markdown/remark/src/shiki.ts index 1005254bbbbe..43d84c609ad7 100644 --- a/packages/markdown/remark/src/shiki.ts +++ b/packages/markdown/remark/src/shiki.ts @@ -34,6 +34,11 @@ export interface CreateShikiHighlighterOptions { theme?: ThemePresets | ThemeRegistration | ThemeRegistrationRaw; themes?: Record; langAlias?: HighlighterCoreOptions['langAlias']; + /** + * Custom regex engine for Shiki. + * Use JavaScript engine for environments that can't load WASM files (e.g. Cloudflare Workers). + */ + engine?: HighlighterCoreOptions['engine']; } export interface ShikiHighlighterHighlightOptions { @@ -81,6 +86,7 @@ export async function createShikiHighlighter({ theme = 'github-dark', themes = {}, langAlias = {}, + engine, }: CreateShikiHighlighterOptions = {}): Promise { theme = theme === 'css-variables' ? cssVariablesTheme() : theme; @@ -88,6 +94,7 @@ export async function createShikiHighlighter({ langs: ['plaintext', ...langs], langAlias, themes: Object.values(themes).length ? Object.values(themes) : [theme], + ...(engine ? { engine } : {}), }; const key = JSON.stringify(highlighterOptions, Object.keys(highlighterOptions).sort()); @@ -225,3 +232,6 @@ export async function createShikiHighlighter({ function normalizePropAsString(value: Properties[string]): string | null { return Array.isArray(value) ? value.join(' ') : (value as string | null); } + +// Re-export ThemePresets type for consumers +export type { ThemePresets }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f8974bd11ad..60547f21cb84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4912,6 +4912,9 @@ importers: '@cloudflare/vite-plugin': specifier: ^1.25.0 version: 1.25.0(@cloudflare/workers-types@4.20260213.0)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))(workerd@1.20260212.0) + obug: + specifier: ^2.1.1 + version: 2.1.1 piccolore: specifier: ^0.1.3 version: 0.1.3 From 7b235dbf57e6263d4e51bbb8e8819f5a7d5f5d41 Mon Sep 17 00:00:00 2001 From: ematipico Date: Thu, 19 Feb 2026 14:57:29 +0000 Subject: [PATCH 4/9] revert changes --- packages/astro/package.json | 2 + packages/astro/src/core/logger/node.ts | 121 ++---------------- packages/integrations/cloudflare/src/index.ts | 2 - pnpm-lock.yaml | 6 + 4 files changed, 20 insertions(+), 111 deletions(-) diff --git a/packages/astro/package.json b/packages/astro/package.json index 7598ff47fb0d..fd32c3d8252a 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -148,6 +148,7 @@ "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", + "obug": "^2.1.1", "p-limit": "^7.3.0", "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", @@ -180,6 +181,7 @@ "@playwright/test": "1.58.2", "@types/aria-query": "^5.0.4", "@types/cssesc": "^3.0.2", + "@types/debug": "^4.1.12", "@types/dlv": "^1.1.5", "@types/hast": "^3.0.4", "@types/html-escaper": "3.0.4", diff --git a/packages/astro/src/core/logger/node.ts b/packages/astro/src/core/logger/node.ts index fe4405152f77..e43f98eaf4c8 100644 --- a/packages/astro/src/core/logger/node.ts +++ b/packages/astro/src/core/logger/node.ts @@ -1,6 +1,5 @@ import type { Writable } from 'node:stream'; -import { inspect } from 'node:util'; -import colors from 'piccolore'; +import { createDebug, enable as obugEnable } from 'obug'; import type { AstroInlineConfig } from '../../types/public/config.js'; import { Logger } from './core.js'; import { getEventPrefix, type LogMessage, type LogWritable, levels } from './core.js'; @@ -25,120 +24,27 @@ export const nodeLogDestination: LogWritable = { }, }; -interface DebugLogger { - lastTime: number; - namespace: string; - color: (text: string) => string; -} - -const debuggers: Record = {}; - -// Color functions array for namespace coloring (similar to debug package) -const colorFunctions = [ - colors.cyan, - colors.magenta, - colors.blue, - colors.yellow, - colors.green, - colors.red, - colors.gray, -]; - -function selectColorFunction(namespace: string): (text: string) => string { - let hash = 0; - for (let i = 0; i < namespace.length; i++) { - hash = (hash << 5) - hash + namespace.charCodeAt(i); - hash |= 0; - } - return colorFunctions[Math.abs(hash) % colorFunctions.length]; -} - -function humanizeTime(ms: number): string { - if (ms >= 1000) { - return `${(ms / 1000).toFixed(1)}s`; - } - return `${ms}ms`; -} +const debuggers: Record> = {}; /** * Emit a message only shown in debug mode. - * Mimics the debug package's behavior and format. + * Astro (along with many of its dependencies) uses the `debug` package for debug logging. * You can enable these logs with the `DEBUG=astro:*` environment variable. + * More info https://github.com/debug-js/debug#environment-variables */ -function debug(type: string, ...messages: any[]) { +function debug(type: string, ...messages: Array) { const namespace = `astro:${type}`; - - // Check if debug is enabled for this namespace before doing anything - if (!isDebugEnabled(namespace)) { - return; - } - - // Initialize logger for this namespace if needed - if (!debuggers[namespace]) { - debuggers[namespace] = { - lastTime: Date.now(), - namespace, - color: selectColorFunction(namespace), - }; - } - - const logger = debuggers[namespace]; - const now = Date.now(); - const delta = now - logger.lastTime; - logger.lastTime = now; - - const prefix = logger.color(namespace); - const diff = logger.color(`+${humanizeTime(delta)}`); - - // Format each message - for (const message of messages) { - let formatted: string; - if (typeof message === 'string') { - formatted = message; - } else { - // Use util.inspect for objects (similar to debug package) - formatted = inspect(message, { colors: true, depth: null }); - } - - // Add prefix to each line (like debug package does) - const lines = formatted.split('\n'); - for (let i = 0; i < lines.length; i++) { - if (i === 0) { - process.stderr.write(` ${prefix} ${lines[i]} ${diff}\n`); - } else { - process.stderr.write(` ${prefix} ${lines[i]}\n`); - } - } - } + debuggers[namespace] = debuggers[namespace] || createDebug(namespace); + return debuggers[namespace](...(messages as [any, ...any[]])); } -/** - * Check if debug logging is enabled for a namespace based on DEBUG env var. - * Supports patterns like: DEBUG=astro:*, DEBUG=astro:cli, DEBUG=* - */ -function isDebugEnabled(namespace: string): boolean { - const envDebug = process.env.DEBUG; - if (!envDebug) return false; - - const patterns = envDebug.split(',').map((p) => p.trim()); - return patterns.some((pattern) => { - if (pattern === '*') return true; - if (pattern.endsWith(':*')) { - const prefix = pattern.slice(0, -2); - return namespace === prefix || namespace.startsWith(prefix + ':'); - } - return namespace === pattern; - }); -} +// This is gross, but necessary since we are depending on globals. +(globalThis as any)._astroGlobalDebug = debug; -/** - * Enable verbose debug logging for Astro and Vite. - * This updates the DEBUG environment variable. - * Since debug() now checks isDebugEnabled() on every call, we don't need to recreate loggers. - */ export function enableVerboseLogging() { - process.env.DEBUG = 'astro:*,vite:*'; - + // Enable debug logging via obug's enable function + // obug provides the same API as debug package + obugEnable('astro:*,vite:*'); debug('cli', '--verbose flag enabled! Enabling: DEBUG="astro:*,vite:*"'); debug( 'cli', @@ -146,9 +52,6 @@ export function enableVerboseLogging() { ); } -// This is gross, but necessary since we are depending on globals. -(globalThis as any)._astroGlobalDebug = debug; - export function createNodeLogger(inlineConfig: AstroInlineConfig): Logger { if (inlineConfig.logger) return inlineConfig.logger; diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index 096c3e4290d5..71048175ce1e 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -9,7 +9,6 @@ import { astroFrontmatterScanPlugin } from './esbuild-plugin-astro-frontmatter.j import { getParts } from './utils/generate-routes-json.js'; import { type ImageService, setImageConfig } from './utils/image-config.js'; import { createConfigPlugin } from './vite-plugin-config.js'; -import { createWasmUrlPlugin } from './vite-plugin-wasm-url.js'; import { cloudflareConfigCustomizer, DEFAULT_SESSION_KV_BINDING_NAME, @@ -191,7 +190,6 @@ export default function createIntegration(args?: Options): AstroIntegration { createConfigPlugin({ sessionKVBindingName, }), - createWasmUrlPlugin(), ], }, image: setImageConfig(args?.imageService ?? 'compile', config.image, command, logger), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60547f21cb84..f46cfb0f3a8f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -598,6 +598,9 @@ importers: neotraverse: specifier: ^0.6.18 version: 0.6.18 + obug: + specifier: ^2.1.1 + version: 2.1.1 p-limit: specifier: ^7.3.0 version: 7.3.0 @@ -680,6 +683,9 @@ importers: '@types/cssesc': specifier: ^3.0.2 version: 3.0.2 + '@types/debug': + specifier: ^4.1.12 + version: 4.1.12 '@types/dlv': specifier: ^1.1.5 version: 1.1.5 From db9e89ad011e55835e5925134a0490605f6d8b71 Mon Sep 17 00:00:00 2001 From: ematipico Date: Thu, 19 Feb 2026 15:20:58 +0000 Subject: [PATCH 5/9] fix linting warnings --- packages/astro/src/core/config/merge.ts | 2 +- packages/astro/src/core/create-vite.ts | 2 +- packages/astro/src/core/errors/dev/utils.ts | 17 ---------------- packages/astro/src/core/util.ts | 20 ------------------- packages/integrations/cloudflare/package.json | 1 - .../test/astro-dev-platform.test.js | 2 -- 6 files changed, 2 insertions(+), 42 deletions(-) diff --git a/packages/astro/src/core/config/merge.ts b/packages/astro/src/core/config/merge.ts index 6cfa2778d608..5f6487147998 100644 --- a/packages/astro/src/core/config/merge.ts +++ b/packages/astro/src/core/config/merge.ts @@ -1,7 +1,7 @@ import { mergeConfig as mergeViteConfig } from 'vite'; import type { DeepPartial } from '../../type-utils.js'; import type { AstroConfig, AstroInlineConfig } from '../../types/public/index.js'; -import { arraify, isObject, isURL } from '../util.js'; +import { arraify, isObject, isURL } from '../util-runtime.js'; function mergeConfigRecursively( defaults: Record, diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 369027e35cdf..f58ecce9b9ba 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -46,7 +46,7 @@ import { vitePluginMiddleware } from './middleware/vite-plugin.js'; import { joinPaths } from './path.js'; import { vitePluginServerIslands } from './server-islands/vite-plugin-server-islands.js'; import { vitePluginSessionDriver } from './session/vite-plugin.js'; -import { isObject } from './util.js'; +import { isObject } from './util-runtime.js'; import { vitePluginEnvironment } from '../vite-plugin-environment/index.js'; import { ASTRO_VITE_ENVIRONMENT_NAMES } from './constants.js'; import { vitePluginChromedevtools } from '../vite-plugin-chromedevtools/index.js'; diff --git a/packages/astro/src/core/errors/dev/utils.ts b/packages/astro/src/core/errors/dev/utils.ts index 7768e6c38403..c55a639c130e 100644 --- a/packages/astro/src/core/errors/dev/utils.ts +++ b/packages/astro/src/core/errors/dev/utils.ts @@ -9,7 +9,6 @@ import type { SSRError } from '../../../types/public/internal.js'; import { removeLeadingForwardSlashWindows } from '../../path.js'; import { normalizePath } from '../../viteUtils.js'; import { AggregateError, type ErrorWithMetadata } from '../errors.js'; -import { AstroErrorData } from '../index.js'; import { codeFrame } from '../printer.js'; import { normalizeLF } from '../utils.js'; @@ -223,22 +222,6 @@ function cleanErrorStack(stack: string) { .join('\n'); } -export function getDocsForError(err: ErrorWithMetadata): string | undefined { - if (err.name !== 'UnknownError' && err.name in AstroErrorData) { - return `https://docs.astro.build/en/reference/errors/${getKebabErrorName(err.name)}/`; - } - - return undefined; - - /** - * The docs has kebab-case urls for errors, so we need to convert the error name - * @param errorName - */ - function getKebabErrorName(errorName: string): string { - return errorName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - } -} - const linkRegex = /\[([^[]+)\]\(([^)]*)\)/g; const boldRegex = /\*\*(.+)\*\*/g; const urlRegex = / ((?:https?|ftp):\/\/[-\w+&@#\\/%?=~|!:,.;]*[-\w+&@#\\/%=~|])/gi; diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index 8b96af135e3a..9b7807480f71 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -8,16 +8,6 @@ import { hasSpecialQueries } from '../vite-plugin-utils/index.js'; import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './constants.js'; import { removeQueryString, removeTrailingForwardSlash, slash } from './path.js'; -/** Returns true if argument is an object of any prototype/class (but not null). */ -export function isObject(value: unknown): value is Record { - return typeof value === 'object' && value != null; -} - -/** Cross-realm compatible URL */ -export function isURL(value: unknown): value is URL { - return Object.prototype.toString.call(value) === '[object URL]'; -} - /** Check if a file is a markdown file based on its extension */ export function isMarkdownFile(fileId: string, option?: { suffix?: string }): boolean { if (hasSpecialQueries(fileId)) { @@ -31,16 +21,6 @@ export function isMarkdownFile(fileId: string, option?: { suffix?: string }): bo return false; } -/** Wraps an object in an array. If an array is passed, ignore it. */ -export function arraify(target: T | T[]): T[] { - return Array.isArray(target) ? target : [target]; -} - -export function padMultilineString(source: string, n = 2) { - const lines = source.split(/\r?\n/); - return lines.map((l) => ` `.repeat(n) + l).join(`\n`); -} - const STATUS_CODE_PAGES = new Set(['/404', '/500']); /** diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index eb3167e25ea8..45916614b135 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -44,7 +44,6 @@ "@astrojs/internal-helpers": "workspace:*", "@astrojs/underscore-redirects": "workspace:*", "@cloudflare/vite-plugin": "^1.25.0", - "obug": "^2.1.1", "piccolore": "^0.1.3", "tinyglobby": "^0.2.15", "vite": "^7.3.1" diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.js b/packages/integrations/cloudflare/test/astro-dev-platform.test.js index e03d9689f45d..779d2a1b2a25 100644 --- a/packages/integrations/cloudflare/test/astro-dev-platform.test.js +++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.js @@ -64,12 +64,10 @@ describe('AstroDevPlatform', () => { const res = await fixture.fetch('/code-test'); assert.equal(res.status, 200); const html = await res.text(); - console.log('HTML output:', html); const $ = cheerio.load(html); // Verify the page rendered successfully with Code component assert.equal($('h1').text(), 'Testing Code Component'); // Verify the code block was rendered - console.log('Pre elements found:', $('pre').length); assert.ok($('pre').length > 0, 'Code block should be rendered'); }); }); From 81e158db67f7c2243f1f5a570bf447a6dcfc4602 Mon Sep 17 00:00:00 2001 From: ematipico Date: Thu, 19 Feb 2026 15:23:57 +0000 Subject: [PATCH 6/9] remove another package --- packages/astro/package.json | 1 - pnpm-lock.yaml | 6 ------ 2 files changed, 7 deletions(-) diff --git a/packages/astro/package.json b/packages/astro/package.json index fd32c3d8252a..b69a2f00bf40 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -181,7 +181,6 @@ "@playwright/test": "1.58.2", "@types/aria-query": "^5.0.4", "@types/cssesc": "^3.0.2", - "@types/debug": "^4.1.12", "@types/dlv": "^1.1.5", "@types/hast": "^3.0.4", "@types/html-escaper": "3.0.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f46cfb0f3a8f..52313c74b813 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -683,9 +683,6 @@ importers: '@types/cssesc': specifier: ^3.0.2 version: 3.0.2 - '@types/debug': - specifier: ^4.1.12 - version: 4.1.12 '@types/dlv': specifier: ^1.1.5 version: 1.1.5 @@ -4918,9 +4915,6 @@ importers: '@cloudflare/vite-plugin': specifier: ^1.25.0 version: 1.25.0(@cloudflare/workers-types@4.20260213.0)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))(workerd@1.20260212.0) - obug: - specifier: ^2.1.1 - version: 2.1.1 piccolore: specifier: ^0.1.3 version: 0.1.3 From e6b9610963a00026cda035fcdd9763f7f6dc3e84 Mon Sep 17 00:00:00 2001 From: ematipico Date: Thu, 19 Feb 2026 15:26:12 +0000 Subject: [PATCH 7/9] changeset --- .changeset/floppy-cases-hug.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/floppy-cases-hug.md diff --git a/.changeset/floppy-cases-hug.md b/.changeset/floppy-cases-hug.md new file mode 100644 index 000000000000..5e453a25456c --- /dev/null +++ b/.changeset/floppy-cases-hug.md @@ -0,0 +1,6 @@ +--- +'@astrojs/cloudflare': patch +'astro': patch +--- + +Fixes an issue where the use of the `Code` component would result in an unexpected error. From 171816280d4fcc411dd6420890e1fcfbe712772d Mon Sep 17 00:00:00 2001 From: ematipico Date: Fri, 20 Feb 2026 13:17:21 +0000 Subject: [PATCH 8/9] Use better soluition for workerd engine Co-authored-by: rururux --- packages/astro/components/Code.astro | 12 ------------ packages/markdown/remark/package.json | 5 +++++ .../markdown/remark/src/shiki-engine-default.ts | 7 +++++++ .../markdown/remark/src/shiki-engine-workerd.ts | 8 ++++++++ packages/markdown/remark/src/shiki.ts | 16 +++++++++------- 5 files changed, 29 insertions(+), 19 deletions(-) create mode 100644 packages/markdown/remark/src/shiki-engine-default.ts create mode 100644 packages/markdown/remark/src/shiki-engine-workerd.ts diff --git a/packages/astro/components/Code.astro b/packages/astro/components/Code.astro index d3f380863461..322da1f3d09a 100644 --- a/packages/astro/components/Code.astro +++ b/packages/astro/components/Code.astro @@ -10,9 +10,6 @@ import type { HTMLAttributes } from '../types.js'; // Code.astro always uses Shiki, so import the virtual CSS module import 'virtual:astro:shiki-styles.css'; -// Import JavaScript engine for Cloudflare Workers -// Workers can't load WASM files from filesystem, so use JS engine instead -import { createJavaScriptRegexEngine } from 'shiki/engine/javascript'; interface Props extends Omit, 'lang'> { /** The code to highlight. Required. */ @@ -112,14 +109,6 @@ if (typeof lang === 'object') { } } -// Detect Cloudflare Workers environment -// Workers can't load WASM files from filesystem, so use JavaScript RegExp engine -// Check for Cloudflare context that's injected by @astrojs/cloudflare adapter -const isCloudflareWorkers = - ('cf' in Astro.request) || // Cloudflare request object - ('cfContext' in Astro.locals) || // Cloudflare context in locals - ('cloudflare' in Astro.locals); // Alternative location - const highlighter = await createShikiHighlighter({ langs: [ typeof lang === 'string' @@ -131,7 +120,6 @@ const highlighter = await createShikiHighlighter({ ], theme, themes, - ...(isCloudflareWorkers ? { engine: createJavaScriptRegexEngine() } : {}), }); // Combine style-to-class transformer with user-provided transformers diff --git a/packages/markdown/remark/package.json b/packages/markdown/remark/package.json index e8e1a03f88b5..65fca0df5e17 100644 --- a/packages/markdown/remark/package.json +++ b/packages/markdown/remark/package.json @@ -14,6 +14,7 @@ "main": "./dist/index.js", "exports": { ".": "./dist/index.js", + "./shiki/engine": "./dist/engine.js", "./shiki": "./dist/shiki.js", "./shiki-style-collector": "./dist/shiki-style-collector.js", "./transformers/style-to-class": "./dist/transformers/style-to-class.js" @@ -22,6 +23,10 @@ "#import-plugin": { "browser": "./dist/import-plugin-browser.js", "default": "./dist/import-plugin-default.js" + }, + "#shiki-engine": { + "workerd": "./dist/shiki-engine-workerd.js", + "default": "./dist/shiki-engine-default.js" } }, "files": [ diff --git a/packages/markdown/remark/src/shiki-engine-default.ts b/packages/markdown/remark/src/shiki-engine-default.ts new file mode 100644 index 000000000000..6ac938d313ca --- /dev/null +++ b/packages/markdown/remark/src/shiki-engine-default.ts @@ -0,0 +1,7 @@ +// shiki-engine-default.ts +import type { RegexEngine } from 'shiki'; +import { createOnigurumaEngine } from 'shiki/engine/oniguruma'; + +export function loadShikiEngine(): Promise { + return createOnigurumaEngine(import('shiki/wasm')); +} diff --git a/packages/markdown/remark/src/shiki-engine-workerd.ts b/packages/markdown/remark/src/shiki-engine-workerd.ts new file mode 100644 index 000000000000..44c1da540458 --- /dev/null +++ b/packages/markdown/remark/src/shiki-engine-workerd.ts @@ -0,0 +1,8 @@ +// shiki-engine-worker.ts +import type { RegexEngine } from 'shiki'; +import { createOnigurumaEngine } from 'shiki/engine/oniguruma'; + +export function loadShikiEngine(): Promise { + // @ts-ignore wasm type + return createOnigurumaEngine(import('shiki/onig.wasm')); +} diff --git a/packages/markdown/remark/src/shiki.ts b/packages/markdown/remark/src/shiki.ts index 43d84c609ad7..16876ab494e3 100644 --- a/packages/markdown/remark/src/shiki.ts +++ b/packages/markdown/remark/src/shiki.ts @@ -8,6 +8,7 @@ import { type HighlighterGeneric, isSpecialLang, type LanguageRegistration, + type RegexEngine, type ShikiTransformer, type ThemeRegistration, type ThemeRegistrationRaw, @@ -15,6 +16,7 @@ import { import { globalShikiStyleCollector } from './shiki-style-collector.js'; import { transformerStyleToClass } from './transformers/style-to-class.js'; import type { ThemePresets } from './types.js'; +import { loadShikiEngine } from '#shiki-engine'; export interface ShikiHighlighter { codeToHast( @@ -34,11 +36,6 @@ export interface CreateShikiHighlighterOptions { theme?: ThemePresets | ThemeRegistration | ThemeRegistrationRaw; themes?: Record; langAlias?: HighlighterCoreOptions['langAlias']; - /** - * Custom regex engine for Shiki. - * Use JavaScript engine for environments that can't load WASM files (e.g. Cloudflare Workers). - */ - engine?: HighlighterCoreOptions['engine']; } export interface ShikiHighlighterHighlightOptions { @@ -81,20 +78,25 @@ const cssVariablesTheme = () => // Caches Promise for reuse when the same theme and langs are provided const cachedHighlighters = new Map(); +let shikiEngine: RegexEngine | undefined = undefined; + export async function createShikiHighlighter({ langs = [], theme = 'github-dark', themes = {}, langAlias = {}, - engine, }: CreateShikiHighlighterOptions = {}): Promise { theme = theme === 'css-variables' ? cssVariablesTheme() : theme; + if (shikiEngine === undefined) { + shikiEngine = await loadShikiEngine(); + } + const highlighterOptions = { langs: ['plaintext', ...langs], langAlias, themes: Object.values(themes).length ? Object.values(themes) : [theme], - ...(engine ? { engine } : {}), + engine: shikiEngine, }; const key = JSON.stringify(highlighterOptions, Object.keys(highlighterOptions).sort()); From 4e1ef2afa11d8a0ba1787d726fb040e8b4d73883 Mon Sep 17 00:00:00 2001 From: ematipico Date: Fri, 20 Feb 2026 14:12:04 +0000 Subject: [PATCH 9/9] fix linting --- knip.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/knip.js b/knip.js index 0b6ebf7efc04..166660a63dc0 100644 --- a/knip.js +++ b/knip.js @@ -85,7 +85,7 @@ export default { 'packages/markdown/remark': { entry: [testEntry], // package.json#imports are not resolved at the moment - ignore: ['src/import-plugin-browser.ts'], + ignore: ['src/import-plugin-browser.ts', 'src/shiki-engine-workerd.ts'], }, 'packages/upgrade': { entry: ['src/index.ts', testEntry],