Skip to main content

One post tagged with "node"

View All Tags

Getting started with Drayman

ยท 4 min read

Drayman is a server-side component framework that allows you to use any available HTML element, web component or custom Drayman third-party component together with server-side code in a single script.

With Drayman, the browser only renders what the user should see - all logic and calculations happen server-side and UI is written using JSX syntax.

The best way to show Drayman capabilities is to create something with it. So let's get started.

File viewer component#

Let's build a component that allows the user to select a file from the file system and view it's contents.

First, you need to install Drayman. It can be done by running these commands:

npx @drayman/framework-init@latest my-appcd my-appnpm start

The website will be available at http://localhost:3033.

Initial component template#

Go to src/components/home.tsx and replace its contents with this code:

src/components/home.tsx
export const component: DraymanComponent = async () => {  return async () => {    return (      <>        <p>Select a file to view it directly from file system</p>        <select></select>        <br />        <pre></pre>      </>    );  };};

You will see an initial skeleton of our component. Further <select> will be used to show available files and <pre> will show contents of the selected file.

Filling select with options#

Because Drayman runs a component server-side, we can use any Node.js library. In our case we will use the fs module.

Let's read file names from the project root directory and fill <select> options with them:

src/components/home.tsx
import { promises as fs } from "fs";
export const component: DraymanComponent = async () => {  const files = (await fs.readdir("./")).filter((x) => x.includes("."));
  return async () => {    return (      <>        <p>Select a file to view it directly from file system</p>        <select>          {files.map((fileName) => (            <option>{fileName}</option>          ))}        </select>        <br />        <pre></pre>      </>    );  };};

Right now our component is only showing some elements without any interactivity. Our next step will be to add it.

Reacting to user actions#

We need to remember which file the user has selected to show its contents. It can be done by using the onchange event attribute and attaching a function that will be executed server-side. We also need to add the value attribute to each option so that select would know which option was selected.

Let's also add the fs.readFile function inside the <pre> tag so that Drayman would read file contents during re-render. We won't show the pre until a file is actually selected:

src/components/home.tsx
import { promises as fs } from "fs";
export const component: DraymanComponent = async () => {  const files = (await fs.readdir("./")).filter((x) => x.includes("."));  let selectedFile;
  return async () => {    return (      <>        <p>Select a file to view it directly from file system</p>        <select          onchange={async ({ value }) => {            selectedFile = value;          }}        >          {files.map((fileName) => (            <option value={fileName}>{fileName}</option>          ))}        </select>        <br />        {selectedFile && <pre>{await fs.readFile(selectedFile, "utf-8")}</pre>}      </>    );  };};

If you make a selection from the dropdown, you will see that nothing happens on the page - file contents don't appear. That is because with Drayman you must strictly tell when a component needs to be re-rendered. It can be done by using a special helper function forceUpdate.

Import it and add to the onchange event after the selected file was saved:

src/components/home.tsx
import { promises as fs } from "fs";
export const component: DraymanComponent = async ({  forceUpdate,}) => {  const files = (await fs.readdir("./")).filter((x) => x.includes("."));  let selectedFile;
  return async () => {    return (      <>        <p>Select a file to view it directly from file system</p>        <select          onchange={async ({ value }) => {            selectedFile = value;            await forceUpdate();          }}        >          {files.map((fileName) => (            <option value={fileName}>{fileName}</option>          ))}        </select>        <br />        {selectedFile && <pre>{await fs.readFile(selectedFile, "utf-8")}</pre>}      </>    );  };};

Now our component is complete and file contents are shown on select: final-result

Conclusion#

We have built a component that combines server-side logic and client-side view in a single script.

If this felt interesting to you, visit the official docs to deep-dive into Drayman framework!