برنامه نویسی

Svelte without Kit – انجمن DEV 👩‍💻👨‍💻

من Svelte را خیلی دوست دارم که می خواهم از آن در همه پروژه هایم استفاده کنم! اغلب این پروژه‌ها برنامه‌های میکرو هستند که به یک چارچوب برنامه کامل نیاز ندارند – آنها چند صفحه HTML با چند نقطه پایانی API سمت سرور هستند. SvelteKit برای این مورد استفاده بیش از حد است، زیرا نیازی به مسیریابی، بارگذاری اولیه، رندر سفارشی یا تقریباً تمام ویژگی های عالی ارائه شده توسط SvelteKit ندارد.

اسناد Svelte راهنمایی زیادی در مورد نحوه استقرار یک برنامه بدون SvelteKit ارائه نمی دهند، در واقع فقط یک پاراگراف در اسناد وجود دارد که در مورد نحوه عملکرد این کار صحبت می کند –

اگر به یک چارچوب برنامه کامل نیاز ندارید و به جای آن می‌خواهید یک سایت/برنامه فقط frontend ساده بسازید، می‌توانید با اجرای npm init vite و انتخاب گزینه svelte از Svelte (بدون کیت) با Vite نیز استفاده کنید. با این کار، npm run build فایل های HTML، JS و CSS را در داخل دایرکتوری dist تولید می کند.

این پست نحوه استفاده از Svelte با Express، یک چارچوب وب مینیمالیستی را شرح می دهد. این به دو بخش تقسیم می شود – محیط توسعه و ساخت یک ظرف برای استقرار تولید، زیرا ما از مراحل ساخت کمی متفاوت برای هر یک از آنها استفاده می کنیم.

راه اندازی

Express یک چارچوب وب عالی است، برای تنظیم نقاط پایانی HTTP و پردازش درخواست ها/پاسخ ها بسیار ساده است. انواع پلاگین های میان افزاری برای رسیدگی به مواردی مانند authnz و رندر وجود دارد. بدنه های درخواست JSON به صورت بومی در آخرین نسخه Express پشتیبانی می شوند. در حالی که میان افزارها می توانند قابلیت های Express را به میزان قابل توجهی گسترش دهند، در این راه اندازی ما به دنبال مینیمالیسم مطلق هستیم. ما به یک موتور رندر نیاز داریم تا بتوانیم داده ها را به عنوان خصوصیات از مسیرهای روی سرور به اجزای Svelte خود تزریق کنیم. اما این در مورد آن است.

همچنین برای شروع کار، مرحله ساخت برای استفاده از Svelte بسیار مهم است. از آنجایی که Svelte از قبل کامپایل شده است، به سادگی ارائه فایل های Svelte به طور مستقیم از طریق Express نیست. در عوض، این دارایی‌ها باید توسط Vite ساخته شوند تا بتوانند به مشتری مرورگر ارائه شوند. Vite تمام مؤلفه‌های Svelte ما را در فایل‌های جاوا اسکریپت و CSS کوچک‌شده، همراه با وابستگی‌های JS مورد استفاده توسط مؤلفه‌ها بسته‌بندی می‌کند. همچنین کتابخانه های CSS مانند Tailwindcss با Postcss.

برای مدیریت مرحله کامپایل، می‌خواهیم از مقداری اسکریپت در محیط توسعه‌دهنده محلی خود استفاده کنیم. هر زمان که یک دستور ساخت را اجرا می کند .svelte فایل ایجاد/تغییر/حذف می شود و فایل های تولید شده را برای سرویس Express کپی کنید. (متاسفانه، بارگذاری مجدد داغ در مرورگر وجود ندارد). برای استقرار، ما Svelte را به عنوان گامی در ساخت یک کانتینر Docker برای اجرا بر روی یک ارائه دهنده میزبان کامپایل می کنیم.

اکسپرس با html-express-js

برنامه ما یک ربات چت ساده است که پیامی را از بخش جلویی Svelte دریافت می کند و یک پاسخ تصادفی را بازتاب می دهد. جلسات چت را با یک شناسه تصادفی در حافظه ذخیره می کند. این یک برنامه فوق العاده پیچیده نیست، اما باید یک جلسه چت را بر اساس یک شناسه در مسیر درخواست HTTP مسیریابی کنیم. این شناسه نمونه ای از حالت سمت سرور است که توسط Svelte به عنوان ویژگی بارگذاری می شود.

ما Express را با کمی میان افزار پیکربندی می کنیم – express.static، express.json، cors و html-express-js. express.static Svelte js/css کامپایل شده را از محلی ارائه خواهد کرد ./public/assets فهرست راهنما. json و cors برای واکشی داده ها از اجزای Svelte ما ضروری هستند. و در نهایت، html-express-js حداقل قابلیت‌های قالب‌سازی را فراهم می‌کند، به طوری که می‌توانیم داده‌ها را به صورت HTML برای درخواست‌های GET ارائه کنیم.

در اینجا باطن اصلی Express، به عنوان server.js

// ./server.js
import express, { response } from 'express';
import cors from 'cors';
import { resolve } from 'path';
import htmlExpress from 'html-express-js';

const __dirname = resolve();
const app = express();
const port = process.env.PORT || 3000;
const chats = {};

// Configure html-express-js as the rendering engine.
// Templates will be in the local directory ./public
app.engine(
  'js',
  htmlExpress()
);
app.set('view engine', 'js');
app.set('views', `${__dirname}/public`);

// Configure express to serve static assets from
// the local directory ./public/assets. This is where
// compiled Svelte files will get copied into.
app.use('/assets', express.static(`${__dirname}/public/assets`));

// Configure express to parse json and allow CORS requests
app.use(express.json());
app.use(cors());

// POST endpoint for the front-end to send chats
// The front-end sends a list of all chats on each request
app.post('/:cid', function(req, res) {
  chats[req.params.cid] = req.body;
  res.send("Ok");
});

// GET endpoint for the front-end to load chats by identifier
// The list of chats is sent as a JSON array
app.get('/chats/:cid', function (req, res) {
  let cachedchats = []
  if (req.params.cid && chats[req.params.cid]) {
    cachedchats = chats[req.params.cid]
  }

  res.send(cachedchats);
})

// GET endpoint for loading HTML from the template in public/homepage.js
// If a chat identifier is in the path, parse as :cid and render in template
app.get(['/', '/:cid'], function (req, res, next) {
  res.render('homepage', {
    title: 'Very Cool Chatbot',
    cid: req.params.cid
  });
});

app.listen(port, () => console.log(`Node app listening on port ${port}!`));
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به نقطه پایانی GET برای مسیر ریشه توجه کنید – همچنین a را تجزیه می کند cid پارامتر از مسیر و آن را به html-express-js قالب. آن پارامتر را در قالب و همچنین در مؤلفه root Svelte در زیر مشاهده خواهید کرد.

Svelte مستقل

ما پروژه Svelte را در یک زیر شاخه راه اندازی کردیم ./svelte با استفاده از Vite، همانطور که در اسناد توصیه شده است –

همچنین می توانید از Svelte (بدون کیت) با Vite با اجرا استفاده کنید npm init vite و گزینه Svelte را انتخاب کنید.

پس از مقداردهی اولیه و اجرای یک بیلد با استفاده از npm run build، می توانیم نگاهی به دارایی های تولید شده در زیر بیاندازیم ./svelte/dist. نکته قابل توجه فایل HTML است که ایجاد می شود، در واقع بسیار ساده است –

<!-- ./svelte/dist/index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- meta tags -->
    <script type="module" crossorigin src="https://dev.to/assets/index-acdd3185.js"></script>
    <link rel="stylesheet" href="/assets/index-972eb3c3.css">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ارجاعات HTML الف .js و .css فایلی که در مرحله ساخت ایجاد می شود. و یک تک وجود دارد <div id="app"></div> که توسط Svelte برای تزریق اجزای HTML/JS/CSS کامپایل شده که به عنوان برنامه اصلی وب عمل می کنند استفاده می شود. این بدان معنی است که ما می توانیم از همان فایل های JS/CSS کامپایل شده در هر فایل HTML استفاده کنیم، تا زمانی که یک div با id="app" جایی در قالب

html-express-js

ما یک فایل HTML مشابه با الگوی خود ایجاد می کنیم که توسط Express ارائه می شود. آن را بارگذاری خواهد کرد .js و .css فایل ایجاد شده توسط ساختن Svelte، و شامل یک div واحد با id="app". همچنین دارای داده‌هایی است که از باطن سرور Express ارائه شده است، به یاد داشته باشید که پارامتر مسیر فراخوانی شده است cid از بالا؟

// public/homepage.js
import { html } from 'html-express-js';

export const view = (data, state) => html`
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>${data.title}</title>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <!-- Precompiled JS/CSS files by Svelte during build step -->
      <script type="module" crossorigin src="https://dev.to/assets/index-acdd3185.js"></script>
      <link rel="stylesheet" href="http://dev.to/assets/index-972eb3c3.css">
    </head>

    <body>
      <!-- data.cid is the parsed path variable from Express -->
      <div id="app" data-chat-id="${data.cid}"></div>
    </body>
  </html>
`
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سیم کشی همه با هم

چگونه به داده های قالب موجود در مؤلفه Svelte خود دسترسی پیدا کنیم؟ در اینجا App.svelte است که ریشه برنامه جلویی ما را بارگیری می کند. از JS/HTML DOM ساده برای خواندن مقدار مشخصه داده از قسمت اصلی برنامه استفاده می‌کند. id="app". فوق العاده آسان!

<!-- ./svelte/src/App.svelte -->
<script>
  import Chatbox from "./lib/Chatbox.svelte";

  // Lookup main app div
  const app = document.getElementById("app");
  // Access `data-chat-id` attribute from div
  let chatId = app.dataset.chatId;

</script>

<main class="font-mono text-primary h-full">
    <!-- other markup -->

    <Chatbox {chatId} />
</main>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در آزمایش من، این برای پارامترهای ساده مانند رشته ها عالی عمل کرد. برای بارگیری داده‌های پیچیده‌تر JSON، متوجه شدم که همیشه به درستی نمایش داده نمی‌شود html-express-js الگو، به ویژه برای ویژگی های رشته های جاسازی شده که حاوی نقل قول هستند. در آن صورت، به جای آن، هنگام نصب کامپوننت Svelte، داده های JSON را واکشی می کنم.

در نهایت باید فایل های JS/CSS تولید شده را از آن کپی کنیم ./svelte/dist/assets به ./public/assets تا بتوان با اکسپرس به آنها خدمت رسانی کرد. با توجه به اینکه نام فایل‌ها شامل یک پسوند تصادفی برای از بین بردن حافظه پنهان مرورگر است، کمی کد برای خواندن نام فایل‌های JS/CSS از سیستم فایل و رندر آنها در قالب اضافه می‌کنیم:

//./server.js
// ...other includes

import fs from 'fs';

const __dirname = resolve();

function readAssets() {
  const js = fs.readdirSync(`${__dirname}/public/assets`).filter((f) => f.endsWith('.js'));
  const css = fs.readdirSync(`${__dirname}/public/assets`).filter((f) => f.endsWith('.css'));

  return { js, css };
}

// ...other setup and endpoints

app.get(['/', '/:cid'], function (req, res, next) {
  const { js, css } = readAssets();
  res.render('homepage', {
    title: 'Very Cool Chatbot',
    cid: req.params.cid,
    js,
    css
  });
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

// public/homepage.js
import { html } from 'html-express-js'

const renderJs = (js) => {
  return js.map((j) => `<script type="module" crossorigin src="https://dev.to/assets/${j}"></script>`).join('\n');
}

const renderCss = (css) => {
  return css.map((c) => `<link rel="stylesheet" href="https://dev.to/assets/${c}" />`).join('\n');
}

export const view = (data, state) => html`
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>${data.title}</title>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      ${renderJs(data.js)}
      ${renderCss(data.css)}
    </head>

    <body data-theme="forest">
      <div id="app" data-chat-id="${data.cid}"></div>
    </body>
  </html>
`
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

DevEx

در بررسی تاکنون – ما یک برنامه Express را برای ارائه دارایی‌های ثابت راه‌اندازی کرده‌ایم، یک برنامه Svelte مستقل ایجاد کرده‌ایم، و الگویی اضافه کرده‌ایم که برنامه Svelte را از دارایی‌های کامپایل‌شده Vite مقداردهی اولیه می‌کند و همچنین داده‌ها را از سرور ارائه می‌کند. با این حال، هنوز هم نیاز به ساخت برنامه Svelte و کپی کردن فایل‌های دارایی کامپایل شده در فهرستی برای Express دارد، که دستورات زیادی برای اجرا همزمان با تغییر فعال برنامه Svelte است. بیایید چند اسکریپت تنظیم کنیم تا این کار آسان تر شود.

ابتدا یک Makefile ساده برای اجرای بیلد Vite و کپی فایل های کامپایل شده در فهرست دارایی های Express –

# ./Makefile
SHELL := /bin/bash

build:
    pushd svelte \
    && npm install \
    && npm run build \
    && popd \
    && rm -f ./public/assets/* \
    && cp ./svelte/dist/assets/* ./public/assets/

run:
    npm install \
    && node server.js

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما همچنین یک اسکریپت پوسته کوچک به نام ایجاد می کنیم ./watch-svelte برای مشاهده تغییرات در *.svelte فایل ها و بیلد را به صورت خودکار اجرا کنید. این ما را از اجرای دستوری هر بار که یک جزء Svelte را تغییر می‌دهیم نجات می‌دهد –

# ./watch-svelte
#!/bin/bash

inotifywait -q -m -r -e modify,create,delete ./svelte | while read DIRECTORY EVENT FILE; do
    if [[ $FILE == *.svelte ]]; then
        make build
    fi
done

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ساخت تولید

برای استقرار برنامه در تولید، یک Dockerfile ایجاد می کنیم که هم برنامه Svelte را می سازد و هم برنامه Express را بسته بندی می کند. ظرف به دست آمده را می توان در بسیاری از ارائه دهندگان میزبانی اجرا کرد، برای مثال ما در fly.io مستقر شده است

Dockerfile از یک ساخت چند مرحله‌ای استفاده می‌کند که به کوچک‌تر نگه داشتن اندازه کانتینر حاصل کمک می‌کند زیرا ما هیچ یک از وابستگی‌های توسعه‌دهنده Vite یا Svelte را شامل نمی‌شویم.

FROM node:18-alpine as svelte-build

RUN mkdir -p /home/node/svelte/node_modules && chown -R node:node /home/node/svelte

WORKDIR /home/node/svelte

ADD svelte ./
RUN npm install
RUN npm run build

FROM ubuntu:latest

RUN apt-get update && apt-get install -y gnupg2 wget vim
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && wget -q -O - https://deb.nodesource.com/setup_16.x | bash - \
    && apt-get update \
    && DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends nodejs
    && rm -rf /var/lib/apt/lists/*

RUN useradd -Ums /bin/bash node
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app

WORKDIR /home/node/app
USER node

ADD public ./public
COPY --from=svelte-build --chown=node:node /home/node/svelte/dist/assets/* ./public/assets/

COPY server.js ./
COPY package.json ./
RUN npm install

EXPOSE 3000

CMD node server.js

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و بس! امیدواریم که این یک مرجع مفید برای استفاده از Svelte در سایر برنامه های میکرو باشد که در آن قابلیت های SvelteKit غیر ضروری است.

کد نویسی مبارک

تصویر هدر با کمک DALL·E 2 ایجاد شد

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا