Skip to main content
Files inside extra/extensions/ aren’t web-accessible. To serve a stylesheet, script or image, list it in extra.public, and the installer copies it into the web root when the plugin is installed or updated.

Declare files to publish

composer.json
By default, files land in {web root}/e/{vendor}/{package}/, which is served from /e/{vendor}/{package}/....

Entry formats

A plain string keeps the whole source path, which is why the newer object form is clearer. A target that starts with / is resolved against the web root, so use it sparingly: that’s a shared namespace, and a generic name like /sdk.js can collide with another plugin.
The object form requires a recent heyaikeedo/composer. Require "^1.2.0" when you use { "source": ..., "target": ... } entries, and "^1.0.0" when plain strings are enough.

When files are copied

The web root comes from the PUBLIC_DIR environment variable, so installations that serve from public_html work without any change on your side.
Only files that existed when the package was installed are copied. Editing a file during development doesn’t republish it: run composer require acme/hello again, or copy it yourself while iterating.

Reference published files

For a build with hashed filenames, publish the Vite manifest along with the bundle and resolve the name in PHP:
Hashed filenames from an older build aren’t deleted when you publish a new one, because the mapping records what the current install copied. Clean stale files out of your build directory before packaging a release.

Development workflow

Point an environment variable at your dev server, and fall back to the published path:
.env
Remember that env exposes the whole environment to templates, so read only the key you need and never dump the object.

What not to publish

  • Source files, tests and configuration. Publish build output only.
  • Anything containing credentials. Published files are world-readable.
  • Large media that would be better served from the CDN. See Files and storage.