npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

assetlink-plugin-dev-support

v1.0.0-alpha16

Published

Provides build and development support for Asset Link plugins

Downloads

19

Readme

Welcome to the documentation for Asset Link's Plugin Dev Support package!

Usage

mkdir example_alink_plugins && cd example_alink_plugins
npm init -y
npm install --save-dev assetlink-plugin-dev-support webpack webpack-cli webpack-dev-server

webpack.config.js

const { GenerateDefaultPluginConfigYmlFilesPlugin, createDevServerConfig } = require('assetlink-plugin-dev-support');

module.exports = {
  // We have no entry since this package just contains uncompiled plugins
  entry: {},
  output: {
    // Use the current directory to prevent a 'dist/' folder from being created there should be no output, otherwise
    path: __dirname,
  },
  mode: 'development',
  plugins: [
    new GenerateDefaultPluginConfigYmlFilesPlugin({
      pluginDir: __dirname,
      // This must match your drupal module name for Asset Link to be able to serve your plugins
      drupalModuleName: 'example_alink_plugins',
    }),
  ],
  devServer: createDevServerConfig({
    pluginDir: __dirname,
  }),
};

package.json

Update package.json with "build" and "serve" scripts;

diff --git a/package.json b/package.json
index 0abd22b..bc028b4 100644
--- a/package.json
+++ b/package.json
@@ -5,5 +5,6 @@
   "main": "index.js",
   "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "build": "webpack build",
+    "serve": "webpack serve"
   },
   "repository": {

** *.alink.* Plugin Files

The configuration above expects the plugins to be in the root of the package. e.g. ./NameBobAssetActionProvider.alink.js would be a sibling of webpack.config.js.

example_alink_plugins.info.yml

name: A package with some plugins for farmOS Asset Link
description: Provides Asset Link plugins that do awesome stuff
type: module
package: Example farmOS Asset Link Plugins
core_version_requirement: ^9
dependencies:
  - farmos_asset_link

Build Config Yaml Files

npm run build

Serve Plugins for Development

npm run serve

By default this will serve the plugins using a free port at http://farmos.test. You'll need to somehow create a DNS entry pointing at that domain.

Alternatively, you can just use localhost by exporting the following environment variable;

export ASSET_LINK_PLUGIN_SERVING_DEV_HOST="http://localhost"

Using the Served Plugins

The plugins are served under a /plugins/ path. So "NameBobAssetActionProvider.alink.js" would by default be served at "http://farmos.test:8080/plugins/NameBobAssetActionProvider.alink.js" (maybe with a different port).

Also a plugin list is served at /plugins.repo.json (e.g. "http://farmos.test:8080/plugins.repo.json") which can be installed via the Manage Plugins page in Asset Link and which specifies an updateChannel websocket. This means that - if everything is working correctly - plugins should be live reloaded by Asset Link when they are changed on the local filesystem.

Note: It is probably necessary for the protocol (e.g. http vs https) to match between the farmOS / Asset Link instance and the dev server this creates. If connecting from https, the instructions below for enabling HTTPS in the dev server are most likely required.

HTTPS

To enable HTTPS the following steps are needed;

mkdir -p ./devcerts/mydomain.farmos.test/
cp /path/to/my/dev/server/rootCA.pem ./devcerts/rootCA.pem
cp /path/to/my/dev/server/privkey.pem ./devcerts/mydomain.farmos.test/privkey.pem
cp /path/to/my/dev/server/fullchain.pem ./devcerts/mydomain.farmos.test/fullchain.pem
export ASSET_LINK_PLUGIN_SERVING_DEV_HOST='https://mydomain.farmos.test'
npm run serve

Note: It is necessary for the browser where Asset Link is running to fully trust the certificates above.

Check out mkcert as a convenient tool for creating/trusting certs for development on Linux.

Example package

See https://github.com/symbioquine/example-assetlink-plugin-pkg

Plugins that require a (Webpack) build step

For a plugin to include modules that don't come with Asset Link, a Webpack build step may be required.

First we would create the new plugin in a src directory;

mkdir ./src
edit ./src/ExampleChartPage.alink.js

src/ExampleChartPage.alink.js

import { h } from 'vue';
import {
  Chart as ChartJS,
  Colors,
  CategoryScale,
  LinearScale,
  BarElement,
  Legend
} from 'chart.js'

ChartJS.register(
  Colors,
  BarElement,
  CategoryScale,
  LinearScale,
  Legend
);

import {
  Bar as BarChart
} from 'vue-chartjs'

export default class ExampleChartPage {
  static onLoad(handle, assetLink) {

    handle.defineRoute('com.example.farmos_asset_link.routes.v0.example_chart_page', route => {
      route.path('/example-chart-page');

      const data = [
          { year: 2010, count: 10 },
          { year: 2011, count: 20 },
          { year: 2012, count: 15 },
          { year: 2013, count: 25 },
          { year: 2014, count: 22 },
          { year: 2015, count: 30 },
          { year: 2016, count: 28 },
      ];

      route.component(async () => h(BarChart, {
        data: {
          labels: data.map(row => row.year),
          datasets: [
            {
              label: 'Acquisitions by year',
              data: data.map(row => row.count)
            }
          ]
        }
      }));
    });

  }
}

Add our dependencies;

npm install chart.js vue-chartjs

Finally, our webpack.config.js gets a bit more complicated than the earlier example;

--- a/./webpack.config.js
+++ b/./webpack.config.js
@@ -1,17 +1,42 @@
-const { GenerateDefaultPluginConfigYmlFilesPlugin, createDevServerConfig } = require('assetlink-plugin-dev-support');
+const {
+  assetLinkIncludedLibraries,
+  GenerateDefaultPluginConfigYmlFilesPlugin,
+  createDevServerConfig
+} = require('assetlink-plugin-dev-support');
 
 module.exports = {
-  // We have no entry since this package just contains uncompiled plugins
-  entry: {},
+  entry: {
+    // Add an entry here for each plugin in the `src` directory that needs building
+    'ExampleChartPage.alink.js': './src/ExampleChartPage.alink.js',
+  },
   output: {
-    // Use the current directory to prevent a 'dist/' folder from being created there should be no output, otherwise
+    // Output the built plugins in the current directory - alongside any unbuilt plugins
     path: __dirname,
+    // Use just the entry name as our output plugin name
+    filename: '[name]',
+    // Make our built plugin code use module import/exports
+    library: { type: 'commonjs-module' },
+    // Required, but don't worry about it (For nerds: with the default `publicPath: "auto"` Webpack
+    // outputs code that doesn't work in our Asset Link browser environment - similar to this issue:
+    // https://github.com/angular-architects/module-federation-plugin/issues/96)
+    publicPath: '/',
   },
+  // This can be changed to 'production' - see https://webpack.js.org/configuration/mode/
   mode: 'development',
+
+  // Output a module and don't try and bundle things like `vue` that are provided by Asset Link
+  experiments: {
+    outputModule: true,
+  },
+  externalsType: 'module',
+  externals: {
+    ...assetLinkIncludedLibraries,
+  },

Example package with Built Plugin

See https://github.com/symbioquine/example-assetlink-built-plugin-pkg

Vue SFC Plugins that require a (Webpack) build step

If we want to write .alink.vue plugins that need a build step to include other modules, we can do that too.

From the previous example we can rename our ExampleChartPage.alink.js to ExampleChartPage.alink.vue and make a few changes;

mv ./src/ExampleChartPage.alink.js ./src/ExampleChartPage.alink.vue
edit ./src/ExampleChartPage.alink.vue

The new ExampleChartPage.alink.vue file;

<script setup>
import {
  Chart as ChartJS,
  Colors,
  CategoryScale,
  LinearScale,
  BarElement,
  Legend
} from 'chart.js'

ChartJS.register(
  Colors,
  BarElement,
  CategoryScale,
  LinearScale,
  Legend
);

import {
  Bar as BarChart
} from 'vue-chartjs'

const data = [
  { year: 2010, count: 10 },
  { year: 2011, count: 20 },
  { year: 2012, count: 15 },
  { year: 2013, count: 25 },
  { year: 2014, count: 22 },
  { year: 2015, count: 30 },
  { year: 2016, count: 28 },
];

const chartData = {
  labels: data.map(row => row.year),
  datasets: [
    {
      label: 'Acquisitions by year',
      data: data.map(row => row.count)
    }
  ]
};
</script>

<template>
  <bar-chart :data="chartData"></bar-chart>
</template>

<script>
export default {
  onLoad(handle, assetLink) {
    handle.defineRoute('com.example.farmos_asset_link.routes.v0.example_chart_page', route => {
      route.path('/example-chart-page');
      route.component(handle.thisPlugin);
    });
  }
}
</script>

<style scoped>
/* This style block isn't required, just included as an example to show that the scoped styling works */
canvas {
  border: solid black 10px;
}
</style>

Add our dependencies;

npm install -D vue-loader vue-style-loader css-loader

Update webpack.config.js;

--- a/./webpack.config.js
+++ b/./webpack.config.js
@@ -1,3 +1,5 @@
+const { VueLoaderPlugin } = require("vue-loader");
+
 const {
   assetLinkIncludedLibraries,
   GenerateDefaultPluginConfigYmlFilesPlugin,
@@ -7,7 +9,8 @@ const {
 module.exports = {
   entry: {
     // Add an entry here for each plugin in the `src` directory that needs building
-    'ExampleChartPage.alink.js': './src/ExampleChartPage.alink.js',
+    'ExampleSimplePage.alink.js': './src/ExampleSimplePage.alink.vue',
+    'ExampleChartPage.alink.js': './src/ExampleChartPage.alink.vue',
   },
   output: {
     // Output the built plugins in the current directory - alongside any unbuilt plugins
@@ -33,7 +36,27 @@ module.exports = {
     ...assetLinkIncludedLibraries,
   },
 
+  module: {
+    rules: [
+      {
+        test: /\.vue$/i,
+        exclude: /(node_modules)/,
+        use: {
+          loader: "vue-loader",
+        },
+      },
+      {
+        test: /\.css$/,
+        use: [
+          { loader: "vue-style-loader" },
+          { loader: "css-loader" },
+        ],
+      },
+    ]
+  },
+
   plugins: [
+    new VueLoaderPlugin(),
     new GenerateDefaultPluginConfigYmlFilesPlugin({
       pluginDir: __dirname,
       drupalModuleName: 'example_built_vue_alink_plugins',

Example package with Built Vue SFC Plugins

See https://github.com/symbioquine/example-assetlink-built-vue-plugin-pkg

GenerateDefaultPluginConfigYmlFilesPlugin API

farmOS modules that package Asset Link plugins can just hardcode the install yaml files, but this convenience Webpack plugin is also provided to generate them automatically.

function GenerateDefaultPluginConfigYmlFilesPlugin(options)

options.pluginDir

This is the directory where the plugins are located. Usually, this will just be __dirname.

pluginDir: __dirname

options.drupalModuleName

This is the name of the drupal module in which the resulting yaml files will be packaged.

drupalModuleName: 'example_alink_plugins'

options.configOutputDir

Optionally, it is possible to specify where the resulting yaml files will be output to.

Defaults to ${options.pluginDir}/config/install if not specified.

configOutputDir: `${__dirname}/../somewhere/else`

options.pluginUrlFn

Optionally, it is possible to specify the plugin URL as a function of the plugin filename and the options.

Defaults to (filename, options) => `{module:${options.drupalModuleName}}/${filename}` if not specified.

pluginUrlFn: (filename) => `{base_path}alink/plugins/${filename}`,

options.pluginConfigMutator

Optionally, it is possible to specify a function that will mutate the final yaml config before it is written to disk. This can be used to add module dependencies or sidebar whitelists.

Defaults to (pluginConfig) => { /* No-op */ } if not specified.

pluginConfigMutator: (pluginConfig) => {
  if (pluginConfig.id === 'MyPlansPlugin') {
    pluginConfig.sidebarUrlPattern = "https?:\\/\\/.*\\/plan\\/(\\d+)";
    pluginConfig.dependencies.enforced.module.push('farm_crop_plan');
  }
}