Отож, друзі, як і обіцяв, ми продовжуємо :-)
Сьогодні ми розгорнемо Rails із master гілки, створимо наш перший api-застосунок, а також зробимо всі базові налаштування; створимо базову структуру нашого фронтенд застосунку, встановимо базові залежності, такі як react, webpack, babel, express, налаштуємо express сервер, а також напишемо наш hello world.
Я дуже надіюся, що у вас вже встановлені ruby (2.2.1) та nodejs (0.12/4.0.0). І ви хоч раз із ними працювали, і пояснювати вам що це і для чого це не потрібно.
Проте якщо це не так, прошу звертатись до мене за допомогою контактів, які розташовані нижче.
Ruby on Rails 5
Я люблю все нове, люблю тестувати. Так як поки я не користуюся зовсім нестабільними фічами Рельси версії 5, такі як Action Cabble, Turbolinks3, а всього лиш rails-api gem, який об'єднали із ядром, то можу без проблем* створити новий застосунок з допомогою команд rails new todoapp-server --api
Ви, звичайно, можете працювати зі звичною для вас Rails 4.2, та встановивши rails-api gem, створити новий застосунок із допомогою rails-api new todoapp-server
.
[* не зовсім без проблем, так як тепер по-іншому потрібно запускати наші рельси (дивись нижче)]
То ж, перше що нам потрібно, клонувати репозиторій rails, вказавши куди, щоб не засмічувати наш проект:
$ git clone https://github.com/rails/rails.git ~/path_to_folder/rails
Після того як клонування пройшло успішно (а це може зайняти трішки часу), зайти в папку проекту і запустити команду:
$ bundle install # також можна використовувати просто bundle
І все, готово.
todoapp-server
Після встановлення всіх залежностей, можемо створити наш застосунок:
$ bundle exec path_to_rails/railtities/exe/rails new path_to_project/todoapp-server --api --edge
$ cd path_to_project/todoapp-server
$ bundle
Все готово, у нас є новий проект на rails 5.
Давайте тепер подивимось що у нас в Gemfile
.
source 'https://web.archive.org/web/20230605174052/https://rubygems.org'
gem 'rails', github: "rails/rails"
gem 'sprockets-rails', github: "rails/sprockets-rails"
gem 'sprockets', github: "rails/sprockets"
gem 'sass-rails', github: "rails/sass-rails"
gem 'arel', github: "rails/arel"
gem 'rack', github: "rack/rack"
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use Unicorn as the app server
# gem 'unicorn'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
# Use ActiveModelSerializers to serialize JSON responses
gem 'active_model_serializers', '~> 0.10.0.rc2'
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
# gem 'rack-cors'
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug'
end
group :development do
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
В принципі нічого незвичного, чи не так? Але є одна відмінність: немає групи ґемів, яка відповідає за assets. Все тому що нам не потрібні компілятори sass чи coffee для api-сервера, також не потрібні jQuery, Turbolinks чи щось у тому роді.
Крім того у нас Active Model Serializers, який буде серіалізувати (видозмінювати) наш json так, як нам потрібно.
Так як ми плануємо розміщувати наші сервер і фронтенд на одному домені (у нашому випадку це localhost), то нам потрібно дозволити Cross-Origin Resource Sharing (CORS), тобто дозволити запити в контексті одного домену. Це можна зробити наступним чином: знайдіть лінійку із gem 'rack-cors'
та відкоментуйте її і ще раз запустіть команду bundle install
.
А тоді вставити (скоріше відкоментувати) невеличкий блок коду в файл todoapp-server/config/initializers/cors.rb
# todoapp-server/config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins 'https://web.archive.org/web/20230605174052/http://localhost:3000' # адреса нашого майбутнього фронтенд застосунку
resource '*', # можна обмежити доступ лише до певних ресурсів
# крім того можна дозволити лише певні види хедерів та запитів
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
І все, готово. Тепер можна запустити наш сервер на порті 3001 з допомогою команди:
$ bundle exec bin/rails server -p 3001
Якщо ви ведете розробку з-під vagrant, вам доведеться також вказати ip-адресу 0.0.0.0, щоб мати доступ на хост-машині через localhost:3001.
$ bundle exec bin/rails server -b 0.0.0.0 -p 3001
а також прописати в Vagrantfile
наступне:
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
...
config.vm.network :forwarded_port, guest: 3000, host: 3000
config.vm.network :forwarded_port, guest: 3001, host: 3001
...
end
Тепер можна й закомітити наші зміни:
$ git init
$ git add .
$ git commit -am "setup rails 5 project"
React
Розібравшись із нашим сервером, можна приступити до налаштування клієнтської сторони.
Залежності
Ми будемо встановлювати всі залежності через npm
, тому у папці todoapp-client
виконуємо команду ініціалізації нового проекту npm:
$ npm init
та просто клікаємо enter, якщо ви не хочете заповняти всі поля.
Крім того давайте встановимо наші залежності:
$ npm i --save react react-dom
Якщо ви з-під вагранту, і у вас виникають якісь містичні помилки під час встановлення, вам, можливо, доведеться в кінці кожної команди дописувати --no-bin
(принаймні мені потрібно це робити).
Крім того нам потрібні ще розробницькі залежності.
Отож, ми будемо писати на EcmaScript 2015 (також es6, es next і т.д.) - останній стандарт Javascript, і для того щоб це діло працювало у всіх-всіх браузерах, змушені використовувати babel, який конвертує все в es5; бандлити все діло буде в нас webpack; крім того ми хочемо, щоб наші компоненти рендерились заново, якщо відбуваються зміни в їх файлі, тому ми будемо використовувати react-transform; піднімати наш весь фронт-енд будемо на express сервері.
Встановимо спершу babel:
$ npm i --save-dev babel-core babel-loader
Тепер встановимо webpack та декілька мідлварів до нього:
$ npm i --save-dev webpack webpack-hot-middleware webpack-dev-middleware
# крім того вам можливо буде потрібно встановити вебпак глобально
$ npm i -g webpack
Давайте встановимо тепер react-transform зі всією інфраструктурою:
$ npm i --save-dev babel-plugin-react-transform react-transform-catch-errors react-transform-hmr redbox-react
[Пічалька для користувачів вагранту: react-transform та react-hot-loader чомусь не працють з-під вагранту, якщо хтось знайде вирішення цієї проблеми, будь ласка, напишіть мені]
І на останок потрібно встановити express
$ npm i --save-dev express
А також не забути закомітити наші зміни:
$ git add .
$ git commit -am "add base dependencies for todoapp-client"
Базові налаштування
Встановивши всі потрібні нам залежності, можна приступити до створення різних конфігураційних файлів.
Розпочнімо із .babelrc
, який є файлом налаштувань babel:
// .babelrc
{
"stage": 0, // зазвичай краще так не робити, але...
"env": { // а тут ми налаштовуємо наш react-transform
"development": {
"plugins": ["react-transform"],
"extra": {
"react-transform": {
"transforms": [{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
}, {
"transform": "react-transform-catch-errors",
"imports": ["react", "redbox-react"]
}]
}
}
}
}
}
Крім того, створимо два конфіга webpack - один для розробки, інший для продакшену:
// webpack.config.dev.js
// весь наш застосунок буде в папці app
// вхідною точкою нашого застосунку буде файл app/index.js
// бандлитись все буде в папку dist/bundle.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval',
entry: [
'webpack-hot-middleware/client',
'./app/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
module: {
loaders: [{
test: /\\.js$/,
loaders: ['babel'],
include: path.join(__dirname, 'app')
}]
}
};
// webpack.config.prod.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'source-map',
entry: [
'./app/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
],
module: {
loaders: [{
test: /\\.js$/,
loaders: ['babel'],
include: path.join(__dirname, 'app')
}]
}
};
А тепер давайте напишемо наш розробницький сервер:
// server.js
var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.config.dev');
var HOST = 'localhost';
var PORT = 3000;
var app = express();
var compiler = webpack(config);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: config.output.publicPath
}));
app.use(require('webpack-hot-middleware')(compiler));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, '/app/index.html'));
});
app.listen(PORT, HOST, function(err) {
if (err) {
console.log(err);
return;
}
console.log('Listening at http://' + HOST + ':' + PORT);
});
А ще нам потрібно вписати декілька скриптів для npm:
// package.json
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "NODE_ENV=production webpack --config webpack.config.prod.js",
"start": "node server.js"
}
...
Ми круті! Ми вже на фінішній прямій до закінчення всіх налаштувань.
Можна відзначити це коммітом:
$ git add .
$ git commit -am "add base configs"
Базова структура та Hello World!
Розпочнімо з того, що створимо папку app
, а в ній папку components
, та файл index.js
та index.html
:
$ mkdir app && cd app
$ mkdir components
$ touch index.js
$ touch index.html
Спершу створимо базову структуру в файлі index.html
:
<title>Simple Todo App</title>
<div>
</div>
<script src="/static/bundle.js"></script>
Продовжимо це все тим, що напишемо наш файл, якиє є вхідною точкою нашого застосунку - index.js
, де ми просто рендеримо наш компонент TodoApp
, який ми зараз напишемо, в ноду нашого index.html, все просто:
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {TodoApp} from './components';
const rootElement = document.getElementById('root');
ReactDOM.render(<todoapp>, rootElement);
Ну і напишемо наш Hello World!
// components/TodoApp.js
import React, {Component} from 'react';
export default class TodoApp extends Component {
render() {
return (
<div>Hello World!</div>
);
}
}
А також покладемо в папку із нашими компонентами файл index.js
, який буде всього лиш експортувати усі наші компоненти із даної папки, щоб пізніше можна було написати
import {Component, AnotherComponent} from './components';
:
// components/index.js
export TodoApp from './TodoApp';
Ну і все, дітки, можемо запустити наш сервер, перейти у браузер і побачити Hello World!:
$ npm start
І все працює! Ура!
Тепер можна й закомітити:
$ git add .
$ git commit -am "Hello world"
Підводне каміння
Під час розробки ви можете зіткнутись із деякими проблемами. Можу вас запевнити, що код цей весь працює, так як я його пишу тоді ж, як пишу статтю.
- Можливо у вас буде в терміналі помилка, що не можливо знайти якийсь модуль, то спробуйте запустити
npm i
ще раз. - Можливо в консолі браузера пише, що реакт не може створити елемент, який null - перегляньте чи немає десь звичайної синтаксичної помилки, або ж чи всюди є
export
(власне у мене бувало, що я зависав на довший час і не міг зрозуміти чому не працює, а я всього лиш забув export прописати в файлі компонента) та чи правильний import. - Не забувайте користуватись
console.log(), якщо потрібно
. - Ще раз наголошую, що react-transform та react-hot-loader не працють з-під ваграрнту, і якщо ви їх якось подружили - напишіть мені, буду дуже вдячний.
Що далі?
В наступній статті ми нарешті додамо якісь фічі до наших сервера та клієнта:
- будемо використовувати redux!
- зможемо інітіалізувати наш застосунок;
- зможемо додавати тудушки;
- видаляти наші тудушки;
- позначати їх виконаними.
А стаття вже зовсім скоро!
Корисні посилання:
Тут невеличка збірка корисних посилань, які можуть вам бути у нагоді зараз:
- Офіційний сайт React.js та документація, репозиторій на гітхабі.
- Офіційний сайт Webpack, також там присутня документація.
- Книжка-збірник рецептів про реакт та вебпак.
- Офіційний сайт Babel, також присутня документація і застосування фіч es6 в контексті реакта.
- Master гілка Ruby on Rails Guides, де є найсвіжіші гайди по всьому, що є у master гілці rails.
Контакти
Якщо вам подобається те що я роблю, або ж не подобається, або ж хочете мене поправити, чи може допомогти, чи просто вам нудно і хочете з кимось поспілкуватись, можете мені написати:
- @terry-s в нашому чаті Gitter
- Вконтакті
- Або на пошту
Репозиторій постійно буде знаходитись за посиланням codeguida/fullstack-rr.
Ще немає коментарів