# plain.vendor
**Download and manage vendored CSS and JavaScript dependencies from CDNs.**
- [Overview](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#overview)
- [Adding dependencies](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#adding-dependencies)
- [Syncing dependencies](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#syncing-dependencies)
- [Updating dependencies](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#updating-dependencies)
- [Configuration options](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#configuration-options)
- [Custom filenames](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#custom-filenames)
- [Source maps](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#source-maps)
- [Version placeholders](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#version-placeholders)
- [FAQs](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#faqs)
- [Installation](https://plainframework.com/docs/plain-vendor/plain/vendor/?llm#installation)
## Overview
You can use `plain vendor` to download JavaScript and CSS files from CDNs and store them locally in your project. This keeps third-party assets under version control and avoids runtime dependencies on external CDNs.
Dependencies are configured in your `pyproject.toml` and downloaded to `app/assets/vendor/`.
```toml
# pyproject.toml
[tool.plain.vendor.dependencies]
htmx = {url = "https://unpkg.com/htmx.org@{version}/dist/htmx.min.js", installed = "2.0.4"}
alpine = {url = "https://cdn.jsdelivr.net/npm/alpinejs@{version}/dist/cdn.min.js", installed = "3.14.8"}
```
After configuring dependencies, run `plain vendor sync` to download them:
```bash
plain vendor sync
```
The files are saved to `app/assets/vendor/` and can be included in your templates:
```html
```
## Adding dependencies
You can add a new dependency directly from the command line:
```bash
plain vendor add https://unpkg.com/htmx.org/dist/htmx.min.js
```
This downloads the file, extracts the version from the URL, and adds an entry to your `pyproject.toml`. You can also specify a custom name:
```bash
plain vendor add https://unpkg.com/htmx.org/dist/htmx.min.js --name htmx
```
## Syncing dependencies
The `sync` command clears all existing vendored files and re-downloads everything from scratch:
```bash
plain vendor sync
```
Use this when you first clone a project or want to ensure your vendored files match your configuration.
## Updating dependencies
The `update` command checks for newer versions and updates your `pyproject.toml`:
```bash
# Update all dependencies
plain vendor update
# Update specific dependencies
plain vendor update htmx alpine
```
The update process tries several strategies to find newer versions:
1. Requests the "latest" tag (supported by many CDNs)
2. Increments version numbers to probe for new releases
## Configuration options
### Custom filenames
If you want to rename a file when it's downloaded, use the `filename` option:
```toml
[tool.plain.vendor.dependencies]
htmx = {url = "https://unpkg.com/htmx.org@{version}/dist/htmx.min.js", installed = "2.0.4", filename = "htmx.js"}
```
### Source maps
You can automatically download source maps alongside your vendored files:
```toml
[tool.plain.vendor.dependencies]
htmx = {url = "https://unpkg.com/htmx.org@{version}/dist/htmx.min.js", installed = "2.0.4", sourcemap = true}
```
When `sourcemap = true`, the tool appends `.map` to the filename and downloads from the same directory. For non-standard source map filenames, provide the filename directly:
```toml
[tool.plain.vendor.dependencies]
example = {url = "https://example.com/lib.min.js", installed = "1.0.0", sourcemap = "lib.min.js.map"}
```
You can also use the `--sourcemap` flag when adding dependencies:
```bash
plain vendor add https://unpkg.com/htmx.org/dist/htmx.min.js --sourcemap
```
### Version placeholders
URLs can include a `{version}` placeholder that gets replaced with the installed version number:
```toml
htmx = {url = "https://unpkg.com/htmx.org@{version}/dist/htmx.min.js", installed = "2.0.4"}
```
When you run `plain vendor sync`, the placeholder is replaced with `2.0.4`. This makes it easy to see which version is installed and enables the update command to try newer versions.
## FAQs
#### What file types are supported?
The vendor tool accepts JavaScript (`application/javascript`, `text/javascript`), CSS (`text/css`), and JSON (`application/json`) files. Other content types will raise an error.
#### Where are vendored files stored?
All vendored files are downloaded to `app/assets/vendor/`. This directory is created automatically if it doesn't exist.
#### How does version detection work?
When you add a dependency or update to a new version, the tool parses version numbers from the final URL (after any redirects). It looks for patterns like `1.2.3` or `1.2` in the URL path.
#### What happens if a CDN is unavailable?
The sync and update commands will fail with an error if any dependency cannot be downloaded. You'll see which dependencies failed in the output.
## Installation
Install the `plain.vendor` package from [PyPI](https://pypi.org/project/plain.vendor/):
```bash
uv add plain.vendor
```
After installation, the `plain vendor` command becomes available. Configure your dependencies in `pyproject.toml`:
```toml
[tool.plain.vendor.dependencies]
htmx = {url = "https://unpkg.com/htmx.org@{version}/dist/htmx.min.js", installed = "2.0.4"}
```
Then run the sync command to download them:
```bash
plain vendor sync
```
Your vendored files will be available in `app/assets/vendor/` and can be referenced in templates using the `asset` template filter.