Документация Запланировать пилот

Создание справочника сотрудников

В этом руководстве вы узнаете, как с помощью D1 создать справочник сотрудников. Это приложение позволит пользователям просматривать данные о сотрудниках организации, а администраторам добавлять новых сотрудников прямо в приложении. Для этого вам сначала нужно будет настроить База данных D1 для удобного управления данными, а затем разработаете и развернёте приложение с помощью Фреймворк HonoX ↗ и Cloudflare Pages.

Предварительные требования

Прежде чем приступить к этому руководству, убедитесь, что у вас есть следующее:

Если вы не хотите проходить настройку сейчас, просмотреть готовый код ↗ на GitHub.

1. Установите HonoX

В этом руководстве вы будете использовать HonoX ↗, метафреймворк для создания full-stack сайтов и веб-API при сборке вашего приложения. Чтобы использовать HonoX в своём проекте, выполните hono-create команда.

Чтобы начать, выполните следующую команду:

npm create hono@latest

В процессе настройки вам нужно будет указать имя каталога проекта и выбрать шаблон. При выборе укажите x-basic шаблон.

2. Инициализируйте приложение HonoX

После настройки проекта вы увидите список сгенерированных файлов, как показано ниже. Это типичная структура проекта для приложения HonoX:

.
├── app
│   ├── global.d.ts // global type definitions
│   ├── routes
│   │   ├── _404.tsx // not found page
│   │   ├── _error.tsx // error page
│   │   ├── _renderer.tsx // renderer definition
│   │   ├── about
│   │   │   └── [name].tsx // matches `/about/:name`
│   │   └── index.tsx // matches `/`
│   └── server.ts // server entry file
├── package.json
├── tsconfig.json
└── vite.config.ts

Проект содержит каталоги с кодом приложения, маршрутами и настройками сервера, а также конфигурационные файлы для управления пакетами, TypeScript и Vite.

3. Создайте базу данных

Чтобы создать базу данных для своего проекта, используйте инструмент командной строки Cloudflare Wrangler, которое поддерживает wrangler d1 команду для операций с базой данных D1. Создайте новую базу данных с именем staff-directory с помощью следующей команды:

npx wrangler d1 create staff-directory

После создания базы данных вам нужно будет настроить привязка в конфигурационный файл Wrangler чтобы интегрировать базу данных с приложением.

Эта привязка позволяет приложению взаимодействовать с ресурсами Cloudflare, такими как базы данных D1, пространства имён KV и бакеты R2. Чтобы настроить её, создайте файл Wrangler в корневом каталоге проекта и укажите основные параметры:

{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "staff-directory",
	// Set this to today's date
	"compatibility_date": "2026-08-28"
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "staff-directory"
# Set this to today's date
compatibility_date = "2026-08-28"

Далее добавьте данные привязки базы данных в файл Wrangler. Для этого нужно указать имя привязки (в данном случае, DB), которая будет использоваться для обращения к базе данных в вашем приложении, вместе с database_name и database_id указанный при создании базы данных:

{
	"d1_databases": [
		{
			"binding": "DB",
			"database_name": "staff-directory",
			"database_id": "f495af5f-dd71-4554-9974-97bdda7137b3"
		}
	]
}
[[d1_databases]]
binding = "DB"
database_name = "staff-directory"
database_id = "f495af5f-dd71-4554-9974-97bdda7137b3"

Теперь ваше приложение настроено для доступа и взаимодействия с базой данных D1, будь то через командную строку или напрямую в коде.

Также потребуется внести изменения в конфигурационный файл Vite в vite.config.js. Добавьте следующие параметры конфигурации, чтобы Vite был правильно настроен для работы с привязками Cloudflare в локальной среде:

import adapter from "@hono/vite-dev-server/cloudflare";

export default defineConfig(({ mode }) => {
	if (mode === "client") {
		return {
			plugins: [client()],
		};
	} else {
		return {
			plugins: [
				honox({
					devServer: {
						adapter,
					},
				}),
				pages(),
			],
		};
	}
});

4. Взаимодействуйте с D1

Чтобы взаимодействовать с базой данных D1, вы можете напрямую выполнять SQL-команды с помощью wrangler d1 execute команда:

wrangler d1 execute staff-directory --command "SELECT name FROM sqlite_schema WHERE type ='table'"

Приведённая выше команда позволяет выполнять запросы или операции прямо из командной строки.

Для таких операций, как первоначальное заполнение данными или пакетная обработка, можно передать SQL-файл с командами. Для этого создайте schema.sql файл в корневом каталоге вашего проекта и вставьте свои SQL-запросы в этот файл:

CREATE TABLE locations (
    location_id INTEGER PRIMARY KEY AUTOINCREMENT,
    location_name VARCHAR(255) NOT NULL
);

CREATE TABLE departments (
    department_id INTEGER PRIMARY KEY AUTOINCREMENT,
    department_name VARCHAR(255) NOT NULL
);

CREATE TABLE employees (
    employee_id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(255) NOT NULL,
    image_url VARCHAR(255) NOT NULL,
    join_date DATE NOT NULL,
    location_id INTEGER REFERENCES locations(location_id),
    department_id INTEGER REFERENCES departments(department_id)
);

INSERT INTO locations (location_name) VALUES ('London, UK'), ('Paris, France'), ('Berlin, Germany'), ('Lagos, Nigeria'), ('Nairobi, Kenya'), ('Cairo, Egypt'), ('New York, NY'), ('San Francisco, CA'), ('Chicago, IL');

INSERT INTO departments (department_name) VALUES ('Software Engineering'), ('Product Management'), ('Information Technology (IT)'), ('Quality Assurance (QA)'), ('User Experience (UX)/User Interface (UI) Design'), ('Sales and Marketing'), ('Human Resources (HR)'), ('Customer Support'), ('Research and Development (R&D)'), ('Finance and Accounting');

Приведённые выше запросы создадут три таблицы: Locations, Departments, а также Employees. Чтобы заполнить эти таблицы начальными данными, используйте INSERT INTO команду. После подготовки файла схемы с помощью этих команд его можно применить к базе данных D1. Для этого используйте --file флаг, чтобы указать файл схемы для выполнения:

wrangler d1 execute staff-directory --file=./schema.sql

Чтобы выполнить схему локально и заполнить локальный каталог тестовыми данными, передайте --local флаг к приведённой выше команде.

5. Создайте SQL-операторы

После того как вы настроите базу данных D1 и сконфигурируете файл Wrangler, как описано в предыдущих шагах, ваша база данных станет доступна в коде через DB привязку. Это позволяет напрямую работать с базой данных, подготавливая и выполняя инструкции SQL. На следующем шаге вы узнаете, как с помощью этой привязки выполнять типичные операции с базой данных, такие как получение данных и вставка новых записей.

Получение данных из базы данных

export const findAllEmployees = async (db: D1Database) => {
	const query = `
      SELECT employees.*, locations.location_name, departments.department_name
      FROM employees
      JOIN locations ON employees.location_id = locations.location_id
      JOIN departments ON employees.department_id = departments.department_id
      `;
	const { results } = await db.prepare(query).run();
	const employees = results;
	return employees;
};

Вставка данных в базу данных

export const createEmployee = async (db: D1Database, employee: Employee) => {
	const query = `
      INSERT INTO employees (name, position, join_date, image_url, department_id, location_id)
      VALUES (?, ?, ?, ?, ?, ?)`;

	const results = await db
		.prepare(query)
		.bind(
			employee.name,
			employee.position,
			employee.join_date,
			employee.image_url,
			employee.department_id,
			employee.location_id,
		)
		.run();
	const employees = results;
	return employees;
};

Полный список всех запросов, используемых в приложении, см. в db.ts ↗ файл в кодовой базе.

6. Разработайте интерфейс

Приложение использует hono/jsx для рендеринга. Настроить Renderer можно в app/routes/_renderer.tsx с использованием миддлвара, отрисовывающего JSX и служащего точкой входа для вашего приложения:

import { jsxRenderer } from 'hono/jsx-renderer'
import { Script } from 'honox/server'

export default jsxRenderer(({ children, title }) => {
  return (
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>{title}</title>
        <Script src="/app/client.ts" async />
      </head>
      <body>{children}</body>
    </html>
  )
})

Добавьте привязки, определённые ранее в global.d.ts файл, где определены глобальные типы для TypeScript, что обеспечивает согласованность типов во всём приложении:

declare module "hono" {
	interface Env {
		Variables: {};
		Bindings: {
			DB: D1Database;
		};
	}
}

Это приложение использует Tailwind CSS ↗ для стилизации. Чтобы использовать Tailwind CSS, см. Документация TailwindCSS ↗, либо выполните шаги доступен на GitHub ↗.

Чтобы вывести список сотрудников, вызовите findAllEmployees функцию из своего db.ts файл и вызовите его внутри routes/index.tsx файл. createRoute() функция, присутствующая в файле, служит вспомогательной функцией для определения маршрутов, обрабатывающих разные HTTP методы, такие как GET, POST, PUT, или DELETE.

import { css } from 'hono/css'
import { createRoute } from 'honox/factory'
import Counter from '../islands/counter'

const className = css`
  font-family: sans-serif;
`

export default createRoute((c) => {
  const name = c.req.query('name') ?? 'Hono'
  return c.render(
    <div class={className}>
      <h1>Hello, {name}!</h1>
      <Counter />
    </div>,
    { title: name }
  )
})

Существующий код в файле содержит заглушку, использующую компонент Counter. Замените этот раздел следующим блоком кода:

import { createRoute } from 'honox/factory'
import type { FC } from 'hono/jsx'
import type { Employee } from '../db'
import { findAllEmployees, findAllDepartments, findAllLocations } from '../db'

const EmployeeCard: FC<{ employee: Employee }> = ({ employee }) => {
  const { employee_id, name, image_url, department_name, location_name } = employee;
  return (
    <div className="max-w-sm bg-white border border-gray-200 rounded-lg shadow-md">
      <a href={`/employee/${employee_id}`}>
        <img className="bg-indigo-600 p-4 rounded-t-lg" src={image_url} alt={name} />
        //...
      </a>
    </div>
  );
};

export const GET = createRoute(async (c) => {
  const employees = await findAllEmployees(c.env.DB)
  const locations = await findAllLocations(c.env.DB)
  const departments = await findAllDepartments(c.env.DB)
  return c.render(
    <section className="flex-grow">
      <h1 className="mb-4 text-3xl font-extrabold text-gray-900 dark:text-white md:text-5xl lg:text-6xl mt-12">
        <span className="text-transparent bg-clip-text bg-gradient-to-r to-blue-600 from-sky-400">{`Directory `}</span>
      </h1>
      //...
      </section>
      <section className="flex flex-wrap -mx-4">
        {employees.map((employee) => (
          <div className="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-2 mb-4">
            <EmployeeCard employee={employee} />
          </div>
        ))}
      </section>
    </section>
  )
})

Этот фрагмент кода показывает, как импортировать findAllEmployees, findAllLocations, а также findAllDepartments функции из db.ts файл и как использовать привязку c.env.DB чтобы вызвать эти функции. С их помощью вы можете получать и отображать полученные данные на странице.

Добавление сотрудника

Используйте export POST маршрут для создания нового сотрудника через /admin страница:

import { createRoute } from "honox/factory";
import type { Employee } from "../../db";
import { getFormDataValue, getFormDataNumber } from "../../utils/formData";
import { createEmployee } from "../../db";

export const POST = createRoute(async (c) => {
	try {
		const formData = await c.req.formData();
		const imageFile = formData.get("image_file");
		let imageUrl = "";

		// TODO: process image url with R2

		const employeeData: Employee = {
			employee_id: getFormDataValue(formData, "employee_id"),
			name: getFormDataValue(formData, "name"),
			position: getFormDataValue(formData, "position"),
			image_url: imageUrl,
			join_date: getFormDataValue(formData, "join_date"),
			department_id: getFormDataNumber(formData, "department_id"),
			location_id: getFormDataNumber(formData, "location_id"),
			location_name: "",
			department_name: "",
		};

		await createEmployee(c.env.DB, employeeData);
		return c.redirect("/", 303);
	} catch (error) {
		return new Response("Error processing your request", { status: 500 });
	}
});

Хранение изображений в R2

При создании нового сотрудника загруженное изображение можно сохранить в бакете R2 ещё до добавления в базу данных.

Чтобы сохранить изображение в бакете R2:

  1. Создайте bucket R2.
  2. Загрузите изображение в этот бакет.
  3. Получите публичный URL изображения из бакета. Этот URL затем сохраняется в базе данных и указывает на изображение, хранящееся в бакете R2.

Используйте wrangler r2 bucket create команду для создания бакета:

wrangler r2 bucket create employee-avatars

После создания бакета добавьте привязку бакета R2 в файл Wrangler:

{
	"r2_buckets": [
		{
			"binding": "MY_BUCKET",
			"bucket_name": "employee-avatars"
		}
	]
}
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "employee-avatars"

Передайте привязку R2 в global.d.ts файле:

declare module "hono" {
	interface Env {
		Variables: {};
		Bindings: {
			DB: D1Database;
			MY_BUCKET: R2Bucket;
		};
	}
}

Чтобы сохранить загруженное изображение в бакете R2, используйте put() метод, предоставляемый R2. Он позволяет загрузить файл изображения в ваш бакет:

if (imageFile instanceof File) {
	const key = `${new Date().getTime()}-${imageFile.name}`;
	const fileBuffer = await imageFile.arrayBuffer();

	await c.env.MY_BUCKET.put(key, fileBuffer, {
		httpMetadata: {
			contentType: imageFile.type || "application/octet-stream",
		},
	});
	console.log(`File uploaded successfully: ${key}`);
	imageUrl = `https://pub-8d936184779047cc96686a631f318fce.r2.dev/${key}`;
}

См. GitHub ↗ с полным кодом проекта.

7. Разверните своё приложение HonoX

Когда приложение готово к развертыванию, используйте Wrangler для сборки и развертывания проекта в Cloudflare Network. Убедитесь, что вы вошли в аккаунт Cloudflare, выполнив wrangler whoami команду. Если вы не выполнили вход, Wrangler предложит войти, создав API-ключ, с помощью которого можно автоматически отправлять аутентифицированные запросы с вашего компьютера.

После успешного входа убедитесь, что ваш файл Wrangler настроен так же, как показано в блоке кода ниже:

{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "staff-directory",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"r2_buckets": [
		{
			"binding": "MY_BUCKET",
			"bucket_name": "employee-avatars"
		}
	],
	"d1_databases": [
		{
			"binding": "DB",
			"database_name": "staff-directory",
			"database_id": "f495af5f-dd71-4554-9974-97bdda7137b3"
		}
	]
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "staff-directory"
# Set this to today's date
compatibility_date = "2026-08-28"

[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "employee-avatars"

[[d1_databases]]
binding = "DB"
database_name = "staff-directory"
database_id = "f495af5f-dd71-4554-9974-97bdda7137b3"

Запустите wrangler deploy чтобы развернуть проект в Cloudflare. После развёртывания вы можете проверить работу приложения, перейдя по предоставленному URL-адресу развёртывания. В браузере должно отобразиться ваше приложение с базовым интерфейсом, который вы создали. Если в вашей базе данных нет данных, перейдите в /admin страницу, чтобы добавить нового сотрудника, и это должно вернуть нового сотрудника на вашей домашней странице.

Заключение

В этом руководстве вы создали приложение справочника сотрудников, в котором пользователи могут просматривать всех сотрудников организации. Обратитесь к Репозиторий Staff Directory ↗ с полным исходным кодом.

демонстрация Staff Directory

Запросите бесплатный пилот

Запланировать пилот