Инструкция
Создание 100% статически связанного однофайлового веб-приложения с React и Rust
Обновлено 23 мая 2019 г.
В этом руководстве будут рассмотрены основы создания минимального приложения React, которое можно развернуть в виде статически связанного двоичного файла Rust. Для этого весь ваш код, включая HTML, JavaScript, CSS и Rust, упакован в один файл, который будет работать практически на любой 64-битной системе Linux, независимо от версии ядра или установленных библиотек.
Полный исходный код доступен на GitHub.
Зачем?
- Упрощенное развертывание: наличие статического двоичного кода означает, что вам просто нужно скопировать файл на сервер и запустить его.
- Кроссплатформенные собственные приложения с графическим интерфейсом. Одной из самых больших проблем при создании кроссплатформенного приложения с графическим интерфейсом пользователя является работа с библиотекой графического интерфейса, предназначенной для всех интересующих вас платформ. Такой подход позволяет вам использовать браузер пользователя для этой цели. Это несколько похоже на то, что выполняет Electron, но ваш бэкэнд в Rust, а не в JavaScript, и пользователь переходит к приложению из своего браузера. Здесь, безусловно, есть компромиссы, но это может хорошо работать для некоторых приложений. Впервые я познакомился с этим подходом путем синхронизации , которая написана на go, но делает нечто подобное.
- Потому что я был одержим статической связью столько, сколько себя помню, и я не совсем уверен, почему.
Предпосылки
- Среда сборки Linux
- Rust с cargo
- Узел с npm
Инициализируйте каталог проекта
Мы позволим Cargo управлять каталогом проектов для нас. Запустите следующие команды:
cargo new --bin react_rust_webapp cd react_rust_webapp
Создание приложения React
Сначала установите React, Babel и Webpack:
mkdir ui cd ui npm init -y npm install --save react react-dom npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react webpack webpack-cli
Затем создайте исходные файлы:
mkdir dist touch dist/index.html mkdir src touch src/index.js
Поместите следующий контент в dist/index.html:
<!doctype html>
<html>
<head>
<title>Static React and Rust</title>
</head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html>
И установите в src/index.js следующее:
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1>Hi there</h1>,
document.getElementById('root')
);
Нам также понадобится файл .babelrc:
{
"presets": [
"react",
"env",
],
}
И webpack.config.js файл:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
}
]
}
};
Теперь вы должны быть в состоянии проверить, работает ли интерфейс. Запускаем:
npx webpack --mode development
Это сгенерирует dist/bundle.js. Если вы запустите веб-сервер в dist каталоге, вы сможете успешно обработать пример содержимого.
Теперь для части Rust.
Настройка бэкэнда Rust
Перейти в react_rust_webappкаталог:
cd ..
Первое, что нам нужно сделать, это установить веб-фреймворк. Я обнаружил, что Руил отлично подходит для этого простого примера. Я тоже очень люблю Rocket.
Добавьте rouille к вашим зависимостям Cargo.toml:
[package] name = "react_rust_webapp" version = "0.1.0" [dependencies] rouille = "2.1.0"
Теперь измените, src/main.rs, чтобы иметь следующий контент:
#[macro_use]
extern crate rouille;
use rouille::Response;
fn main() {
let index = include_str!("../ui/dist/index.html");
let bundle = include_str!("../ui/dist/bundle.js");
rouille::start_server("0.0.0.0:5000", move |request| {
let response = router!(request,
(GET) ["/"] => {
Response::html(index)
},
(GET) ["/bundle.js"] => {
Response::text(bundle)
},
_ => {
Response::empty_404()
}
);
response
});
}
Как это работает?
Во время компиляции include_str! читает указанный файл и вставляет содержимое в виде статической строки в скомпилированный двоичный файл. Эта строка затем доступна как обычная переменная.
Код маршрута только устанавливает две конечные точки HTTP, "/" и "/bundle.js". Вместо того, чтобы возвращать файлы из файловой системы, как это обычно делается с веб-приложением, мы возвращаем содержимое статических строк из двоичного файла.
Чтобы узнать больше об использовании Rouille для более сложных вещей, обратитесь к их документам.
Запуск
Хорошо, теперь, если все прошло хорошо, мы сможем запустить его. Убедитесь, что ui/dist/bundle.js он уже создан, как указано выше. Затем запустите:
cargo run
Он должен запустить сервер через порт 5000. Если вы перейдете по адресу http://localhost:5000 в вашем браузере, вы должны увидеть «Hi there».
Статическое связывание
Эта часть может быть пропущена, если вам не нужно 100% статическое связывание. В любом случае Rust статически связывает большинство библиотек по умолчанию, за исключением таких вещей, как libc.
Если вы хотите продолжить, вам сначала нужно установить musl libc в вашей системе и убедиться, что команда musl-gcc находится в вашем PATH.
Затем повторите груз следующим образом:
cargo run --target=x86_64-unknown-linux-musl
Построение производства
Для меньших двоичных файлов соберите bundle.jsследующее (из с ui/):
npx webpack --mode production
И запустить груз следующим образом:
cargo build --release --target=x86_64-unknown-linux-musl
Вы должны получить статически связанный двоичный файл в react_rust_webapp/target/x86_64-unknown-linux-musl/release/
Заключение
Это только основы. С этим можно многое сделать, в том числе:
- Используется build.rsдля автоматической сборки приложения React при компиляции Rust.
- Взять номер порта из командной строки
- Сериализованные (возможно, JSON) запросы и ответы
- Запустите webpack как команду сценария npm
- Ориентируйтесь на другие ОС. Я еще не пробовал, но это должно быть в основном переносимо на MacOS и Windows, благодаря великолепной Rust / Cargo и универсальной доступности веб-браузеров.
Есть вопрос по инструкции?
Опишите, на каком шаге возникла проблема
Укажите устройство, версию системы и что уже пробовали — так ответ будет полезнее.
Помощь
Не нашли ответ?
Опишите проблему — подскажем, куда двигаться дальше, и по возможности дополним материал.
Комментарии
Загружаем обсуждение…
Оставьте комментарий…