Create a Fresh plugin!

#Deno
#Fresh
#Web Development
#Plugins
#JavaScript

A news

There is exciting news at Deno land. The Fresh team released v1.1 of the Fresh web framework. You can check details here from the official deno blog. There are many new features have been introduced by the new release. But the most awesome one should be the brand-new plugin system

What is a Deno plugin

So let's see what is a Fresh plugin. Base on the Official Document:

  1. It is an object with the Plugin interface. If you checked the definition, you will find that an object with only name property is a legal Plugin, however useless.

  2. A plugin could contain multi entrypoints that represent as a Record<string,string>, otherwise {scriptName:scriptContent}. So they are eventually some named scripts that COULD be bundled by the esbuild, and sent to the client. In those entrypoints we can do anything that javascript can do in the Web context. for examples, adding new tags, adding new eventListeners.

  3. Finally the render() property is one of the hooks (currently the only one) Fresh offered us to extend users' code. render() hooks should return PluginRenderResult, that have scripts and styles properties. With the script, we pass the name that we just provided to the plugin.entrypoints and its state(the data we want to path to the entrypoint which needs to be a JSON serializable JavaScript value). this will tell Fresh to ship entrypoint with this name to the client side. and the styles property is for the additional style sheets.

Create a Fresh plugin

So, to build a new plugin. Thanks to the Frame editors, this is very easy and can be accomplished in minutes. Let's try it!

what we will build today

Today we want to build a plugin that will add a gtag for users' Fresh site. And the user should only need to add one line of code to gain extended effect.

The plugin Api

1. Create a file named index.ts

Firstly we write down our plugin API parts.

import { Plugin } from "$fresh/server.ts";
import { PluginRenderContext } from "$fresh/src/server/types.ts";
// we named our plugin's end point as gaPlugin
// and this plugin will receive GaConfig as parameter
// GaConfig contain a property: gaKey
// so our plugin only need User to provide a gaKey which is looks like G-XXXXXXXXX.
export function gaPlugin(config: GaConfig): Plugin {
  return {
    name: "fresh_ga", // our plugin called fresh_ga
    // we pass a file plugin.ts and named it main. it contains the only entrypoint script.
    entrypoints: { main: import.meta.resolve("./plugin.ts") },
    render(ctx: PluginRenderContext) {
      ctx.render();
      return {
        // we return the entrypoint name main, and pass the config as state
        scripts: [
          {
            entrypoint: "main",
            state: config,
          },
        ],
      };
    },
  };
}

export interface GaConfig {
  gaKey: string;
}

2. Create our entrypoint plugin.ts

Now we need to create the true part that will do something for our user!

import { GaConfig } from "./index.ts";
// our only entrypoint main receive state as GaConfig as we said last part
// note: export function as default is IMPORTANT
export default function main(config: GaConfig) {
  // here we create a script tag for the gtag script
  // then append it to the user site's head
  const gaTag = document.createElement("script");
  gaTag.src = `https://www.googletagmanager.com/gtag/js?id=${config.gaKey}`;
  gaTag.async = true;
  document.head.appendChild(gaTag);
  // create another script tag to contain the gtag's setup script.
  // then also append it to the user site's head. that's all!
  const s = document.createElement("script");
  s.textContent = `window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', '${config.gaKey}');`;
  document.head.appendChild(s);
}

Usage

Now we can use our plugin. put those two files under a directory named plugin/, then mv plugin/ to any of Fresh projects.

At the main.ts

import { gaPlugin } from "./plugin/index.ts";

await start(manifest, {
  plugins: [
    // ...
    gaPlugin({ gaKey: "G-xxxxxxxxxx" }),/
    // ...
  ],
});

then in your terminal run deno task dev, and go to localhost:8000 we can check that our site's head got two additional <script /> like below;

script_tag

5. See the full module

You can check the full module at fresh-ga