К статье
Практический материал

Разработка и Конфигурация · 13 мин

Директивы компиляции 1С в обычных и управляемых формах

Как используются директивы компиляции 1С: #Если Сервер, Клиент, ТолстыйКлиент. Отличия обычных и управляемых форм, примеры кода и типичные ошибки.

Директивы компиляции в 1С — это инструкции препроцессору, которые определяют, какой фрагмент кода будет скомпилирован и выполнен в конкретном контексте: на сервере, на тонком клиенте, в веб-клиенте или в толстом клиенте. Они записываются в виде конструкций #Если ... Тогда ... #КонецЕсли и позволяют одному и тому же модулю работать в разных средах исполнения.

Потребность в таких директивах возникла вместе с управляемым приложением, где код формы может исполняться одновременно в двух контекстах — клиентском и серверном. В обычном приложении вся логика выполнялась на клиенте, поэтому директивы там играют вспомогательную роль, а в управляемых формах они становятся обязательным инструментом, особенно в общих модулях без признака «Клиент» или «Сервер».

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

Какие директивы компиляции существуют в 1С

Платформа поддерживает фиксированный набор директив, каждая из которых соответствует определённому контексту исполнения. Основные из них: Сервер, Клиент, ТонкийКлиент, ТолстыйКлиентОбычноеПриложение, ТолстыйКлиентУправляемоеПриложение, ВебКлиент, ВнешнееСоединение, МобильныйКлиент, МобильноеПриложениеКлиент, МобильноеПриложениеСервер. Также доступны логические операторы И, ИЛИ, НЕ для составных условий.

Типовая конструкция выглядит так:

#Если Сервер Тогда

// код, выполняемый только на сервере

#ИначеЕсли ТонкийКлиент Тогда

// код для тонкого клиента

#Иначе

// код для остальных контекстов

#КонецЕсли

Важно понимать, что директива работает на этапе компиляции модуля: платформа физически исключает неподходящие ветки из исполняемого кода. Это отличает её от обычного условия Если, которое проверяется во время выполнения и требует, чтобы весь код был синтаксически корректен в текущем контексте.

Директивы в обычных формах: зачем они нужны и когда избыточны

В обычном приложении код формы исполняется целиком на стороне толстого клиента. Здесь нет разделения на клиентский и серверный контексты внутри формы, поэтому директивы компиляции в модуле обычной формы практически не нужны: любая ветка #Если ТолстыйКлиентОбычноеПриложение будет истинной всегда, а ветки для сервера — всегда ложными.

Тем не менее директивы встречаются в конфигурациях с обычными формами в двух случаях. Первый — общие модули, которые должны одинаково работать и в обычном, и в управляемом режиме (например, при постепенном переходе конфигурации на управляемое приложение). Второй — код, который использует объекты, недоступные на сервере или в веб-клиенте, например работу с файловой системой через диалоги.

Типичный пример для общего модуля, используемого в обоих режимах:

#Если ТолстыйКлиентОбычноеПриложение Тогда

Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);

// ...

#Иначе

// вариант для тонкого или веб-клиента

#КонецЕсли

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

Директивы в управляемых формах: роль и ограничения

В управляемой форме модуль компилируется дважды — на клиенте и на сервере, а разделение кода выполняется прежде всего аннотациями &НаКлиенте, &НаСервере, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста. Аннотации — основной и рекомендуемый способ разделения контекстов в форме.

Директивы компиляции внутри управляемой формы применяются точечно: когда внутри одной процедуры нужно выполнить разный код в зависимости от среды исполнения. Классический пример — процедура с аннотацией &НаКлиентеНаСервереБезКонтекста, где часть логики допустима только на сервере:

&НаКлиентеНаСервереБезКонтекста

Процедура ЗаполнитьПараметры(Форма)

#Если Сервер Тогда

// обращение к базе данных

#КонецЕсли

КонецПроцедуры

Ограничение: директивы внутри формы усложняют чтение и отладку, а отладчик не всегда очевидно показывает, какая ветка исполняется в текущем сеансе. Поэтому внутри формы предпочтительнее выносить серверную логику в отдельные процедуры &НаСервере, а директивы оставлять для общих модулей.

Директивы в общих модулях: основной сценарий использования

Наиболее оправданное применение директив — общие модули, у которых включены одновременно несколько признаков контекста, например «Сервер» и «Клиент (управляемое приложение)». Такой модуль компилируется в каждом из указанных контекстов, и код, допустимый только в одном из них, обязан быть обёрнут в директиву.

Типичный пример — модуль работы с файлами, где на сервере используется файловая система сервера, а на клиенте — асинхронные методы расширения работы с файлами. Без директив модуль просто не скомпилируется: серверный контекст не знает клиентских объектов, и наоборот.

Правила безопасного проектирования таких модулей:

  • по возможности разделяйте модуль на два: с признаком «Сервер» и с признаком «Клиент», вместо одного смешанного;
  • если смешанного модуля не избежать, оборачивайте контекстно-зависимый код в директивы целиком, включая объявления переменных;
  • проверяйте компиляцию модуля во всех включённых контекстах через конфигуратор (проверка конфигурации с выбором режимов);
  • не используйте в смешанных модулях методы, недоступные хотя бы в одном из заявленных контекстов, вне директив.
Как проверить корректность директив
  1. 1
    Откройте конфигуратор и запустите «Конфигурация → Проверка конфигурации».
  2. 2
    Отметьте режимы проверки: тонкий клиент, веб-клиент, сервер, толстый клиент — все, в которых работает решение.
  3. 3
    Убедитесь, что нет ошибок вида «Переменная не определена» или «Процедура или функция с указанным именем не определена» в модулях с директивами.
  4. 4
    Прогоните ключевые сценарии в каждом клиенте: тонком, веб, толстом.

Сравнение подходов: директивы, аннотации и раздельные модули

Выбор между директивами компиляции, аннотациями и разделением на отдельные модули зависит от места кода и объёма контекстно-зависимой логики. Сравнение по практическим критериям:

ПодходГде применяетсяПлюсыОграничения
Аннотации &НаКлиенте / &НаСервереМодули управляемых формНаглядность, контроль платформой, корректная передача контекстаТолько на уровне целых процедур
Директивы #ЕслиОбщие модули, отдельные фрагменты внутри процедурГибкость на уровне строк кода, работают в любом модулеХуже читаемость, сложнее отладка, ошибки выявляются только при компиляции в нужном контексте
Раздельные общие модулиБольшие блоки клиентской и серверной логикиЧистая архитектура, простая проверкаТребует дисциплины в именовании и структуре

Сравнение вариантов

Директивы #Если

Подходят для небольших вставок контекстно-зависимого кода в общих модулях. Ограничение — ухудшают читаемость при большом объёме.

Аннотации &НаСервере / &НаКлиенте

Стандарт для управляемых форм. Не работают в общих модулях и модулях объектов.

Раздельные модули

Лучший вариант для большого объёма различающейся логики. Требуют продуманной структуры конфигурации.

Типичные ошибки и риски при работе с директивами

Самая распространённая ошибка — обращение к серверному объекту (например, запросу или менеджеру справочника) вне директивы в модуле, который компилируется и на клиенте. Результат — ошибка компиляции при запуске тонкого или веб-клиента, при этом в толстом клиенте всё может работать, и проблема обнаруживается поздно.

Вторая частая ошибка — использование директивы #Если Клиент с предположением, что она означает «любой клиент». На практике поведение зависит от контекста компиляции, и надёжнее указывать конкретные директивы: ТонкийКлиент, ВебКлиент, либо комбинацию через ИЛИ.

Третья группа проблем — директивы вокруг объявлений процедур и функций. Если обернуть в #Если объявление экспортной процедуры, то в другом контексте её не существует, и все вызовы из других модулей должны быть так же обёрнуты в директивы, иначе получите «Процедура не определена».

Типичные ошибки
01
Серверный код без директивы в смешанном общем модуле — ошибка компиляции в тонком или веб-клиенте, обнаруживается только при проверке всех режимов.
02
Копирование директив из управляемых форм в обычные — лишний код, который никогда не меняет поведение.
03
Оборачивание объявления экспортной процедуры в #Если без директив в местах вызова — «Процедура не определена» в другом контексте.
04
Проверка конфигурации только в режиме толстого клиента — ошибки директив для сервера и веб-клиента остаются незамеченными.

Практические рекомендации по выбору формы записи

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

Для управляемых форм основной инструмент — аннотации. Директивы оставьте для процедур &НаКлиентеНаСервереБезКонтекста и для случаев, когда небольшой фрагмент внутри процедуры должен отличаться по контексту. Если таких фрагментов становится много — это сигнал, что процедуру стоит разделить на клиентскую и серверную.

Для общих модулей предпочтительна явная специализация: суффиксы «Клиент», «Сервер», «КлиентСервер» в именах (как принято в типовых конфигурациях) и соответствующие признаки в свойствах модуля. Директивы внутри клиент-серверных модулей должны быть исключением, а не нормой.

Маршрут решения

Как выбрать действие

Код находится в модуле управляемой формыИспользуйте аннотации &НаКлиенте / &НаСервере; директивы — только для мелких фрагментов внутри процедур
Общий модуль должен работать и на клиенте, и на сервереЛибо разделите на два модуля, либо оберните контекстно-зависимый код в #Если Сервер / #Если Клиент
Конфигурация работает только в обычном приложенииДирективы в формах не нужны; используйте их только в общих модулях совместимости
Модуль не компилируется в одном из клиентовЗапустите проверку конфигурации по всем режимам и найдите код вне директив, недоступный в этом контексте

Как проверить, что директивы работают правильно

Главный инструмент проверки — штатная проверка конфигурации в конфигураторе с отмеченными режимами исполнения. Она выявляет обращения к несуществующим в данном контексте объектам ещё до запуска. Дополнительно полезно встроить в код отладочные признаки: например, функцию, возвращающую текущий режим, чтобы убедиться, что исполняется ожидаемая ветка.

Признаки корректной работы: конфигурация проходит проверку во всех используемых режимах, сценарий выполняется одинаково в тонком и веб-клиенте, в журнале регистрации нет ошибок компиляции модулей. Тревожный признак — ошибка «Переменная не определена» или «Процедура не определена» у части пользователей: почти всегда это означает код вне директивы, недоступный в их клиенте.

Контрольные точки

Как проверить результат

Проверка конфигурации по всем режимам
Норма

Нет ошибок компиляции ни в одном режиме

Тревожный признак

Ошибки «не определена» в тонком или веб-клиенте

Запуск сценария в разных клиентах
Норма

Поведение идентично в тонком, веб и толстом клиенте

Тревожный признак

Ошибки или другое поведение у части пользователей

Журнал регистрации после обновления
Норма

Нет ошибок компиляции модулей

Тревожный признак

Ошибки компиляции у отдельных сеансов

Частые вопросы

Чем директива #Если отличается от обычного условия Если?

Директива обрабатывается на этапе компиляции: неподходящие ветки физически исключаются из кода. Обычное условие проверяется при выполнении, поэтому весь код внутри него должен компилироваться в текущем контексте — обернуть серверный вызов в обычное Если на клиенте не получится.

Нужны ли директивы в модуле обычной формы?

Как правило, нет: обычная форма исполняется только в толстом клиенте обычного приложения, и условия препроцессора там всегда дают один и тот же результат. Исключение — код, скопированный из общих модулей с поддержкой нескольких режимов.

Что лучше в управляемой форме: директивы или аннотации?

Аннотации &НаКлиенте и &НаСервере — основной механизм: они нагляднее, контролируются платформой и корректно работают с передачей контекста. Директивы оправданы только для небольших фрагментов внутри процедур, прежде всего с аннотацией &НаКлиентеНаСервереБезКонтекста.

Почему модуль работает в толстом клиенте, но падает в тонком?

Почти всегда причина в коде, который доступен только в толстом клиенте и не обёрнут в директиву #Если ТолстыйКлиентУправляемоеПриложение или аналог. Запустите проверку конфигурации с включённым режимом тонкого клиента — конфигуратор укажет проблемные строки.

Можно ли оборачивать в директиву объявление процедуры?

Технически да, но тогда все вызовы этой процедуры из других модулей также должны быть обёрнуты в те же директивы, иначе в другом контексте возникнет ошибка «Процедура не определена». Для экспортных процедур надёжнее разделять модули, а не объявления.

Какие директивы использовать для веб-клиента?

Для веб-клиента предусмотрена директива #Если ВебКлиент. Если код должен выполняться и в тонком, и в веб-клиенте, используйте составное условие через ИЛИ: #Если ТонкийКлиент ИЛИ ВебКлиент Тогда.

Итог

Что важно запомнить

В обычных формах директивы компиляции почти не нужны — весь код исполняется на толстом клиенте. В управляемых формах основной механизм разделения контекстов — аннотации &НаКлиенте и &НаСервере, а директивы #Если применяются точечно внутри процедур и в общих модулях с несколькими контекстами. Любые изменения директив проверяйте через проверку конфигурации во всех режимах исполнения.