How a Single Input Box Enables Unlimited Backend Logic Flexibility

This article explains how a function input box, combined with parameter interpolation and a sandboxed Node.js environment, lets backend developers write arbitrary JavaScript to dynamically generate HTML components, handle complex logic, and maintain security, offering unparalleled flexibility for ever‑changing business requirements.

HomeTech
HomeTech
HomeTech
How a Single Input Box Enables Unlimited Backend Logic Flexibility

A Single Input Box That Meets the Backend's Ever‑Changing Demands

In backend management systems we often face complex, constantly evolving business requirements. Traditional configuration approaches struggle to satisfy such demands. This article presents a flexible solution: a function input box that allows users to write JavaScript code with parameter interpolation and sandboxed execution, enabling a wide range of dynamic scenarios.

Why Write Functions Directly in the Input Box?

Limitations of Traditional Form Inputs

Dynamic Logic Handling : Need to generate different content based on varying conditions.

Complex Data Transformation : Requires sophisticated calculations and conversions on input data.

Conditional Branching : Logic branches must be executed according to parameter values.

Data Linkage : Multiple parameters have complex inter‑dependencies.

Advantages of an Input‑Box Function

Unlimited Flexibility : JavaScript’s expressive power is virtually unrestricted.

Dynamic Execution : Results can be generated at runtime based on parameters.

Logic Reuse : Complex logic can be encapsulated into reusable functions.

Easy Debugging : Debug via console.log and similar tools.

How to Define an Input‑Box Function

We define a function‑input box named output. Users write JavaScript inside it; the backend executes the code and returns dynamic HTML tags.

Interface Display

Custom Component Content Output

Component Content : an asynchronous JS function

Function Name : output Function Parameters : (auto‑injected) config,

option
config

: General parameter collection object. option: Customizable parameter collection object.

Function Return : an array of objects, each describing an HTML tag (a component may consist of multiple tags). type: Tag type (script / style / link / meta, etc.). name: Component name for identification. attrs: Tag attribute collection. content: Tag content.

Basic Example

In our system the main use case is dynamic generation of web components composed of one or more tags (script, style, link, meta). Users define the component structure, style, and behavior by writing a function:

async function output(config, option, query) {
  const content = await fetchData({
    url: config.url,
  });
  return [
    {
      type: 'script',
      name: 'example-component',
      attrs: [{ name: 'type', value: 'text/javascript' }],
      content: content,
    },
  ];
}

Security: Sandbox Isolation

Sandbox Environment Design

To ensure safe execution of user code we create a sandbox using Node.js vm module:

import vm from 'node:vm';
// Create a restricted sandbox context
const sandbox = {
  _, // lodash
  console, // console output
  fetchData, // data request method
  transformCustomVariables, // custom variable transformation
  URL,
};
const context = vm.createContext(sandbox);

Security Measures

Limited Global Objects : Only expose necessary APIs, preventing access to sensitive system resources.

Code Execution Isolation : User code runs in an independent context, unable to affect the main process.

Error Capture : Robust error handling prevents malicious code from crashing the system.

Resource Limits : Execution time and memory limits can be set to avoid infinite loops.

Executing the Input‑Box Function

The backend reads the function string from the input box ( userFunctionString) and processes it:

const handleTemplate = async (userFunctionString, config, option) => {
  try {
    // 1. Parameter interpolation
    const replacedUserFunctionString = replaceInterpolate(userFunctionString, { config, option });
    // 2. Execute user code in sandbox
    const userFunction = vm.runInContext(`(${replacedUserFunctionString})`, context);
    // 3. Run the function and get result
    const result = await userFunction(config, option);
    // 4. Post‑process (e.g., minify code)
    const processedResult = result.map(item => ({
      ...item,
      content: uglifyCode(item.content),
    }));
    return processedResult;
  } catch (error) {
    throw new Error(`Function execution error: ${error.message}`);
  }
};

Provided Objects and Methods Reference

lodash ( _) – rich utility functions. fetchData – generic HTTP request wrapper (axios based) with retry, cache, timeout support.

Flexibility: Parameter Interpolation

Two Parameter Types

Our system defines two kinds of parameters, each serving a specific purpose:

1. config (General Parameters)

Source : Front‑end parameter input, manually configured by the user.

Characteristics : Auto‑incremental, can dynamically add new configuration items.

Usage : Stores generic configuration such as project ID, environment variables, etc.

2. option (Custom Parameters)

Source : Front‑end parameter input, manually configured by the user.

Characteristics : Auto‑incremental, tailored to specific business scenarios.

Usage : Stores business‑related custom configuration.

Supported Parameter Types

The input box accepts all standard JavaScript data types, allowing users to write code as they would in a normal JS file. The backend correctly processes the following:

Basic Types

Number: e.g., 42 String: e.g., "This is a description" Boolean: checkbox input – true/false

Composite Types

Array: ['frontend', 'backend', 'fullstack', /\d+/] Object:

{api: {baseUrl: 'https://api.example.com', timeout: 5000, headers: {'Content-Type': 'application/json'}}, features: ['feature1', 'feature2']}

Function:

function (value) { return value.toString().padStart(2, '0'); }

Interpolation Mechanism Implementation

Interpolation Syntax

We use {{}} as the interpolation marker, supporting config and option parameters:

function output(config, option) {
  // These interpolations are replaced before execution
  const theme = '{{config.theme}}';
  const buttonColor = '{{option.buttonColor}}';
  const features = {{option.features}};
  return [{
    type: 'style',
    name: 'dynamic-style',
    attrs: [{ name: 'type', value: 'text/css' }],
    content: `
      .container {
        theme: ${theme};
        --button-color: ${buttonColor};
      }
      .features::after {
        content: '${features.join(', ')}';
      }
    `,
  }];
}

Interpolation Processing Logic

Convert the raw input values to proper JavaScript values according to their declared type, ensuring validity.

Transform the concrete parameter values back into strings and replace them in the function template, so the backend can execute the code correctly.

/** Replace interpolation placeholders in a template */
function replaceInterpolate(template, { config, option }) {
  const reg = /\{\{\s*(config\.[^}]+|option\.[^}]+)\s*\}\}/g;
  if (!reg.test(template)) return template;
  return _.template(template, { interpolate: reg })({
    config: formatParams(config),
    option: formatParams(option),
  });
}

/** Recursively format objects */
function formatParams(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [key, stringifyValueAsExpression(value)])
  );
}

/** Convert a JavaScript value to a valid JS expression string */
function stringifyValueAsExpression(value) {
  if (value instanceof RegExp) return value.toString();
  if (Array.isArray(value)) return `[${value.map(stringifyValueAsExpression).join(',')}]`;
  if (typeof value === 'object' && value !== null) {
    return `{${Object.entries(value)
      .map(([k, v]) => `${k}:${stringifyValueAsExpression(v)}`)
      .join(',')}}`;
  }
  if (typeof value === 'string') return `'${value.replace(/'/g, "\\'")}'`;
  if (value == null) return 'null';
  return String(value);
}

Actual Application Cases

Case 1: Conditional Font Management Component

This case shows how to load font resources dynamically based on the option switches and generate corresponding CSS variables and utility classes.

function output(config, option) {
  const { 'custom-regular': enableRegular, 'custom-medium': enableMedium, 'custom-bold': enableBold } = option;
  const fontList = [
    { name: 'custom-regular', content: '@font-face { font-family: custom-regular; src: local("CustomFont"), local("CustomFont_Regular"), url("https://cdn.example.com/fonts/CustomFont_Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }' },
    { name: 'custom-medium', content: '@font-face { font-family: custom-medium; src: local("CustomFont_Medium"), url("https://cdn.example.com/fonts/CustomFont_Medium.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }' },
    { name: 'custom-bold', content: '@font-face { font-family: custom-bold; src: local("CustomFont_Bold"), url("https://cdn.example.com/fonts/CustomFont_Bold.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }' },
  ];
  const activeKeys = Object.keys(option).filter(item => option[item]);
  const filterList = fontList.filter(item => activeKeys.includes(item.name));
  const content = _.template(`
    <% _.forEach(list, function(item) { %>
      {{ item.content }}
    <% }); %>
    :root {
      <% _.forEach(list, function(item) { var cleanItem = item.name.replace('custom-', ''); %>
        --font-{{ cleanItem }}: custom-{{ cleanItem }};
      <% }); %>
    }
    <% _.forEach(list, function(item) { var cleanItem = item.name.replace('custom-', ''); %>
      .f-{{ cleanItem.split('-').map(word => word[0]).join('') }} { font-family: var(--font-{{ cleanItem }}); }
    <% }); %>
  `)({ list: filterList });
  return [{
    type: 'style',
    name: 'Font Management CSS Variables',
    attrs: [{ name: 'type', value: 'text/css' }],
    content: content,
  }];
}

Case 2: Webpage Grayscale Component

async function output(config, option, query) {
  const customCss = option.customCss || '';
  return [{
    type: 'script',
    name: 'Webpage Grayscale',
    attrs: [],
    content: `
      (function () {
        let grayscaleStyleElement = null;
        let intervalId = null;
        function enableGrayscale() {
          if (grayscaleStyleElement) return;
          const style = document.createElement('style');
          style.innerHTML = `html {filter: grayscale(0.95);-webkit-filter: grayscale(0.95);}${customCss}`;
          document.documentElement.insertBefore(style, document.head);
          grayscaleStyleElement = style;
        }
        function disableGrayscale() {
          if (grayscaleStyleElement) {
            document.documentElement.removeChild(grayscaleStyleElement);
            grayscaleStyleElement = null;
          }
        }
        function getMillTime(d) { return d ? new Date(d).getTime() : Date.now(); }
        function handleGrayscale(startTime, endTime) {
          const currentTime = getMillTime();
          if (currentTime >= startTime && currentTime <= endTime) enableGrayscale();
          else disableGrayscale();
          if (currentTime > endTime && !grayscaleStyleElement) {
            clearInterval(intervalId);
            intervalId = null;
          }
        }
        function scheduleGrayscaleEffect() {
          const startTime = getMillTime({{option.startDate}});
          const endTime = getMillTime({{option.endDate}});
          handleGrayscale(startTime, endTime);
          intervalId = setInterval(() => { handleGrayscale(startTime, endTime); }, 10000);
        }
        scheduleGrayscaleEffect();
      })();
    `,
  }];
}

Summary

Extreme Flexibility : Users can write arbitrarily complex logic.

Powerful Expressiveness : All JavaScript features (conditionals, loops, function calls) are available.

Secure Execution : Sandbox isolation guarantees system safety.

Rich Parameter Support : Multiple data types and interpolation mechanisms.

Good Extensibility : New APIs and features can be added easily.

Future Enhancements

Template Library : Provide ready‑made code templates for users.

Visual Debugging : Offer intuitive tools to view function outputs.

Version Management : Support version control and rollback of user functions.

backendDynamic Configurationsandboxcode-generationfunction-input
HomeTech
Written by

HomeTech

HomeTech tech sharing

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.