docs/docs/en/runjs/context/import-async.md
Dynamically loads ESM modules or CSS by URL; use in all RunJS scenarios. For third-party ESM use ctx.importAsync(); for UMD/AMD use ctx.requireAsync(). Pass a .css URL to load and inject styles.
| Scenario | Description |
|---|---|
| JSBlock | Load Vue, ECharts, Tabulator, etc. for custom charts, tables, boards |
| JSField / JSItem / JSColumn | Load small ESM utils (e.g. dayjs plugins) for rendering |
| Event flow / action events | Load dependencies then run logic |
importAsync<T = any>(url: string): Promise<T>;
| Parameter | Type | Description |
|---|---|---|
url | string | ESM or CSS URL. Supports shorthand <package>@<version> or subpath <package>@<version>/<path> (e.g. [email protected], dayjs@1/plugin/relativeTime.js), resolved with configured CDN prefix; full URLs also supported. For .css URLs, loads and injects styles. For React-dependent libs add [email protected],[email protected] to share the same React instance. |
.css URL; it is injected into the page).[email protected] → https://esm.sh/[email protected].@dnd-kit/core, react-big-calendar) add [email protected],[email protected] to avoid Invalid hook call from multiple React instances.https://esm.sh)/+esm)ctx.importAsync().const Vue = await ctx.importAsync('[email protected]');
const relativeTime = await ctx.importAsync('dayjs@1/plugin/relativeTime.js');
const pkg = await ctx.importAsync('https://cdn.example.com/my-module.js');
await ctx.importAsync('https://cdn.example.com/theme.css');
const echarts = await ctx.importAsync('[email protected]');
const chartEl = document.createElement('div');
chartEl.style.width = '100%';
chartEl.style.height = '400px';
ctx.render(chartEl);
const chart = echarts.init(chartEl);
const option = {
title: { text: 'Sales Overview', left: 'center' },
tooltip: { trigger: 'axis' },
legend: { data: ['Sales', 'Profit'], top: '10%' },
xAxis: { type: 'category', data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] },
yAxis: { type: 'value' },
series: [
{ name: 'Sales', type: 'bar', data: [120, 200, 150, 80, 70, 110] },
{ name: 'Profit', type: 'line', data: [20, 40, 30, 15, 12, 25] },
],
};
chart.setOption(option);
window.addEventListener('resize', () => chart.resize());
chart.on('click', (params) => {
ctx.message.info(`Clicked ${params.seriesName} on ${params.name}, value: ${params.value}`);
});
await ctx.importAsync('[email protected]/dist/css/tabulator.min.css');
const { TabulatorFull } = await ctx.importAsync('[email protected]');
const tableEl = document.createElement('div');
ctx.render(tableEl);
const table = new TabulatorFull(tableEl, {
data: [
{ id: 1, name: 'Alice', age: 25, city: 'Beijing' },
{ id: 2, name: 'Bob', age: 30, city: 'Shanghai' },
{ id: 3, name: 'Charlie', age: 28, city: 'Guangzhou' },
],
columns: [
{ title: 'ID', field: 'id', width: 80 },
{ title: 'Name', field: 'name', width: 150 },
{ title: 'Age', field: 'age', width: 100 },
{ title: 'City', field: 'city', width: 150 },
],
layout: 'fitColumns',
pagination: true,
paginationSize: 10,
});
table.on('rowClick', (e, row) => {
const rowData = row.getData();
ctx.message.info(`Row clicked: ${rowData.name}`);
});
const { Calendar } = await ctx.importAsync('@fullcalendar/[email protected]');
const dayGridPlugin = await ctx.importAsync('@fullcalendar/[email protected]');
const calendarEl = document.createElement('div');
calendarEl.id = 'calendar';
ctx.render(calendarEl);
const calendar = new Calendar(calendarEl, {
plugins: [dayGridPlugin.default || dayGridPlugin],
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth',
},
});
calendar.render();
For React-based libs like @dnd-kit/core, use [email protected],[email protected] so the same React instance is used and hooks work:
const React = await ctx.importAsync('[email protected]');
const { createRoot } = await ctx.importAsync('[email protected]/client');
const core = await ctx.importAsync('@dnd-kit/[email protected][email protected],[email protected]');
// Use core (DndContext, useDraggable, useDroppable, etc.) with React
await ctx.importAsync('[email protected]/lib/css/react-big-calendar.css');
const React = await ctx.importAsync('[email protected]');
const { Calendar, dateFnsLocalizer } = await ctx.importAsync('[email protected][email protected],[email protected]');
const { format, parse, startOfWeek, getDay } = await ctx.importAsync('[email protected]');
const enUS = await ctx.importAsync('[email protected]/locale/en-US.js');
const localizer = dateFnsLocalizer({
format,
parse,
startOfWeek,
getDay,
locales: { 'en-US': enUS },
});
const events = [
{ title: 'All Day Event', start: new Date(2026, 0, 28), end: new Date(2026, 0, 28), allDay: true },
{ title: 'Meeting', start: new Date(2026, 0, 29, 10, 0), end: new Date(2026, 0, 29, 11, 0) },
];
ctx.render(
<Calendar
localizer={localizer}
events={events}
startAccessor="start"
endAccessor="end"
style={{ height: '80vh' }}
/>
);
ctx.importAsync() for better module semantics.[email protected],[email protected] (or the version your app uses) to avoid Invalid hook call.