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:
parent
4f711109df
commit
781ac9ac25
20 changed files with 548 additions and 313 deletions
7
.changeset/strong-socks-type.md
Normal file
7
.changeset/strong-socks-type.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
'@verdaccio/ui-theme': major
|
||||
'@verdaccio/ui-components': major
|
||||
'@verdaccio/web': major
|
||||
---
|
||||
|
||||
fix package configuration issues
|
|
@ -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'],
|
||||
},
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
```
|
|
@ -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.
|
||||
|
|
42
website/docs/plugin-filter.md
Normal file
42
website/docs/plugin-filter.md
Normal 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).
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
182
website/docs/plugin-theme.md
Normal file
182
website/docs/plugin-theme.md
Normal 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"/>
|
|
@ -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.
|
||||
|
|
|
@ -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',
|
||||
],
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
```
|
|
@ -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.
|
||||
|
|
42
website/versioned_docs/version-5.x/plugin-filter.md
Normal file
42
website/versioned_docs/version-5.x/plugin-filter.md
Normal 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).
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
182
website/versioned_docs/version-5.x/plugin-theme.md
Normal file
182
website/versioned_docs/version-5.x/plugin-theme.md
Normal 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"/>
|
|
@ -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_.
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue