Создание приложений

Цикл приложения

Выберите и пройдите путь платформенного файла, Python, веб-приложения или ограниченного HTTP в соответствии со способом поставки.

Переходите к этой странице после раздела Первое приложение. Этапы разработки общие, но поставка различается: выберите один нужный продукт, а не собирайте все цели подряд.

  • Платформенный файл подходит для отдельного исполняемого файла, которому при развёртывании не нужна среда выполнения Топаза.
  • Python подходит, если в среде развёртывания уже есть Python 3.11 или новее.
  • Web Application подходит, если Топаз владеет моделью браузерного приложения, сообщениями, обновлением состояния и представлением.
  • Ограниченный HTTP-сервис подходит для проверенного обработчика запросов, работающего под управлением супервизора и, для публичного трафика, за обратным прокси.

Raw Web и Worker предназначены для интеграции с существующей средой JavaScript. Они описаны в разделе WASM и песочница.

Общий цикл разработки

Начните с проверенного пакета из двух модулей. Манифест текущего платформенного пакета имеет следующее содержимое; сохраните его как topaz.toml:

TOML
[package]
name = "task_summary"
version = "0.1.0"
language = "5.11"
entry = "src/main.tpz"

[build]
target = "native"
deterministic = true

[dependencies]
std = "5.11"

Вспомогательный модуль выполняет вычисление приложения:

TOPAZ
export function remainingMinutes(values: Array<int>) -> int {
  let mut total = 0
  for value in values {
    total += value
  }
  total
}

Входной модуль превращает результат в наблюдаемую команду:

TOPAZ
import src.summary { remainingMinutes }

export function main(args: Array<string>, stdin: string) -> Result<int, string> {
  let minutes = remainingMinutes([10, 25])
  print("remaining={minutes}")
  Ok(0)
}

Один раз создайте topaz.lock, затем выполняйте обычную работу в одном порядке:

BASH
topaz lock --root task-summary
topaz fmt --check --root task-summary
topaz check --root task-summary --locked
topaz test --root task-summary --locked
topaz run --root task-summary --locked

Команда fmt --check сообщает об отличиях форматирования, не меняя файлы. Неудачные check и test останавливаются до записи продукта. Исправьте первую диагностику Топаза и повторите ту же команду. Подробности диагностического кода можно получить командой topaz explain TPZ####.

Путь А: платформенное командное приложение или Python

Для платформенной сборки нужен набор инструментов Rust, соответствующий текущей операционной системе и архитектуре. Для сборки Python Rust не нужен, но готовый продукт требует Python 3.11 или новее.

Соберите только тот продукт, который собираетесь поставлять:

BASH
topaz build --release --root task-summary --locked --out-dir native-product
topaz build --target python --root task-summary --locked --out-dir python-product

Деревья релизных продуктов выглядят так:

Вывод
native-product/
├── GENERATED-OUTPUT-NOTICE.txt
├── LICENSE
├── NOTICE
├── target
│   └── release
│       └── program[.exe]
└── topaz-artifact.json

python-product/
├── GENERATED-OUTPUT-NOTICE.txt
├── LICENSE
├── NOTICE
├── program.py
├── topaz-artifact.json
└── topaz_py_rt.py

program[.exe] означает program в Unix и program.exe в Windows. Скопируйте весь выбранный каталог в новое место и запускайте из его корня:

BASH
./target/release/program
python3 program.py

Первая команда относится к платформенному продукту, вторая — к продукту Python; это альтернативы. Если приложение объявляет [capabilities.fs], поместите рядом с продуктом его data/ и доступные для записи каталоги, а корень продукта оставьте рабочим каталогом. Данные приложения не включаются автоматически ни в платформенный продукт, ни в продукт Python.

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

Путь Б: управляемое веб-приложение

Для сборки Web Application нужен Rust с установленной целью wasm32-unknown-unknown. Не преобразуйте командный входной модуль, а создайте проверенный каркас:

BASH
topaz init --target web-app --root hello-web
topaz lock --root hello-web
topaz fmt --check --root hello-web
topaz check --root hello-web --locked
topaz test hello-web/tests/app.tpz --root hello-web --locked
topaz dev --root hello-web --port 8000
topaz build --root hello-web --locked --release --out-dir web-product

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

TOPAZ
import std.dom { Html, WebAppEvent, WebAppStep, text }

export record Model {
  message: string,
}

export enum Msg {
  Ready,
}

export function init() -> WebAppStep<Model, Msg> {
  WebAppStep { model: Model { message: "Hello from Topaz" }, commands: [] }
}

export function update(model: Model, message: Msg, event: WebAppEvent) -> WebAppStep<Model, Msg> {
  WebAppStep { model: model, commands: [] }
}

export function view(model: Model) -> Html<Msg> {
  text(model.message)
}

topaz dev — сервер разработки на адресе обратной петли, который сохраняет последний исправный продукт после ошибочного изменения. Это не производственный сервер. Итоговый каталог содержит HTML, проверенную среду приложения, оболочку Raw Web, WASM, метаданные полномочий, объявленные стили и ресурсы, а также общие лицензионные файлы и манифест артефакта. Скопируйте каталог целиком на статический сервер и раздавайте его по HTTP; открытие модулей ES через file:// не является путём развёртывания.

Data Lens — поддерживаемый многомодульный пример этого пути.

Путь В: ограниченный HTTP-сервис

Если продукт представляет собой обработчик запросов, а не команду или браузерный интерфейс, создайте каркас сервиса:

BASH
topaz init --target http-service --root hello-service
topaz lock --root hello-service
topaz fmt --check --root hello-service
topaz check --root hello-service --locked
topaz test --root hello-service --locked
topaz dev --root hello-service --port 8080
topaz build --root hello-service --locked --release --out-dir service-product

Граница обработчика конкретна и синхронна:

TOPAZ
import std.http { HttpRequest, HttpResponse, text }

export function handle(req: HttpRequest) -> HttpResponse {
  if req.url.path() == "/health" {
    return text(200, "ok")
  }
  text(404, "not found")
}

Продукт сервиса содержит один платформенный исполняемый файл, встроенные ограниченные настройки, уведомления сторонних компонентов и общие файлы артефакта. По умолчанию он слушает адрес обратной петли. Для другого адреса требуется явный аргумент процесса; цель не добавляет TLS, HTTP/2, исходящие сетевые запросы или универсальный веб-фреймворк.

Раздел Ограниченный HTTP-сервис завершает этот путь: в нём описаны бюджеты, наблюдаемые ошибки, запуск без исходников и восстановление после проблем развёртывания.

Связанная документация