Зачем использовать EJS с Vite?
Давайте рассмотрим пример сценария: вы создаете веб-приложение, которое будет работать в пограничных местоположениях CDN с использованием Cloudflare Workers. В этом случае у вас могут быть следующие требования:
- Вам необходимо настроить обратный прокси-сервер для некоторых сторонних веб-сайтов, таких как Frame, Intercom Helpdesk и т. д.
- Вы должны иметь возможность вставлять пользовательские фрагменты кода HTML/JS на страницы этих веб-сайтов.
- Фрагменты кода должны корректно работать в различных средах, таких как рабочая среда и тест/контроль качества.
- Чтобы оптимизировать комплект приложений, необходимо предварительно скомпилировать эти шаблоны, а не включать библиотеку шаблонов.
В таких случаях использование EJS в сочетании с Vite может быть выгодным выбором.
Как это выглядит?
Фрагмент HTML удобно вынесен в отдельный файл с подсветкой синтаксиса HTML/JS и автодополнением кода (views/analytics.ejs
):
<script async src="https://www.googletagmanager.com/gtag/js?id=<%- env.GA_MEASUREMENT_ID %>"></script> <script> window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments); } gtag("js", new Date()); gtag("config", "<%- env.GA_MEASUREMENT_ID %>"); </script>
В то время как скрипт Cloudflare Worker внедряет его в целевую страницу (HTML), загруженную из Framer:
import { Hono } from "hono"; import analytics from "../views/analytics.ejs"; export const app = new Hono<Env>(); // Serve landing pages, inject Google Analytics app.use("*", async ({ req, env }, next) => { const url = new URL(req.url); // Skip non-landing pages if (!["/", "/about", "/home"].includes(url.pathname)) { return next(); } const res = await fetch("https://example.framer.app/", req.raw); return new HTMLRewriter() .on("body", { element(el) { el.onEndTag((tag) => { try { tag.before(analytics(env), { html: true }); } catch (err) { console.error(err); } }); }, }) .transform(res.clone()); });
Как предварительно скомпилировать шаблоны EJS с помощью Vite?
Установите модули NPM ejs
и @types/ejs
в качестве зависимостей разработки (yarn add ejs @types/ejs -D
).
Добавьте следующий плагин в ваш файл vite.config.ts
:
import { compile } from "ejs"; import { readFile } from "node:fs/promises"; import { relative, resolve } from "node:path"; import { defineConfig } from "vite"; export default defineConfig({ ... plugins: [ { name: "ejs", async transform(_, id) { if (id.endsWith(".ejs")) { const src = await readFile(id, "utf-8"); const code = compile(src, { client: true, strict: true, localsName: "env", views: [resolve(__dirname, "views")], filename: relative(__dirname, id), }).toString(); return `export default ${code}`; } }, }, ], });
Как заставить импорт .ejs
работать с TypeScript?
- Добавьте
**/*.ejs
в список включенных файлов в файлеtsconfig.json
. - Добавьте следующее объявление типа в ваш
global.d.ts
файл:
declare module "*.ejs" { /** * Generates HTML markup from an EJS template. * * @param locals an object of data to be passed into the template. * @param escape callback used to escape variables * @param include callback used to include files at runtime with `include()` * @param rethrow callback used to handle and rethrow errors * * @return Return type depends on `Options.async`. */ const fn: ( locals?: Data, escape?: EscapeCallback, include?: IncludeCallback, rethrow?: RethrowCallback, ) => string; export default fn; }
kriasoft/relay-starter-kit
— это всеобъемлющий шаблон проекта веб-приложения с полным стеком, который предварительно настроен со всеми упомянутыми функциями (находится в папке /edge
).
Если вам нужна помощь с веб-инфраструктурой и DevOps, не стесняйтесь обращаться ко мне в Codementor или Discord. Я здесь, чтобы помочь! Удачного кодирования!