create-react-app (CRA) и создать собственный шаблон для React-приложений. Здесь речь пойдёт о преимуществах и недостатках CRA, а так же будет предложено решение, которое способно заменить create-react-app.
Что такое CRA?
Create React App — это набор инструментов, созданный и поддерживаемый разработчиками из Facebook. CRA предназначен для быстрого создания шаблонных проектов React-приложений. При использовании CRA база React-проекта создаётся с помощью одной команды.
Сильные стороны CRA
- CRA позволяет создать базу для React-проекта одной командой:
npx create-react-app my-app - Использование CRA избавляет разработчика от необходимости глубокого изучения вспомогательных инструментов. Разработчик может сосредоточиться на React и не беспокоиться о настройке Webpack, Babel и других служебных механизмов.
- При применении CRA разработчику требуется лишь одна зависимость, имеющая отношение к сборке проекта. Это —
react-scripts. Эта зависимость включает в себя все остальные зависимости сборки, в результате оказывается, что, например, для установки и обновления зависимостей достаточно одной команды:npm install react-scripts@latest
Недостатки CRA
- При использовании CRA усложняется использование собственных конфигураций сборки проектов. Один из способов обхода этого ограничения заключается в использовании команды
eject, но это лишает CRA-проекты преимущества в виде единственной зависимости сборки. Ещё один способ использования собственных конфигураций заключается в применении пакетов наподобие customize-cra или react-app-rewired, но подобные конфигурации отличаются ограниченными возможностями. - CRA скрывает от разработчика внутренние механизмы вспомогательных подсистем проектов. React-разработчик должен знать о том, что именно происходит в ходе подготовки React-приложения к реальной работе. Но так как в CRA используется уже не раз упомянутая «политика одной зависимости», у начинающего разработчика может возникнуть впечатление того, что
react-scripts— это единственная зависимость, которая нужна для запуска React-приложения. Начинающий может попросту не знать о том, что, на самом деле,react-scripts— это, по сути, лишь «упаковка» для транспилятора (Babel) и бандлера (Webpack), которые играют ведущую роль в подготовке React-приложений к реальной работе. Я, признаться, и сам этого не знал до тех пор, пока не прочитал этот замечательный материал. - CRA, как мне кажется, перегружен возможностями, которые, в каком-то проекте, вполне могут оказаться невостребованными. Например, заготовки приложений, создаваемые с помощью CRA, поддерживают SASS. То есть, если в проекте используется обычный CSS или Less, поддержка SASS окажется совершенно ненужной. Вот, если интересно, файл
package.jsonCRA-приложения после командыeject. В этом файле «развёрнуты» зависимости, раньше представленныеreact-scripts.
Альтернативой CRA может стать разработка собственного шаблона для быстрого создания базовых React-проектов.
Альтернатива CRA
Разрабатывая альтернативу CRA, мы собираемся оснастить её возможностью быстрого, с использованием лишь одной команды, создания базовых React-проектов. Это повторяет одну из полезных возможностей create-react-app. А недостатки CRA мы, конечно, в нашу систему переносить не будем, самостоятельно устанавливая зависимости и настраивая проект. В наш проект не попадут две других полезных возможности CRA (избавление разработчика от необходимости изучения вспомогательных механизмов и схема «одной зависимости»), так как они несут с собой и недостатки (сокрытие внутренних механизмов вспомогательных подсистем от разработчика и сложность настройки собственных конфигураций сборки проектов).
Вот репозиторий, в котором имеется весь код, который мы будем обсуждать в этом материале.
Начнём работу с инициализации проекта средствами npm и с инициализации его git-репозитория:
npm init git init
Создадим файл .gitignore следующего содержания:
node_modules build
Это позволит нам не включать в состав репозитория папки, имена которых присутствуют в файле.
Теперь поразмыслим о том, какие основные зависимости нам нужны для того чтобы собрать и запустить React-приложение.
Библиотеки react и react-dom
Это — единственные зависимости времени выполнения, которые нам нужны:
npm install react react-dom --save
Транспилятор (Babel)
Транспилятор Babel преобразует код, соответствующий стандартам ECMAScript 2015+, в код, который будет работать и в новых, и в устаревших браузерах. Babel, благодаря применению пресетов, используется и для обработки JSX-кода:
npm install @babel/core @babel/preset-env @babel/preset-react --save-dev
Вот как выглядит простая конфигурация Babel, предназначенная для подготовки к работе React-приложений. Эту конфигурацию можно добавить в файл .babelrc или в package.json:
{ "presets": [ "@babel/preset-env", "@babel/preset-react" ] }
Babel поддерживает множество пресетов и плагинов. Их можно добавлять в проект по мере возникновения необходимости в них.
Бандлер (Webpack)
Бандлер Webpack отвечает за сборку проекта, формируя на основе кода проекта и кода его зависимостей единственный файл (бандл) приложения. При использовании таких техник оптимизации проектов, как разделение кода, в бандл приложения могут входить и несколько файлов.
npm install webpack webpack-cli webpack-dev-server babel-loader css-loader style-loader html-webpack-plugin --save-dev
Простая конфигурация Webpack, предназначенная для сборки пакетов React-приложений, выглядит так, как показано ниже:
const path = require('path'); const HtmlWebPackPlugin = require('html-webpack-plugin'); module.exports = { output: { path: path.resolve(__dirname, 'build'), filename: 'bundle.js', }, resolve: { modules: [path.join(__dirname, 'src'), 'node_modules'], alias: { react: path.join(__dirname, 'node_modules', 'react'), }, }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', }, }, { test: /\.css$/, use: [ { loader: 'style-loader', }, { loader: 'css-loader', }, ], }, ], }, plugins: [ new HtmlWebPackPlugin({ template: './src/index.html', }), ], };
Сюда, в соответствии с нуждами конкретного приложения, можно добавить различные загрузчики. Если вам эта тема интересна — взгляните на мой материал, где я рассказываю о конфигурациях Webpack, которыми можно воспользоваться для подготовки React-приложений к использованию в продакшне.
Это — все необходимые нам зависимости. Теперь давайте добавим в проект шаблонный HTML-файл и заготовку React-компонента.
Создадим в директории проекта папку src и добавим в неё файл index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React Boilerplate</title> </head> <body> <div id="root"></div> </body> </html>
В той же папке создадим React-компонент HelloWorld:
import React from 'react'; const HelloWorld = () => { return ( <h3>Hello World</h3> ); }; export default HelloWorld;
В ту же папку добавим файл index.js:
import React from 'react'; import { render } from 'react-dom'; import HelloWorld from './HelloWorld'; render(<HelloWorld />, document.getElementById('root'));
И наконец — добавим в package.json описания скриптов для запуска (start) и сборки (build) проекта:
"scripts": { "start": "webpack-dev-server --mode=development --open --hot", "build": "webpack --mode=production" }
Вот и всё. Теперь в нашем распоряжении имеется работоспособная заготовка React-приложения. Убедиться в этом можно, выполнив команды npm start и npm run build.
Теперь давайте оснастим нашу систему возможностью подготовки шаблона проекта с помощью единственной команды. То есть — воссоздадим одну из сильных сторон CRA. Мы собираемся использовать исполняемый JS-файл, который будет вызываться при вводе соответствующей команды в командной строке. Например, подобная команда может выглядеть так:
reactjs-boilerplate new-project
Для реализации этой идеи мы собираемся воспользоваться разделом bin файла package.json.
Сначала установим пакет fs-extra:
npm i fs-extra
Теперь создадим исполняемый JS-файл start.js, который будет расположен в папке bin нашего проекта. Поместим в этот файл следующий код:
#!/usr/bin/env node const fs = require("fs-extra"); const path = require("path"); const https = require("https"); const { exec } = require("child_process"); const packageJson = require("../package.json"); const scripts = `"start": "webpack-dev-server --mode=development --open --hot", "build": "webpack --mode=production"`; const babel = `"babel": ${JSON.stringify(packageJson.babel)}`; const getDeps = (deps) => Object.entries(deps) .map((dep) => `${dep[0]}@${dep[1]}`) .toString() .replace(/,/g, " ") .replace(/^/g, "") // исключим зависимость, используемую только в этом файле, не относящуюся к шаблону .replace(/fs-extra[^\s]+/g, ""); console.log("Initializing project.."); // создадим папку и инициализируем npm-проект exec( `mkdir ${process.argv[2]} && cd ${process.argv[2]} && npm init -f`, (initErr, initStdout, initStderr) => { if (initErr) { console.error(`Everything was fine, then it wasn't: ${initErr}`); return; } const packageJSON = `${process.argv[2]}/package.json`; // заменим скрипты, задаваемые по умолчанию fs.readFile(packageJSON, (err, file) => { if (err) throw err; const data = file .toString() .replace( '"test": "echo \\"Error: no test specified\\" && exit 1"', scripts ) .replace('"keywords": []', babel); fs.writeFile(packageJSON, data, (err2) => err2 || true); }); const filesToCopy = ["webpack.config.js"]; for (let i = 0; i < filesToCopy.length; i += 1) { fs.createReadStream(path.join(__dirname, `../${filesToCopy[i]}`)).pipe( fs.createWriteStream(`${process.argv[2]}/${filesToCopy[i]}`) ); } // npm, при установке пакета, удалит файл .gitignore, поэтому его нельзя скопировать из локальной папки шаблона; этот файл нужно загрузить. После отправки кода в GitHub-репозиторий пользуйтесь raw-файлом .gitignore https.get( "https://raw.githubusercontent.com/Nikhil-Kumaran/reactjs-boilerplate/master/.gitignore", (res) => { res.setEncoding("utf8"); let body = ""; res.on("data", (data) => { body += data; }); res.on("end", () => { fs.writeFile( `${process.argv[2]}/.gitignore`, body, { encoding: "utf-8" }, (err) => { if (err) throw err; } ); }); } ); console.log("npm init -- done\n"); // установка зависимостей console.log("Installing deps -- it might take a few minutes.."); const devDeps = getDeps(packageJson.devDependencies); const deps = getDeps(packageJson.dependencies); exec( `cd ${process.argv[2]} && git init && node -v && npm -v && npm i -D ${devDeps} && npm i -S ${deps}`, (npmErr, npmStdout, npmStderr) => { if (npmErr) { console.error(`Some error while installing dependencies ${npmErr}`); return; } console.log(npmStdout); console.log("Dependencies installed"); console.log("Copying additional files.."); // копирование дополнительных файлов с кодом fs.copy(path.join(__dirname, "../src"), `${process.argv[2]}/src`) .then(() => console.log( `All done!\n\nYour project is now ready\n\nUse the below command to run the app.\n\ncd ${process.argv[2]}\nnpm start` ) ) .catch((err) => console.error(err)); } ); } );
Теперь давайте свяжем этот исполняемый JS-файл с командой из package.json:
"bin": { "your-boilerplate-name": "./bin/start.js" }
Создадим локальную связь для пакета:
npm link
Теперь, после выполнения этой команды, если в терминале выполнить команду вида your-boilerplate-name my-app, будет вызван наш исполняемый файл start.js. Он создаст новую папку с именем my-app, скопирует в неё файлы package.json, webpack.config.js и .gitignore, а так же папку src, и установит зависимости нового проекта my-app.
Замечательно. Теперь всё это работает на вашем компьютере и позволяет вам, пользуясь единственной командой, создавать базовые React-проекты, обладающие собственной конфигурацией сборки.
Вы можете пойти дальше и опубликовать свой шаблон в реестре npm. Для того чтобы это сделать, сначала надо отправить проект в GitHub-репозиторий. А дальше — следуйте этим инструкциям.
Примите поздравления! Только что мы, буквально за несколько минут, создали альтернативу create-react-app. Наше решение не перегружено ненужными возможностями (в проекты, созданные на его основе, можно добавлять зависимости по мере возникновения необходимости в них). Пользуясь им, можно легко подстраивать конфигурацию сборки проекта под свои нужды.
Конечно, наше решение минималистично. Проекты, создаваемые на его основе, нельзя признать готовыми к использованию в продакшне. Для того чтобы подготовить их к реальной работе, нужно оснастить наш шаблон некоторыми настройками Webpack, ответственными за оптимизацию сборок проектов.
Я подготовил шаблон reactjs-boilerplate, позволяющий создавать проекты, готовые к работе в продакшне. Тут используется соответствующая конфигурация сборки, линтинг и хуки, ответственные за проверку проекта перед созданием коммитов. Испытайте этот шаблон. Если у вас появятся какие-то идеи по его совершенствованию, или если вы решите сделать вклад в его разработку — присоединяйтесь к работе над ним.
Итоги
Вот о чём мы говорили в этом материале:
- Мы разобрали плюсы и минусы
create-react-app. - Мы реализовали в своём проекте полезную возможность CRA по созданию заготовок React-приложений одной командой. А от недостатков CRA мы избавились.
- Мы оснастили свой проект минимальными конфигурациями Webpack и Babel, необходимыми для сборки и запуска React-приложений.
- Мы создали React-компонент
HelloWorld.js, предусмотрели возможность сборки проекта и его запуска с использованием сервера разработки. - Мы создали исполняемый JS-файл и связали его с соответствующей командой, воспользовавшись разделом
binфайлаpackage.json. - Мы воспользовались командой
npm linkс целью создания локальной связи для нашего проекта и получения возможности создавать новые базовые проекты на его основе с помощью единственной команды.
Надеюсь, этот материал поможет вам в деле разработки проектов, основанных на React.
Пользуетесь ли вы create-react-app при создании новых React-проектов?
ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/515008/


Добавить комментарий