Разработка и Конфигурация · 13 мин
Директивы компиляции 1С в обычных и управляемых формах
Как используются директивы компиляции 1С: #Если Сервер, Клиент, ТолстыйКлиент. Отличия обычных и управляемых форм, примеры кода и типичные ошибки.
Директивы компиляции в 1С — это инструкции препроцессору, которые определяют, какой фрагмент кода будет скомпилирован и выполнен в конкретном контексте: на сервере, на тонком клиенте, в веб-клиенте или в толстом клиенте. Они записываются в виде конструкций #Если ... Тогда ... #КонецЕсли и позволяют одному и тому же модулю работать в разных средах исполнения.
Потребность в таких директивах возникла вместе с управляемым приложением, где код формы может исполняться одновременно в двух контекстах — клиентском и серверном. В обычном приложении вся логика выполнялась на клиенте, поэтому директивы там играют вспомогательную роль, а в управляемых формах они становятся обязательным инструментом, особенно в общих модулях без признака «Клиент» или «Сервер».
Ниже разобрано, какие директивы существуют, как они ведут себя в обычных и управляемых формах, когда их применять, а когда лучше обойтись аннотациями &НаСервере и &НаКлиенте, и какие ошибки чаще всего допускают разработчики.
Какие директивы компиляции существуют в 1С
Платформа поддерживает фиксированный набор директив, каждая из которых соответствует определённому контексту исполнения. Основные из них: Сервер, Клиент, ТонкийКлиент, ТолстыйКлиентОбычноеПриложение, ТолстыйКлиентУправляемоеПриложение, ВебКлиент, ВнешнееСоединение, МобильныйКлиент, МобильноеПриложениеКлиент, МобильноеПриложениеСервер. Также доступны логические операторы И, ИЛИ, НЕ для составных условий.
Типовая конструкция выглядит так:
#Если Сервер Тогда
// код, выполняемый только на сервере
#ИначеЕсли ТонкийКлиент Тогда
// код для тонкого клиента
#Иначе
// код для остальных контекстов
#КонецЕсли
Важно понимать, что директива работает на этапе компиляции модуля: платформа физически исключает неподходящие ветки из исполняемого кода. Это отличает её от обычного условия Если, которое проверяется во время выполнения и требует, чтобы весь код был синтаксически корректен в текущем контексте.
Директивы в обычных формах: зачем они нужны и когда избыточны
В обычном приложении код формы исполняется целиком на стороне толстого клиента. Здесь нет разделения на клиентский и серверный контексты внутри формы, поэтому директивы компиляции в модуле обычной формы практически не нужны: любая ветка #Если ТолстыйКлиентОбычноеПриложение будет истинной всегда, а ветки для сервера — всегда ложными.
Тем не менее директивы встречаются в конфигурациях с обычными формами в двух случаях. Первый — общие модули, которые должны одинаково работать и в обычном, и в управляемом режиме (например, при постепенном переходе конфигурации на управляемое приложение). Второй — код, который использует объекты, недоступные на сервере или в веб-клиенте, например работу с файловой системой через диалоги.
Типичный пример для общего модуля, используемого в обоих режимах:
#Если ТолстыйКлиентОбычноеПриложение Тогда
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
// ...
#Иначе
// вариант для тонкого или веб-клиента
#КонецЕсли
Если конфигурация работает только в обычном режиме, добавление директив в модуль формы не даёт ничего, кроме лишнего визуального шума. Это частая ошибка при копировании кода из управляемых форм.
Директивы в управляемых формах: роль и ограничения
В управляемой форме модуль компилируется дважды — на клиенте и на сервере, а разделение кода выполняется прежде всего аннотациями &НаКлиенте, &НаСервере, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста. Аннотации — основной и рекомендуемый способ разделения контекстов в форме.
Директивы компиляции внутри управляемой формы применяются точечно: когда внутри одной процедуры нужно выполнить разный код в зависимости от среды исполнения. Классический пример — процедура с аннотацией &НаКлиентеНаСервереБезКонтекста, где часть логики допустима только на сервере:
&НаКлиентеНаСервереБезКонтекста
Процедура ЗаполнитьПараметры(Форма)
#Если Сервер Тогда
// обращение к базе данных
#КонецЕсли
КонецПроцедуры
Ограничение: директивы внутри формы усложняют чтение и отладку, а отладчик не всегда очевидно показывает, какая ветка исполняется в текущем сеансе. Поэтому внутри формы предпочтительнее выносить серверную логику в отдельные процедуры &НаСервере, а директивы оставлять для общих модулей.
Директивы в общих модулях: основной сценарий использования
Наиболее оправданное применение директив — общие модули, у которых включены одновременно несколько признаков контекста, например «Сервер» и «Клиент (управляемое приложение)». Такой модуль компилируется в каждом из указанных контекстов, и код, допустимый только в одном из них, обязан быть обёрнут в директиву.
Типичный пример — модуль работы с файлами, где на сервере используется файловая система сервера, а на клиенте — асинхронные методы расширения работы с файлами. Без директив модуль просто не скомпилируется: серверный контекст не знает клиентских объектов, и наоборот.
Правила безопасного проектирования таких модулей:
- по возможности разделяйте модуль на два: с признаком «Сервер» и с признаком «Клиент», вместо одного смешанного;
- если смешанного модуля не избежать, оборачивайте контекстно-зависимый код в директивы целиком, включая объявления переменных;
- проверяйте компиляцию модуля во всех включённых контекстах через конфигуратор (проверка конфигурации с выбором режимов);
- не используйте в смешанных модулях методы, недоступные хотя бы в одном из заявленных контекстов, вне директив.
- 1Откройте конфигуратор и запустите «Конфигурация → Проверка конфигурации».
- 2Отметьте режимы проверки: тонкий клиент, веб-клиент, сервер, толстый клиент — все, в которых работает решение.
- 3Убедитесь, что нет ошибок вида «Переменная не определена» или «Процедура или функция с указанным именем не определена» в модулях с директивами.
- 4Прогоните ключевые сценарии в каждом клиенте: тонком, веб, толстом.
Сравнение подходов: директивы, аннотации и раздельные модули
Выбор между директивами компиляции, аннотациями и разделением на отдельные модули зависит от места кода и объёма контекстно-зависимой логики. Сравнение по практическим критериям:
| Подход | Где применяется | Плюсы | Ограничения |
|---|---|---|---|
| Аннотации &НаКлиенте / &НаСервере | Модули управляемых форм | Наглядность, контроль платформой, корректная передача контекста | Только на уровне целых процедур |
| Директивы #Если | Общие модули, отдельные фрагменты внутри процедур | Гибкость на уровне строк кода, работают в любом модуле | Хуже читаемость, сложнее отладка, ошибки выявляются только при компиляции в нужном контексте |
| Раздельные общие модули | Большие блоки клиентской и серверной логики | Чистая архитектура, простая проверка | Требует дисциплины в именовании и структуре |
Сравнение вариантов
Подходят для небольших вставок контекстно-зависимого кода в общих модулях. Ограничение — ухудшают читаемость при большом объёме.
Стандарт для управляемых форм. Не работают в общих модулях и модулях объектов.
Лучший вариант для большого объёма различающейся логики. Требуют продуманной структуры конфигурации.
Типичные ошибки и риски при работе с директивами
Самая распространённая ошибка — обращение к серверному объекту (например, запросу или менеджеру справочника) вне директивы в модуле, который компилируется и на клиенте. Результат — ошибка компиляции при запуске тонкого или веб-клиента, при этом в толстом клиенте всё может работать, и проблема обнаруживается поздно.
Вторая частая ошибка — использование директивы #Если Клиент с предположением, что она означает «любой клиент». На практике поведение зависит от контекста компиляции, и надёжнее указывать конкретные директивы: ТонкийКлиент, ВебКлиент, либо комбинацию через ИЛИ.
Третья группа проблем — директивы вокруг объявлений процедур и функций. Если обернуть в #Если объявление экспортной процедуры, то в другом контексте её не существует, и все вызовы из других модулей должны быть так же обёрнуты в директивы, иначе получите «Процедура не определена».
Практические рекомендации по выбору формы записи
Для обычных форм правило простое: директивы не нужны, за исключением общих модулей, рассчитанных на несколько режимов работы. Если код предназначен только для обычного приложения, пишите его без препроцессорных конструкций.
Для управляемых форм основной инструмент — аннотации. Директивы оставьте для процедур &НаКлиентеНаСервереБезКонтекста и для случаев, когда небольшой фрагмент внутри процедуры должен отличаться по контексту. Если таких фрагментов становится много — это сигнал, что процедуру стоит разделить на клиентскую и серверную.
Для общих модулей предпочтительна явная специализация: суффиксы «Клиент», «Сервер», «КлиентСервер» в именах (как принято в типовых конфигурациях) и соответствующие признаки в свойствах модуля. Директивы внутри клиент-серверных модулей должны быть исключением, а не нормой.
Как выбрать действие
Как проверить, что директивы работают правильно
Главный инструмент проверки — штатная проверка конфигурации в конфигураторе с отмеченными режимами исполнения. Она выявляет обращения к несуществующим в данном контексте объектам ещё до запуска. Дополнительно полезно встроить в код отладочные признаки: например, функцию, возвращающую текущий режим, чтобы убедиться, что исполняется ожидаемая ветка.
Признаки корректной работы: конфигурация проходит проверку во всех используемых режимах, сценарий выполняется одинаково в тонком и веб-клиенте, в журнале регистрации нет ошибок компиляции модулей. Тревожный признак — ошибка «Переменная не определена» или «Процедура не определена» у части пользователей: почти всегда это означает код вне директивы, недоступный в их клиенте.
Как проверить результат
Нет ошибок компиляции ни в одном режиме
Ошибки «не определена» в тонком или веб-клиенте
Поведение идентично в тонком, веб и толстом клиенте
Ошибки или другое поведение у части пользователей
Нет ошибок компиляции модулей
Ошибки компиляции у отдельных сеансов
Частые вопросы
Чем директива #Если отличается от обычного условия Если?
Директива обрабатывается на этапе компиляции: неподходящие ветки физически исключаются из кода. Обычное условие проверяется при выполнении, поэтому весь код внутри него должен компилироваться в текущем контексте — обернуть серверный вызов в обычное Если на клиенте не получится.
Нужны ли директивы в модуле обычной формы?
Как правило, нет: обычная форма исполняется только в толстом клиенте обычного приложения, и условия препроцессора там всегда дают один и тот же результат. Исключение — код, скопированный из общих модулей с поддержкой нескольких режимов.
Что лучше в управляемой форме: директивы или аннотации?
Аннотации &НаКлиенте и &НаСервере — основной механизм: они нагляднее, контролируются платформой и корректно работают с передачей контекста. Директивы оправданы только для небольших фрагментов внутри процедур, прежде всего с аннотацией &НаКлиентеНаСервереБезКонтекста.
Почему модуль работает в толстом клиенте, но падает в тонком?
Почти всегда причина в коде, который доступен только в толстом клиенте и не обёрнут в директиву #Если ТолстыйКлиентУправляемоеПриложение или аналог. Запустите проверку конфигурации с включённым режимом тонкого клиента — конфигуратор укажет проблемные строки.
Можно ли оборачивать в директиву объявление процедуры?
Технически да, но тогда все вызовы этой процедуры из других модулей также должны быть обёрнуты в те же директивы, иначе в другом контексте возникнет ошибка «Процедура не определена». Для экспортных процедур надёжнее разделять модули, а не объявления.
Какие директивы использовать для веб-клиента?
Для веб-клиента предусмотрена директива #Если ВебКлиент. Если код должен выполняться и в тонком, и в веб-клиенте, используйте составное условие через ИЛИ: #Если ТонкийКлиент ИЛИ ВебКлиент Тогда.
Что важно запомнить
В обычных формах директивы компиляции почти не нужны — весь код исполняется на толстом клиенте. В управляемых формах основной механизм разделения контекстов — аннотации &НаКлиенте и &НаСервере, а директивы #Если применяются точечно внутри процедур и в общих модулях с несколькими контекстами. Любые изменения директив проверяйте через проверку конфигурации во всех режимах исполнения.