Plugin: server side field preprocessing

QA

There is no new feature, we just need to ensure there is no regression:

  • In the BO of Singapore, edit a page, change the content in Quill, insert a new image, save the document
  • In the public site, it should be displayed

Implementation

A new backend TS project inside the Quill-editor plugin

  • Move the file quill-delta.ts in a new directory plugins/quill-editor/backend-src/.
  • Create a new file plugins/quill-editor/tsconfig.backend.json with the following content:
{
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "module": "CommonJS",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "outDir": "./dist-backend",
  },
  "include": ["backend-src/**/*.ts"],
}
  • In plugins/quill-editor/package.json, add a script and edit the build:
    "build": "tsc && vite build && npm run build:backend",
    "build:backend": "tsc --project tsconfig.backend.json",

Augment the package: packages/plugin-lib

In quill-delta.ts, we'll have to replace these imports:

import { applyRatioToImageSize, isImageSize } from "@paroicms/server-image-cache-engine";
import { escapeHtml } from "../../../common/mail/html-helpers";
import { platformLog } from "../../../context";
import type { RenderingContext } from "../../../liquidjs-tools/liquidjs-rendering/rendering-context";
import { makeImageAvailable } from "../../../public-payload/make-image-available";
import type { SiteContext } from "../../../site-context/site-context.types";

But the only package we want to import is plugin-lib. Here is what to do:

  • Move the file packages/server-image-cache-engine/src/public-helpers.ts in plugin-lib (export it, then update the imports everywhere it is used)
  • Move the file html-helpers.ts in plugin-lib too
  • Create a PluginSiteContext in plugin-lib, with a sub-part of SiteContext (site-context.types.ts) by copy/paste. It can contain:
    • fqdn
    • siteUrl
    • siteSchema
    • themeConf
    • multilingual
    • siteLog (move the interface AppLog in plugin-lib)

We don't need platformLog, we will use siteContext.siteLog instead.

Do not move the code of makeImageAvailable function: we will use a useImage passed as a parameter instead.

Augment the plugin API

In packages/plugin-lib/types/backend-plugin-types.d.ts, the PluginApi interface, add:

  registerFieldProcessor(
    dataType: string,
    preprocessor: FieldPreprocessor
  );

With:

export interface FieldPreprocessorOptions {
  absoluteUrls?: boolean;
  outputType?: "plainText"
}

export type FieldPreprocessor = (
  ctx: FieldPreprocessorContext,
  value: unknown,
  options?: FieldPreprocessorOptions
) => unknown | Promise<unknown>

export interface FieldPreprocessorContext {
  siteContext: PluginSiteContext
  useImage(
    options: { imageUid: string; size: ImageSize }
  ): Promise<PublicImage>;
}

Now, implement (in the server) this new API registerFieldProcessor. It should simply keep the field processor in a new map of field processors, in the site context. Add this declaration in SiteContext (site-context.types.ts):

  /** The key is the `dataType` */
  fieldPreprocessors: Map<string, FieldPreprocessor[]>

In render-delta-fields.ts:

  • rename the file to preprocess-fields.ts
  • rename renderQuillDeltaFields to preprocessFields
  • Replace the implementation by:
    • create a FieldPreprocessorContext, with a new callback useImage which just calls makeImageAvailable
    • call the field preprocessors
  • create another function named preprocessField (singular) for preprocessing a single field

In the plugin, use the new API

Notice: You can look into plugins/video/plugin.cjs, there is an example of code that uses the server API for plugins.

Now, in plugins/quill-editor/plugin.cjs: create a preprocessor function with this implementation:

  • if outputType === "plainText", then call convertQuillDeltaToPlainText from plugins/quill-editor/dist-backend/quill-delta.js (in dist-backend/, because it is the compiled version here)
  • Otherwise, call convertQuillDeltaToHtml

… and register this new preprocessor function using api.registerFieldProcessor.

Edited by Oswald FAFOLAHAN