Vue Flow Quickstart and Best Practices
Tags: webdev, tutorial, programming, vue
Published: 2024-02-02 17:30:05



![workflow demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghpxrjlt969sqdcwqoat.png)

## 📝 Preface

The immense popularity of large language models (LLMs) in 2023 looks set to continue this year. Following OpenAI's groundbreaking releases of GPT-3 and subsequent iterations, LLMs have become the cutting edge in natural language processing. Numerous tech firms and developers are racing to bring their own LLM offerings to market, capitalizing on intense interest in this burgeoning field. Harnessing the power of LLMs appears to be the wise course forward for those seeking to remain at the forefront of AI capabilities. 🤖

My employer has opted to develop its own product in this sphere, integrating proprietary APIs across the organization. The workflow chart constitutes the crux of this endeavor, empowering users to tailor personalized processes. In the following article, I will illuminate the pivotal steps to constructing such workflow diagrams within web interfaces. It is my sincere aspiration that these insights provide some modicum of assistance to readers pursuing similar objectives. 🙏


## 📚 Finding the Right Workflow Library

At my present employer, the predominant front-end technology stack comprises `Vue3` and `TypeScript`. Consequently, I sought out a workflow library grounded in `Vue3` and ideally authored in `TypeScript`. Despite utilizing [LogicFlow](https://site.logic-flow.cn/docs/#/en/) previously, its integration with `Vue3` proved insufficiently seamless.Therefore, for this demonstration, I opted for [VueFlow](https://vueflow.dev/), which boasts exceptional support for `Vue3`.

## ⚙️ Core Capabilities to Implement
1. 🖱 Drag & Drop Elements to Create New Nodes
2. 🎨 Customizing Nodes
3. ➡️ Connect Nodes with Drag-Based Edges
4. 📤 Pass Data Between Nodes
5. 💾 Save/Load Workflow State

---

## 🖱 Drag & Drop Elements to Create New Nodes

Set the element `draggable` and add `dragstart` event handler:
```Vue
<script setup>
function handleDragStart(event, nodeType) {
  event.dataTransfer.setData("node", nodeType);
}
</script>

<template>
  <div 
    draggable 
    @dragstart="handleDragStart($event, 'someNode')">
    ...
  </div>
</template>
```

Define drop zone with `ondragover` and `ondrop` handlers:
```Vue
<template>
  <div
    @drop="handleDrop"
    @dragover="handleDragOver">
    
    <VueFlow>
      ...
    </VueFlow>

  </div>  
</template>

<script>
function handleDrop(event) {
  // Create node from dragged data
  const nodeType = event.dataTransfer.getData('node') 
  const newNode = {
    type: nodeType,
    ...
  }

  addNode(newNode)
}

function handleOnDragOver(event) {
  event.preventDefault();

  if (event.dataTransfer) {
    event.dataTransfer.dropEffect = "move";
  }
}
</script>
```
This enables dragging elements into the flowchart canvas to create new nodes programmatically. 💡

As the code above shows, we can do our business logic in the drop event handler. In this demo, we just add our custom node to the workflow canvas with addNodes. By the way, we can use the `useVueFlow` hook provided by VueFlow to conveniently add/delete nodes & edges in our app.

## 🎨 Customizing Nodes

Two approaches exist for defining customized nodes. The first employs template slots, whereby dynamic resolution furnishes a slot denominated `#node-custom` when the custom type is anticipated. The second leverages the `node-types` prop. In my estimation, the latter approach promotes superior organization. Thus, I opted to utilize the `node-types` technique for node definition.

Constructing a bespoke node is remarkably straightforward - simply codify the node UI as an ordinary Vue component. This convenience is quite remarkable.

```Vue
<script setup lang="ts">
import StartNode from '@/components/vue-flow/nodes/start-node.vue'
import EndNode from '@/components/vue-flow/nodes/end-node.vue'
import LLMNode from '@/components/vue-flow/nodes/LLM-node.vue'
import CodeNode from '@/components/vue-flow/nodes/code-node.vue'
import KnowledgeNode from '@/components/vue-flow/nodes/knowledge-node.vue'
import ApiNode from '@/components/vue-flow/nodes/api-node.vue'

  const nodeTypes = {
    start: markRaw(StartNode),
    end: markRaw(EndNode),
    LLM: markRaw(LLMNode),
    code: markRaw(CodeNode),
    knowledge: markRaw(KnowledgeNode),
    api: markRaw(ApiNode)
  }
</script>

<template>
  <div class="relative h-full w-full">
    <VueFlow :node-types="nodeTypes">
    </VueFlow>
  </div>
</template>
```

## ➡️ Connect Nodes with Drag-Based Edges

1. Employ the `onConnect` hook, invoked upon establishing a connection between two nodes.
2. Within the callback, call `addEdges` to forge an edge linking the nodes.
3. When instantiating the novel node, the `isValidTargetPos` attribute can be defined to constrain permissible connections to specific target nodes.
```Typescript
const { onConnect, addEdges } = useVueFlow()
onConnect((params) => {
  addEdges(params)
})
```
Automatically connect nodes on drag.

## 📤 Pass Data Between Nodes

Our envisioned workflow platform necessitates obtanining data from preceding nodes and replaying it to subsequent nodes. This imposes the requirement of devising a technique to retrieve a node's antecedent data.

The current node's attributes incorporate a `connectedEdges` field. By filtering for connected nodes where the current node constitutes the `target` node type, we can identify the direct predecessor. The `findNode` function can then be invoked upon that node to extract its bound data for passage downstream.

This leverages existing node properties and methods to fulfill the prerequisite of data sharing between ajacent nodes in the workflows.
```Typescript
import { useNode, useVueFlow } from "@vue-flow/core";

const node = useNode();
const { findNode } = useVueFlow();
watchEffect(() => {
  if (node.connectedEdges && node.connectedEdges.value.length > 0) {
    const filteredEdges = node.connectedEdges.value.filter(
      (item) => item.target === node.id
    );
    referenceOptions.value = filteredEdges.map((edge) => {
      const node = findNode(edge.source);
      const currentItem: Option = {
        groupName: node?.data.title ?? node?.label,
        options: [],
      };

      if (node?.data.output) {
        node?.data.output
          .filter((item: any) => Boolean(item.name))
          .forEach((option: any) => {
            currentItem.options.push({
              label: option.name,
              value: option.name,
            });
          });
      } else {
        currentItem.options = [];
      }
      return currentItem;
    });
  }
});
```

## 💾 Save/Load Workflow State

To enable integration with back-end APIs, persisting the current workflow state is requisite. Retrieving the diagram data proves straightforward - simply invoke the `toObject` method form the `useVueFlow` hook. Similarly, restoring a saved workflow is readily achievable by applying the appropriate utilities furnished by the hook.

Leveraging the capabilities surface by useVueFlow provides a clean and convenient approach to serializing and deserializing the workflow for server communication and storage.

For illustration, the workflow data can be obtained, persisted, and restored as follows:
```TypeScript
// Retrieve workflow data
const data = toObject(workflow); 

// Save data to backend
saveWorkflow(data);

// Reconstruct workflow from data
setNodes(data.nodes);
setEdges(data.edges);
```
Through this approach, the current workflow state can be serialized and sent to the backend for storage. Later, it can be fetched and deserialized to recreate the diagram programmatically by re-instantiating the nodes and edges.

This enables full persistence of workflows to facilitate saving progress and resuming from previous sessions. The `useVueFlow` hook provides convenient utility methods to capture and restore the diagram state.

## Additional Beneficial Capabilities

- Copying, deleting, and otherwise modifying nodes through handy utility functions.

VueFlow furnishes abundant helper methods to effortlessly copy, remove, or otherwise alter nodes within the workflow diagram. This greatly simplifies tasks like duplicating portions of the workflow.

- Supplementary plugins for expanded functionality.

A range of optional VueFlow plugins exist that introduce additional capabilities including minimaps, grid backgrounds, node resizer, and more. These afford further ways to customize the environment to suit specific needs.

In summary, VueFlow comes well-equipped with built-in utilities and an ecosystem of plugins to enable advanced workflows and streamlined customization beyond core dragging and connecting of nodes.

## 🏁 Conclusion

At its core, constructing a web-based flowchart entails thoughtfully organizing components into a cohesive application. The crux lies with the components themselves, irrespective of the framework such as React or Vue. The process simply involves adhering to documentation, logically structuring components, and conveniently adding/removing them as needed. I hope these insights offer useful pointers on building flowchart tools.

Through creating this demo, I've gained significant clarity around implementing web apps centered on flowcharts. The heart of such applications remains the components - whether using React, Vue, or any other JavaScript framework. It's a matter of fitting components into the framework's architecture. This principle persists unchanged; the steps are to comprehend documentation, keep the framework tidy, and seamlessly inject or remove components. I hope this article📚 provides helpful tips on flowchart apps. Thank you for reading - have an excellent day!😃

---
🚀 Live Demo: [https://chat-bot-workflow.vercel.app/](https://chat-bot-workflow.vercel.app/)
📚 Original Article: [https://www.monsterpi13.dev/writing/vue-flow-quickstart-and-best-practices](https://www.monsterpi13.dev/writing/vue-flow-quickstart-and-best-practices)
📂 GitHub Repo: [https://github.com/MonsterPi13/chatBot-workflow](https://github.com/MonsterPi13/chatBot-workflow)