@emahuni/directus
Version:
A wrapper around the Directus CLI to enhance its module resolution capabilities, allowing for more flexible and efficient management of dependencies in the Directus API/server.
191 lines (127 loc) • 10.9 kB
Markdown
# @emahuni/directus
A CLI wrapper for [Directus](https://directus.io/) to enhance its module resolution capabilities, enabling the use of `rollup.config.js` or `rolldown.config.js` for building and runtime server API module resolution.
## What's New in v0.3.0?
This version introduces a powerful set of CLI commands to streamline the development workflow, especially for complex Directus projects that require a separate, development-focused build of the Directus App.
- **Automated Dev Environment Setup:** A new `directus setup` command completely automates the process of cloning the Directus repository, installing dependencies, and creating a development build of the app. This is done automatically the first time you run the `directus dev` command.
- **Seamless Build Switching:** The `directus dev` and `directus start` commands now automatically switch between development and production builds of the Directus app, ensuring that you are always running the correct version for your environment.
- **Vue Devtools Integration:** The `directus dev` command starts the development server with the necessary configurations to allow the Directus App Studio to connect to Vue Devtools.
- **Modular and Extensible CLI:** The internal architecture of the CLI has been refactored to be more modular and extensible, making it easier to add new features and commands in the future.
## Why?
The standard Directus extension development workflow has some limitations, especially during development (no access to Vue-Devtools) and when dealing with dependencies. Extensions often bundle their own dependencies, leading to larger extension sizes and potential version conflicts. This package aims to solve these issues by:
- **Enabling Access to Vue-Devtools:** Allows the use of Vue-Devtools in the development environment, which is essential for debugging and inspecting the state of the Directus API during development.
- **Reducing Extension Size:** Reduces the size of extensions by bundling only the necessary dependencies, eliminating the need for bundling common dependencies like Vue and Pinia.
- **Reducing Dependency Conflicts:** Reduces the risk of dependency conflicts by bundling only the necessary dependencies, eliminating the need for bundling common dependencies like Vue and Pinia.
- **Improved Build Performance:** Reduces the build time by only bundling the necessary dependencies, eliminating the need for bundling common dependencies like Vue and Pinia.
- **Improved Development Experience:** Provides a more streamlined development experience by using the same build process for both development and production.
- **Enabling CommonJS Packages:** Allows the use of CommonJS packages within Directus extensions, which are primarily ESM-based.
- **Externalizing Dependencies:** Provides a mechanism to externalize dependencies from extensions. These dependencies can then be installed once at the API level.
- **Centralized Resolution:** This CLI wrapper intercepts the Directus startup process to inject a custom module resolver. This resolver allows Directus to find and use the externalized packages from the root `node_modules` directory of the Directus API project.
This approach was born out of the needs of other packages like `@emahuni/directus.app.guts`, which addresses another pain-point where users want to use Directus App internal code for their own extensions. It externalizes all its peer dependencies to remain lean but will fail since Directus won't know how to resolve the expected external packages. By using this wrapper, extensions built on such a lean approach can also avoid bundling common dependencies, leading to a more efficient and streamlined Directus environment.
The core logic is powered by `@emahuni/rolldown-wrapper` and a custom `resolveFromApiNodeModules` plugin, which together modify Directus's internal extension bundling (which uses Rollup/Rolldown) to enable this advanced module resolution strategy.
## Features
- **Automated Development Environment:** Set up a complete development environment for the Directus App with a single command.
- **Development and Production Builds:** Easily switch between a development build (with Vue Devtools) and a production build.
- **Use `rollup.config.js` or `rolldown.config.js`:** Customize the build process for the API.
- **CommonJS Support:** Seamlessly use CommonJS packages in your ESM-based Directus extensions.
- **Dependency Externalization:** Externalize extension dependencies to be managed at the API project level, reducing bundle sizes and avoiding dependency duplication.
## Installation
First remove directus from your project but take note of its version number:
```bash
pnpm remove directus
```
Then, install `@emahuni/directus`:
```bash
pnpm add @emahuni/directus@0.3.0-directus-11.11.0
```
The wrapper's sub-version number (`-directus-11.11.0`) must match the version of Directus you are using. The initial version of this package (`0.3.0`) follows standard semantic versioning. When a new feature, breaking change, or bug fix is introduced in this wrapper, this version will be bumped accordingly. When a new version of Directus is released, the sub-version number will be updated to match.
Finally, update your `package.json` type to `module` to enable ESM support.
```json
{
"type": "module"
}
```
## Uninstallation
To remove this wrapper and revert to the standard Directus CLI, follow these steps:
1. **Uninstall the wrapper:**
```bash
pnpm remove @emahuni/directus
```
2. **Reinstall Directus:**
Remember the version of Directus you were using. If you don't, you can check your `pnpm-lock.yaml` or `package.json` history.
```bash
pnpm add directus@<version>
```
Replace `<version>` with the version of Directus you noted down during installation (e.g., `11.11.0`).
## Usage
This package provides a `directus` binary that wraps the original Directus CLI. You can use it in your `package.json` scripts just like you would with the standard `directus` command.
### Standard Commands
All standard Directus commands are passed through to the original Directus CLI.
```json
{
"scripts": {
"start": "directus start",
"schema:apply": "directus schema apply ./schema.yaml"
}
}
```
### Custom CLI Commands
This wrapper adds several custom commands to enhance the development workflow:
| Command | Description |
| --- | --- |
| `directus dev` | Starts the development server. This command ensures that a development build of the Directus app is used, which includes support for Vue Devtools. If a dev build is not found, it will be created automatically. |
| `directus start` | Starts the production server. This command uses the standard production build of the Directus app. |
| `directus setup` | Automates the setup of a local development environment for the Directus app. It clones the Directus repository, installs dependencies, and builds the app for development. Use the `-f` or `--force` flag to redo the setup from scratch. |
| `directus reinit` | Re-initializes the Directus app by removing the existing app directory and re-cloning the repository. |
| `directus reinstall` | Reinstalls the Directus app dependencies. |
| `directus rebuild` | Rebuilds the Directus app. |
| `directus resymlink` | Re-creates the `dist-dev` symlinks. |
**Example Workflow:**
1. **Initial Setup:**
Run `pnpm exec directus setup` to prepare your development environment. This only needs to be done once.
2. **Development:**
Use `pnpm exec directus dev` to start the development server with Vue Devtools enabled.
3. **Production:**
Use `pnpm start` (assuming you have a "start": "directus start" script in your `package.json`) to run the production server.
## Externalizing Dependencies
The reason why this package exists is to avoid bundling common dependencies like Vue and Pinia. This is achieved by externalizing dependencies from extensions. These dependencies can then be installed once at the API level.
In your extension use an `extension.config.js` file:
1. Install `@azimutlabs/rollup-plugin-external`: `pnpm add -D @azimutlabs/rollup-plugin-external`
2. Create the `extension.config.js` file in the root of your extension.
3. Paste the following code in it:
```javascript
import { rollupPluginExternal } from '@azimutlabs/rollup-plugin-external';
export default {
plugins: [
rollupPluginExternal({
useDependencies : false,
usePeerDependencies: true,
useBuiltins : true,
}),
],
};
```
This means that Rollup will avoid bundling any dependencies that are not explicitly imported. Crucially, it will also leave out peer dependencies and Node.js built-ins. This resolves the issue where the build hangs on the second run.
The dependencies that are excluded from the bundle should be declared under `peerDependencies` in your **package.json**. After that, make sure you use the `@emahuni/directus` package as the entry point for your server. This ensures that any dependencies installed in your API, which the extension relies on, are properly resolved.
## Example
If your extension imports `await-until` like this:
```js
import awaitUntil from 'await-until';
```
…and you added it as a `devDependency`, it will not be bundled with your extension. Instead, you must also add it to `peerDependencies` and install `await-until` as a dependency in your API project (because it is now a peer requirement).
This approach makes every extension that follows the same pattern lightweight, while sharing the same `await-until` dependency across all extensions. It will only be downloaded once and loaded on demand in the browser, keeping the Directus API lean and efficient.
## Why This Matters
At present, Directus bundles every dependency used by an extension directly into the extension itself. This leads to code duplication, bloated builds, and inefficiency. Worse still, when Directus aggregates all extensions into one large bundle for the browser, the same dependency (like `await-until`) ends up included multiple times. This is the solution to that problem.
## Changelog
### v0.3.0 (2025-09-04)
- **feat:** Enhanced and modularized the Directus development setup with new CLI commands (`dev`, `setup`, etc.).
- **feat:** Added automated build switching between `dev` and `prod` builds.
- **feat:** Integrated Vue Devtools support when running in `dev` mode.
- **refactor:** Migrated the codebase to ES Modules for improved maintainability.
- **refactor:** Extracted the `resolveFromApiNodeModules` Rollup plugin into its own module.
## Contributing
Contributions are welcome! Please open an issue or submit a pull request.
## Author
- Emmanuel Mahuni
- Email: emahuni@gmail.com
## License
ISC