0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-16 21:56:25 -05:00

docs: add docs for theme and filter plugins (#3619)

* docs: add docs for theme and filter plugins

* typos

* typos

* Create strong-socks-type.md

* Update plugins.md

* typos
This commit is contained in:
Juan Picado 2023-02-18 15:42:19 +01:00 committed by GitHub
parent 4f711109df
commit 781ac9ac25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 548 additions and 313 deletions

View file

@ -0,0 +1,7 @@
---
'@verdaccio/ui-theme': major
'@verdaccio/ui-components': major
'@verdaccio/web': major
---
fix package configuration issues

View file

@ -2,8 +2,11 @@ const path = require('path');
module.exports = () => {
return {
// location of the static files, webpack output
staticPath: path.join(__dirname, 'static'),
// webpack manifest json file
manifest: require('./static/manifest.json'),
// main manifest files to be loaded
manifestFiles: {
js: ['runtime.js', 'vendors.js', 'main.js'],
},

View file

@ -8,7 +8,8 @@
"main": "./build/index.js",
"types": "build/index.d.ts",
"files": [
"./build"
"./build",
"./src"
],
"scripts": {
"test": "cross-env TZ=UTC jest --config jest/jest.config.js",

View file

@ -14,6 +14,12 @@ export async function loadTheme(config: any) {
{ config, logger },
// TODO: add types { staticPath: string; manifest: unknown; manifestFiles: unknown }
function (plugin: any) {
/**
*
- `staticPath`: is the same data returned in Verdaccio 5.
- `manifest`: A webpack manifest object.
- `manifestFiles`: A object with one property `js` and the array (order matters) of the manifest id to be loaded in the template dynamically.
*/
return plugin.staticPath && plugin.manifest && plugin.manifestFiles;
},
config?.serverSettings?.pluginPrefix ?? 'verdaccio-theme'
@ -27,7 +33,7 @@ export async function loadTheme(config: any) {
}
export default async (config, auth, storage) => {
const pluginOptions = (await loadTheme(config)) || require('@verdaccio/ui-theme')();
const pluginOptions = (await loadTheme(config)) || require('@verdaccio/ui-theme')(config.web);
// eslint-disable-next-line new-cap
const router = express.Router();

View file

@ -1,66 +0,0 @@
---
id: dev-plugins
title: 'Developing Plugins'
---
There are many ways to extend `verdaccio`, the kind of plugins supported are:
- [Authentication](plugin-auth.md)
- [Middleware](plugin-middleware.md)
- [Storage](plugin-storage.md)
- Theme
- Filter plugins
> We recommend developing plugins using our [TypeScript type definitions](https://github.com/verdaccio/monorepo/tree/9.x/core/types).
# Other plugins
The following plugins are valid and in process of incubation.
## Theme Plugin {#theme-plugin}
The plugin must return a function that returns a **string**. The string should be the absolute location of the root of your user interface.
### API {#api}
```javascript
const path = require('path');
module.exports = (...arguments) => {
return path.join(__dirname, 'static');
};
```
It is imporant that the name of the plugin **must start with `verdaccio-theme-` prefix**.
### Theme Example {#theme-example}
- [@verdaccio/ui-theme](https://github.com/verdaccio/ui): The default Verdaccio theme based in React.js.
## Filter Plugin {#filter-plugin}
Since [`4.1.0`](https://github.com/verdaccio/verdaccio/pull/1313)
Filter plugins were introduced due a [request](https://github.com/verdaccio/verdaccio/issues/818) in order
to be able to filter metadata from uplinks.
More [info in the PR](https://github.com/verdaccio/verdaccio/pull/1161).
```yaml
filters:
storage-filter-blackwhitelist:
filter_file: /path/to/file
```
### API {#api-1}
The method `filter_metadata` will allow you to filter metadata that comes from any uplink, it is `Promise` based
and has to return the same metadata modified.
> Do not remove properties from the metadata, try to do not mutate rather return a new object.
```
interface IPluginStorageFilter<T> extends IPlugin<T> {
filter_metadata(packageInfo: Package): Promise<Package>;
}
```

View file

@ -3,7 +3,7 @@ id: plugin-auth
title: 'Authentication Plugin'
---
## What's an Authentication Plugin? {#whats-an-authentication-plugin}
## What's an authentication plugin? {#whats-an-authentication-plugin}
Is a sort plugin that allows to handle who access or publish to a specific package. By default the `htpasswd` is built-in, but can
easily be replaced by your own.

View file

@ -0,0 +1,42 @@
---
id: plugin-filter
title: 'Filter Plugin'
---
## What's a filter plugin? {#whats-a-filter-plugin}
:::caution
Filter plugins are **experimental** and requires more users feedback
:::caution
### When to use a filter plugin? {#when-to-use}
If you need to mutate the metadata for different reasons this is a way to do it, all manifest request are intercepted, but the tarballs, user, profile or tokens requests are not included. A good example to review is the [verdaccio-plugin-secfilter](https://github.com/Ansile/verdaccio-plugin-secfilter).
### Plugin structure {#build-structure}
The plugin only has one async method named `filter_metadata` that reference of the manifest and must return a copy (or modified object but not recommended) of the metadata.
```ts
export default class VerdaccioMiddlewarePlugin implements IPluginStorageFilter<CustomConfig> {
async filter_metadata(metadata: Readonly<Manifest>): Promise<Package> {
// modify the metadata
const newMetadata = { ...metadata, ...{ name: 'fooName' } };
return newMetadata;
}
}
```
### Configuration
Just add `filters` to the `config.yaml` file and your own plugin options.
```yaml
filters:
storage-filter-blackwhitelist:
filter_file: /path/to/file
```
More [info in the PR](https://github.com/verdaccio/verdaccio/pull/1161).

View file

@ -3,7 +3,7 @@ id: plugin-middleware
title: 'Middleware Plugin'
---
## What's an Middleware Plugin? {#whats-an-middleware-plugin}
## What's a Middleware Plugin? {#whats-a-middleware-plugin}
Middleware plugins have the capability to modify the API (web and cli) layer, either adding new endpoints or intercepting requests.

View file

@ -3,7 +3,7 @@ id: plugin-storage
title: 'Storage Plugin'
---
## What's an Storage Plugin? {#whats-an-storage-plugin}
## What's a Storage Plugin? {#whats-a-storage-plugin}
Verdaccio by default uses a file system storage plugin [local-storage](https://github.com/verdaccio/verdaccio/tree/master/packages/plugins/local-storage). The default storage can be easily replaced, either using a community plugin or creating one by your own.

View file

@ -0,0 +1,182 @@
---
id: plugin-theme
title: 'Theme Plugin'
---
## What's a theme plugin? {#whats-a-theme-plugin}
Verdaccio uses by default a [custom UI](https://www.npmjs.com/package/@verdaccio/ui-theme) that provides a good set of feature to visualize the packages, but might be case your team needs some custom extra features and here is where a custom theme is an option. The plugin store static assets that will be loaded in the client side when the page is being rendered.
### How a theme plugin load phase works?
```mermaid
stateDiagram-v2
state if_loads <<choice>>
state if_load_fails <<choice>>
start : Verdaccio start
Yes: Loading custom plugin
No: Custom plugin not found
Yes_loads: Plugin loads successfully
No_loads: Plugin fails on load
load_default: Load default theme (@verdaccio/theme-ui)
Crash: Verdaccio stops
[*] --> start
start --> if_loads
if_loads --> No: false
if_loads --> Yes : true
Yes --> if_load_fails
No --> load_default
if_load_fails --> No_loads: false
if_load_fails --> Yes_loads : true
No_loads --> Crash
```
### How the assets of the theme loads? {#loads}
:::caution
By default the application loads on `http://localhost:4873`, but in cases where a resverse proxy with custom domain are involved the assets are loaded based on the property `__VERDACCIO_BASENAME_UI_OPTIONS.base` and `__VERDACCIO_BASENAME_UI_OPTIONS.basename`, thus only one domain configuration can be used.
:::caution
The theme loads only in the client side, the application renders HTML with `<script>` tags to render the application, the bundler takes care of load any other assets as `svg`, `images` or _chunks_ associated with it.
### The `__VERDACCIO_BASENAME_UI_OPTIONS` object
The `window.__VERDACCIO_BASENAME_UI_OPTIONS` is available in the browser global context, the shape is documented is defined by the [here](https://verdaccio.org/docs/next/api/types/modules/#templateuioptions) at the `TemplateUIOptions` types definitions.
```js
// output example
{
"darkMode": false,
"basename": "/",
"base": "https://registry.my.org/",
"primaryColor": "#4b5e40",
"version": "5.20.1",
"pkgManagers": [
"yarn",
"pnpm",
"npm"
],
"login": true,
"logo": "",
"title": "Verdaccio Registry",
"scope": "",
"language": "es-US"
}
```
### Theme Configuration {#theme-configuration}
By default verdaccio loads the `@verdaccio/ui-theme` which is bundled in the main package, if you want to load your custom plugin has to be installed where could be found.
```bash
$> npm install --global verdaccio-theme-dark
```
:::caution
The plugin name prefix must start with `verdaccio-theme-xxx`, otherwise the plugin will be ignored.
:::caution
You can load only **one theme at a time (if more are provided the first one is being selected)** and pass through options if you need it.
```yaml
theme:
dark:
option1: foo
option2: bar
```
These options will be available
### Plugin structure {#build-structure}
If you have a custom user interface theme has to follow a specific structure:
```
{
"name": "verdaccio-theme-xxxx",
"version": "1.0.0",
"description": "my custom user interface",
"main": "index.js",
}
```
The main file `index.js` file should contain the following content.
```
module.exports = () => {
return {
// location of the static files, webpack output
staticPath: path.join(__dirname, 'static'),
// webpack manifest json file
manifest: require('./static/manifest.json'),
// main manifest files to be loaded
manifestFiles: {
js: ['runtime.js', 'vendors.js', 'main.js'],
},
};
};
```
If any of the following properties are not available, the plugin won't load, thus follow this structure.
- `staticPath`: is the absolute/relative location of the statics files, could be any path either with `require.resolve` or build your self, what's important is inside of the package or any location that the Express.js middleware is able to find, behind the scenes the [`res.sendFile`](https://expressjs.com/en/api.html#res.sendFile) is being used.
- `manifest`: A Webpack manifest object.
- `manifestFiles`: A object with one property `js` and the array (order matters) of the manifest id to be loaded in the template dynamically.
- The `manifestFiles` refers to the main files must be loaded as part of the `html` scripts in order to load the page, you don't have to include the _chunks_ since are dynamically loaded by the bundler.
#### Manifest file {#manifest-and-webpack}
Verdaccio requires a [manifest](https://webpack.js.org/concepts/manifest/) object to render the html dynamically, in combination with the `manifestFiles` the application understand what to render.
> Currently only support `js` but if you also need `css`, we are open to discuss it and further improvements.
```
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
plugins: [
...
new WebpackManifestPlugin({
// this is optional depends of your implementation
removeKeyHash: true,
}),
...
],
```
#### Manifest with other bundlers
There is no feedback with other bundlers being used with theme plugins, but with `esbuild` could be possible generate manifests.
Alternatives:
- https://www.npmjs.com/package/esbuild-plugin-manifest
## Components UI {#components}
:::note
The components UI is an experimental feature can be used since verdccio@5.x, it's open to changes and **feedback is welcome**.
:::note
Create a new user interface from scratch is big effort, to facilitate the task exist the [@verdaccio/ui-components](https://www.npmjs.com/package/@verdaccio/ui-components) package. The components are based on the **React** library and **Material UI**.
The package export parts of the user interface that could be reused:
- React Hooks
- Providers (React Context API)
- Components
- Sections: **(Sidebar, Detail, Header, Home Page and Footer)**
https://ui-components.verdaccio.org
<iframe src="https://ui-components.verdaccio.org" height="900"/>

View file

@ -10,9 +10,8 @@ There are 5 types of plugins:
- [Authentication](plugin-auth.md)
- [Middleware](plugin-middleware.md)
- [Storage](plugin-storage.md)
- Custom Theme and filters
> If you are interested to develop your own plugin, read the [development](dev-plugins.md) section.
- [Theme UI](plugin-theme.md)
- [Filters](plugin-filter.md)
## Usage {#usage}
@ -94,7 +93,7 @@ auth:
### Middleware Configuration {#middleware-configuration}
This is an example how to set up a middleware plugin. All middleware plugins must be defined in the **middlewares** namespace.
Example how to set up a middleware plugin. All middleware plugins must be defined in the **middlewares** namespace.
```yaml
middlewares:
@ -106,7 +105,13 @@ middlewares:
### Storage Configuration {#storage-configuration}
This is an example how to set up a storage plugin. All storage plugins must be defined in the **store** namespace.
:::caution
If the `store` property is defined in the `config.yaml` file, the `storage` property is being ignored.
:::caution
Example how to set up a storage plugin. All storage plugins must be defined in the **store** namespace.
```yaml
store:
@ -116,17 +121,10 @@ store:
### Theme Configuration {#theme-configuration}
Verdaccio allows to replace the User Interface with a custom one, we call it **theme**.
By default, uses `@verdaccio/ui-theme` that comes built-in, but, you can use something different installing your own plugin.
```bash
$> npm install --global verdaccio-theme-dark
npm install --global verdaccio-theme-dark
```
> The plugin name prefix must start with `verdaccio-theme`, otherwise the plugin won't load.
You can load only one theme at a time and pass through options if you need it.
```yaml
@ -136,75 +134,31 @@ theme:
option2: bar
```
### Theme plugin development
### Filter Configuration (Experimental) {#filter-configuration}
> Since v.5.0.0
If you have a custom UI plugin for the them you will need to adapt your build to the new requirements.
The previous version you only need to return a function with a string and the path of the directory.
```
const path = require('path');
module.exports = () => {
return path.join(__dirname, 'static');
};
```
The module must return an object and the `index.html` is ignored since support dynamic rendering, eg:
```
staticPath: '/somePath/node_modules/verdaccio-theme-custom/static',
manifest: {
'main.js': '-/static/main.c21a97b1dbe8456a9c76.js',
'runtime.js': '-/static/runtime.c21a97b1dbe8456a9c76.js',
'NotFound.js': '-/static/NotFound.c21a97b1dbe8456a9c76.js',
'Provider.js': '-/static/Provider.c21a97b1dbe8456a9c76.js',
'Version.js': '-/static/Version.c21a97b1dbe8456a9c76.js',
'Home.js': '-/static/Home.c21a97b1dbe8456a9c76.js',
'Versions.js': '-/static/Versions.c21a97b1dbe8456a9c76.js',
'UpLinks.js': '-/static/UpLinks.c21a97b1dbe8456a9c76.js',
'Dependencies.js': '-/static/Dependencies.c21a97b1dbe8456a9c76.js',
'Engines.js': '-/static/Engines.c21a97b1dbe8456a9c76.js',
'Dist.js': '-/static/Dist.c21a97b1dbe8456a9c76.js',
'Install.js': '-/static/Install.c21a97b1dbe8456a9c76.js',
'Repository.js': '-/static/Repository.c21a97b1dbe8456a9c76.js',
'vendors.js': '-/static/vendors.c21a97b1dbe8456a9c76.js',
'718.c21a97b1dbe8456a9c76.js': '-/static/718.c21a97b1dbe8456a9c76.js',
'238.c21a97b1dbe8456a9c76.js': '-/static/238.c21a97b1dbe8456a9c76.js',
'73.c21a97b1dbe8456a9c76.js': '-/static/73.c21a97b1dbe8456a9c76.js'
},
manifestFiles: { js: [ 'runtime.js', 'vendors.js', 'main.js' ] }
```
- `staticPath`: is the same data returned in Verdaccio 4.
- `manifest`: A webpack manifest object.
- `manifestFiles`: A object with one property `js` and the array (order matters) of the manifest id to be loaded in the template dynamically.
#### Manifest and Webpack {#manifest-and-webpack}
Verdaccio uses the webpack [manifest](https://webpack.js.org/concepts/manifest/) object to render the html dynamically, in combination with the `manifestFiles` the application understand what to render.
> Currently only support `js` but if you also need `css`, we are open to discuss it and further improvements.
```
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
plugins: [
...
new WebpackManifestPlugin({
removeKeyHash: true,
}),
...
],
A real example from [npm i -g verdaccio-plugin-secfilter](https://github.com/Ansile/verdaccio-plugin-secfilter) filter plugin.
```yaml
filters:
plugin-secfilter:
block:
- scope: @evil # block all packages in scope
- package: semvver # block a malicious package
- package: @coolauthor/stolen
versions: '>2.0.1' # block some malicious versions of previously ok package
# uses https://www.npmjs.com/package/semver syntax
```
## Legacy plugins {#legacy-plugins}
### Sinopia Plugins {#sinopia-plugins}
:::caution
After version 6 sinopia plugins are not longer supported due the naming convention.
:::caution
> If you are relying on any sinopia plugin, remember are deprecated and might no work in the future.
- [sinopia-npm](https://www.npmjs.com/package/sinopia-npm): auth plugin for sinopia supporting an npm registry.

View file

@ -57,17 +57,23 @@ module.exports = {
type: 'category',
label: 'Development',
items: [
'plugins',
'dev-plugins',
{
type: 'link',
label: 'Search Plugins',
href: '/dev/plugins-search',
},
{
type: 'category',
label: 'Dev Guides',
items: ['plugin-generator', 'plugin-auth', 'plugin-middleware', 'plugin-storage'],
label: 'Plugins',
items: [
'plugins',
'plugin-generator',
'plugin-auth',
'plugin-middleware',
'plugin-storage',
'plugin-theme',
'plugin-filter',
{
type: 'link',
label: 'Search Plugins',
href: '/dev/plugins-search',
},
],
},
'node-api',
],

View file

@ -1,66 +0,0 @@
---
id: dev-plugins
title: 'Developing Plugins'
---
There are many ways to extend `verdaccio`, the kind of plugins supported are:
- [Authentication](plugin-auth.md)
- [Middleware](plugin-middleware.md)
- [Storage](plugin-storage.md)
- Theme
- Filter plugins
> We recommend developing plugins using our [TypeScript type definitions](https://github.com/verdaccio/monorepo/tree/9.x/core/types).
# Other plugins
The following plugins are valid and in process of incubation.
## Theme Plugin {#theme-plugin}
The plugin must return a function that returns a **string**. The string should be the absolute location of the root of your user interface.
### API {#api}
```javascript
const path = require('path');
module.exports = (...arguments) => {
return path.join(__dirname, 'static');
};
```
It is imporant that the name of the plugin **must start with `verdaccio-theme-` prefix**.
### Theme Example {#theme-example}
- [@verdaccio/ui-theme](https://github.com/verdaccio/ui): The default Verdaccio theme based in React.js.
## Filter Plugin {#filter-plugin}
Since [`4.1.0`](https://github.com/verdaccio/verdaccio/pull/1313)
Filter plugins were introduced due a [request](https://github.com/verdaccio/verdaccio/issues/818) in order
to be able to filter metadata from uplinks.
More [info in the PR](https://github.com/verdaccio/verdaccio/pull/1161).
```yaml
filters:
storage-filter-blackwhitelist:
filter_file: /path/to/file
```
### API {#api-1}
The method `filter_metadata` will allow you to filter metadata that comes from any uplink, it is `Promise` based
and has to return the same metadata modified.
> Do not remove properties from the metadata, try to do not mutate rather return a new object.
```
interface IPluginStorageFilter<T> extends IPlugin<T> {
filter_metadata(packageInfo: Package): Promise<Package>;
}
```

View file

@ -3,7 +3,7 @@ id: plugin-auth
title: 'Authentication Plugin'
---
## What's an Authentication Plugin? {#whats-an-authentication-plugin}
## What's an authentication plugin? {#whats-an-authentication-plugin}
Is a sort plugin that allows to handle who access or publish to a specific package. By default the `htpasswd` is built-in, but can
easily be replaced by your own.

View file

@ -0,0 +1,42 @@
---
id: plugin-filter
title: 'Filter Plugin'
---
## What's a filter plugin? {#whats-a-filter-plugin}
:::caution
Filter plugins are **experimental** and requires more users feedback
:::caution
### When to use a filter plugin? {#when-to-use}
If you need to mutate the metadata for different reasons this is a way to do it, all manifest request are intercepted, but the tarballs, user, profile or tokens requests are not included. A good example to review is the [verdaccio-plugin-secfilter](https://github.com/Ansile/verdaccio-plugin-secfilter).
### Plugin structure {#build-structure}
The plugin only has one async method named `filter_metadata` that reference of the manifest and must return a copy (or modified object but not recommended) of the metadata.
```ts
export default class VerdaccioMiddlewarePlugin implements IPluginStorageFilter<CustomConfig> {
async filter_metadata(metadata: Readonly<Manifest>): Promise<Package> {
// modify the metadata
const newMetadata = { ...metadata, ...{ name: 'fooName' } };
return newMetadata;
}
}
```
### Configuration
Just add `filters` to the `config.yaml` file and your own plugin options.
```yaml
filters:
storage-filter-blackwhitelist:
filter_file: /path/to/file
```
More [info in the PR](https://github.com/verdaccio/verdaccio/pull/1161).

View file

@ -3,7 +3,7 @@ id: plugin-middleware
title: 'Middleware Plugin'
---
## What's an Middleware Plugin? {#whats-an-middleware-plugin}
## What's a middleware plugin? {#whats-a-middleware-plugin}
Middleware plugins have the capability to modify the API (web and cli) layer, either adding new endpoints or intercepting requests.

View file

@ -3,7 +3,7 @@ id: plugin-storage
title: 'Storage Plugin'
---
## What's an Storage Plugin? {#whats-an-storage-plugin}
## What's a storage plugin? {#whats-an-storage-plugin}
Verdaccio by default uses a file system storage plugin [local-storage](https://github.com/verdaccio/verdaccio/tree/master/packages/plugins/local-storage). The default storage can be easily replaced, either using a community plugin or creating one by your own.

View file

@ -0,0 +1,182 @@
---
id: plugin-theme
title: 'Theme Plugin'
---
## What's a theme plugin? {#whats-a-theme-plugin}
Verdaccio uses by default a [custom UI](https://www.npmjs.com/package/@verdaccio/ui-theme) that provides a good set of feature to visualize the packages, but might be case your team needs some custom extra features and here is where a custom theme is an option. The plugin store static assets that will be loaded in the client side when the page is being rendered.
### How a theme plugin load phase works?
```mermaid
stateDiagram-v2
state if_loads <<choice>>
state if_load_fails <<choice>>
start : Verdaccio start
Yes: Loading custom plugin
No: Custom plugin not found
Yes_loads: Plugin loads successfully
No_loads: Plugin fails on load
load_default: Load default theme (@verdaccio/theme-ui)
Crash: Verdaccio stops
[*] --> start
start --> if_loads
if_loads --> No: false
if_loads --> Yes : true
Yes --> if_load_fails
No --> load_default
if_load_fails --> No_loads: false
if_load_fails --> Yes_loads : true
No_loads --> Crash
```
### How the assets of the theme loads? {#loads}
:::caution
By default the application loads on `http://localhost:4873`, but in cases where a resverse proxy with custom domain are involved the assets are loaded based on the property `__VERDACCIO_BASENAME_UI_OPTIONS.base` and `__VERDACCIO_BASENAME_UI_OPTIONS.basename`, thus only one domain configuration can be used.
:::caution
The theme loads only in the client side, the application renders HTML with `<script>` tags to render the application, the bundler takes care of load any other assets as `svg`, `images` or _chunks_ associated with it.
### The `__VERDACCIO_BASENAME_UI_OPTIONS` object
The `window.__VERDACCIO_BASENAME_UI_OPTIONS` is available in the browser global context, the shape is documented is defined by the [here](https://verdaccio.org/docs/next/api/types/modules/#templateuioptions) at the `TemplateUIOptions` types definitions.
```js
// output example
{
"darkMode": false,
"basename": "/",
"base": "https://registry.my.org/",
"primaryColor": "#4b5e40",
"version": "5.20.1",
"pkgManagers": [
"yarn",
"pnpm",
"npm"
],
"login": true,
"logo": "",
"title": "Verdaccio Registry",
"scope": "",
"language": "es-US"
}
```
### Theme Configuration {#theme-configuration}
By default verdaccio loads the `@verdaccio/ui-theme` which is bundled in the main package, if you want to load your custom plugin has to be installed where could be found.
```bash
$> npm install --global verdaccio-theme-dark
```
:::caution
The plugin name prefix must start with `verdaccio-theme-xxx`, otherwise the plugin will be ignored.
:::caution
You can load only **one theme at a time (if more are provided the first one is being selected)** and pass through options if you need it.
```yaml
theme:
dark:
option1: foo
option2: bar
```
These options will be available
### Plugin structure {#build-structure}
If you have a custom user interface theme has to follow a specific structure:
```
{
"name": "verdaccio-theme-xxxx",
"version": "1.0.0",
"description": "my custom user interface",
"main": "index.js",
}
```
The main file `index.js` file should contain the following content.
```
module.exports = () => {
return {
// location of the static files, webpack output
staticPath: path.join(__dirname, 'static'),
// webpack manifest json file
manifest: require('./static/manifest.json'),
// main manifest files to be loaded
manifestFiles: {
js: ['runtime.js', 'vendors.js', 'main.js'],
},
};
};
```
If any of the following properties are not available, the plugin won't load, thus follow this structure.
- `staticPath`: is the absolute/relative location of the statics files, could be any path either with `require.resolve` or build your self, what's important is inside of the package or any location that the Express.js middleware is able to find, behind the scenes the [`res.sendFile`](https://expressjs.com/en/api.html#res.sendFile) is being used.
- `manifest`: A Webpack manifest object.
- `manifestFiles`: A object with one property `js` and the array (order matters) of the manifest id to be loaded in the template dynamically.
- The `manifestFiles` refers to the main files must be loaded as part of the `html` scripts in order to load the page, you don't have to include the _chunks_ since are dynamically loaded by the bundler.
#### Manifest file {#manifest-and-webpack}
Verdaccio requires a [manifest](https://webpack.js.org/concepts/manifest/) object to render the html dynamically, in combination with the `manifestFiles` the application understand what to render.
> Currently only support `js` but if you also need `css`, we are open to discuss it and further improvements.
```
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
plugins: [
...
new WebpackManifestPlugin({
// this is optional depends of your implementation
removeKeyHash: true,
}),
...
],
```
#### Manifest with other bundlers
There is no feedback with other bundlers being used with theme plugins, but with `esbuild` could be possible generate manifests.
Alternatives:
- https://www.npmjs.com/package/esbuild-plugin-manifest
## Components UI {#components}
:::note
The components UI is an experimental feature can be used since verdccio@5.x, it's open to changes and **feedback is welcome**.
:::note
Create a new user interface from scratch is big effort, to facilitate the task exist the [@verdaccio/ui-components](https://www.npmjs.com/package/@verdaccio/ui-components) package. The components are based on the **React** library and **Material UI**.
The package export parts of the user interface that could be reused:
- React Hooks
- Providers (React Context API)
- Components
- Sections: **(Sidebar, Detail, Header, Home Page and Footer)**
https://ui-components.verdaccio.org
<iframe src="https://ui-components.verdaccio.org" height="900"/>

View file

@ -10,9 +10,8 @@ There are 5 types of plugins:
- [Authentication](plugin-auth.md)
- [Middleware](plugin-middleware.md)
- [Storage](plugin-storage.md)
- Custom Theme and filters
> If you are interested to develop your own plugin, read the [development](dev-plugins.md) section.
- [Theme UI](plugin-theme.md)
- [Filters](plugin-filter.md)
## Usage {#usage}
@ -94,7 +93,7 @@ auth:
### Middleware Configuration {#middleware-configuration}
This is an example how to set up a middleware plugin. All middleware plugins must be defined in the **middlewares** namespace.
Example how to set up a middleware plugin. All middleware plugins must be defined in the **middlewares** namespace.
```yaml
middlewares:
@ -106,7 +105,13 @@ middlewares:
### Storage Configuration {#storage-configuration}
This is an example how to set up a storage plugin. All storage plugins must be defined in the **store** namespace.
:::caution
If the `store` property is defined in the `config.yaml` file, the `storage` property is being ignored.
:::caution
Example how to set up a storage plugin. All storage plugins must be defined in the **store** namespace.
```yaml
store:
@ -116,17 +121,10 @@ store:
### Theme Configuration {#theme-configuration}
Verdaccio allows to replace the User Interface with a custom one, we call it **theme**.
By default, uses `@verdaccio/ui-theme` that comes built-in, but, you can use something different installing your own plugin.
```bash
$> npm install --global verdaccio-theme-dark
npm install --global verdaccio-theme-dark
```
> The plugin name prefix must start with `verdaccio-theme`, otherwise the plugin won't load.
You can load only one theme at a time and pass through options if you need it.
```yaml
@ -136,75 +134,16 @@ theme:
option2: bar
```
### Theme plugin development
> Since v.5.0.0
If you have a custom UI plugin for the them you will need to adapt your build to the new requirements.
The previous version you only need to return a function with a string and the path of the directory.
```
const path = require('path');
module.exports = () => {
return path.join(__dirname, 'static');
};
```
The module must return an object and the `index.html` is ignored since support dynamic rendering, eg:
```
staticPath: '/somePath/node_modules/verdaccio-theme-custom/static',
manifest: {
'main.js': '-/static/main.c21a97b1dbe8456a9c76.js',
'runtime.js': '-/static/runtime.c21a97b1dbe8456a9c76.js',
'NotFound.js': '-/static/NotFound.c21a97b1dbe8456a9c76.js',
'Provider.js': '-/static/Provider.c21a97b1dbe8456a9c76.js',
'Version.js': '-/static/Version.c21a97b1dbe8456a9c76.js',
'Home.js': '-/static/Home.c21a97b1dbe8456a9c76.js',
'Versions.js': '-/static/Versions.c21a97b1dbe8456a9c76.js',
'UpLinks.js': '-/static/UpLinks.c21a97b1dbe8456a9c76.js',
'Dependencies.js': '-/static/Dependencies.c21a97b1dbe8456a9c76.js',
'Engines.js': '-/static/Engines.c21a97b1dbe8456a9c76.js',
'Dist.js': '-/static/Dist.c21a97b1dbe8456a9c76.js',
'Install.js': '-/static/Install.c21a97b1dbe8456a9c76.js',
'Repository.js': '-/static/Repository.c21a97b1dbe8456a9c76.js',
'vendors.js': '-/static/vendors.c21a97b1dbe8456a9c76.js',
'718.c21a97b1dbe8456a9c76.js': '-/static/718.c21a97b1dbe8456a9c76.js',
'238.c21a97b1dbe8456a9c76.js': '-/static/238.c21a97b1dbe8456a9c76.js',
'73.c21a97b1dbe8456a9c76.js': '-/static/73.c21a97b1dbe8456a9c76.js'
},
manifestFiles: { js: [ 'runtime.js', 'vendors.js', 'main.js' ] }
```
- `staticPath`: is the same data returned in Verdaccio 4.
- `manifest`: A webpack manifest object.
- `manifestFiles`: A object with one property `js` and the array (order matters) of the manifest id to be loaded in the template dynamically.
#### Manifest and Webpack {#manifest-and-webpack}
Verdaccio uses the webpack [manifest](https://webpack.js.org/concepts/manifest/) object to render the html dynamically, in combination with the `manifestFiles` the application understand what to render.
> Currently only support `js` but if you also need `css`, we are open to discuss it and further improvements.
```
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
plugins: [
...
new WebpackManifestPlugin({
removeKeyHash: true,
}),
...
],
```
## Legacy plugins {#legacy-plugins}
### Sinopia Plugins {#sinopia-plugins}
:::caution
Plugins from sinopia era are deprecated but still available in verdaccio@5.x versions but already removed from next 6.x versions, consider migrate them or stop using them for future updates.
:::caution
> If you are relying on any sinopia plugin, remember are deprecated and might no work in the future.
- [sinopia-npm](https://www.npmjs.com/package/sinopia-npm): auth plugin for sinopia supporting an npm registry.
@ -224,6 +163,3 @@ const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
- [sinopia-gitlab](https://www.npmjs.com/package/sinopia-gitlab): Gitlab authentication plugin for sinopia
- [sinopia-ldap](https://www.npmjs.com/package/sinopia-ldap): LDAP auth plugin for sinopia.
- [sinopia-github-oauth-env](https://www.npmjs.com/package/sinopia-github-oauth-env) Sinopia authentication plugin with github oauth web flow.
> All sinopia plugins should be compatible with all future verdaccio versions. Anyhow, we encourage contributors to migrate them to the
> modern verdaccio API and using the prefix as _verdaccio-xx-name_.

View file

@ -44,17 +44,23 @@
"type": "category",
"label": "Development",
"items": [
"plugins",
"dev-plugins",
{
"type": "link",
"label": "Search Plugins",
"href": "/dev/plugins-search"
},
{
"type": "category",
"label": "Dev Guides",
"items": ["plugin-generator", "plugin-auth", "plugin-middleware", "plugin-storage"]
"label": "Plugins",
"items": [
"plugins",
"plugin-generator",
"plugin-auth",
"plugin-middleware",
"plugin-storage",
"plugin-theme",
"plugin-filter",
{
"type": "link",
"label": "Search Plugins",
"href": "/dev/plugins-search"
}
]
},
"node-api"
]