npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vite-plugin-cep-reload

v0.1.0

Published

Dev-only Vite plugin for reloading CEP ExtendScript bundles without restarting the CEP panel.

Readme

vite-plugin-cep-reload

Dev-only Vite plugin for reloading CEP ExtendScript bundles without restarting the CEP panel window.

The goal is to make the CEP development loop tolerable: save your ExtendScript bundle, let the panel detect the change, and see updated host-side behavior without closing and reopening the extension.

Status

This plugin has been tested in After Effects so far.

The repo now includes example projects for both direct host-script reloads and generated host-bundle reloads. Cross-host validation is still limited, though, and reports from Premiere Pro, Photoshop, Illustrator, Media Encoder, or other CEP hosts are still useful.

What it does

This plugin serves the current signature of a CEP ExtendScript .jsx file from the Vite dev server. A small client runtime inside the CEP panel polls that endpoint and, when the file changes, calls CSInterface.evalScript(...) with:

  • $.evalFile(bundlePath)
  • an optional bootstrap function call

This is full ExtendScript re-execution, not true module-level HMR.

When Vite serves your HTML entry, the client runtime is injected automatically during dev.

If your CEP panel loads a local index.html from the extension folder and only points module scripts at the Vite dev server, Vite cannot transform that HTML. In that setup, import virtual:cep-reload/client manually from your panel entry module.

Scope

  • Dev only
  • Works with Vite panel apps, including CEP setups that use Vite+ as the local toolchain
  • Does not bundle or transpile ExtendScript
  • Assumes your CEP host script exists at a stable path during development, whether that file is edited directly or generated by a host build step
  • Designed for CEP hosts in general, but currently verified only in After Effects

Installation

npm install -D vite-plugin-cep-reload

Usage

Most CEP panels that load a local extension HTML should use both steps:

  1. Register the plugin in vite.config.ts.
  2. Import virtual:cep-reload/client in the panel entry module that is loaded by the CEP panel.

CEP setup

import { defineConfig } from "vite";
import { cepReload } from "vite-plugin-cep-reload";

export default defineConfig({
  plugins: [
    cepReload({
      scriptPath: "host/index.jsx",
      bootstrap: "__cepReloadBootstrap",
      pollingIntervalMs: 700,
    }),
  ],
});
import "virtual:cep-reload/client";

Add that import near the top of your panel entry file, for example src/main.ts.

With that setup in place, the normal loop is:

  1. Save the ExtendScript output file referenced by scriptPath.
  2. Let the CEP client notice the changed signature from the Vite dev server.
  3. Re-run the host script through CSInterface.evalScript(...).
  4. Keep the CEP panel open while iterating.

Production-like CEP setup with built host output

In a real CEP project, you will often author host-side code in src/host/* and compile it into one stable ExtendScript bundle such as dist/host/index.jsx.

That is a good fit for this plugin. Point scriptPath at the built output, not at the authoring source file.

Example structure:

my-extension/
├─ src/
│  ├─ main.ts
│  └─ host/
│     ├─ index.ts
│     └─ commands.ts
├─ dist/
│  └─ host/
│     └─ index.jsx
├─ CSXS/
│  └─ manifest.xml
├─ index.html
└─ vite.config.ts

Example Vite config:

import { defineConfig } from "vite";
import { cepReload } from "vite-plugin-cep-reload";

export default defineConfig({
  plugins: [
    cepReload({
      scriptPath: "dist/host/index.jsx",
      bootstrap: "__cepReloadBootstrap",
    }),
  ],
});

Example panel entry:

import "virtual:cep-reload/client";

Example host bundle shape:

if (!$.global.__MY_EXTENSION__) {
  $.global.__MY_EXTENSION__ = {
    initialized: false,
  };
}

function registerCommands() {
  // Register menu items, event handlers, or startup hooks.
}

function __cepReloadBootstrap() {
  if (!$.global.__MY_EXTENSION__.initialized) {
    $.global.__MY_EXTENSION__.initialized = true;
  }

  registerCommands();
}

Typical dev loop in that setup:

  1. Run your host-script build in watch mode so dist/host/index.jsx stays up to date.
  2. Run the Vite dev server for the panel UI.
  3. Keep the CEP panel open in Adobe.
  4. Edit src/host/* and let your build pipeline rewrite dist/host/index.jsx.
  5. Let the reload client detect the changed output bundle and re-run it.

This is usually a better mental model than editing host/index.jsx directly. The repo includes a dedicated built-host example for this setup. The plugin only cares that one stable .jsx file exists on disk and changes when your host code is rebuilt.

Why the manual import is usually required in CEP

In many CEP extensions, Adobe loads a local index.html from the extension folder, and that HTML points its module scripts at the Vite dev server.

In that setup:

  • vite.config.ts is still required so the dev server can expose reload status and the virtual client module.
  • transformIndexHtml() does not run, because Vite is not serving the panel HTML itself.
  • The client must therefore be installed by importing virtual:cep-reload/client manually from your panel entry.

Config-only setup

If your app uses a normal Vite-served HTML entry, the plugin can inject the client automatically and the manual import is optional.

Do not rely on config-only setup when Adobe is loading the panel's local extension HTML. In that CEP mode, the manual virtual:cep-reload/client import is required because Vite never gets a chance to transform the HTML file that the host opens.

Options

type CepReloadOptions = {
  scriptPath: string;
  bootstrap?: string | false;
  pollingIntervalMs?: number;
  log?: boolean;
};
  • scriptPath: absolute or Vite-root-relative path to the built ExtendScript .jsx file that should be reloaded.
  • bootstrap: optional global function reference to call after $.evalFile(...), for example __cepReloadBootstrap or MyNamespace.bootstrap.
  • pollingIntervalMs: how often the CEP panel checks for a changed host script signature. Default is 700.
  • log: enable or disable plugin/client logging. Default is true.

How reload works

When the CEP client sees a changed file signature from the dev server, it runs an ExtendScript payload equivalent to:

(function () {
  try {
    $.evalFile("/absolute/path/to/host.jsx");
    if (typeof __cepReloadBootstrap === "function") {
      __cepReloadBootstrap();
    }
    return "CEP_RELOAD_OK";
  } catch (error) {
    return "CEP_RELOAD_ERROR:" + String(error);
  }
})();

Important note about bootstrap

bootstrap is optional. Users do not need to wrap all of their functions with it.

Reload always starts with $.evalFile(...), so top-level code in the host script runs again automatically. Use bootstrap only when you want one explicit, idempotent re-entry function after evaluation, such as re-registering handlers, menus, or startup state.

Your bootstrap function should be idempotent. Reloading ExtendScript can otherwise stack side effects such as duplicate menu registrations, event listeners, or global state initialization.

Example:

if (!$.global.__MY_CEP_EXTENSION__) {
  $.global.__MY_CEP_EXTENSION__ = {};
}

function __cepReloadBootstrap() {
  // Re-register handlers safely.
}

Limitations

  • Automatic HTML injection only works when Vite serves the HTML entry.
  • CEP extensions that load a local index.html still need import "virtual:cep-reload/client" in the panel entry.
  • Only one ExtendScript output file is supported in 0.1.0.
  • This package does not manage production CEP builds or manifest installation.
  • Polling is intentionally simple and favors dev reliability over instant sub-100ms response time.
  • Behavior outside After Effects is not yet well validated.