دوسری سائٹس میں ایمبیڈ کرنا

ایک اسکرپٹ ٹیگ سے دوسری سائٹ میں ایپ شامل کریں: ⁦text build --embed⁩، <text-console>، سرور پر رینڈر شدہ روٹس اور ہوسٹنگ۔

text build --embed آپ کی ایپ کو اس طرح بلڈ کرتا ہے کہ دوسری سائٹ اسے ایک اسکرپٹ ٹیگ سے شامل کر سکے، مثلاً مارکیٹنگ صفحہ، دستاویزات کی سائٹ، WordPress یا Webflow صفحہ، یا ⁦React 18⁩ ایپ۔ DevTools کھولنے والے وزیٹرز کو آپ کی ایپ کونسول میں ملتی ہے۔ دوسرے وزیٹرز صرف embed.js ڈاؤن لوڈ کرتے ہیں (gzip کے ساتھ تقریباً 3 kB)، الا یہ کہ صفحے پر <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 نہیں جو سائٹ کی اپنی فائلوں کی جگہ لے سکے۔ سرور پر رینڈر شدہ روٹس، روٹ ہینڈلرز یا مڈل ویئر والی ایپ کو محض اسٹیٹک اپ لوڈ کے بجائے سرور درکار ہوتا ہے۔ vercel اور cloudflare اڈاپٹرز روٹ ہینڈلرز اور مڈل ویئر چلاتے ہیں، اور سرور پر رینڈر شدہ روٹس کو 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، text.config.ts فائل میں embed: true کے برابر ہے۔ ڈیفالٹس بدلنے کے لیے ایک آبجیکٹ پاس کریں:

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کوکیز اور Authorization ہٹانے کے بجائے allowOrigins سے آنے والی لائیو سیشن درخواستوں کے ساتھ اس سرور کے لیے براؤزر کریڈینشلز بھیجیں۔ عین اوریجنز درکار ہیں

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، یا Mac پر ⁦⌘⌥J⁩، I، C یا K)، یا جب وہ <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() کونسول کے اندر نیویگیٹ کرتے ہیں۔ کلائنٹ پر رینڈر شدہ ایپس میں مکمل URLs نئے ٹیب میں کھلتے ہیں۔
  • صفحے پر موجود Text.js ایپ کو ترجیح ملتی ہے۔ اس کے شروع ہونے پر چلتا ہوا ایمبیڈ ان ماؤنٹ ہو جاتا ہے، کیز پڑھنا بند کر دیتا ہے اور اپنا گلوبل ہٹا دیتا ہے۔ جب کوئی دوسری ایپ کونسول استعمال کر رہی ہو تو لوڈ ہونے والا ایمبیڈ ایک وارننگ لاگ کرتا ہے اور شروع نہیں ہوتا۔
  • ایمبیڈ اپنا ⁦React 19⁩ بنڈل کرتا ہے۔ اس میں react-dom یا بیئر امپورٹس نہیں ہوتے، اس لیے صفحے کا React ورژن، 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ایپ کے فریم دکھائیں
chromeDevTools ونڈو میں فریم دکھائیں
titleبار کا عنوان (ڈیفالٹ: text.config.ts میں title)
hintsدکھانے والی کیز، جیسے "← →:switch region, Enter:open" (ڈیفالٹ: text.config.ts میں hints)
actionپہلے کیا کرنا ہے، جو “یہاں کلک کریں اور …” کے طور پر دکھتا ہے (ڈیفالٹ: text.config.ts میں action، یا پہلا اشارہ دبائیں)

ٹچ اسکرینز پر مرر ایپ شروع کیے بغیر پہلا فریم دکھاتا ہے، اور بار چھپی رہتی ہے۔ ایلیمنٹ کا متن انگریزی میں ہے۔

اس کی جگہ محفوظ کرنا

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 ہے۔ مرر اپنی قدرتی چوڑائی تک (120 کالم پر 885 px) گرڈ کا تناسب برقرار رکھتا ہے، اور chrome مزید 43 px شامل کرتا ہے۔ سائز فونٹس پر منحصر نہیں ہے۔ @textjs/app/experimental کا reserveCss(cols, rows) یہی سطر لوٹاتا ہے۔

صفحے کے ابتدائی نظر آنے والے حصے میں مرر عموماً صفحے کا سب سے بڑا ایلیمنٹ ہوتا ہے، اس لیے یہ صفحے کا ⁦Largest Contentful Paint⁩ (LCP) مقرر کرتا ہے۔ اس کا پہلا فریم پہلے embed.js اور پھر ایلیمنٹ کی فائل لوڈ ہونے کے بعد بنتا ہے۔ باقی صفحہ اسی طرح پینٹ ہوتا ہے جیسے ایمبیڈ کے بغیر ہوتا۔ صفحے میں مزید نیچے موجود مرر LCP پر اثر نہیں ڈالتا۔ اپنی مؤخر اسکرپٹس والے صفحے، مثلاً React ایپ میں، <script type="module" async src="…"> ان کا انتظار کیے بغیر embed.js چلاتا ہے، اس لیے ابتدائی نظر آنے والے حصے میں مرر جلد بنتا ہے۔

اسٹائلنگ

مرر کو درمیان میں رکھنے کے لیے اسے آٹو اِن لائن مارجنز دیں:

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 ہیڈر ہٹا دیتا ہے، اس لیے مڈل ویئر کو سائن آؤٹ شدہ وزیٹر نظر آتا ہے۔ credentials: true انہیں برقرار رکھتا ہے، اور اسے عین اوریجنز درکار ہوتے ہیں۔ براؤزر انہیں تب بھیجتا ہے جب صفحے اور سرور کا رجسٹر ہونے والا ڈومین مشترک ہو (www.example.com اور console.example.com) اور کوکی سرور کا احاطہ کرتی ہو (Domain=example.com، یا console.example.com پر سیٹ ہو)۔ دوسری سائٹس سے یہ صرف SameSite=None; Secure کے ساتھ سیٹ کردہ کوکیز بھیجتا ہے، اور تھرڈ پارٹی کوکیز بلاک کرنے والے براؤزر کوئی کوکی نہیں بھیجتے۔
  • لائیو سیشن کنیکٹ ہوتے ہی، اور دوبارہ کنیکٹ ہونے پر، /__textjs/live کو OPTIONS پری فلائٹس بھیجتا ہے۔ پری فلائٹس میں کوکیز یا Authorization نہیں ہوتے، اس لیے اس پاتھ سے میچ کرنے والے مڈل ویئر کو سائن اِن کے بغیر 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)<text-console> کے لیے mount(element, shell?) فنکشن لوٹاتا ہے
reserveCss(cols, rows)وہ CSS جو <text-console> کی جگہ محفوظ رکھتی ہے

ENGAGE_SELECTOR اور BYPASS_SELECTOR ان ایلیمنٹس کے سلیکٹرز ہیں جو ایپ شروع کرتے ہیں اور ان ایلیمنٹس کے جو اپنی کیز اپنے پاس رکھتے ہیں۔

⁦GitHub⁩ پر اس صفحے میں ترمیم کریں