Создание менеджера рассылок с Turso и Qwik
Платформы для рассылки новостей ненадежны или дороги. Я создал собственное решение, используя Qwik и Turso, пограничную базу данных на базе SQLite.
Информационный бюллетень — это инструмент стратегии маркетинга по электронной почте, используемый отдельными лицами, издателями, организациями и предприятиями для обмена ценной информацией и интересным контентом со своими клиентами, помогая в продвижении продаж и привлечении трафика на свои веб-сайты.
В этом посте я собираюсь продемонстрировать, как создать информационный бюллетень, используя Turso, пограничную базу данных, основанную на libSQL от ChiselStrike, и Qwik, возобновляемую среду мгновенного запуска приложений, созданную людьми из Builder. .ио.
Прежде чем перейти к строительной части, я хотел бы поделиться несколькими причинами, почему я работаю над этим и использую выбранную технологию.
Платформы для рассылок либо ненадежны, либо дороги, вот почему я развернул свою собственную
Мой любимый вариант для моих собственных информационных бюллетеней был Revue, но Twitter недавно закрыл его, а другие, такие как Ghost и ConvertKit, на мой взгляд, довольно дороги, поэтому я провел небольшое исследование, чтобы создать свой собственный, чтобы у вас не было к.
Я следил за Qwik, возобновляемой, мгновенно запускаемой средой приложений, и мне нравится философия, стоящая за ней, поэтому было несложно ее построить. Я соединил его с Turso, DBaaS (база данных как услуга), которая имеет лучший DX (опыт разработчика), с которым я когда-либо сталкивался — что является одной из причин, по которой я присоединился к компании, полное раскрытие — для скорость и низкую задержку, которую он может обеспечить вместе с Qwik.
Создание менеджера рассылок с помощью Turso и Qwik
Создаваемый нами менеджер рассылки состоит из трех страниц.
Первая страница — это та, с которой подписчики взаимодействуют при подписке, она включает краткое введение в суть информационного бюллетеня и форму.
Во-вторых, страница, доступная редактору информационного бюллетеня, которая позволяет им просматривать электронные письма подписчиков, блоги, на которые они подписаны (если их несколько), и даты подписки.
Третья страница — это страница отписки. Как и в любом хорошем информационном бюллетене, вы хотели бы предоставить своим подписчикам возможность как подписаться на рассылку, так и отказаться от нее.
В идеале вторая страница должна включать некоторую аутентификацию, поскольку она должна гарантировать ограниченный доступ, но мы не будем рассматривать аутентификацию в этом посте.
Исходный код проекта, над которым мы работаем в этом посте, также доступен в этом репозитории GitHub.
Предпосылки:
- Прежде чем продолжить, убедитесь, что у вас установлена последняя LTS-версия Node.js для создания проектов Qwik и использования узловых модулей.
- Присоединяйтесь к закрытой бета-версии Turso, чтобы использовать ее в своих проектах.
- Без доступа к частной бета-версии Turso вам необходимо настроить и работать с локальной файловой базой данных SQLite.
Настройка базы данных Turso
Инструкции по установке Turso, созданию базы данных и получению URL-адреса базы данных Turso можно найти в инструкциях по инициализации проекта в репозитории GitHub.
Вам понадобится URL-адрес базы данных Turso, полученный после создания базы данных, поскольку он необходим внутри нашего приложения.
Если вы не можете получить доступ к Turso через частную бета-программу, вы все равно можете продолжить настройку проекта, используя маршрут локальной базы данных SQLite. Детали настройки локальных баз данных SQLite задокументированы здесь.
Приложение Qwik
Как уже говорилось, и как вы заметите, изучив исходный код, проект построен с использованием фреймворка Qwik, и мы используем клиент libSQL для TypeScript (@libsql/client) для выполнения запросов на нашем база данных. Благодаря этому мы можем беспрепятственно работать с локальными файловыми базами данных SQLite так же, как с нашими базами данных Turso на периферии.
То, что мы будем неоднократно видеть в коде Qwik, — это символ $
. Пусть вас не смущает, Qwik использует его для обозначения извлечения кода как для разработчика, так и для оптимизатора Qwik. Qwik разбивает приложение на множество более мелких частей, называемых символами, с помощью Qwik Optimizer. Подробнее об этом можно прочитать в документации Qwik.
Давайте рассмотрим самые интересные части менеджера рассылок.
Домашняя страница информационного бюллетеня
Внутри домашней страницы мы обновляем состояние загрузки и вызываем функцию subscribeToNewsletter()
при отправке формы <form onSubmit$>
.
useSignal()
и useStore()
— это два хука Qwik, которые вы найдете на всех страницах, используемых для объявления реактивного состояния. useSignal()
принимает начальное значение и возвращает реактивный сигнал, состоящий из объекта с одним свойством .value
, в то время как хук useStore()
принимает объект в качестве начального значения и возвращает реактивный объект.
Серверная функция в Qwik — server$
позволяет нам работать на серверном уровне приложения рядом с нашим клиентским кодом. Вот больше информации об этом и вот демонстрация.
subscribeToNewsletter()
внутри домашней страницы — это функция сервера, которая отправляет информацию о подписке в базу данных Turso и информирует нас о состоянии подписки.
import { createClient } from "@libsql/client"; export const subscribeToNewsletter = server$( async (email: string, newsletter: string) => { if (!email || !newsletter) { return { success: false, message: "Email cannot be empty!", }; } const db = createClient({ url: import.meta.env.VITE_DB_URL, }); await db.execute("insert into newsletters(email, website) values(?, ?)", [ email, newsletter, ]); const response = await db.execute( "select * from newsletters where email = ? and website = ?", [email, newsletterBlog] ); const subscriber = responseDataAdapter(response); return subscriber[0] ? { success: true, message: "You've been subscribed!", } : { success: false, message: "Sorry something isn't right, please retry!", }; } ); export default component$(() => { const email = useSignal(""); const loading = useSignal(false); const emailRegex = /\b[\w.-]+@[\w.-]+\.\w{2,4}\b/gi; const notification = useStore({ message: "", status: "", }); return ( <form preventdefault:submit onSubmit$={async () => { if (!emailRegex.test(email.value)) { alert("Email not valid!"); return; } loading.value = true; const response = await subscribeToNewsletter( email.value, newsletterBlog ); loading.value = false; notification.message = response.message; notification.status = response.success ? "success" : "error"; }} > <input onInput$={(e) => { email.value = (e.target as HTMLInputElement).value }} name="email" type="email" /> <button type="submit" >Subscribe</button> </form> ); });
Qwik также поддерживает SEO (поисковую оптимизацию). Чтобы настроить его на страницах, мы экспортируем головной объект типа DocumentHead
с метаданными заголовка HTML. Мы можем видеть это внутри каждой из трех страниц: домашней, админки и отписки.
Вот предварительный просмотр главной страницы.
Страница администратора рассылки
В пользовательском интерфейсе компонента страницы администрирования новостной рассылки мы используем компонент Ресурс Qwik, который отображает свои дочерние элементы, когда переданный ресурс разрешается, и отображает запасной вариант, когда он находится в ожидании или отклонен.
В Qwik ресурсы создаются методом useResource$
. Мы можем увидеть демонстрацию ресурса, взглянув на subscribersResource
, необходимый для <Resource ... />
component, упомянутого выше.
const subscriberRows = (subscribers: NewsletterSubscriber[]) => { return subscribers?.length < 1 ? ( <tr> <td colSpan={4} > No subscribers found </td> </tr> ) : ( subscribers?.map((sub: NewsletterSubscriber, index: number) => { return ( <tr key={sub.id}> <td>{index + 1}</td> <td>{sub.email}</td> <td> {sub.website} </td> <td> {formatDate(sub.created_at)} </td> </tr> ); }) ); }; export default component$(() => { const subscribersResource = useResource$<ResourceResponse>(async () => { const response = await db.execute('select * from newsletters'); const subscribers = response?.success ? responseDataAdapter(response) : []; return { message: "Fetched subscribers", data: subscribers, }; }); return( <div> <h1>Newsletter Admin</h1> <Resource value={subscribersResource} onRejected={() => <Noty message="Failed to fetch subscribers" type="error" />} onPending={() => <LoadingAnimation/>} onResolved={(res: ResourceResponse) => <table> <thead> <tr> <th>No.</th> <th>Email</th> <th>Website</th> <th>Joined</th> </tr> </thead> <tbody> {subscriberRows(res.data)} </tbody> </table> } ></Resource> </div> ); });
После добавления некоторых подписчиков мы должны увидеть таблицу, заполненную их информацией, при посещении этой страницы.
Страница отписки от рассылки
Обычно ссылки для отказа от подписки должны быть доступны в электронных письмах с информационными бюллетенями. Чтобы отписать пользователей, нам нужно передать параметры маршруту отписки.
Файловая маршрутизация Qwik аналогична другим платформам, поскольку мы передаем параметры маршрута, объявляя их как имена каталогов в квадратных скобках.
Чтобы передать параметры domain и email, мы настроили структуру каталогов для страницы отписки следующим образом.
└── routes ├── unsubscribe │ └── [email] │ └── [domain] │ └── index.tsx
Затем мы используем функцию Qwik useLocation()
для получения объекта RouteLocation
для активного местоположения, из которого мы получаем параметры email и domain. Мы используем эти два параметра, чтобы удалить данные пользователя из базы данных, чтобы отписать их от рассылки внутри другой серверной функции.
Весь процесс отказа от подписки автоматизирован благодаря тому, что unsubscribeFromNewsletter()
, которая также является функцией Qwik server$, запускается при отображении компонента страницы в браузере. Мы делаем это, вызывая эту функцию внутри хука useBrowserVisibleTask()
.
import { createClient } from "@libsql/client"; export default component$(() => { const location = useLocation(); const email = useSignal(location.params.email); const domain = useSignal(location.params.domain); const loading = useSignal(false); const notification = useStore({ message: "", status: "", }); const unsubscribeFromNewsletter = server$(async () => { const db = createClient({ url: import.meta.env.VITE_DB_URL, }); const deleteRecord = await db.execute( "delete from newsletters where email = ? and website like ?", [email.value, domain.value] ); if (!deleteRecord.success) { return { success: false, message: "Sorry, something isn't right, please reload the page!", }; } return { success: true, message: "Unsubscribed!", }; }); useBrowserVisibleTask$(async () => { loading.value = true; const res = await unsubscribeFromNewsletter(); notification.message = res.message; notification.status = res.success ? "success" : "error"; loading.value = false; }); });
Вот демонстрация того, что произойдет при отписке пользователей, начиная с представления почты.
Это все для менеджера рассылки. Посетите репозиторий проекта на GitHub, чтобы получить исходный код и узнать о нем больше.
Чтобы узнать больше о Qwik, посетите их официальную документацию. В настоящее время Turso находится в закрытом бета-тестировании, и вы можете присоединиться к нему, перейдя на веб-сайт ChiselStrike.