Некоторые технологии просто должны были быть вместе - HTML и CSS, узловые и одностраничные приложения, и, конечно же, Angular и Salesforce. Какие? Вы никогда не думали об использовании структуры одностраничного приложения в качестве интерфейса для вашей системы управления взаимоотношениями с клиентами? Что ж, позвольте мне познакомить вас с настройками, инструментами и трюками, которые позволят вашему приложению Angular работать на странице Salesforce VisualForce.

Предпосылки

В этом руководстве предполагается, что вы хотите создать приложение Angular (версии 2.0 или новее) и у вас есть организация Salesforce (версия 39.0 или новее) для его развертывания. Кроме того, он предполагает базовые знания в области разработки Angular 2+ и Salesforce.

Шаг 1. Общение в Salesforce

Прежде чем мы сможем сделать что-нибудь действительно интересное, нам нужно запустить наше приложение Angular «в» Salesforce. На практике это означает, что мы собираемся создать страницу VisualForce, но вместо того, чтобы заполнять ее компонентами VisualForce, мы будем использовать ее для загрузки нашего приложения Angular. Эта часть занимает больше всего времени на настройку, но как только у нас появятся основы, будет легко добавить такие функции, как статические ресурсы, маршрутизация по глубоким ссылкам и, конечно же, доступ к вашим данным Salesforce!

Предположим, у вас уже есть проект Angular CLI, который компилирует (для этого достаточно использовать команду ng new) Сначала нам нужно взять один из выходных данных нашего Angular build: файл index.html и переведите его на страницу VisualForce. Это означает, что нужно исходить из этого:

К этому:

Вы заметите несколько ключевых отличий:

  • Теги html заменяются тегами apex: page.
  • Инструкция предварительной обработки doctype удалена.
  • Теги, для которых обычно не нужен закрывающий тег, например base, meta и link, теперь требуют закрывающего тега.
  • Ссылки на статические файлы, включая Javascript, css и даже файлы значков, используют странный синтаксис.

Первые три - это просто требования к определению страницы VisualForce. Последний пункт касается того, как Salesforce представляет ссылки на статические ресурсы. В рамках нашего развертывания мы собираемся объединить выходные данные сборки Angular в Salesforce Статический ресурс. Доступ к статическим ресурсам на странице VisualForce осуществляется с помощью макроса:

{! URLFOR ($ Resource. [Название пакета], ‘[путь к файлу в пакете]’)}

Когда Salesforce обслуживает страницу VisualForce, он разрешает все ссылки в указанном выше стиле на вашей странице, так что к тому времени, когда он попадет в ваш браузер, макрос был заменен действительным URL-адресом. Важно отметить, что эта замена выполняется только на странице VisualForce, а не в каком-либо загруженном ею Javascript.

Нам придется выполнять это преобразование каждый раз, когда мы изменяем наше приложение Angular, так что давайте автоматизируем его! Я написал для этого скрипт на Python, но вы можете использовать любой инструмент по вашему выбору:

Здесь у меня есть аргумент сценария, который позволяет мне указать имя пакета статических ресурсов. Поэтому вызов этого сценария из корня каталога моего проекта Angular после запуска «ng build» приведет к созданию необходимой страницы VisualForce:

Шаг 2. «Здравствуйте, Salesforce-gular»

Теперь, когда мы, по крайней мере, понимаем, как должна выглядеть страница VisualForce под управлением Angular, давайте развернем ее! Для этого мы собираемся использовать инструмент Force.com Migration, который представляет собой инструмент на основе ANT для передачи и извлечения артефактов Salesforce в организацию. Поэтому, если вы еще этого не сделали, загрузите и установите Apache ANT и получите файл jar ANT Salesforce (https://developer.salesforce.com/docs/atlas.en-us.daas.meta/daas/forcemigrationtool_install.htm )

Давайте устроимся более организованно. Создайте подкаталог внутри вашего проекта Angular и заполните его следующим образом:

src-dev-deploy - это то место, где мы настроим наш «проект Salesforce» в макете, понятном инструменту миграции Force.com. ant-salesforce.jar взят из инструмента миграции Force.com.

package.xml - это метаданные для нашего проекта, который выглядит так:

dev.sf содержит учетные данные вашей организации Salesforce, и не следует добавлять в Git. Не забудьте добавить dev.sf в ваш .gitignore!

build.xml - это сценарий ANT, который использует наш проект Salesforce и развертывает его в организации:

Все, что осталось сделать, это заполнить проект Salesforce, используя выходные данные нашей сборки Angular. Мы уже сделали половину этого в visualforce_transform.py. В завершение добавим еще пару вещей:

  • Примите имя для страницы VisualForce, на которую мы будем выполнять развертывание.
  • Подтвердите каталог, в котором развернут проект.
  • Создайте файл шаблона метаданных рядом с созданной страницей VisualForce.
  • Заархивируйте сборку Angular и создайте пакет статических ресурсов для развертывания.

Теперь мы, наконец, готовы к упаковке и развертыванию в нашей организации Salesforce! Выполнение следующих команд из корня вашего проекта Angular сделает ваше приложение доступным по адресу: [URL вашей организации] / apex / sftestpage

Шаг 3. Кому нужен бэкэнд? У меня есть Salesforce!

Ничего из этого не было бы очень полезно, если бы мы фактически не могли представить или взаимодействовать с какими-либо данными в нашей CRM, верно? Чтобы создать мост между Angular и миром Salesforce APEX, мы собираемся использовать нечто, называемое контроллером VisualForce. Контроллер - это просто класс APEX, который предоставляет методы, которые может вызывать страница VisualForce. Использование контроллера дает два преимущества:

  • Вызовы к контроллеру APEX не засчитываются в лимиты вызовов REST для вашей организации.
  • Salesforce автоматически создает оболочку Javascript для каждого метода контроллера!

Для начала перейдите в консоль разработчика Salesforce и создайте новый класс с именем «sftestcontroller». Скопируйте и вставьте следующий код и сохраните файл:

Теперь нам нужно обновить наше приложение Angular, чтобы оно получило ссылку на оболочку контроллера, предоставленную Salesforce:

Нам также необходимо обновить скрипт visualforce_transform, чтобы ввести правильное имя контроллера вместо переменной $ SFCONTROLLER. Это позволяет отделить код Angular от любых изменений именования, происходящих в Salesforce:

Теперь мы можем добавить интерфейс TypeScript, который отражает то, как мы вызываем метод контроллера, и вызывать наш первый метод контроллера в компоненте Angular!

Помните, что для просмотра изменений на своей странице вам придется снова запустить ng build и команду ant deploy. Уже надоел этот рабочий процесс? Продолжайте читать, шаг 6 направлен на то, чтобы сделать вашу итерацию намного проще😀

В качестве побочного примечания, в репозитории GitHub, ссылка на который приведена в конце этого сообщения, я показываю один способ обернуть вызовы контроллера в Observables, которые, как правило, лучше работают с Angular по сравнению с использованием обратных вызовов.

Шаг 4. Почему я не вижу гифки с кошками?

Вы, наверное, заметили, что изображения, которые вы пытаетесь показать с помощью тегов ‹img› с такими путями, как «assets / awesome_cat.gif», не отображаются. Напомним, что ко всем статическим ресурсам сборки Angular необходимо обращаться по полностью определенному URL-адресу, который создается с помощью макроса URLFOR. Хорошо, мы просто изменим все наши теги ‹img›, чтобы они выглядели так, верно?

‹Img src =” {! URLFOR ($ Resource.sftestassets, ‘assets / awesome_cat.gif’)} ”›

К сожалению, это не работает. Причина в том, что Salesforce обрабатывает этот макрос только на самой странице VisualForce, а не в загружаемом Javascript, откуда берутся все наши шаблоны Angular HTML. К счастью, эту логику довольно просто воспроизвести. Нам просто нужно получить базовый URL-адрес для нашего пакета ресурсов с помощью макроса где-нибудь в нашем index.html (который переводится на страницу VisualForce) и назначить его глобальной переменной. На этом этапе легко создать канал Angular, который добавляет эту глобальную переменную в начало любых путей к ресурсам.

Во-первых, модификация index.html:

Затем небольшое изменение в visualforce_transform.py:

Наконец, канал Angular и пример его использования:

Следует отметить, что пути к изображениям в CSS (например, в свойстве background) обновлять не нужно. Это связано с тем, что браузер ищет файлы, на которые есть ссылки в CSS, относительно того места, откуда таблица стилей была загружена из ,, а не того места, откуда был загружен документ HTML.

Шаг 5: Нам нужно углубиться.

Проницательные наблюдатели, возможно, уже заметили, что, когда они перемещаются по страницам Angular, URL-адрес в строке браузера затирает базу URL-адреса страницы VisualForce (/ apex / sftestpage). Если вы попытаетесь скопировать и вставить один из этих URL-адресов, вы просто получите большую уродливую страницу «URL больше не существует» от Salesforce. Это не идеальный вариант для веб-приложения. Итак, как мы поддерживаем Angular d eep ссылки в Salesforce?

  • Необходимо переключиться с маршрутизации push-состояний HTML (по умолчанию для Angular 2+) обратно на маршрутизацию на основе хешей. Это связано с тем, что Salesforce не знает, что наш гибрид Angular / VisualForce обрабатывает любую маршрутизацию за пределами URL-адреса развертывания. Таким образом, единственный способ заставить Salesforce игнорировать угловую часть маршрута и передать ее нам - это использовать URL-адрес на основе хэша, например apex / sftestpage # path / to / my / angular / route.
  • При попытке получить доступ к URL-адресу Salesforce, который содержит маршрут Angular после хэша, и пользователь не вошел в систему, Salesforce запомнит запрошенный URL-адрес (включая сегмент хеш-кода) и переадресует это место после входа в систему, что именно то, что вы бы сделали. хотите от системы с глубокими ссылками.

HashLocationStrategy, включенная в Angular, на самом деле не создает действительные URL-адреса для использования с глубокими ссылками Salesforce. Причина в том, что перед хешем добавляется завершающая косая черта, которую Salesforce не принимает. Нам нужно использовать модифицированную версию, которая исправляет это и добавляет сегменты вершины и имени страницы:

Нам снова нужно изменить index.html и visualforce_transform.py, чтобы сделать эту корневую переменную страницы доступной:

Не забудьте заменить встроенную стратегию определения местоположения, добавив блок {предоставляет:} в свой основной модуль!

Обратите внимание, что ленивая загрузка маршрутов невозможна при развертывании Angular / Salesforce. Это связано с тем, что аргумент «deployUrl» для «ng build» должен быть указан во время компиляции, и мы не знаем URL развертывания для статических ресурсов до тех пор, пока приложение не будет развернуто. Следовательно, Angular попытается загрузить файлы Javascript фрагментов относительно файла index.html и потерпит неудачу.

Шаг 6: «Но я скучаю по серверу…» - Улучшение рабочего процесса разработчика

Итак, у вас есть приложение Angular, работающее в Salesforce, с доступом ко всем возможностям платформы, а также ко всем интерфейсным функциям, которые у вас обычно есть (с некоторыми компромиссами). Есть одно вопиющее исключение: команда ng serve для экономии времени больше не работает. Это, конечно, связано как с необходимостью преобразования индексного файла, так и с его развертыванием с новым пакетом статических ресурсов каждый раз, когда наше приложение изменяется. Нам нужно определить новый идеальный (или максимально приближенный) рабочий процесс:

  • Изменяются файлы, которые являются частью проекта Angular.
  • Angular проект автоматически перестраивается.
  • Затем файл index.html автоматически преобразуется, и сборка Angular упаковывается.
  • Наконец, автоматически запускается инструмент миграции force.com для развертывания новой версии страницы и статических ресурсов.

Как мы можем этого добиться? Первые два шага просты, все, что нам нужно, это отдельный терминал, на котором запущена ng build с флагом --watch. Как и в случае с ng serve, содержимое папки / dist будет повторно заполняться каждый раз при изменении исходного файла. Чтобы организовать последние два шага, мы будем использовать старого друга фронтенд-разработчика по имени Gulp.

В следующем фрагменте показан сценарий Gulp, который при запуске будет следить за каталогом / dist на предмет изменений, и при обнаружении этих изменений он сначала вызовет наш сценарий visualforce_transform, а в случае успеха запустит задачу ant, необходимую для развертывания в Salesforce:

Добавьте следующие пакеты к своим зависимостям package.json dev и запустите npm install:

Чтобы запустить этот параллельный процесс, просто запустите команду gulp из корня проекта. Это приводит к объединенному времени около 20–60 секунд (в зависимости от скорости загрузки в Salesforce) между тем, когда вы сохраняете исходный файл, и когда вы можете увидеть результаты в Salesforce. Это не подача, но это лучше, чем ничего!

Заключение, и готовый продукт

Использование Angular вместо компонентов VisualForce напрямую - отличный вариант для кросс-функциональных команд, у которых есть фронтенд-разработчики, не обязательно обладающие знаниями о разработке Salesforce, что позволяет экспертам Salesforce сосредоточиться на моделировании данных и коде APEX. Это также хороший вариант, если вы хотите, чтобы пользователи вашей организации Salesforce были полностью индивидуализированы.

Рабочую демонстрацию этой идеи можно найти по адресу https://github.com/arutnik/salesforce-angular-demo. Все, что нужно, чтобы опробовать его, - это ваша собственная организация разработчиков Salesforce.