Я опубликовал обновленное руководство на 2020 год, в котором описаны улучшения и обновления экосистемы React. Начать работу сейчас намного проще, чем в 2017 году, когда было опубликовано это руководство. Направляйтесь туда, чтобы получить самую свежую информацию!
tl;dr
По-прежнему довольно сложно создать основы с помощью React с нуля; следуйте этому руководству или вместо этого клонируйте это репо!
Фон
Я уже пару месяцев хотел научиться пользоваться React. На то есть множество причин, но для меня некоторые из них наиболее очевидны:
- Мы используем его в Stripe для некоторых наших объектов, и мне нравится свободно владеть нашим технологическим стеком, хотя я работаю над маркетингом.
- Такие технологии, как Webpack 2 и babel, действительно интересны.
- Вокруг этого много шума, и я хочу знать, почему!
По мере того, как я пытался копаться и извлекать уроки из множества учебных пособий, я обнаружил, что ландшафт React и его периферийные инструменты постоянно меняются в наши дни. Это также означает, что очень сложно просто добраться до базовой настройки, чтобы поиграть с самим React.
Лично я каждый раз, запуская npm init
, сталкивался с тысячей руководств, которые не вполне работали - либо я клонировал репозитории git с устаревшими версиями пакетов, либо они включали инструмент, который я не нужны, или они не применяли лучшие сегодняшние практики. И ни один из них не покажет вам, как развернуть приложение в таком месте, как Heroku, и получить все, что ж, просто работает.
Примечание: Почему не
create-react-app
? Ну, это определенно ближе всего к тому, что я хотел. Однако он не позволяет производить дополнительную настройку конфигурации webpack или какой-либо поддержки SASS без предварительного извлечения, поэтому мы идем дальше :(
Итак, после прочтения многих, многих руководств (и многократных ударов головой о стол) я внес все необходимые изменения и, наконец, создал основу для своего простого приложения.
Я думал, что задокументирую все, что нужно, чтобы добраться сюда, чтобы другие на моем месте могли добраться до стартовой линии немного быстрее.
«Стек»
Этот учебник поможет вам:
- создать многостраничное приложение React, которое будет бесплатно размещено на Heroku.
- Мы будем использовать React Router для обслуживания разных вещей по разным URL.
- Также будем использовать Webpack (и настроим поддержку babel и SASS).
- Мы тонко обернем встроенный webpack-dev-сервер Webpack в Express для фактического обслуживания наших страниц.
Примечания
После прочтения многих, многих руководств этот «стек», кажется, включает в себя наиболее популярные инструменты для хорошей отправной точки для погружения в React.
Я использовал лучшие практики там, где их знал, но вряд ли это будет высокопроизводительное приложение, поскольку я все еще учусь и ищу новые пути - я буду обновлять этот блог по мере того, как узнаю больше.
Пожалуйста, свяжитесь с нами или создайте запрос на перенос, если что-то не так.
Предпосылки
Это руководство предполагает знакомство с общими концепциями веб-разработки и JavaScript. С тактической точки зрения предполагается, что вы установили:
- Узел (включая npm):
$ node -v v7.5.0 $ npm -v v4.1.2
$ git --version git version 2.11.1
Настройка файла
Хорошо, приступим. Я собираюсь создать двухстраничный веб-сайт с «домашней» страницей и страницей «свяжитесь со мной».
$ mkdir -p about-me && cd about-me $ npm init
Вы можете либо заполнить подсказки, когда npm init
, либо просто нажать Enter до конца. Теперь у вас в папке должен быть файл с именем package.json
.
about-me/ └── package.json
Пока мы это делаем, давайте также создадим репозиторий git. Мы также позаботимся о том, чтобы не помещать в репозиторий тысячи файлов, которые вскоре будут заполнены путем установки пакетов узлов:
$ git init $ touch .gitignore && echo 'node_modules' > .gitignore
Теперь давайте создадим необходимую нам структуру каталогов:
$ touch Procfile && touch server.js && touch webpack.config.js && touch webpack.config.dev.js && mkdir -p src/components/views && mkdir -p src/stylesheets && touch index.html && touch src/index.jsx && touch src/routes.jsx && touch src/components/app.jsx && touch src/components/views/home.jsx && touch src/components/views/contact.jsx && touch src/stylesheets/base.scss && touch src/stylesheets/home.scss && touch src/stylesheets/contact.scss
Теперь наш каталог должен выглядеть так:
about-me/ ├── src/ | ├── components/ | | ├── app.jsx | | └── views/ | | ├── home.jsx | | └── contact.jsx | ├── index.jsx | ├── routes.jsx | └── stylesheets/ | ├── base.scss | ├── home.scss | └── contact.scss ├── .gitignore ├── index.html ├── package.json ├── Procfile ├── server.js ├── webpack.config.js └── webpack.dev.config.js
Откройте папку в любом редакторе - я использую SublimeText. (С SublimeText я рекомендую установить плагины для выделения формата JSX и SCSS.) Вот как сейчас выглядит структура папок и файлов:
Пришло время установить некоторые зависимости для ядра React, а также обслуживание и маршрутизацию:
$ npm i --save react react-dom react-router $ npm i --save express body-parser
Затем давайте установим webpack с несколькими зависимостями для переноса scss и jsx в css и js:
$ npm i --save webpack webpack-dev-server webpack-dev-middleware
webpack-hot-middleware
$ npm i --save [email protected]
$ npm i --save babel-core babel-loader babel-preset-es2015 babel-preset-react node-sass sass-loader css-loader style-loader
(Примечание: важно установить нестандартную версию extract-text-plugin, поскольку она несовместима с последней версией Webpack.)
База и маршрутизация
Давайте настроим нашу страницу index.html для доступа к скомпилированным js и css:
<!DOCTYPE html> <html> <head> <link rel="stylesheet" type="text/css" href="/public/app.css" /> </head> <body> <div id="app"></div> <script type="text/javascript" src="/public/bundle.js" charset="utf-8"></script> </body> </html>
Маршрутизация
Мы используем модуль под названием react-router
, чтобы React отображал разные представления для разных URL-адресов.
Мы будем использовать index.jsx, чтобы настроить наш маршрутизатор и получить нужные файлы SCSS…
import React from 'react'; import ReactDom from 'react-dom'; import { Router, browserHistory } from 'react-router'; import routes from './routes'; require('./stylesheets/base.scss'); require('./stylesheets/home.scss'); require('./stylesheets/contact.scss'); ReactDom.render( <Router history={browserHistory} routes={routes} />, document.querySelector('#app') );
… И routes.jsx, чтобы определить их:
import React from 'react'; import { Route, IndexRoute } from 'react-router'; import App from './components/app'; import Home from './components/views/home'; import Contact from './components/views/contact'; export default ( <Route path='/' component={App}> <IndexRoute component={Home} /> <Route path='contact' component={Contact} /> <Route path='*' component={Home} /> </Route> );
Как видите, путь / будет направлен на app.jsx, и мы настроим два представления для / (home.jsx) и / contact (contact.jsx). Мы также указываем, что любой неуказанный URL-адрес должен обслуживать нашу домашнюю страницу.
Представления и контроллеры
Теперь мы можем настроить некоторые из простых контроллеров для разных страниц, которые мы хотим обслуживать:
Вот как выглядит app.jsx:
import React, { Component } from "react"; export default class App extends Component { render() { return ( <div> {this.props.children} </div> ); } }
Он ничего не делает, кроме как настраивает шаблон для отображения представлений, которые мы настроим следующим, начиная с home.jsx:
import React, { Component } from "react"; import { browserHistory } from 'react-router'; export default class Home extends Component { componentDidMount() { browserHistory.push('/'); } render() { return ( <div id="home"> This is the home page. </div> ); } }
Поскольку это представление для всех, я предпочитаю изменить URL-адрес на /, если кто-то попадет в это представление. (например, если я действительно запрошу / shop, мы откроем главный экран и изменим URL-адрес на /.)
Вот очень похожий contact.jsx:
import React, { Component } from "react"; export default class Contact extends Component { render() { return ( <div id="contact"> This is the contact me page. </div> ); } }
Стиль
Давайте настроим несколько фиктивных файлов SASS, чтобы увидеть, как все проверяется при компиляции. Начиная с base.scss…
$var: blue; body { background: $var; }
… Затем contact.scss…
#contact { color: #fff }
… И, наконец, home.scss:
#home { color: red; }
Эти файлы мы в конечном итоге будем использовать для хранения стилей CSS для конкретной страницы.
Экспресс и Webpack
Мы собираемся использовать express
как очень тонкую оболочку для веб-пакета при развертывании нашего приложения.
Прежде всего, давайте внесем небольшое изменение в package.json, чтобы сообщить ему, что он использует нашу версию Node в качестве движка и изменит точку входа с index.js на server.js:
... "main": "server.js", "engines": { "node": ">=7.5.0" }, ...
Чтобы запустить приложение, нам нужно настроить два файла конфигурации для webpack, которые соответствуют средам prod и dev.
webpack.config.js:
const ExtractTextPlugin = require('extract-text-webpack-plugin'); var webpack = require('webpack'); module.exports = { context: __dirname, entry: "./src/index.jsx", output: { path: __dirname + '/public', filename: "bundle.js", publicPath: '/public/' }, module: { loaders: [ { test: /\.js|.jsx?$/, exclude: /(node_modules)/, loader: 'babel-loader', query: { presets: ['react', 'es2015'] } }, { test: /\.scss$/, loader: ExtractTextPlugin.extract('css-loader!sass-loader') } ] }, resolve: { extensions: ['.js', '.jsx'], }, plugins: [ new ExtractTextPlugin({ filename: 'app.css', allChunks: true }) ], devServer: { historyApiFallback: true, contentBase: './' } };
webpack.config.dev.js
var path = require('path'); var webpack = require('webpack'); module.exports = { context: __dirname, entry: "./src/index.jsx", output: { path: path.resolve(__dirname, 'public/'), filename: "bundle.js", publicPath: '/public/' }, module: { loaders: [ { test: /\.js|.jsx?$/, exclude: /(node_modules)/, loader: 'babel-loader', query: { presets: ['react', 'es2015'] } }, { test: /\.scss$/, loader: 'style-loader!css-loader!sass-loader?sourceMap' } ] }, resolve: { extensions: ['.js', '.jsx'], }, plugins: [ new webpack.HotModuleReplacementPlugin() ], devServer: { historyApiFallback: true, contentBase: './' } };
И наконец, наш файл server.js выглядит так:
var path = require('path'); var bodyParser = require('body-parser'); var express = require('express'); var webpack = require('webpack'); var config = require('./webpack.config.dev.js'); var app = express(); var compiler = webpack(config); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(require('webpack-dev-middleware')(compiler, { noInfo: true, publicPath: config.output.publicPath })); app.use(require('webpack-hot-middleware')(compiler)); app.use('/public', express.static('public')); app.get('*', function(req, res) { res.sendFile(path.resolve(__dirname, 'index.html')); }); app.listen(process.env.PORT || 5000, function(err) { if (err) { console.log(err); return; } console.log('Listening at http://localhost:5000'); });
Запуск нашего сайта
Давайте обновим наш файл package.json, добавив несколько скриптов, чтобы упростить запуск наших серверов:
... "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --hot --inline", "start": "node server.js" }, ...
Теперь, когда все настроено, вы можете запускать:
npm run dev
(Это подберет параметры нашего webpack.config.dev.js.)
Если вы посетите http: // localhost: 8080 /, вы должны увидеть:
Если вы хотите запустить сайт в соответствии с нашей производственной установкой, вы можете запустить:
npm start
Если вы посетите http: // localhost: 5000 / contact, вы должны увидеть:
Развертывание на Heroku
Совершить
Если пока все выглядит хорошо, давайте перейдем к git:
$ git add . $ git commit -am "initial scaffolding for about-me app"
Настройка Heroku
Я предполагаю, что вы создали учетную запись и следовали их руководству, чтобы настроить интерфейс командной строки Heroku.
Первое развертывание
Внутри файла Procfile добавьте следующее:
web: node server
Затем вы можете выполнить шаги на странице документации Heroku, чтобы развернуть приложение:
$ heroku create $ git push heroku master $ heroku ps:scale web=1 $ heroku open
Вот и все! Наше простое приложение теперь работает на Heroku!
Мысли на прощание
Этот урок оставляет вас только в самом начале. Теперь вы можете начать создавать это простое приложение по своему усмотрению, настроив все вещи и начав экспериментировать с различными частями этого конкретного «стека» React.
Хотя мне будет сложно поддерживать это руководство в актуальном состоянии, я настоятельно призываю вас отправить запрос на перенос в репозиторий, если вы заметите что-то неладное!
Спасибо за прочтение :)