assetlink-plugin-dev-support v1.0.0-alpha16
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');
}
}
1 month ago
2 months ago
8 months ago
8 months ago
9 months ago
10 months ago
10 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago