Externals
Externals adalah nilai yang disediakan aplikasi host Anda untuk DSL:
state, fungsi, dan komponen. Di dalam DSL semuanya diakses dengan
awalan $. Inilah cara sebuah halaman menjangkau dunia luar — pengguna yang
login, helper formatDate, atau komponen ikon dari design system Anda.
Daftarkan saat membuat runtime:
import { Nu } from '@nuforge/core';
import * as t from '@nuforge/types';
const nu = Nu.create({
externals: {
states: [
t.externalState({ name: 'user', init: { name: 'Ada', plan: 'Pro' } }),
],
functions: (nu) => [
t.externalFunc({ name: 'shout', func: (s) => String(s).toUpperCase() }),
],
components: [
t.externalComponent({
name: 'Badge',
render: Badge, // komponen React
props: [t.componentProp({ name: 'label' })],
}),
],
},
});
Memakai externals di DSL
| Jenis | Dideklarasikan | Dipakai di DSL |
|---|---|---|
| State | t.externalState({ name, init }) | $user, $user.name |
| Fungsi | t.externalFunc({ name, func }) | $shout($user.name) |
| Komponen | t.externalComponent({ name, render, props }) | <$Badge label={$user.plan} /> |
component App() {} => (
<div>
<h2>{$shout($user.name)}</h2>
<p>{"Paket saat ini:"} <$Badge label={$user.plan} /></p>
</div>
)
Tag komponen eksternal memakai awalan
$dan diresolusi ke komponen React yang Anda berikan sebagairender. Hanya prop yang Anda deklarasikan dipropsyang diteruskan.
State bersifat read-only bagi DSL
State eksternal di-deep-freeze, jadi ekspresi hanya bisa membaca-nya —
tidak pernah bisa mengubah state host. Mencoba menetapkan nilai ke external
(mis. $user.name = "x") ditolak oleh evaluator.
Hanya host yang dapat memperbarui state eksternal, dan melakukannya akan me-render ulang setiap view yang membacanya:
nu.externals.updateStateValue('user', { name: 'Grace', plan: 'Team' });
Inilah jembatan untuk mendorong data host secara live (auth, store, hasil query) ke halaman yang sedang berjalan: jaga state eksternal tetap sinkron dengan state aplikasi Anda, dan halaman bereaksi otomatis.
Fungsi eksternal
Fungsi eksternal adalah fungsi host biasa. Ia menerima argumen yang sudah dievaluasi dan nilai kembaliannya mengalir kembali ke ekspresi:
t.externalFunc({ name: 'formatPrice', func: (n) => `$${Number(n).toFixed(2)}` });
// DSL: <span>{$formatPrice(item.price)}</span>
Bentuk factory functions: (nu) => [...] memberi Anda instance Nu bila sebuah
fungsi perlu membaca atau mengubah dokumen.
Komponen eksternal
Komponen eksternal memungkinkan DSL me-render komponen React asli dari basis kode Anda — primitif design system, chart, apa pun. Frame meneruskan prop yang dideklarasikan (dan children) ke komponen Anda:
function Badge({ label }: { label?: string }) {
return <span className="badge">{label}</span>;
}
// didaftarkan dengan props: [t.componentProp({ name: 'label' })]
// DSL: <$Badge label={$user.plan} />
Lihat langsung (dengan kontrol host yang memperbarui $user) di
halaman Contoh.
Komponen eksternal berbasis hook
render sebuah komponen eksternal adalah komponen fungsi React biasa — ia bisa
memakai hook apa pun secara internal, persis seperti di mana pun di pohon React
lainnya. Tidak ada adapter khusus yang perlu diakali; efek scroll-linked reveal
yang dibangun di atas useScroll/useTransform dari motion didaftarkan
sebagai external dengan cara yang sama seperti Badge di atas:
import { motion, useScroll, useTransform } from 'motion/react';
import { useRef } from 'react';
function FadeInOnScroll({ children }: { children?: React.ReactNode }) {
const ref = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({ target: ref });
const opacity = useTransform(scrollYProgress, [0, 1], [0, 1]);
return <motion.div ref={ref} style={{ opacity }}>{children}</motion.div>;
}
// didaftarkan dengan props: [] — konten datang lewat children
// DSL: <$FadeInOnScroll><h2>{"Muncul saat discroll"}</h2></$FadeInOnScroll>
Catatan — kanvas editor yang di-render ke dalam
<iframe>.IframeCanvasmilik@nuforge/editormem-portal frame ke<iframe>terisolasi demi isolasi CSS. Sebuah React portal cuma memindahkan node DOM ke dalam iframe itu — JavaScript yang membangunnya tetap berjalan di realm halaman host. Hook apa pun yang membaca globalwindow/documentpolos (posisi scroll,matchMedia, defaultResizeObserver/IntersectionObserver) akan diam-diam mengamati halaman host, bukan iframe yang sebenarnya dilihat dan discroll pengguna. Resolve window/document asli kanvas denganuseCanvasWindow()(dari@nuforge/editor/@nuforge/editor/react), bukan global ambient — ia mengembalikan{ doc, window }milik iframe sendiri di dalamIframeCanvas, dan cukup fallback ke global ambient di tempat lain (mis. render<NuFrame/>langsung tanpa iframe):import { useCanvasWindow } from '@nuforge/editor/react'; import { useEffect, useRef } from 'react'; const { doc } = useCanvasWindow(); const container = useRef<HTMLElement | null>(null); useEffect(() => { container.current = doc?.scrollingElement as HTMLElement | null; }, [doc]); const { scrollYProgress } = useScroll({ target: ref, container });
Langkah berikutnya
- Runtime & Core API —
nu.change, history, frame. - Ekstensi — plug-in host dengan state-nya sendiri.
- Model Keamanan — alasan state host dibekukan.