هنگام ساخت برنامه های تحت وب، ما بیشتر backend را از frontend جدا می کنیم و با استفاده از GraphQL یا REST API بین آنها ارتباط برقرار می کنیم. با این حال، این معمولاً برنامه ما را پیچیده می کند و hosting responsibilities و دیپلوی کردن را برای بک اند و فرانت را افزایش می دهد.
حتی در هنگام ساختن یک برنامه وب که جدا نشده از سمت سرور، ما توسط گزینه های قالب ظاهری ارائه شده توسط فریمورک های سمت سرور محدود می شویم. اگر راهی برای ایجاد یک برنامه کاملاً جاوا اسکریپت تک صفحه ای برای جایگزینی ویو های رندر شده در سمت سرور بدون پیچیدگی اضافی ساخت API و یک فرانت اند جداگانه وجود داشت چه؟
این مقاله به نحوه دستیابی به این هدف با استفاده از Inertia.js، Vue.js و AdonisJs می پردازد. برای دنبال کردن و تکمیل این آموزش، به Node.js نصب شده و دانش اولیه جاوا اسکریپت و Vue.js نیاز دارید.
AdonisJs
AdonisJs یک فریمورک وب محبوب Node.js برای ساخت API و برنامه های سمت سرور است. به دلیل سینتکس تمیز و شهودی خود شناخته شده است. AdonisJs در درجه اول از فریمورک قالب Edge در قسمت فرانت استفاده می کند. با این حال، با اینرسی، می توانیم از فریمورک های فرانت اند مانند React، Vue و Svelte استفاده کنیم.
Inertia.js
Inertia یک کتابخانه محبوب برای ساخت برنامه های تک صفحه ای فول استک (SPA) با استفاده از فریمورک های پشتیبانی شده مانند React، Vue و Svelte در فرانت اند است. در درون خودش ، Inertia با استفاده از آداپتورهای لاراول و سایر فریم ورک ها را پشتیبانی می کند. Inertia همچنین به شما امکان می دهد SPA هایی ایجاد کنید که مانند برنامه های کاربردی رندر شده توسط سرور سنتی عمل می کنند و در عین حال از مزایای معماری SPA استفاده می کنند.
Vue.js
ما در این مقاله از Vue.js به عنوان فریمورک انتخابی خود استفاده خواهیم کرد. Vue.js یک فریمورک محبوب جاوا اسکریپت برای ساخت رابط کاربری است. این به دلیل سادگی و انعطاف پذیری خود شناخته شده است و اغلب برای ایجاد SPA و برنامه های کاربردی وب (PWA) استفاده می شود.
راه اندازی یک پروژه AdonisJs و Inertia.js
برای ایجاد یک برنامه AdonisJs، دستور زیر را اجرا کنید:
npm init adonis-ts-app@latest adonis-inertia-app
اکنون می توانیم با کد زیر وارد پروژه خود شویم:
cd adons-inertia-app
پس از انجام این کار، میتوانیم آداپتور inertiajs-adonisjs را برای اضافه کردن اینرسی به پروژه AdonisJs
خود پیکربندی کنیم. برای انجام این کار، آداپتور را با دستور زیر نصب کنید:
npm i @eidellev/inertia-adonisjs
پس از نصب، میتوانیم با اجرای دستور زیر تنظیماتی را اضافه کنیم:
$ node ace configure @eidellev/inertia-adonisjs
در طول نصب، از ما چند سوال پرسیده می شود. ما با موارد زیر پاسخ خواهیم داد:
❯ Enter the edge file you would like to use as your entrypoint · app
❯ Would you like to install the Inertia.js client-side adapter? (Y/n) · true
❯ Would you like to use SSR? (y/N) · true
❯ Which client-side adapter would you like to set up? · @inertiajs/inertia-vue3
هنگامی که پیکربندی کامل شد و وابستگی ها نصب شدند، می توانیم vue-loader
را برای استفاده در وب پک برای بارگیری فایل های Vue نصب کنیم:
npm i -D vue-loader
اکنون، باید آن را به پیکربندی Encore
وب پک خود درwebpack.config.js./
اضافه کنیم:
// ./webpack.config.js
// ...
/*
|--------------------------------------------------------------------------
| Enable Vue loader
|--------------------------------------------------------------------------
|
| Uncomment the following lines of code to enable support for vue. Also make
| sure to install the required dependencies.
|
*/
Encore.enableVueLoader(() => {}, {
version: 3,
runtimeCompilerBuild: false,
useJsx: false
})
پیکربندی میدلور آداپتور inertiajs-adonisjs
بیایید میدلور آداپتور inertiajs-adonisjs را با افزودن آن به فایلstart/kernel.ts./
به صورت گلوبال در پروژه خود ثبت کنیم:
// ./start/kernel.ts
// ...
/*
|--------------------------------------------------------------------------
| Global middleware
|--------------------------------------------------------------------------
|
| An array of global middleware, that will be executed in the order they
| are defined for every HTTP requests.
|
*/
Server.middleware.register([
() => import('@ioc:Adonis/Core/BodyParser'),
// import the inertia-adonis middleware
() => import('@ioc:EidelLev/Inertia/Middleware'),
])
اکنون که آداپتور در پروژه ما پیکربندی شده است، می توانیم برنامه Vue خود را با Inertia متصل کنیم.
اتصال برنامه Vue.js به Inertia.js
در فایل برنامه ویو resources/js/app.js/.
می آیم ، createInertiaApp
را وارد کرده و برخی از تنظیمات را مانند شکل زیر اضافه کنید:
// ./resources/js/app.js
import { createApp, h } from "vue";
import { createInertiaApp } from "@inertiajs/inertia-vue3";
import '../css/app.css'
createInertiaApp({
resolve: (name) => require(`./pages/${name}`),
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el);
},
});
تابع resolve
مستلزم آن است که کامپوننت صفحه در resources/js/Pages/.
مطابق با نام مجموعه در سمت سرور ارائه شود. در تابع setup
، ما ()CreateApp
را فراخوانی می کنیم تا برنامه را با props
و plugin
ها رندر کنیم.
نحوه تنظیم رندر سمت سرور
برای اینکه رندر سمت سرور کار کند، چند وابستگی نصب می کنیم:
npm install -D @vue/server-renderer @inertiajs/server
سپس، باید یک نقطه ورودی اسکریپت اضافی مخصوص SSR را در یک فایل جدید اضافه کنیم، همانطور که در زیر نشان داده شده است:
./resources/js/ssr.js
// ./resources/js/ssr.js
import { createSSRApp, h } from "vue";
import { renderToString } from "@vue/server-renderer";
import { createInertiaApp } from "@inertiajs/inertia-vue3";
export default function render(page) {
return createInertiaApp({
page,
render: renderToString,
resolve: (name) => require(`./Pages/${name}`),
setup({ app, props, plugin }) {
return createSSRApp({
render: () => h(app, props),
}).use(plugin);
},
});
}
ما همچنین Vue loader
را در webpack.ssr.config.js/.
فعال می کنیم:
// ./webpack.ssr.config.js
/*
|--------------------------------------------------------------------------
| Enable Vue loader
|--------------------------------------------------------------------------
|
| Uncomment the following lines of code to enable support for vue. Also make
| sure to install the required dependencies.
|
*/
Encore.enableVueLoader(() => {}, {
version: 3,
runtimeCompilerBuild: false,
useJsx: false,
})
راه اندازی Route
تنظیم route ها بسیار ساده است. برای راهاندازی route در برنامه Inertia
و Vue
خود، روت ها را ثبت میکنیم و از ()inertia.render
برای ارائه آنها استفاده میکنیم. در این بخش، خواهیم دید که چگونه می توانیم کامپوننت صفحه اصلی را ایجاد کنیم و route را در یک فایل routes.ts
تنظیم کنیم. ما همچنین خواهیم دید که چگونه میتوانیم props ها را به روت خود منتقل کنیم.
ایجاد صفحه اصلی برای روت با /
بیایید با ایجاد یک صفحه resources/js/Pages/Home.vue/.
یک route جدید برای /
ایجاد کنیم:
<!-- ./resources/js/Pages/Home.vue -->
<template>
<section>
<header>
<h1>Home</h1>
<p>Home page</p>
</header>
</section>
</template>
اکنون که یک کامپوننت برای Home
داریم، میتوانیم route را در start/routes.ts/.
ثبت کنیم:
// ./start/routes.ts
import Route from '@ioc:Adonis/Core/Route'
Route.get('/', async ({ inertia }) => {
return inertia.render('Home')
})
پاس دادن props
همانطور که در زیر نشان داده شده است میتوانیم از فایل routeهای ./start/routes.ts props را به کامپوننت خود ارسال کنیم.
// ./start/routes.ts
// ...
Route.get("/", async ({ inertia }) => {
return inertia.render("Home", {
title: "Home",
message: "Hello World",
});
});
سپس در resources/js/Pages/Home.vue/.
کد زیر را اضافه کنید:
<!-- ./resources/js/Pages/Home.vue -->
<script>
export default {
props: {
// Define props here
title: String,
message: String,
},
};
</script>
<template>
<section>
<header>
<h1>{{ title }}</h1>
<p>{{ message }}</p>
</header>
</section>
</template>
برنامه را با اجرای npm run dev
شروع کنید و سرور SSR را با اجرای node ace ssr:watch
در یک ترمینال جدید راه اندازی کنید.
نحوه راه اندازی Tailwind CSS
برای راه اندازی Tailwind CSS در برنامه خود، باید بسته های زیر را نصب کنیم:
npm i -D postcss-loader tailwindcss
سپس فایل پیکربندی را با دستور زیر تولید می کنیم:
npx tailwindcss init
این یک فایل tailwind.config.js/.
تولید می کند تا فایل ها را برای Tailwind CSS مشخص کند تا موارد Tailwind را اسکن و اعمال کند و از shaking پشتیبانی کند. در فایل tailwind.config.js/.
کد زیر را اضافه کنید:
// ./tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./resources/**/*.{edge,js,ts,vue,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
پیکربندی PostCSS
اکنون، PostCSS را پیکربندی می کنیم. ابتدا PostCSSLLoader
را در webpack.config.js/.
فعال کنید
//./webpack.config.js
/*
|--------------------------------------------------------------------------
| CSS loaders
|--------------------------------------------------------------------------
|
| Uncomment one of the following line of code to enable support for
| PostCSS or CSS.
|
*/
Encore.enablePostCssLoader()
در مرحله بعد، یک فایل postcss.config.js/.
برای فراخوانی plugins
Tailwind CSS ایجاد می کنیم:
// ./postcss.config.js
module.exports = {
plugins: [
require('tailwindcss')()
]
}
در نهایت، دستورالعملهای Tailwind را به resources/css/app.css/.
اضافه میکنیم:
/* ./resources/css/app.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
اکنون، وقتی سرور توسعه دهنده خود را مجددا راه اندازی می کنیم، باید ببینیم که تمام سبک های پیش فرض با استایل های Tailwind CSS بازنشانی شده اند.
ایجاد کامپوننت های Vue.js
ما می توانیم مانند یک برنامه معمولی Vue کامپوننت هایی را ایجاد و به برنامه خود اضافه کنیم. حالا بیاید کامپوننت SiteNav
و SiteHeader
را بسازیم.
ساخت کامپوننت SiteNav و SiteHeader
یک فایل جدید resources/js/components/SiteNav.vue/.
مانند شکل زیر ایجاد کنید:
→- ./resources/js/components/SiteNav.vue -->
<template>
<nav class="site-nav">
<div class="wrapper">
<ul class="links">
<li class="link">
<Link href="/login">Login</Link>
</li>
<li class="link">
<Link href="/register">Register</Link>
</li>
</ul>
</div>
</nav>
</template>
<script setup>
import { Link } from "@inertiajs/inertia-vue3";
</script>
<style scoped>
.site-nav .links {
@apply flex gap-2;
}
.links .link {
@apply text-gray-600;
}
</style>
در کد بالا، ما از کامپوننت Inertia Link
برای پیوند بین routeها استفاده می کنیم.
کامپوننت SiteHeader
اکنون برای ایجاد کامپوننت SiteHeader
، یک فایل جدید به نام resources/js/components/SiteHeader.vue/.
ایجاد کنید:
<!-- ./resources/js/components/SiteHeader.vue -->
<template>
<header class="site-header">
<div class="wrapper">
<figure class="site-logo">
<span class="font-bold text-2xl">My site</span>
</figure>
<slot />
</div>
</header>
</template>
<style scoped>
.site-header {
@apply sticky top-0 left-0 w-full p-4;
}
.site-header > .wrapper {
@apply flex justify-between items-center p-4 py-2 bg-white max-w-6xl m-auto rounded-lg shadow-md;
}
</style>
در اینجا، ما یک عنصر header
با عنصر site-logo.
برای لوگوی سایت ایجاد کردیم و آن را در بالای صفحه با چند سبک پایه قرار دادیم.
کامپوننت گلوبال
ما میتوانیم کامپوننت های خود را با ثبت آنها در resources/js/app.js/.
در سطح گلوبال در دسترس قرار دهیم. این باعث می شود که ما مجبور نباشیم آنها را در هر فایل وارد کنیم. کد زیر را به پوشه resources/js/app.js/.
خود اضافه کنید:
// ./resources/js/app.js
import { createApp, h } from "vue";
import { createInertiaApp } from "@inertiajs/inertia-vue3";
import DefaultLayout from "./layouts/Default.vue";
import SiteNav from "./components/SiteNav.vue";
import SiteHeader from "./components/SiteHeader.vue";
import "../css/app.css";
createInertiaApp({
resolve: (name) => {
const page = require(`./pages/${name}`).default;
// If the page doesn't have a layout, use the default layout.
if (!page.layout) {
page.layout = DefaultLayout;
}
return page;
},
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.component("site-nav", SiteNav)
.component("site-header", SiteHeader)
.mount(el);
},
});
در اینجا کامپوننت های SiteHeader
و SiteNav
را وارد کرده و در متد کامپوننت ثبت کردیم. در بخش بعدی، این کامپوننت را به layout های خود اضافه میکنیم.
تنظیم layout پیشفرض
ابتدا، با افزودن کد زیر به فایل resources/js/layouts/Default.vue/.
،یک فایل layout پیش فرض ایجاد می کنیم:
<!-- ./resources/js/layouts/Default.vue -->
<template>
<main>
<site-header>
<site-nav />
</site-header>
<slot />
</main>
</template>
در اینجا، ما <slot/>
را برای نمایش view برای صفحه route داریم.
Inertia.js DefaultLayout
در resources/js/app.js/.
خود، layout را که ایجاد کردهایم وارد میکنیم و آن را به ویژگی layout
صفحهای که قرار است رندر شود اضافه میکنیم:
// ./resources/js/app.js
import { createApp, h } from "vue";
import { createInertiaApp } from "@inertiajs/inertia-vue3";
import DefaultLayout from "./layouts/Default.vue";
import "../css/app.css";
createInertiaApp({
resolve: (name) => {
const page = require(`./pages/${name}`).default;
// If the page doesn't have a layout, use the default layout.
if (!page.layout) {
page.layout = DefaultLayout;
}
return page;
},
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el);
},
});
با این کار، هر صفحه با این طرح رندر می شود.
Per-page layouts
برای تعریف layout برای هر صفحه، کامپوننت layout را به ویژگی layout در فایل صفحه اختصاص میدهیم. برای مثال، اگر یک layout جدید در resources/js/layouts/AppLayout.vue/.
ایجاد کنیم، میتوانیم کامپوننت <site-header/>
را اضافه کنیم تا در هر route نمایش داده شود و تگ <slot>
محتوا را ارائه میکند. برای route فعلی :
<!-- ./resources/js/layouts/AppLayout.vue -->
<template>
<main>
<site-header />
<section class="auth-section">
<header class="auth-header">
<h1 class="font-bold text-3xl">
Get started
</h1>
</header>
<div class="wrapper">
<slot />
</div>
</section>
</main>
</template>
<style scoped>
.auth-section > .auth-header {
@apply pt-6 max-w-4xl m-auto;
}
.auth-section > .wrapper{
@apply py-6 max-w-4xl m-auto;
}
</style>
در مرحله بعد، می توانیم یک صفحه ورود با یک فرم ساده در resources/js/pages/Login.vue/.
ایجاد کنیم.
<!-- ./resources/js/pages/Login.vue -->
<template>
<div class="form-cont">
<form class="auth-form">
<div class="wrapper">
<div class="form-control">
<label for="email">Email</label>
<input type="email" id="email" class="form-input" />
</div>
<div class="form-control">
<label for="password">Password</label>
<input type="password" id="password" class="form-input" />
</div>
<div class="action-cont">
<button type="submit" class="cta">Login</button>
</div>
<span> Or <Link class="link" href="/register">Register</Link> </span>
</div>
</form>
</div>
</template>
<script>
import { Link } from "@inertiajs/inertia-vue3";
import AuthLayout from "../layouts/Auth.vue";
export default {
layout: AuthLayout,
components: {
Link,
},
};
</script>
<style scoped>
.auth-form {
@apply relative p-6 bg-white border border-slate-200 rounded-lg;
}
.auth-form > .wrapper {
@apply flex flex-col gap-4;
}
</style>
در اینجا می بینید که ما Layout
را برای این صفحه با وارد کردن و تعریف آن در ویژگی layout
تعریف کردیم. اکنون میتوانیم این صفحه را به routeهای خود در start/routes.ts/.
اضافه کنیم:
// ./start/routes.ts
import Route from "@ioc:Adonis/Core/Route";
Route.get("/", async ({ inertia }) => {
return inertia.render("Home", {
title: "Home",
message: "Hello World",
});
});
Route.get("/login", async ({ inertia }) => {
return inertia.render("Login", {
title: "Login",
});
});
در بخش بعدی، خواهیم دید که چگونه می توانیم از فرم های Inertia.js در برنامه خود استفاده کنیم.
نحوه استفاده از کمک کننده فرم Inertia.js
اینرسی از پردازش فرم های ارسالی که از درخواست های HTTP ناهمزمان استفاده می کنند پشتیبانی می کند. این به ما امکان می دهد تا از پاسخ برای به روز رسانی صفحه خود استفاده کنیم. این request ، هلپر فرم Inertia.js است که مدیریت فرم ها و انجام کارهای رایج مرتبط با فرم را در برنامه Inertia.js آسان تر می کند. بیایید مراحل اصلی استفاده از هلپرهای فرم Inertia.js را برای مدیریت فرم ها در برنامه خود مرور کنیم.
ایجاد کامپوننت FormInput
برای ایجاد کامپوننت FormInput
، یک فایل resources/js/components/FormInput.vue/.
جدید ایجاد کنید:
<!-- ./resources/js/components/FormInput.vue -->
<template>
<div class="form-control">
<label v-if="label" for="password">{{ label }}</label>
<input
:type="type"
v-model="inputVal"
:placeholder="placeholder"
class="form-input"
/>
</div>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
type: {
type: String,
default: "text",
},
label: String,
placeholder: String,
modelValue: String,
});
const emit = defineEmits(["update:modelValue"]);
const inputVal = computed({
get() {
return props.modelValue;
},
set(value) {
emit("update:modelValue", value);
},
});
</script>
بعد، ما از این کامپوننت در صفحات ولیدیشن خود استفاده خواهیم کرد. اکنون، بیایید یک صفحه ثبت نام جدید ایجاد کنیم.
ساخت صفحه ثبت نام
برای ایجاد یک صفحه ثبت نام، مانند زیر، یک فایل resources/js/pages/Register.vue/.
جدید ایجاد کنید.
<!-- ./resources/js/pages/Register.vue -->
<template>
<div class="form-cont">
<form @submit.prevent="form.post('/register')" class="auth-form">
<div class="wrapper">
<FormInput label="Email" type="email" v-model="form.email" />
<FormInput label="Password" type="password" v-model="form.password" />
<div class="action-cont">
<button attr-type="submit" class="cta">Register</button>
</div>
<span> Or <Link class="link" href="/login">Login</Link> </span>
</div>
</form>
</div>
</template>
<script>
import { Link } from "@inertiajs/inertia-vue3";
import FormInput from "../components/FormInput.vue";
import AuthLayout from "../layouts/Auth.vue";
import { useForm } from "@inertiajs/inertia-vue3";
export default {
layout: AuthLayout,
components: {
Link,
FormInput,
},
setup() {
const form = useForm({
email: "",
password: "",
});
return {
form,
};
},
};
</script>
این تقریباً شبیه چیزی است که ما در صفحه ورود به سیستم خود داشتیم. در اینجا، ما از کامپوننت های FormInput
جدیدی که قبلاً ایجاد کرده بودیم استفاده می کنیم. ما همچنین از helper useForm
استفاده میکنیم: import { useForm }
از "@inertiajs/inertia-vue3"
که به فرم در ()setup
اختصاص میدهیم.
با این کار، زمانی که فرم با استفاده از ()form.post
ارسال می شود، می توانیم یک درخواست POST
ارسال کنیم:
<form @submit.prevent="form.post('/register')" class="auth-form">
به روز رسانی Routes
اکنون، بیایید Routes
درخواست ثبت نام GET
و POST
خود را به روز کنیم. برای این کار موارد زیر را در فایل start.routes.ts/.
وارد کنید:
// ./start/routes.ts
Route.get("/register", async ({ inertia }) => {
return inertia.render("Register", {
title: "Regsiter",
});
});
Route.post("/register", async ({ request, response }) => {
console.log({
registerBody: request.body(),
});
return response.redirect("/");
});
در اینجا در Route.post
، ما از بدنه درخواست خارج شدیم و آنها را به route اصلی هدایت کردیم.
ما همچنین می توانیم همین کار را برای صفحه ورود انجام دهیم. بیایید کامپوننت FormInput
خود را به Login
در resources/js/pages/Login.vue/.
اضافه کنیم:
<!-- ./resources/js/pages/Login.vue -->
<template>
<div class="form-cont">
<form @submit.prevent="form.post('/login')" class="auth-form">
<div class="wrapper">
<FormInput label="Email" type="email" v-model="form.email" />
<FormInput label="Password" type="password" v-model="form.password" />
<div class="action-cont">
<button attr-type="submit" class="cta">Login</button>
</div>
<span> Or <Link class="link" href="/register">Register</Link> </span>
</div>
</form>
</div>
</template>
<script>
import { Link } from "@inertiajs/inertia-vue3";
import FormInput from "../components/FormInput.vue";
import AuthLayout from "../layouts/Auth.vue";
import { useForm } from "@inertiajs/inertia-vue3";
export default {
layout: AuthLayout,
components: {
Link,
FormInput,
},
setup() {
const form = useForm({
email: "",
password: "",
});
return {
form,
};
},
};
</script>
سپس در فایل start/routes.ts/.
خود، می توانیم route POST
را اضافه کنیم:
// ./start/routes.ts
// ...
Route.post("/login", async ({ request, response }) => {
console.log({
registerBody: request.body(),
});
return response.redirect("/");
});
نتیجه
این مقاله شروع با AdonisJs، Inertia.js و Vue.js را پوشش میدهد. این فناوریهای عالی میتوانند به توسعهدهندگان کمک کنند تا برنامههای وب سریع و کارآمد ایجاد کنند.
با دنبال کردن مراحل ذکر شده در این مقاله، می توانید به راحتی این فناوری ها را راه اندازی کنید و شروع به ساخت برنامه های خود کنید. این فناوریها با قابلیت افزودن رندر سمت سرور، Tailwind CSS برای استایلسازی و کمککننده فرم Inertia.js برای ارسال فرم، راهحلهای جامعی را برای ساخت برنامههای وب مدرن ارائه میکنند.
چه یک توسعهدهنده باتجربه باشید و چه تازه شروع به کار کردهاید، AdonisJs، Inertia.js و Vue.js برای پروژه بعدیتان با ارزش در نظر گرفتن دارند.