UNPKG

vite-plugin-zephyr

Version:

Vite plugin for Zephyr

291 lines (221 loc) • 10.6 kB
# Vite Plugin Zephyr ![Vite compatibility](https://registry.vite.dev/api/badges?package=vite-plugin-zephyr&tool=vite) <div align="center"> [Zephyr Cloud](https://zephyr-cloud.io) | [Zephyr Docs](https://docs.zephyr-cloud.io) | [Discord](https://zephyr-cloud.io/discord) | [Twitter](https://x.com/ZephyrCloudIO) | [LinkedIn](https://www.linkedin.com/company/zephyr-cloud/) <hr/> <img src="https://cdn.prod.website-files.com/669061ee3adb95b628c3acda/66981c766e352fe1f57191e2_Opengraph-zephyr.png" alt="Zephyr Logo" /> </div> A Vite plugin for deploying applications with Zephyr Cloud. This plugin integrates with Vite's build process to enable seamless deployment of your applications, with optional Module Federation support. Read more from our documentation [here](https://docs.zephyr-cloud.io/integrations/react-vite). ## Get Started The fastest way to get started is to use `create-zephyr-apps` to generate a new Vite application with Zephyr integration and there are various vite examples available: ```bash npx create-zephyr-apps@latest ``` ## Installation ```bash # npm npm install --save-dev vite-plugin-zephyr # yarn yarn add --dev vite-plugin-zephyr # pnpm pnpm add --dev vite-plugin-zephyr # bun bun add --dev vite-plugin-zephyr ``` ## AI Agent Skills (Optional) This package ships the `zephyr-vite` Agent Skill for AI coding agents, together with the shared `zephyr-core` and `zephyr-module-federation` guides. The skills are versioned with the package, so your agent reads guidance that matches the release you installed. Zephyr does not need Intent at runtime. Coding agents only find these skills after you opt in with [TanStack Intent](https://tanstack.com/intent/latest/docs/getting-started/quick-start-consumers): ```sh pnpm add -D @tanstack/intent pnpm dlx @tanstack/intent@latest install ``` Allow `vite-plugin-zephyr` when `install` asks. Intent saves that choice in the `intent.skills` allowlist in your `package.json`. To check or load the skill yourself: ```sh pnpm exec intent list pnpm exec intent load 'vite-plugin-zephyr#zephyr-vite' ``` ## Usage ### Basic Configuration Add the plugin to your Vite configuration: ```javascript // vite.config.js import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { withZephyr } from 'vite-plugin-zephyr'; export default defineConfig({ plugins: [react(), withZephyr()], build: { target: 'chrome89', }, }); ``` ### Multi-Environment and SSR Builds Vite 7 and 8 application-builder invocations collect output across `client`, `server`, RSC, or custom child environments and publish once through the `buildApp` hook. The plugin validates that each current environment contributed output; persisted partial-build contributions are merged atomically. Programmatic `vite.build()` calls, including Slidev builds, use the direct single-environment upload path, as do Vite 5 and single-environment watch builds. When `createBuilder()` instantiates multiple environments, publish through `builder.buildApp()`. Calling `builder.build(environment)` individually is rejected to prevent separate, incomplete deployments. This check tracks actual environment creation, so ordinary legacy SSR builds can still select one server environment. Non-watch programmatic builds collect every output format and publish one combined snapshot when the bundler closes, after all expected writes succeed. External partial output is claimed and committed once for that snapshot. Library `formats` and explicit output arrays are both supported. Separate output directories are preserved relative to their common root; TAP artifact paths remain unchanged. Direct SSR builds infer `snapshotType: 'ssr'` from the selected server build and use its emitted entry chunk, including renamed or hashed filenames. Explicit `snapshotType` and `entrypoint` options take precedence. Multiple server entry chunks require an explicit emitted `entrypoint`. TAP builds do not infer SSR unless explicitly requested. For direct non-watch publication, Zephyr must observe the final `outputOptions`, `writeBundle` and `closeBundle` hooks. Output plugins are checked after normal option hooks have returned their changes. Later post-ordered hooks and unresolved asynchronous output plugins are rejected because they could change the writers or fail after Zephyr records success. Application-builder and watch publication keep their own lifecycles. If publication and partial-claim rollback both fail, the rollback error is logged separately and the original publication error keeps the configured throw-or-log behavior. Vite 6 does not dispatch plugin `buildApp` hooks. Its non-watch publication supports only a single environment without an explicit `builder` configuration; other configurations are rejected to avoid publishing incomplete output. Use Vite 7 or newer for coordinated application builds. Place `withZephyr()` before other plugins that combine `enforce: 'pre'` with a pre-ordered `buildApp` hook. Zephyr checks this order before building so it can start collecting output before any application build hook compiles an environment. The ordering check also applies to legacy builds carrying those plugins. Files generated by a framework after `vite.build()` returns are outside the Vite upload lifecycle. For example, Slidev can generate a PDF, an OG image, `404.html`, and `_redirects` after Vite finishes; those files need a separate post-build publication step if they must be included. ```typescript withZephyr({ snapshotType: 'ssr', entrypoint: 'server/index.mjs', }); ``` - `snapshotType` overrides automatic CSR/SSR detection. - `entrypoint` is relative to the shared snapshot root and is required when an SSR entry cannot be inferred. For intentionally separate Vite invocations, use `withZephyrPartial()` in producer configs and `withZephyr()` in the final config. Give every producer and finalizer the same `invocationId` (or set `ZE_BUILD_INVOCATION_ID`). To derive that identity from a supported CI job, explicitly pass `partialBuild: {}` to the finalizer; an ordinary `withZephyr()` build ignores ambient CI metadata. The plugin fails closed when a producer has no shared build identity. Partial maps are isolated by invocation and generation, protected by an inter-process lock, and claimed transactionally. Commit removes only unchanged claimed revisions, while rollback releases the claim without overwriting a newer concurrent write. ```typescript withZephyrPartial({ invocationId: process.env.BUILD_ID }); withZephyr({ partialBuild: { invocationId: process.env.BUILD_ID } }); ``` For builds with no user-defined `base`, the plugin defaults Vite to `./`. Relative build asset URLs work for hostname deployments and allow Zephyr to add a path prefix later. Explicit bases are preserved; an origin-absolute base such as `/docs/` produces a warning when the application or one of its environments uses path addressing because that URL cannot be relocated under another prefix. This build-time default does not by itself make deep SSR/RSC routes prefix-aware. Runtime HTML generation must still resolve asset URLs against the request/deployment base. The specialized TanStack Start and Vinext plugins coordinate that runtime output separately. ### With Module Federation For microfrontend applications using Module Federation: ```javascript // vite.config.js import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { federation } from '@module-federation/vite'; import { withZephyr } from 'vite-plugin-zephyr'; const mfConfig = { name: 'my-app', remotes: { shared: 'shared@http://localhost:3001/remoteEntry.js', }, shared: { react: { singleton: true }, 'react-dom': { singleton: true }, }, }; export default defineConfig({ plugins: [react(), federation(mfConfig), withZephyr()], build: { target: 'chrome89', }, }); ``` ### TypeScript Configuration ```typescript // vite.config.ts import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { federation, type ModuleFederationOptions } from '@module-federation/vite'; import { withZephyr } from 'vite-plugin-zephyr'; const mfConfig: ModuleFederationOptions = { name: 'host-app', remotes: { 'remote-app': 'remoteApp@http://localhost:3001/remoteEntry.js', }, shared: { react: { singleton: true }, 'react-dom': { singleton: true }, }, }; export default defineConfig({ plugins: [react(), federation(mfConfig), withZephyr()], build: { target: 'chrome89', }, }); ``` ## Features - 🚀 Seamless deployment during Vite build - 🏗️ Optional Module Federation support via [@module-federation/vite](https://github.com/module-federation/vite) - 📦 Asset optimization and caching - 🔧 Zero-config setup for simple applications - 📊 Build analytics and monitoring - 🌐 Global CDN distribution - ⚡ Hot module replacement in development ## Module Federation Support When you need federation, this plugin works with the official [vite plugin from Module Federation](https://github.com/module-federation/vite), providing: - **Host Applications**: Consume remote modules from other applications - **Remote Applications**: Expose modules for consumption by host applications - **Shared Dependencies**: Efficient sharing of common libraries - **Dynamic Imports**: Runtime loading of remote modules ## Getting Started 1. Install the plugin in your Vite project 2. Add it to your Vite configuration 3. Configure Module Federation (if needed) for microfrontends 4. Build your application with `vite build` 5. Your app will be automatically deployed to Zephyr Cloud ## Build Scripts Add these scripts to your `package.json`: ```json { "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" } } ``` ## Requirements - Vite 5.x, 6.x, 7.x, or 8.x - Rollup 4.x - Node.js version supported by your Vite toolchain - Zephyr Cloud account (sign up at [zephyr-cloud.io](https://zephyr-cloud.io)) If you use Module Federation, also install `@module-federation/vite`. ## Examples Check out our [examples directory](../../examples/) for complete working examples: - [vite-react-ts](../../examples/vite-react-ts/) - Basic React + TypeScript setup - [vite-react-mf](../../examples/vite-react-mf/) - Module Federation setup with host and remote ## Contributing We welcome contributions! Please read our [contributing guidelines](../../CONTRIBUTING.md) for more information. ## License Licensed under the Apache-2.0 License. See [LICENSE](LICENSE) for more information.