تعبیه در سایت‌های دیگر

با یک تگ script، اپی به سایتی دیگر اضافه کنید: ⁦text build --embed⁩، <text-console>، مسیرهای رندرشده در سمت سرور و میزبانی.

دستور text build --embed برنامهٔ شما را طوری می‌سازد که سایت دیگری بتواند آن را با یک تگ اسکریپت اضافه کند، مانند یک صفحهٔ بازاریابی، سایت مستندات، صفحهٔ WordPress یا Webflow، یا برنامهٔ ⁦React 18⁩. بازدیدکنندگانی که DevTools را باز می‌کنند، برنامهٔ شما را در کنسول می‌بینند. سایر بازدیدکنندگان فقط embed.js را دانلود می‌کنند (حدود 3 kB با gzip)، مگر اینکه صفحه دارای <text-console> باشد.

جاسازی برنامه‌ها آزمایشی است. دستور text build --embed، گزینهٔ embed، عنصر <text-console> و خروجی‌های @textjs/app/experimental ممکن است در یک انتشار فرعی تغییر کنند. تغییرات ناسازگار را ببینید.

افزودن برنامه به سایت

برنامه را بسازید:

text build --embed

دایرکتوری dist/ را روی هر میزبان استاتیک یا CDN بارگذاری کنید، یا آن را در پوشهٔ public/ سایت کپی کنید، سپس یک تگ به صفحات سایت اضافه کنید:

<script type="module" src="https://console.example.com/embed.js"></script>

فایل embed.js فایل‌های دیگرش را نسبت به URL خودش بارگذاری می‌کند، بنابراین dist/ از هر مسیر یا مبدأیی کار می‌کند. این دایرکتوری فقط شامل embed.js و assets/ است و فایل index.html یا 404.html ندارد که جایگزین فایل‌های خود سایت شود. برنامه‌ای با مسیرهای رندرشده در سمت سرور، کنترل‌گرهای مسیر یا middleware، به‌جای بارگذاری استاتیک صرف، به سرور نیاز دارد. آداپتورهای vercel و cloudflare کنترل‌گرهای مسیر و middleware را اجرا می‌کنند، و مسیرهای رندرشده در سمت سرور به text start یا آداپتور bun نیاز دارند.

برای نشان دادن محل برنامه به بازدیدکنندگان، عنصر <text-console> را در هر جای صفحه اضافه کنید. هر عنصری با data-textjs-engage نیز هنگام فشردن، برنامه را راه‌اندازی می‌کند:

<button type="button" data-textjs-engage>Open in the console</button>

برای امتحان کردن آن به‌صورت محلی، دستور text dev --embed را اجرا کنید. این دستور /embed.js را با یک فریم اول تازه در هر درخواست، و یک صفحهٔ پیش‌نمایش در / (با standalone در /__textjs/embed) ارائه می‌کند که آن را مانند سایت دیگری بارگذاری می‌کند. سایتی روی یک پورت محلی دیگر نیز می‌تواند http://localhost:3000/embed.js را بارگذاری کند.

پیکربندی

دستور text build --embed معادل embed: true در text.config.ts است. برای تغییر پیش‌فرض‌ها، یک شیء ارسال کنید:

text.config.tsts
import { defineConfig } from "@textjs/app";export default defineConfig({  embed: {    initialPath: "/status",  },});
گزینهپیش‌فرضتوضیح
initialPath"/"مسیری که کنسول در آن باز می‌شود. باید با / شروع شود
globalName"text"نام سراسری که برنامه پس از راه‌اندازی، API کنسول خود را تحت آن نصب می‌کند. مقدار false هیچ‌کدام را نصب نمی‌کند
initialClearfalseپاک کردن کنسول صفحه پیش از اولین فریم. به‌طور پیش‌فرض، گزارش‌های قبلی صفحه بالای برنامه باقی می‌مانند
standalonefalseساخت صفحات خود برنامه (index.html) نیز، مانند اجرای text build بدون embed
allowOrigins[]سایت‌هایی که صفحاتشان مجاز به اجرای مسیرهای رندرشده در سمت سرور از این سرور هستند. مسیرهای رندرشده در سمت سرور را ببینید
credentialsfalseارسال اطلاعات احراز هویت مرورگر برای این سرور همراه درخواست‌های نشست زنده از allowOrigins، به‌جای حذف کوکی‌ها و Authorization. به مبدأهای دقیق نیاز دارد

مقدار viewport.width × viewport.height (پیش‌فرض ⁦120 × 36⁩) اندازهٔ اولین فریم است. مقادیر title، hints و action پیش‌فرض‌های <text-console> هستند. با ppr: false، یا زمانی که middleware.ts بتواند با initialPath مطابقت داشته باشد، فایل embed.js فریم اول پیش‌رندرشده ندارد، چون هر کسی می‌تواند embed.js را دانلود کند. نمایش آینه‌ای تا زمانی که برنامه رسم شود خالی می‌ماند.

نحوهٔ رفتار

  • تا زمان قصد استفاده از کنسول، چیز دیگری بارگذاری نمی‌شود. فایل embed.js اولین فریم پیش‌رندرشده را در کنسول ثبت می‌کند، سپس منتظر می‌ماند. برنامه زمانی بارگذاری می‌شود که DevTools به پنجره متصل باشد (هنگام بارگذاری یا پس از آن)، بازدیدکننده در صفحه میان‌بر DevTools را فشار دهد (⁦F12⁩، ⁦Ctrl+Shift+J⁩، I، C یا K، یا ⁦⌘⌥J⁩، I، C یا K در Mac)، یا عنصر <text-console> یا [data-textjs-engage] را فشار دهد. پس از آن، بارگذاری مجدد در همان زبانه، برنامه را بلافاصله راه‌اندازی می‌کند. DevTools در پنجرهٔ مستقل اندازهٔ صفحه را تغییر نمی‌دهد، بنابراین بازدیدکنندگانی که آن را از منو باز کرده‌اند، تا زمانی که یکی از آن عناصر را فشار دهند، اولین فریم را می‌بینند.
  • در صفحه‌های لمسی، برنامه راه‌اندازی نمی‌شود. در دستگاهی که با (hover: none) and (pointer: coarse) مطابقت دارد، فایل embed.js چیزی ثبت نمی‌کند و هیچ شنونده‌ای اضافه نمی‌کند. تنها فایلی که بارگذاری می‌کند، فایل <text-console> برای نمایش آینه‌ای است.
  • کلیدها فقط پس از فعال‌سازی برنامه به‌دست بازدیدکننده به آن می‌رسند. برای فعال‌سازی، بازدیدکننده عنصر <text-console> یا [data-textjs-engage] را فشار می‌دهد، یا روی صفحه (نه پیوند، دکمه یا فیلد) کلیک می‌کند تا فوکوس را از DevTools برگرداند. تایپ در فیلدهای خود صفحه یا در عنصر [data-textjs-bypass] هرگز به برنامه نمی‌رسد، و چرخ ماوس همیشه صفحه را پیمایش می‌کند.
  • URL، تاریخچه و عنوان صفحه هرگز تغییر نمی‌کنند. مسیرها، <Link> و useRouter() درون کنسول جابه‌جا می‌شوند. در برنامه‌های رندرشده در سمت کلاینت، URLهای مطلق در زبانهٔ جدید باز می‌شوند.
  • برنامهٔ Text.js موجود در صفحه اولویت دارد. وقتی راه‌اندازی می‌شود، برنامهٔ جاسازی‌شدهٔ در حال اجرا از حالت mount خارج می‌شود، خواندن کلیدها را متوقف می‌کند و متغیر سراسری خود را حذف می‌کند. برنامهٔ جاسازی‌شده‌ای که هنگام در اختیار بودن کنسول توسط برنامه‌ای دیگر بارگذاری شود، یک هشدار ثبت می‌کند و راه‌اندازی نمی‌شود.
  • برنامهٔ جاسازی‌شده ⁦React 19⁩ خودش را در بسته دارد. این برنامه react-dom یا import بدون مسیر ندارد، بنابراین نسخهٔ React صفحه، نقشهٔ import برای react و ⁦React DevTools⁩ بر آن تأثیر نمی‌گذارند.

زمان بارگذاری فایل‌ها

فایلزمان بارگذاریgzip
embed.jsهمراه صفحه2.9 kB
assets/text-console-[hash].jsوقتی صفحه دارای <text-console> باشد4.0 kB
assets/embed-client-[hash].js و assets/yoga-[hash].wasmهنگام قصد استفاده از کنسول112.8 ⁦kB + 29.0⁩ kB
assets/embed-player-[hash].jsهنگام قصد استفاده از کنسول، به‌جای کلاینت، برای یک مسیر رندرشده در سمت سرور22.7 kB
assets/bidi-[hash].jsاولین باری که برنامه متن راست‌به‌چپ نمایش می‌دهد (بارگذاری موتور bidi را ببینید)10.1 kB

اندازه‌ها برای یک کادر وضعیت حاشیه‌دار با ابعاد ⁦120 × 36⁩ هستند. دستور text build --embed اندازه‌های برنامهٔ شما را چاپ می‌کند. فایل assets/embed-[hash].js نسخه‌ای از embed.js با نامی است که هرگز تغییر نمی‌کند (استقرارها را ببینید).

<text-console>

فایل embed.js عنصر <text-console> را تعریف می‌کند و فایل آن را فقط زمانی بارگذاری می‌کند که یکی از این عناصر در صفحه باشد. این عنصر از ⁦Shadow DOM⁩ استفاده می‌کند، بنابراین CSS صفحه به درون آن نمی‌رسد و سیاست style-src 'self' به تغییری نیاز ندارد.

<text-console></text-console><text-console mirror></text-console><text-console chrome></text-console>

بدون ویژگی‌ها، یک نوار تک‌خطی است. میان‌بر مرورگر برای باز کردن کنسول را نشان می‌دهد، سپس درخواست کلیک می‌کند، سپس کلیدهای برنامه را فهرست می‌کند که هنگام رسیدن به برنامه روشن می‌شوند. در Safari، مرحلهٔ اول می‌گوید گزینهٔ «نمایش قابلیت‌ها برای توسعه‌دهندگان وب» را در تنظیمات Safari روشن کنید.

با mirror، فریم برنامه را در صفحه نشان می‌دهد: اولین فریم پیش‌رندرشده پیش از بارگذاری هر چیز دیگر، سپس برنامهٔ در حال اجرا. فشردن آن برنامه را راه‌اندازی می‌کند و کلیدهای بازدیدکننده را به آن می‌فرستد، بنابراین برنامه با DevTools بسته هم کار می‌کند. ویژگی chrome یک پنجرهٔ DevTools دور نمایش آینه‌ای رسم می‌کند و mirror را نیز فعال می‌کند.

ویژگیتوضیح
mirrorنمایش فریم‌های برنامه
chromeنمایش فریم‌ها در پنجرهٔ DevTools
titleعنوان نوار (پیش‌فرض: title در text.config.ts)
hintsکلیدهای فهرست‌شده، به‌شکل "← →:switch region, Enter:open" (پیش‌فرض: hints در text.config.ts)
actionنخستین کاری که باید انجام شود، با متن «اینجا کلیک کنید و …» (پیش‌فرض: action در text.config.ts، یا فشردن اولین کلید راهنما)

در صفحه‌های لمسی، نمایش آینه‌ای اولین فریم را بدون راه‌اندازی برنامه نشان می‌دهد و نوار پنهان است. متن عنصر به زبان انگلیسی است.

رزرو فضای عنصر

دستور text build --embed یک خط CSS برای شبکهٔ برنامهٔ شما چاپ می‌کند. آن را در شیوه‌نامهٔ صفحه جای‌گذاری کنید. این خط اندازهٔ <text-console> را پیش از بارگذاری فایل عنصر تعیین می‌کند، بنابراین هنگام رسیدن فایل، چیزی در صفحه جابه‌جا نمی‌شود. برای شبکهٔ پیش‌فرض ⁦120 × 36⁩، این خط چنین است:

text-console{display:block;min-height:58px}text-console:is([mirror],[chrome]){position:relative;box-sizing:content-box;min-height:0;max-width:885px;aspect-ratio:885/522}text-console[chrome]{padding-top:43px}@media (hover:none) and (pointer:coarse){text-console:not([mirror],[chrome]){display:none}}

ارتفاع نوار 58 px است. نمایش آینه‌ای نسبت ابعاد شبکه را تا عرض طبیعی آن (885 px برای 120 ستون) حفظ می‌کند، و chrome مقدار 43 px اضافه می‌کند. اندازه به فونت‌ها وابسته نیست. تابع reserveCss(cols, rows) از @textjs/app/experimental همین خط را برمی‌گرداند.

نمایش آینه‌ای در بخش قابل‌مشاهدهٔ اولیه معمولاً بزرگ‌ترین عنصر صفحه است، بنابراین بزرگ‌ترین ترسیم محتوایی صفحه (LCP) را تعیین می‌کند. اولین فریم آن پس از بارگذاری embed.js و سپس فایل عنصر، به‌ترتیب، رسم می‌شود. بقیهٔ صفحه همان‌طور رسم می‌شود که بدون برنامهٔ جاسازی‌شده رسم می‌شد. نمایش آینه‌ای پایین‌تر در صفحه بر LCP تأثیر نمی‌گذارد. در صفحه‌ای با اسکریپت‌های دارای اجرای با تأخیر، مانند برنامهٔ React، تگ <script type="module" async src="…"> فایل embed.js را بدون انتظار برای آن‌ها اجرا می‌کند، بنابراین نمایش آینه‌ای در بخش قابل‌مشاهدهٔ اولیه زودتر رسم می‌شود.

سبک‌دهی

برای وسط‌چین کردن نمایش آینه‌ای، حاشیه‌های درون‌خطی آن را روی auto تنظیم کنید:

text-console {  margin-inline: auto;}

به‌طور پیش‌فرض تیره است. برای رنگ‌های روشن، color-scheme: light را تنظیم کنید، یا دو رنگی را تعیین کنید که تمام طیف‌های دیگر از ترکیبشان ساخته می‌شوند. انتخابگر ::part(frame) به خود فریم سبک می‌دهد. ویژگی chrome پس‌زمینهٔ خود DevTools را حفظ می‌کند.

text-console {  --text-console-bg: #fafafa;  --text-console-fg: #171717;}text-console::part(frame) {  border-radius: 0;}

مسیرهای رندرشده در سمت سرور

وقتی initialPath مسیری با export const runtime = "server" باشد، فایل embed.js به‌جای محیط اجرای کلاینت، پخش‌کنندهٔ فریم را بارگذاری می‌کند. این پخش‌کننده فریم‌ها را از همان سروری که embed.js از آن آمده، به‌صورت جریانی دریافت می‌کند، بنابراین دستور text start یا آداپتور bun را اجرا کنید. آداپتورهای دیگر باعث شکست ساخت می‌شوند. رندر سمت سرور را ببینید.

صفحه‌ای در سایت دیگر فقط زمانی می‌تواند نشست زنده باز کند که مبدأ آن در allowOrigins باشد:

text.config.tsts
import { defineConfig } from "@textjs/app";export default defineConfig({  embed: {    initialPath: "/status",    allowOrigins: ["https://www.example.com", "https://*.example.com"],  },});
  • نشست فقط به مبدأیی پاسخ می‌دهد که آن را باز کرده است.
  • به‌طور پیش‌فرض، Text.js کوکی‌ها و سرآیند Authorization نشست‌های سایت‌های دیگر را حذف می‌کند، بنابراین middleware بازدیدکننده‌ای واردنشده می‌بیند. تنظیم credentials: true آن‌ها را نگه می‌دارد و به مبدأهای دقیق نیاز دارد. مرورگر زمانی آن‌ها را می‌فرستد که صفحه و سرور دامنهٔ قابل‌ثبت مشترکی داشته باشند (www.example.com و console.example.com) و کوکی سرور را پوشش دهد (Domain=example.com، یا روی console.example.com تنظیم شده باشد). از سایت‌های دیگر فقط کوکی‌هایی را می‌فرستد که با SameSite=None; Secure تنظیم شده‌اند، و مرورگرهایی که کوکی‌های شخص ثالث را مسدود می‌کنند هیچ‌کدام را نمی‌فرستند.
  • نشست زنده به‌محض اتصال، و هنگام اتصال مجدد، درخواست‌های پیش‌بررسی OPTIONS را به /__textjs/live می‌فرستد. پیش‌بررسی‌ها کوکی یا Authorization ندارند، بنابراین middleware منطبق با آن مسیر باید درخواست‌های OPTIONS را بدون ورود به حساب عبور دهد.
  • پشت پراکسی معکوس یا CDN، گزینهٔ server.trustProxy را تنظیم کنید (پشت پراکسی را ببینید). بدون آن، نشانی هر بازدیدکننده همان نشانی پراکسی است، بنابراین همهٔ آن‌ها یک سقف نشست به‌ازای هر کلاینت را به اشتراک می‌گذارند.

دستور text dev صفحات روی localhost، 127.0.0.1 و [::1] را در هر پورتی بدون allowOrigins می‌پذیرد، مگر اینکه credentials تنظیم شده باشد.

میزبانی

دستور text start و آداپتورهای bun، vercel و cloudflare خروجی ساخت جاسازی‌شده را با این سرآیندها ارائه می‌کنند. آداپتور static آن‌ها را در _headers می‌نویسد که ⁦Cloudflare Pages⁩ و Netlify آن را می‌خوانند. در هر میزبان دیگر، مانند باکت ذخیره‌سازی یا پوشهٔ public/ خود سایت، آن‌ها را خودتان تنظیم کنید:

مسیرسرآیندها
/embed.jsCache-Control: public, max-age=0, must-revalidate
/assets/*Cache-Control: public, max-age=31536000, immutable
هر دو، وقتی سایت روی مبدأ دیگری استAccess-Control-Allow-Origin: * و Cross-Origin-Resource-Policy: cross-origin

مرورگرها اسکریپت‌های ماژول و WebAssembly را با CORS دریافت می‌کنند، بنابراین فایل‌های روی مبدأ دیگر به Access-Control-Allow-Origin نیاز دارند. فایل yoga-[hash].wasm را به‌صورت فشرده با نوع application/wasm ارائه کنید (WebAssembly را ببینید).

استقرارها

اعتبار embed.js در هر بار بارگذاری صفحه دوباره بررسی می‌شود، بنابراین بازدیدکنندگان جدید بلافاصله استقرار جدید را دریافت می‌کنند. تبی که نسخهٔ قبلی embed.js را بارگذاری کرده است، هنگام باز کردن کنسول از سوی بازدیدکننده، حتی اگر چند ساعت بعد باشد، همچنان فایل‌های بیلد قبلی را وارد می‌کند. دایرکتوری assets/ استقرار قبلی را آنلاین نگه دارید: به‌جای همگام‌سازی همراه با حذف، فایل‌های جدید را روی فایل‌های قدیمی کپی کنید و فایل‌های قدیمی را پس از یک یا دو روز حذف کنید. برای ثابت نگه داشتن یک بیلد، فایل assets/embed-[hash].js آن را در تگ قرار دهید. فایل‌های آن بیلد هم باید آنلاین بمانند.

وقتی فایل‌ها دیگر موجود نباشند، embed.js یک هشدار ثبت می‌کند که از بازدیدکننده می‌خواهد صفحه را دوباره بارگذاری کند، و خودش برنامه را اجرا یا صفحه را دوباره بارگذاری نمی‌کند.

خط‌مشی امنیت محتوا

embed.js به اسکریپت یا سبک درون‌خطی نیاز ندارد. این موارد را به خط‌مشی صفحهٔ میزبان اضافه کنید و وقتی dist/ روی همان مبدأ است، به‌جای مبدأ از 'self' استفاده کنید:

دستورالعملمقدارکاربرد
script-srchttps://console.example.comembed.js و قطعه‌های آن
script-src'wasm-unsafe-eval'Yoga، در برنامه‌های رندرشده در سمت کلاینت
connect-srchttps://console.example.comyoga-[hash].wasm و /__textjs/live برای مسیرهای رندرشده در سمت سرور
img-srcdata:فقط یک <text-console mirror> که برنامهٔ آن <Image> یا <Pixels> را ترسیم می‌کند

بارگذاری برنامه به روش خودتان

@textjs/app/experimental بخش‌هایی را که embed.js از آن‌ها ساخته شده است، برای صفحه‌هایی که برنامه را به روش خودشان بارگذاری می‌کنند صادر می‌کند:

خروجیتوضیحات
startEmbed(paint, boot, src, element?)کاری که embed.js اجرا می‌کند: ثبت اولین فریم، انتظار برای قصد استفاده از کنسول، سپس فراخوانی boot
bootEmbedClient(options)راه‌اندازی یک برنامهٔ رندرشده در سمت کلاینت با مسیریابی درون‌حافظه‌ای و ورودی صفحه‌کلید مشروط برای صفحه
bootEmbedPlayer(options)راه‌اندازی پخش‌کنندهٔ فریم برای یک مسیر رندرشده در سمت سرور
createHostInput(options)ورودی صفحه‌کلید مطابق با قواعد بالا
createTextConsoleMount(config)برگرداندن تابع mount(element, shell?) برای <text-console>
reserveCss(cols, rows)CSS رزروکنندهٔ فضای <text-console>

ENGAGE_SELECTOR و BYPASS_SELECTOR انتخابگرهای عناصری هستند که برنامه را راه‌اندازی می‌کنند و عناصری که کلیدهای خود را نگه می‌دارند.

ویرایش این صفحه در GitHub