Подключение Web SDK через CDN

Сначала запустите полный пример, затем скопируйте его на свою страницу. Он содержит зависимости, стили, языковые пакеты и регистрацию Facade для редактируемой таблицы с вычислением формул.

Попробуйте редактируемую таблицу

  1. Откройте пример или сохраните HTML ниже как index.html.
  2. Откройте его в современном браузере с доступом в Интернет. Сборщик и сервер не нужны. Интерфейс и данные примера — на русском языке.
  3. Сумма в строке «Блокнот» равна 36. Измените количество с 3 на 4 — сумма станет 48. Также можно редактировать ячейки и отменять изменения.
Скачать HTML

Полный пример HTML

Пример использует React 18.3.1 UMD. Глобальный объект React не предоставляет jsx и jsxs, ожидаемые UMD-сборками Univer. Две строки ниже добавляют эти точки входа через публичный API React.createElement. При установке через менеджер пакетов сборщик разрешает react/jsx-runtime; этот UMD-мост в такой конфигурации не нужен.

Ресурсы загружаются из jsDelivr в порядке зависимостей. При сбое пример повторяет запрос той же версии через unpkg и только затем продолжает загрузку. Если оба источника недоступны, запуск останавливается, а на странице отображается незагруженный ресурс.

HTML
<!doctype html><html lang="ru-RU">  <head>    <meta charset="UTF-8" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <title>Пример Univer Sheets через CDN</title>    <style>      html,      body,      #root,      #app {        padding: 0;        margin: 0;        height: 100%;      }    </style>  </head>  <body>    <div id="app"><p role="status" style="padding: 24px; font-family: system-ui">Загрузка Univer…</p></div>    <script>      const cdnBases = ['https://cdn.jsdelivr.net/npm/', 'https://unpkg.com/']      const app = document.getElementById('app')      async function loadResource(path, tag = 'script') {        for (const base of cdnBases) {          const element = document.createElement(tag)          const url = base + path          element.crossOrigin = 'anonymous'          if (tag === 'link') {            element.rel = 'stylesheet'            element.href = url          } else {            element.src = url          }          try {            await new Promise((resolve, reject) => {              element.onload = () => resolve()              element.onerror = () => reject(new Error(url))              document.head.appendChild(element)            })            return          } catch {            element.remove()          }        }        throw new Error(`Could not load ${path} from ${cdnBases.join(' or ')}`)      }      const styles = [        '@univerjs/design@1.4.0/lib/index.css',        '@univerjs/ui@1.4.0/lib/index.css',        '@univerjs/docs-ui@1.4.0/lib/index.css',        '@univerjs/sheets-ui@1.4.0/lib/index.css',        '@univerjs/sheets-formula-ui@1.4.0/lib/index.css',        '@univerjs/sheets-numfmt-ui@1.4.0/lib/index.css',      ]      const reactScripts = [        'react@18.3.1/umd/react.production.min.js',        'react-dom@18.3.1/umd/react-dom.production.min.js',      ]      const sdkScripts = [        'rxjs@7.8.2/dist/bundles/rxjs.umd.min.js',        '@wendellhu/redi@1.1.3/dist/umd/index.js',        '@wendellhu/redi@1.1.3/dist/umd/react-bindings/index.js',        '@univerjs/themes@1.4.0/lib/umd/index.js',        '@univerjs/protocol@1.4.0/lib/umd/index.js',        '@univerjs/core@1.4.0/lib/umd/index.js',        '@univerjs/network@1.4.0/lib/umd/index.js',        '@univerjs/rpc@1.4.0/lib/umd/index.js',        '@univerjs/design@1.4.0/lib/umd/index.js',        '@univerjs/engine-render@1.4.0/lib/umd/index.js',        '@univerjs/engine-formula@1.4.0/lib/umd/index.js',        '@univerjs/drawing@1.4.0/lib/umd/index.js',        '@univerjs/telemetry@1.4.0/lib/umd/index.js',        '@univerjs/ui@1.4.0/lib/umd/index.js',        '@univerjs/docs@1.4.0/lib/umd/index.js',        '@univerjs/docs-ui@1.4.0/lib/umd/index.js',        '@univerjs/sheets@1.4.0/lib/umd/index.js',        '@univerjs/sheets-ui@1.4.0/lib/umd/index.js',        '@univerjs/sheets-formula@1.4.0/lib/umd/index.js',        '@univerjs/sheets-formula-ui@1.4.0/lib/umd/index.js',        '@univerjs/sheets-numfmt@1.4.0/lib/umd/index.js',        '@univerjs/sheets-numfmt-ui@1.4.0/lib/umd/index.js',        '@univerjs/core@1.4.0/lib/umd/facade.js',        '@univerjs/engine-formula@1.4.0/lib/umd/facade.js',        '@univerjs/ui@1.4.0/lib/umd/facade.js',        '@univerjs/docs@1.4.0/lib/umd/facade.js',        '@univerjs/docs-ui@1.4.0/lib/umd/facade.js',        '@univerjs/sheets@1.4.0/lib/umd/facade.js',        '@univerjs/sheets-ui@1.4.0/lib/umd/facade.js',        '@univerjs/sheets-formula@1.4.0/lib/umd/facade.js',        '@univerjs/sheets-numfmt@1.4.0/lib/umd/facade.js',        '@univerjs/design@1.4.0/lib/umd/locale/ru-RU.js',        '@univerjs/ui@1.4.0/lib/umd/locale/ru-RU.js',        '@univerjs/sheets@1.4.0/lib/umd/locale/ru-RU.js',        '@univerjs/sheets-ui@1.4.0/lib/umd/locale/ru-RU.js',        '@univerjs/docs-ui@1.4.0/lib/umd/locale/ru-RU.js',        '@univerjs/sheets-formula-ui@1.4.0/lib/umd/locale/ru-RU.js',        '@univerjs/sheets-numfmt-ui@1.4.0/lib/umd/locale/ru-RU.js',      ]      // Fetch ahead in parallel; main() still executes scripts in dependency order.      for (const [as, paths] of [        ['style', styles],        ['script', [...reactScripts, ...sdkScripts]],      ]) {        for (const path of paths) {          const preload = document.createElement('link')          preload.rel = 'preload'          preload.as = as          preload.crossOrigin = 'anonymous'          preload.href = cdnBases[0] + path          preload.onerror = () => {            preload.onerror = null            preload.href = cdnBases[1] + path          }          document.head.appendChild(preload)        }      }      async function main() {        for (const path of styles) await loadResource(path, 'link')        for (const path of reactScripts) await loadResource(path)        // Bridge the React 18 UMD global to the JSX runtime expected by Univer UMD bundles.        React.jsx = (type, props, key) => React.createElement(type, key === undefined ? props : { ...props, key })        React.jsxs = React.jsx        for (const path of sdkScripts) await loadResource(path)        app.textContent = ''        const { Univer, LocaleType, mergeLocales, UniverInstanceType } = UniverCore        const { FUniver } = UniverCoreFacade        const { UniverRenderEnginePlugin } = UniverEngineRender        const { UniverFormulaEnginePlugin } = UniverEngineFormula        const { UniverUIPlugin } = UniverUi        const { UniverSheetsPlugin } = UniverSheets        const { UniverSheetsUIPlugin } = UniverSheetsUi        const { UniverDocsPlugin } = UniverDocs        const { UniverDocsUIPlugin } = UniverDocsUi        const { UniverSheetsFormulaPlugin } = UniverSheetsFormula        const { UniverSheetsFormulaUIPlugin } = UniverSheetsFormulaUi        const { UniverSheetsNumfmtPlugin } = UniverSheetsNumfmt        const { UniverSheetsNumfmtUIPlugin } = UniverSheetsNumfmtUi        const univer = new Univer({          locale: LocaleType.RU_RU,          locales: {            [LocaleType.RU_RU]: mergeLocales(              UniverDesignRuRU,              UniverUiRuRU,              UniverSheetsRuRU,              UniverSheetsUiRuRU,              UniverDocsUiRuRU,              UniverSheetsFormulaUiRuRU,              UniverSheetsNumfmtUiRuRU,            ),          },        })        univer.registerPlugin(UniverRenderEnginePlugin)        univer.registerPlugin(UniverFormulaEnginePlugin)        univer.registerPlugin(UniverUIPlugin, {          container: 'app',        })        univer.registerPlugin(UniverDocsPlugin)        univer.registerPlugin(UniverDocsUIPlugin)        univer.registerPlugin(UniverSheetsPlugin)        univer.registerPlugin(UniverSheetsUIPlugin)        univer.registerPlugin(UniverSheetsFormulaPlugin)        univer.registerPlugin(UniverSheetsFormulaUIPlugin)        univer.registerPlugin(UniverSheetsNumfmtPlugin)        univer.registerPlugin(UniverSheetsNumfmtUIPlugin)        univer.createUnit(UniverInstanceType.UNIVER_SHEET, {})        const univerAPI = FUniver.newAPI(univer)        window.univerAPI = univerAPI        univerAPI          .getActiveWorkbook()          .getActiveSheet()          .getRange('A1:D3')          .setValues([            ['Товар', 'Кол-во', 'Цена', 'Итого'],            ['Блокнот', 3, 12, '=B2*C2'],            ['Ручка', 5, 2, '=B3*C3'],          ])      }      main().catch((error) => {        console.error(error)        app.setAttribute('role', 'alert')        app.style.cssText =          'padding: 24px; box-sizing: border-box; white-space: pre-wrap; overflow-wrap: anywhere; font: 14px/1.5 system-ui'        app.textContent =          'Не удалось загрузить пример. Проверьте подключение и обновите страницу.' + '\n' + error.message      })    </script>  </body></html>

Правила именования

UMD-скрипты предоставляют экспорты модулей через глобальные объекты. Используйте эти имена для доступа к плагинам и Facade API в коде инициализации:

Пакет или точка входаГлобальное имя
@univerjs/coreUniverCore
@univerjs/docs-uiUniverDocsUi
@univerjs/core/facadeUniverCoreFacade
@univerjs/docs-ui/locale/ru-RUUniverDocsUiRuRU

Согласованные версии

В примере зафиксированы Univer 1.4.0, React и ReactDOM 18.3.1, RxJS 7.8.2. При обновлении меняйте все URL Univer одновременно, включая Facade, CSS и языки. Не загружайте вторую копию библиотек, уже включённых в сборку приложения.

Устранение неполадок

СимптомЧто проверить
ITelemetryServiceЗагрузите @univerjs/telemetry до зависящего от него @univerjs/sheets-ui. Сохраните полный список зависимостей.
FDocumentЗагрузите @univerjs/docs/facade перед @univerjs/docs-ui/facade: Sheets также использует текстовый движок Docs.
[redi], t is not a functionНачните с полного примера: одна копия каждой зависимости и согласованные версии. Проверьте неудачные запросы во вкладке Network.
Пустой редакторЗадайте высоту контейнера. Если сеть или CSP блокирует CDN, разместите зависимости у себя или используйте менеджер пакетов.

Для существующего приложения React или Vue рекомендуем установку через менеджер пакетов: он управляет зависимостями и избавляет от длинного списка скриптов.

Насколько полезно это руководство?

© 2026 DreamNum Co., Ltd.