@distilled.cloud/astro

中文文档
0.17.1发布于 2026/08/06MITTypeScriptES Module构建来源已验证近 30 天下载 2932

Programmatic Astro integration implementing the framework-core Framework service (build/dev), with the deploy target passed as a value; ships the wrangler-free Cloudflare Workers target (a fork of @astrojs/cloudflare over @distilled.cloud/cloudflare-vite-

此软件包已被标记为弃用

Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

原始使用文档
文档目录11 节
  1. Architecture: framework half × deploy-target half
  2. The AstroTarget contract
  3. How the target is passed
  4. Options
  5. Astro.make(options?: AstroFrameworkOptions)
  6. Cloudflare target config ( cloudflare(config) )
  7. E2e-harness usage
  8. What the Cloudflare target does
  9. Build output
  10. Limitations
  11. Testing

@distilled.cloud/astro

Programmatic, wrangler-free Astro integration.

This package implements framework-core's Framework service for Astro — effectful build/dev over Astro's public programmatic API (import { build, dev } from "astro") with a fully in-memory AstroInlineConfig (no astro.config.*) — and takes the deploy target as a value. The Cloudflare Workers target (a fork of @astrojs/cloudflare over @distilled.cloud/cloudflare-vite-plugin, with no wrangler dependency and no wrangler.json anywhere) ships at the ./cloudflare subpath.

import * as Astro from "@distilled.cloud/astro";
import cloudflare from "@distilled.cloud/astro/cloudflare";

const layer = Astro.make({
  target: cloudflare({
    worker: {
      compatibilityDate: "2026-03-10",
      compatibilityFlags: ["nodejs_compat"],
      worker: {
        name: "my-app",
        bindings: [
          /* in-memory bindings */
        ],
      },
    },
  }),
  astro: { site: "https://example.com" },
});
// layer: Layer<Framework> — Framework.build → BuildOutput, Framework.dev → { url }

Architecture: framework half × deploy-target half

The package separates two concerns (see packages/framework-core/README.md, "Architecture: frameworks × deploy targets", for the full doctrine):

HalfModulesContents
Framework (platform-neutral)src/index.ts, src/Astro.ts, src/Target.ts, src/environments.tsThe Framework service implementation: inline-config synthesis (makeAstroInlineConfig), programmatic build()/dev() driving, the shared build-output collector (entryEnvironment: "ssr", skipEnvironments: ["astro", "prerender"]), deploy-target resolution. Zero Cloudflare imports — enforced by test/decoupling.test.ts.
Cloudflare targetsrc/cloudflare.ts (subpath @distilled.cloud/astro/cloudflare), src/integration.ts, src/config-plugin.ts, src/prerenderer.ts, src/prerender-environment.ts, src/prerender-middleware.ts, src/runtime/**The AstroTarget factory plus everything Cloudflare: the forked @astrojs/cloudflare integration over our vite plugin, the vendored runtime entrypoints, the virtual:astro-cloudflare:config plugin, the workerd prerenderer (build-side driver of the __astro_* protocol over cloudflare-runtime), the dev node-prerender middleware plugin.
alchemy source providersrc/source.ts (subpath @distilled.cloud/astro/source)The alchemy Cloudflare.Workers source module (structural SourceProvider mirror): build/hash/dev for the alchemy Worker resource. Cloudflare-specific by definition; constructs the Cloudflare target directly.

A future platform (e.g. AWS) is a new subpath implementing the same AstroTarget seams — no change to the framework half or to framework-core.

The AstroTarget contract

AstroTarget extends framework-core's generic DeployTarget with one framework-specific hook:

interface AstroTarget<Config = unknown> extends DeployTarget<Config> {
  /** The Astro adapter integration pinned into AstroInlineConfig.adapter. */
  readonly integration: () => AstroIntegration;
}

Everything platform-specific rides inside that integration (Astro's adapter API is already the right seam: it injects vite plugins, selects the server entrypoint, and configures the build). The generic DeployTarget seams are honored by the framework half:

  • target.build — wholesale build takeover: when defined, Framework.build delegates the entire production build to the target. (The Cloudflare Astro target does not define it — Astro drives its own build.)
  • finish — a post-build finishing pass, applied via applyDeployTargetFinish after the collector produces the BuildOutput (the Astro build is delivered in-memory, so the finish context carries no on-disk entry).
  • bundle — resolve/bundle metadata (conditions, external); informational for Astro since the integration configures the bundler itself.
  • serve — local serving of built output; the e2e harness's Cloudflare target provides this (miniflare). Not the HMR dev path.

How the target is passed

Astro.make({ target, targetConfig }) accepts a DeployTargetInput:

  • an AstroTarget value — used as-is (full type safety; build it yourself by importing the target module),
  • a factory (config) => AstroTarget — applied to targetConfig,
  • a module specifier string — loaded from the project's node_modules (its default — or named target — export is the value or factory), applied to targetConfig.

Omitting target defaults to "@distilled.cloud/astro/cloudflare", so existing Cloudflare users need no change. The target is resolved once per build/dev operation; a resolved target missing the integration hook fails with a typed FrameworkError.

Options

Astro.make(options?: AstroFrameworkOptions)

OptionTypeDescription
targetAstroTargetInputDeploy target (value / factory / specifier). Default: "@distilled.cloud/astro/cloudflare".
targetConfigunknownConfig handed to a target factory / specifier-loaded module. Opaque to the framework half. Unused when target is a value.
astroAstroInlineConfigExtra Astro config merged into the in-memory inline config (site, base, redirects, integrations, devToolbar, vite, ...). root, configFile: false, and adapter are pinned; output defaults to "server".
rootstringProject root. Defaults to process.cwd().

Cloudflare target config (cloudflare(config))

OptionTypeDescription
workerCloudflareVitePluginOptionsCompatibility date/flags, worker name/bindings/assets behavior, runtime context — everything a wrangler.json would have carried, in-memory. main, viteEnvironments, and Astro's node environments in skipEnvironments are managed by the integration.
sessionKVBindingNamestringKV binding name used for zero-config sessions and injected into Astro's session config when present on the Worker env. Default "SESSION".
sessionsbooleanZero-config sessions (default true): when no session.driver is configured, Astro's cloudflareKVBinding driver is configured against sessionKVBindingName. false leaves the session config untouched.
sessionDevKVbooleanIn dev, auto-inject an in-memory local KV namespace (KvNamespace.local) for the session binding (default true). Disable when the dev worker bindings already deliver a KV binding with that name — binding names must be unique.

Upstream @astrojs/cloudflare adapter options this fork does not support (imageService, imagesBindingName, platformProxy, configPath, persistState, auxiliaryWorkers, inspectorPort, viteEnvironment, cloudflareModules, experimental) are rejected with a clear error instead of being silently ignored — each error names the reason and the migration.

E2e-harness usage

The default export is the harness framework factory. It reads the harness's cloudflare worker options structurally (options.target?.cloudflare?.worker ?? options.vite) and forwards them as the default target's config:

// e2e.config.ts — untyped carriage
export default Options.make({
  target: { cloudflare: { worker: { /* ... */ }, preview: { /* miniflare */ } } },
  framework: "@distilled.cloud/astro",
});

// e2e.config.ts — typed target value (recommended; see fixtures/astro)
framework: (options) =>
  Astro.make({
    target: cloudflare({ worker: Options.resolveCloudflareOptions(options).worker }),
    astro: { devToolbar: { enabled: false } },
  }),

What the Cloudflare target does

The integration is a fork of @astrojs/cloudflare v14.1.3 (which upstream builds on @cloudflare/vite-plugin + a wrangler peer dependency), reworked to be wrangler-free over @distilled.cloud/cloudflare-vite-plugin:

  • Swapped plugin. @cloudflare/vite-plugin → our plugin, main pinned to the vendored server entrypoint (@distilled.cloud/astro/entrypoints/server), worker environment ssr, Astro's node-side astro/prerender environments in skipEnvironments. Dev SSR executes inside workerd via the vite module runner with in-memory bindings; the dev env.ASSETS 404/asset fallback is satisfied by the runtime's vite-aware assets loopback (Assets.local).
  • Dropped. loadWranglerEnv + .dev.vars, wrangler-config file watchers, the previewEntrypoint (our runtime serves the build output), and the output-wrangler.json patch.
  • Workerd prerendering (default, like upstream). prerenderEnvironment: "workerd" builds the prerender environment as a Worker (same treatment as the ssr environment) and serves it from workerd via cloudflare-runtime — no Vite preview server, no wrangler — while the build drives upstream's __astro_* prerender HTTP protocol against it (src/prerenderer.ts). Prerendered pages run in the production runtime: top-level cloudflare:workers imports and the configured worker bindings work at prerender time. prerenderEnvironment: "node" falls back to Astro's stock node prerenderer (+ the dev node-prerender middleware plugin) for pages that need Node-only APIs at build time.
  • Hardwired. The passthrough image service (see limitations).
  • Kept (vendored). The runtime entrypoints/handler/helpers (verified free of wrangler/@cloudflare/vite-plugin imports — enforced by the "vendored runtime purity" test), the virtual:astro-cloudflare:config plugin (not exported upstream), the optimizeDeps.include environment plugin, the cf-imports/cf-externals plugins, and the astro:build:setup server tweaks (ssr.noExternal, sharp external, process-env banner).
  • Kept (build-output parity). The astro:build:done pass mirrors upstream: _redirects is generated from Astro's redirect routes (config redirects + redirect route files, via @astrojs/underscore-redirects) so static/prerendered redirects are served by the asset layer ahead of the Worker; _headers gets an immutable Cache-Control: public, max-age=31536000, immutable rule for the hashed _astro/ assets directory (skipped when the user's _headers already sets Cache-Control on a matching rule, or when build.assetsPrefix points assets at another origin); injectTypes installs the App.Locals runtime types (@distilled.cloud/astro/types.d.ts).
  • Kept (base !== "/"). The client build is nested under the base so the assets directory serves at the URL root, the special files (.assetsignore/_headers/_redirects) are moved back up, and the target's finish pass points BuildOutput.clientDirectory back at the original directory (the in-memory equivalent of upstream's emitted wrangler.json assets.directory patch).
  • Sessions (zero-config). Mirrors upstream: with no configured session.driver, Astro's cloudflareKVBinding driver is configured against the sessionKVBindingName binding (SESSION); the vendored runtime handler injects the live KV binding from the Worker env on each request. In dev, an in-memory KvNamespace.local namespace is auto-added to the worker bindings so Astro.session works with zero setup (disable via sessionDevKV: false when your dev bindings already carry that binding). In production the Worker must be deployed with a KV binding named sessionKVBindingName (with alchemy: give the Worker a KV namespace binding named SESSION).
  • astro:env at build time. The alchemy source provider (@distilled.cloud/astro/source) feeds the Worker's literal env values (strings, Redacted strings, numbers/booleans) into process.env before build/dev, so astro:env server secrets resolve during config load and node prerendering — the role upstream's loadWranglerEnv (wrangler vars
    • .dev.vars) plays.
  • Typegen guard. build/sync run Astro's type generation, which boots a temporary vite server; the integration strips configureServer from the cloudflare plugins in those phases (mirroring upstream) so workerd never boots mid-build — our dev environments degrade to runnable stubs, a supported contract of the dev plugin.

Build output

Framework.build returns the BuildOutput contract in-memory: serverModules (entry first — the ssr entry chunk server/entry.mjs, re-read from disk because Astro injects the serialized SSR manifest after the bundler finishes) and clientDirectory (dist/client, captured as a path so prerendered HTML written after the vite build rides along — including the generated _redirects and _headers files). No wrangler.json, no .wrangler/ directory, anywhere.

Limitations

  • Node prerender fallback loses worker APIs. With prerenderEnvironment: "node", prerendered routes (export const prerender = true) execute in Astro's stock node prerender environment: pages that import cloudflare:workers (or otherwise rely on worker-only APIs) at prerender time will fail to prerender there. The default "workerd" mode does not have this gap — prerendering runs in workerd with the worker's bindings attached.
  • Image service is passthrough. workerd cannot run sharp, and the IMAGES binding is remote-only in our runtime, so the integration hardwires Astro's passthrough image service: images are served as-is (no resizing / format negotiation). The production endpoint is the vendored image-passthrough-endpoint; dev uses Astro's generic node endpoint.
  • Sessions need a deployed KV binding in production. Zero-config sessions work out of the box in dev (in-memory local KV) and configure the built app to read the sessionKVBindingName KV binding from the Worker env — but provisioning that KV namespace on the deployed Worker is the deployment tool's job. Without it, session operations fail at runtime.
  • astro preview is not used. The upstream preview entrypoint hard-depends on a wrangler deploy config; serving built output is the deploy target's serve concern (miniflare in the e2e harness; the alchemy dev loop uses cloudflare-runtime).
  • Version pinning. Astro's JS API is @experimental, and the integration internals (virtual module names, adapter features) are versioned with Astro majors. The fork tracks astro 7.x / adapter v14.1.3; treat version bumps as deliberate migrations backed by the fixture e2e suite.

Testing

  • bun run test — unit tests (test/Astro.test.ts: target module, config synthesis, integration hooks, wholesale-build delegation; test/parity.test.ts: sessions, _redirects/_headers generation, base !== "/" handling, injectTypes, the unsupported-option guard, env feeding; test/decoupling.test.ts: the framework half's cloudflare-free guarantee and runtime purity).
  • fixtures/astro — the playwright e2e suite driving a real app through the harness in both dev (workerd module runner) and live (miniflare over the built output) modes: SSR + bindings, middleware locals/headers, config redirects (served from the generated _redirects in live mode), Astro.session round-trips, immutable asset Cache-Control, JSON/binary endpoints, content collections, prerendered pages, public assets, ASSETS 404 fallback. (A base !== "/" fixture app is not yet part of the suite — the behavior is unit-tested in test/parity.test.ts.)

版本与发布记录

@distilled.cloud/astro 共发布 2 个版本,首次发布于 2026/08/06;过去 12 个月发布了 2 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.17.1latest2026/08/063 个月前
0.17.02026/08/063 个月前

关于 @distilled.cloud/astro 的常见问题

@distilled.cloud/astro 是什么?

Programmatic Astro integration implementing the framework-core Framework service (build/dev), with the deploy target passed as a value; ships the wrangler-free Cloudflare Workers target (a fork of @astrojs/cloudflare over @distilled.cloud/cloudflare-vite-注意:该包已被作者标记为弃用——Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

如何安装 @distilled.cloud/astro?

在项目目录运行 npm install @distilled.cloud/astro,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:vite(^8.0.0)、astro(^7.0.0)、effect(>=4.0.0-beta.102 || >=4.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@distilled.cloud/astro 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@distilled.cloud/astro 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@distilled.cloud/astro 可以商用吗?

@distilled.cloud/astro 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@distilled.cloud/astro 的下载量有多少?

根据 npm 官方下载统计,@distilled.cloud/astro 在 2026/10/13 – 2026/11/11 这 30 天内被下载 2,932 次,日均约 98 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@distilled.cloud/astro 还在维护吗?

最新版本 0.17.1 发布于 2026/08/06(3 个月前);至今共发布 2 个版本,其中过去 12 个月发布了 2 个;首次发布于 2026/08/06。作者已将其标记为弃用,新项目建议寻找替代方案。