Почему JavaScript — это новый «write once, run anywhere»?
Помните старую мечту разработчиков: написал код один раз — и он работает везде? Java обещала это с виртуальной машиной, но на практике всё упиралось в танцы с бубном. А теперь посмотрите на JavaScript. Язык, который когда-то считали «игрушечным» для анимации кнопок, сегодня захватил мир. И знаете что? Он действительно выполняет это обещание.
Кроссплатформенная разработка на JavaScript — это не просто модный тренд. Это способ сократить время выхода продукта, сэкономить бюджет и держать в команде одних и тех же специалистов. В этой статье мы разберем, как один язык позволяет создавать приложения для браузера, мобильных устройств, десктопа и сервера. И да, будут реальные примеры кода.
Архитектура современного кроссплатформенного приложения
Прежде чем кидаться в код, давайте поймем, как устроена современная экосистема. Ключевая идея — разделить логику приложения на три слоя:
- Бизнес-логика — обработка данных, валидация, работа с API. Это ядро, которое не должно зависеть от платформы.
- UI-слой — интерфейс. Он может быть разным для веба, мобилок и десктопа, но часто использует общие компоненты.
- Слой хранения — локальные базы данных, кэш, работа с файловой системой.
Именно JavaScript позволяет написать все три слоя на одном языке. Рассмотрим основные инструменты.
Серверная часть: Node.js как фундамент
Любая кроссплатформенная система начинается с бэкенда. Node.js — это среда выполнения JavaScript вне браузера, построенная на движке V8. Она идеально подходит для создания REST API, обработки WebSocket-соединений и работы с базами данных.
Вот простой пример сервера на Express, который будет обслуживать и веб, и мобильное приложение:
const express = require('express');
const app = express();
const port = 3000;
// Middleware для обработки JSON
app.use(express.json());
// Пример эндпоинта для получения списка пользователей
app.get('/api/users', (req, res) => {
const users = [
{ id: 1, name: 'Анна', email: 'anna@example.com' },
{ id: 2, name: 'Иван', email: 'ivan@example.com' }
];
res.json(users);
});
// POST-запрос для создания нового пользователя
app.post('/api/users', (req, res) => {
const newUser = req.body;
// Здесь обычно идет сохранение в базу данных
console.log('Новый пользователь:', newUser);
res.status(201).json({ message: 'Пользователь создан', user: newUser });
});
app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});
Этот код будет работать одинаково на Windows, macOS и Linux. Более того, вы можете запустить его на Raspberry Pi или в облачном контейнере — никаких изменений не потребуется.
Веб-интерфейс: React как универсальный строительный блок
Когда речь заходит о кроссплатформенной разработке на JavaScript, React — первый кандидат. Его компонентная архитектура позволяет переиспользовать до 70% кода между вебом и мобильными приложениями.
Создадим простой компонент для отображения списка пользователей:
import React, { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/users')
.then(response => response.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(error => console.error('Ошибка:', error));
}, []);
if (loading) {
return <div>Загрузка...</div>;
}
return (
<div>
<h2>Список пользователей</h2>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} — {user.email}
</li>
))}
</ul>
</div>
);
}
export default UserList;
Этот компонент можно использовать как в веб-версии, так и в мобильном приложении с минимальными изменениями. Разница будет только в том, как мы рендерим элементы списка — на вебе это <li>, а в React Native — <View> и <Text>.
Мобильные приложения: React Native в действии
React Native позволяет писать нативные мобильные приложения для iOS и Android, используя JavaScript. Да, вы не ослышались — это не WebView, а настоящие нативные компоненты. Вот как выглядит тот же список пользователей для мобильного приложения:
import React, { useState, useEffect } from 'react';
import { View, Text, FlatList, ActivityIndicator, StyleSheet } from 'react-native';
function UserListMobile() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('http://localhost:3000/api/users')
.then(response => response.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(error => console.error('Ошибка:', error));
}, []);
if (loading) {
return <ActivityIndicator size="large" color="#0000ff" />;
}
return (
<View style={styles.container}>
<Text style={styles.title}>Список пользователей</Text>
<FlatList
data={users}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => (
<View style={styles.userItem}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.email}>{item.email}</Text>
</View>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 20, backgroundColor: '#fff' },
title: { fontSize: 24, fontWeight: 'bold', marginBottom: 20 },
userItem: { padding: 15, borderBottomWidth: 1, borderColor: '#ccc' },
name: { fontSize: 18 },
email: { fontSize: 14, color: '#666' }
});
export default UserListMobile;
Обратите внимание: логика получения данных и состояние загрузки остались теми же. Изменились только компоненты отображения. Это и есть магия кроссплатформенной разработки на JavaScript — вы пишете бизнес-логику один раз, а UI адаптируете под платформу.
Десктопные приложения: Electron для настольных систем
А что если нужно приложение для Windows, macOS и Linux? Тут на помощь приходит Electron. Он упаковывает ваше веб-приложение в нативное окно с полным доступом к файловой системе. Да, Slack, VS Code и Discord написаны именно так.
Минимальный пример Electron-приложения:
// main.js — основной процесс
const { app, BrowserWindow } = require('electron');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
node