JS-модули
Скопировать ссылку на статью
Скопировано

JS-модули позволяют расширить возможности интерфейса системы.

Архитектура JS-модуля

JS-модули является расширенной версией стандартных модулей Маркетплейса. Отличием является то, что они состоят из двух частей: backend-часть и frontend-часть.

Backend-часть JS-модуля

Backend-часть JS-модуля разрабатывается также, как и у стандартных модулей. В ее подготовке вам помогут статьи про основные требования к модулям, подключение и активацию модуля и добавление модуля в Маркетплейс.

Backend-часть модуля должна как минимум содержать логику по подключению и активации модуля в Маркетплейсе. Если frontend-часть модуля будет обращаться к backend-части, то последняя помимо базовой логики должна также предоставлять ендпоинты для обработки запросов, отправляемых из frontend-части.

Важно!

После того, как вы подготовили backend-часть модуля, заведите его в разделе «Модули» партнерского кабинета. Далее обратитесь в партнерский отдел, чтобы для вашего модуля активировали JS-функциональность.

Frontend-часть JS-модуля

Frontend-часть JS-модуля должна представлять собой приложение, написанное на Javascript и Vue 3. Приложение будет выполняться в изолированной среде iframe. Выполнение приложения производится с помощью библиотеки удаленного рендеринга @omnicajs/vue-remote. Связь между приложением и основным интерфейсом системы (далее «хостом») осуществляется через postMessage.

JS-приложение содержит ограничения на используемый функционал Vue и JS, о чем описано подробнее ниже.

Ограничения

1. Ограничения на значения атрибутов элементов в шаблонах Vue-компонентов

Элементам можно присваивать атрибуты, например:

<div
    :class="someClass"
    :style="someStyle"
    :data-value="someValue"
/>

В примере выше атрибуты — это class, style и data-value. Нужно помнить, что в эти атрибуты можно передавать только простые стандартные данные: string, number, boolean, null, undefined. Также могут быть переданы массивы простых данных, объекты ключ-значение, в которых значения — простые данные, либо комбинации перечисленных типов. Любые другие данные, переданные как атрибуты, приведут к сбою работы виджета.

Например, нельзя передать экземпляр такого класса:

class MyClass {
  toString() {
    return somethingThatIsString
  }
}

и ожидать, что произойдет автоматическая конвертация. Вместо этого произойдет сбой.

Также на данный момент не поддерживается атрибут ref из Vue на элементах:

<div ref="myRef" />

2. Выполнение HTTP-запросов

В JS-приложении можно выполнять HTTP-запросы только через JS API. Запросы буду направляться к backend-части модуля.

Важно!

На данный момент данная функциональность в разработке. Описание, как выполнять HTTP-запросы, появится с выходом функциональности.

Другие способы выполнения HTTP-запросов использовать запрещено, они не будут работать.

Точки встраивания (targets) и доступные в них данные

Приложение может встраиваться в определенные точки интерфейса (в коде они называются targets) и оперировать доступными в этих точках данными.

При подготовке JS-приложения вам нужно определиться с перечнем точек встраивания.

В разных точках доступен разный набор данных. Данные реактивные, то есть изменения применяются ко входным объектам при их изменении в интерфейсе (в частности в формах, например, форме заказа, форме клиента и т.п). Некоторые поля мутабельные, то есть их можно изменять в JS-приложении и эти изменения применятся к форме. Такие поля в справочнике отмечены как readonly: false.

Для получения объекта из контекста и полей из объекта, используйте функции из @retailcrm/embed-ui/index.d.ts, например:

import {
    useOrderCardContext,
    useSettingsContext,
    useField,
} from '@retailcrm/embed-ui'

const order = useOrderCardContext()
const address = useField(order, 'delivery.address')

const settings = useSettingsContext()
const locale = useField(settings, 'system.locale')

Перечень точек встраивания

Доступные Vue-компоненты

Ряд Vue-компонентов, на которых строится интерфейс системы, доступен для JS-модулей. Вы можете использовать их для создания интерфейса JS-модуля.

Перечень Vue-компонентов

Разработка JS-приложения

В приложении нужно объявить используемые компоненты из библиотеки интерфейса системы, например:

// src/components/index.ts

const UiButton = defineRemoteComponent('UiButton')
const UiModalWindow = defineRemoteComponent('UiModalWindow', [
    'update:opened',
] as unknown as {
    'update:opened': (opened: boolean) => void,
}, [
    'title',
    'footer',
])

const CrmYandexMap = defineRemoteComponent('CrmYandexMap', [
    'change',
] as unknown as {
    'change': (address: string) => void,
})

export {
    UiButton,
    UiModalWindow,
    CrmYandexMap,
}

Далее написать Vue-компонент(-ы) вашего JS-приложения. Например:

// src/extensions/VExtension.vue

<template>
    <UiButton appearance="secondary" class="mt-4" @click="opened = true">
        На карте
    </UiButton>

    <UiModalWindow v-model:opened="opened" :class="$style['window']">
        <template #title>
            Адрес
        </template>

        <CrmYandexMap 
            :api-key="'dd51f938-0693-457d-ae62-6d50fa668d0a'"
            :address="address || ''"
            @change="address = $event"
        />

        <template #footer>
            <UiButton appearance="secondary" @click="opened = false">
                Закрыть
            </UiButton>
        </template>
    </UiModalWindow>
</template>

<script lang="ts" setup>
import {
    UiButton,
    UiModalWindow,
    CrmYandexMap,
} from '@/components'

import { onMounted, ref } from 'vue'

import {
    useOrderCardContext,
    useField,
} from '@retailcrm/embed-ui'

const order = useOrderCardContext()

const opened = ref(false)
const address = useField(order, 'delivery.address')

onMounted(() => order.initialize())
</script>

<style lang="less" module>
.window :global(.omnica-modal-window__content) {
    padding: 0;
}
</style>

И инициализировать приложение в точках встранивания. Например:

// src/extension.js

import { createWidgetEndpoint } from '@retailcrm/embed-ui'
import { fromInsideIframe } from '@remote-ui/rpc'

import VExtension from '@/extension/VExtension.vue'

createWidgetEndpoint({
    async run (createApp, root, pinia, target) {
        const app = createApp(VExtension, { target })

        app.use(pinia)
        app.mount(root)

        return () => app.unmount()
    },
}, fromInsideIframe())

Более подробно можно посмотреть в документации @omnicajs/vue-remote и @retailcrm/embed-ui.

Примеры расширений вы можете посмотреть в @retailcrm/core-ui-extensions-examples.

Встраивание в интерфейс системы

Сборка JS-приложения

Вам требуется выполнить сборку приложения средствами webpack, vite и т.п. В @retailcrm/core-ui-extensions-examples сборка производится командой yarn build. В папке сборки должен появиться набор из index.html, css-файла и js-файла.

После этого требуется создать в папке сборки файл manifest.json

Структура manifest.json

Файл manifest.json содержит метаданные для JS-приложения. В @retailcrm/core-ui-extensions-examples файл создается автоматически при выполнении команды make zip-archive. Пример содержимого файла manifest.json:

{
  "code": "core-ui-extensions",
  "version": 154,
  "targets": ["order/card:delivery.address"],
  "entrypoint": "index.html",
  "scripts": ["extension.xxx.js"],
  "stylesheet": "extension.xxx.css"
}

Где:

  • code: string — уникальный код приложения. Обязательный параметр
  • version: number — версия приложения. Значение должно быть целым числом и больше 0. Обязательный параметр
  • targets: string[] — точки встраивания приложения. Обязательный параметр
  • entrypoint: string — HTML-файл, который является точкой входа для приложения. Обязательный параметр
  • scripts: string[] — JS-файлы приложения. Обязательный параметр
  • stylesheet: ?string — CSS-файл приложения. Необязательный параметр

Встраивание JS-приложения в интерфейс в ходе разработки

В ходе разработки для целей отладки вы можете встраивать JS-приложение на тех страницах, на которых находятся точки встраивания (targets) приложения.

Для этого запустите сервер, который будет отдавать файлы вашего приложения на базе nodejs, nginx или другого веб-сервера. В @retailcrm/core-ui-extensions-examples есть пример сервера в файле server.mjs. Вы можете его запустить командой node server.mjs.

После этого на нужной странице системе достаточно вызвать window['CRM'].embed.register(). Например:

window['CRM'].embed.register({
  "uuid": "62aa8145-ed53-4862-b28f-f1bc6b36a3a3",
  "targets": [
    "order/card:delivery.address"
  ],
  "entrypoint": "http://localhost:3000/extension/62aa8145-ed53-4862-b28f-f1bc6b36a3a3",
  "stylesheet": "http://localhost:3000/extension/62aa8145-ed53-4862-b28f-f1bc6b36a3a3/stylesheet"
})

Значение uuid может быть произвольным.

Публикация frontend-части

Публикация в маркетплейсе

Как было описано в начале статьи, модуль заводится в маркетплейсе, как и любой другой модуль, и через партнерский отдел в нем требуется активировать JS-функциональность.

После этого в карточке модуля будет доступна форма «JS-файл» для загрузки архива JS-части модуля. В @retailcrm/core-ui-extensions-examples есть команда make zip-archive, где можно посмотреть, как создать архив с модулем.

Архив загружается через форму. Если модуль опубликован в Маркетплейсе, то загруженная версия начнет инициализироваться в интерфейсе аккаунтов системы, где включен модуль.

При изменении исходного кода модуля (добавлении новых функций или исправлении ошибок) вам требуется его собрать, создать архив с новым кодом и загрузить через форму. Новая версия будет практически сразу доступна в аккаунтах, где включен модуль (возможны задержки до 10 мин).

Регистрация JS-модуля в отдельно-взятом аккаунте

Если вы разрабатываете кастомизированный JS-модуль для определенного аккаунта системы, вы можете зарегистрировать его с помощью API-метода POST /api/v5/integration-modules/{code}/edit, указав следующие данные:

  • integrationModule[baseUrl] — базовый адрес сервера модуля
  • integrationModule[integrations][embedJs][entrypoint] — относительный путь к js-скрипту
  • integrationModule[integrations][embedJs][stylesheet] — относительный путь в css-стилям
  • integrationModule[integrations][embedJs][targets] — массив точек встраивания

Если вызов метода был успешный, то на страницах целевого аккаунта, на которых находятся указанные точки встраивания, будет инициализироваться JS-часть вашего модуля.

Благодарим за отзыв.
Была ли статья полезна?
Нет
  • Рекомендации не помогли
  • Нет ответа на мой вопрос
  • Текст трудно понять
  • Не нравится описанный функционал
Да
Предыдущая статья
Работа с ценами на модуль
В Маркетплейс можно размещать как бесплатные, так и платные модули.
Следующая статья
Точки встраивания JS-модулей
Точки интерфейса, куда могут встроиться JS-модули, а также доступные в этих точках объекты