One place for hosting & domains

      приложения

      Создание и настройка проекта React с помощью приложения Create React App


      Автор выбрал Creative Commons для получения пожертвования в рамках программы Write for DOnations.

      Введение

      React — популярная система JavaScript для создания клиентских приложений. Первоначально эта система была разработана Facebook и быстро стала популярной, поскольку она позволяет разработчикам создавать быстрые приложения на основе интуитивно понятной парадигмы программирования, соединяющей JavaScript с похожим на HTML синтаксисом под названием JSX.

      Раньше для создания нового проекта React требовался сложный процесс, состоящий из множества шагов и включающий систему для сборки, компилятор для конвертации современного синтаксиса в читаемый всеми браузерами код, а также базовую структуру директорий. Однако сейчас появилось приложение Create React App, включающее все пакеты JavaScript, необходимые для запуска проекта React, включая системы компиляции кода, проверки соблюдения стандартов кодирования, тестирования и сборки. Также приложение включает сервер с функцией горячей перезагрузки, обновляющей страницу при внесении изменений в код. Также оно создает структуру директорий и компонентов, позволяя перейти к программированию уже через несколько минут.

      Другими словами, вам не нужно беспокоиться о настройке Webpack или другой системы сборки. Вам не нужно настраивать Babel для компиляции кода для совместимости с разными браузерами. Вам не нужно беспокоиться о работе со сложными системами разработки современных клиентских интерфейсов. Вы можете начать создание кода React с минимумом начальной подготовки.

      К завершению этого обучающего руководства у вас будет работающее приложение React, которое вы сможете использовать как основу для любых будущих приложений. Вы внесете первые изменения в код React, обновите стили и выполните сборку для создания полностью минифицированной версии вашего приложения. Также вы будете использовать сервер с горячей перезагрузкой, чтобы мгновенно получать обратную связь и детально изучать компоненты проекта React. Наконец, вы начнете писать собственные компоненты и создадите структуру, которая сможет расти и адаптироваться вместе с вашим проектом.

      Предварительные требования

      Для прохождения этого обучающего руководства вам потребуется следующее:

      • Node.js версии 10.16.0, установленный на вашем компьютере. Чтобы установить его в macOS или Ubuntu 18.04, следуйте указаниям руководства Установка Node.js и создание локальной среды разработки в macOS или раздела Установка с помощью PPA руководства Установка Node.js в Ubuntu 18.04.

      • Также вам нужно понимать основы языка JavaScript, для изучения которого вам подойдет серия Программирование на JavaScript, а также обладать базовыми знаниями языков HTML и CSS.

      Шаг 1 — Создание нового проекта с помощью приложения Create React App

      На этом шаге мы создадим новое приложение, используя диспетчер пакетов npm для запуска удаленного скрипта. Скрипт скопирует необходимые файлы в новую директорию и установит все зависимости.

      При установке Node вы также установили приложение для управления пакетами npm. npm установит пакеты JavaScript для вашего проекта и будет отслеживать детали проекта. Если вы хотите узнать больше об npm, воспользуйтесь обучающим руководством Использование модулей Node.js с npm и package.json.

      npm также включает инструмент npx, отвечающий за запуск исполняемых пакетов. Это означает, что вы сможете запускать код приложения Create React App без предварительной загрузки проекта.

      Используемый пакет выполнит установку create-react-app в указанную вами директорию. Для начала он создаст в директории новый пакет, которому в этом обучающем руководстве мы присвоим имя digital-ocean-tutorial. Если этой директории не существует, исполняемый пакет просто создаст ее. Скрипт также запустит команду npm install в директории проекта для загрузки всех дополнительных зависимостей.

      Для установки базового проекта выполните следующую команду:

      • npx create-react-app digital-ocean-tutorial

      Эта команда запустит процесс сборки, во время которого будет загружен базовый код вместе с определенным числом зависимостей.

      После успешного выполнения скрипта вы увидите соответствующее сообщение:

      Output

      ... Success! Created digital-ocean-tutorial at your_file_path/digital-ocean-tutorial Inside that directory, you can run several commands: npm start Starts the development server. npm run build Bundles the app into static files for production. npm test Starts the test runner. npm run eject Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back! We suggest that you begin by typing: cd digital-ocean-tutorial npm start Happy hacking!

      your_file_path будет текущим путем. Если вы используете macOS, путь будет выглядеть как /Users/your_username; а если вы используете сервер Ubuntu — /home/your_username.

      Также вы увидите список команд npm для выполнения, сборки, запуска и тестирования вашего приложения. Более подробно вы узнаете об этом в следующем разделе.

      Примечание. Также для JavaScript можно использовать диспетчер пакетов yarn. Он поддерживается Facebook и во многом аналогичен по функционалу npm. Изначально в yarn были добавлены некоторые новые функции, такие как блокировка файлов, однако сейчас они реализованы и в npm. Кроме того, в yarn имеются и другие функции, такие как кэширование в автономном режиме. О других отличиях можно узнать из документации по yarn.

      Если вы ранее устанавливали yarn в вашей системе, вы увидите список команд yarn, таких как yarn start. Эти команды работают так же, как и команды npm. Вы можете запускать команды npm, даже если у вас установлен yarn. Если вы предпочитаете yarn, просто заменяйте npm на yarn во всех будущих командах. Результат будет точно таким же.

      Теперь ваш проект настроен в новой директории. Перейдите в новую директорию:

      • cd digital-ocean-tutorial

      Теперь вы находитесь в корневой директории вашего проекта. Вы уже создали новый проект и добавили в него все зависимости. Однако вы не предприняли никаких действий для запуска проекта. В следующем разделе вы научитесь использовать пользовательские скрипты для сборки и тестирования проекта.

      Шаг 2 — Использование скриптов react-scripts

      На этом шаге вы узнаете о различных скриптах react-scripts, устанавливаемых вместе с репозиторием. Вначале вы запустите скрипт test для выполнения тестового кода. Затем вы запустите скрипт build для создания минифицированной версии. В заключение вы узнаете, как использовать скрипт eject для полного контроля персонализированной настройки.

      Перейдите в директорию проекта и изучите ее. Вы можете открыть всю директорию в текстовом редакторе или вывести файлы из него в терминале с помощью следующей команды:

      Флаг -a обеспечивает добавление в вывод скрытых файлов.

      В любом случае вы увидите примерно следующую структуру:

      Output

      node_modules/ public/ src/ .gitignore README.md package-lock.json package.json

      Расскажем обо всех элементах подробнее:

      • node_modules/ содержит все внешние библиотеки JavaScript, используемые приложением. Вам нечасто потребуется использовать его.

      • Директория public/ содержит базовые файлы HTML, JSON и изображений. Это корневые ресурсы вашего проекта. Вы сможете узнать о них более подробно на шаге 4.

      • В директории src/ содержится код React JavaScript для вашего проекта. В основном вы будете работать именно с этой директорией. Более подробно мы расскажем об этой директории на шаге 5.

      • Файл .gitignore содержит несколько директорий и файлов по умолчанию, которые система контроля исходного кода git будет игнорировать, в том числе директорию node_modules. Игнорируемые элементы — это большие директории или файлы журнала, которые не нужны при контроле исходного кода. Также здесь указаны некоторые директории, которые вы создадите с помощью некоторых скриптов React.

      • README.md — это файл разметки, содержащий много полезной информации о приложении Create React App, в том числе обзор команд и ссылки на расширенные опции конфигурации. Сейчас лучше оставить файл README.md в первозданном виде. По мере развития проекта вы будете заменять данные по умолчанию более подробной информацией о вашем проекте.

      Последние два файла используются вашим диспетчером пакетов. При запуске первоначальной команды npx вы создали базовый проект, а также установили дополнительные зависимости. При установке зависимостей вы создали файл package-lock.json. Этот файл используется npm для проверки точного соответствия версий пакетов. Так вы можете быть уверены, что если кто-то другой установит ваш проект, у него будут идентичные зависимости. Поскольку этот файл создается автоматически, вам нечасто потребуется редактировать его.

      Последний файл — package.json. Он содержит метаданные о вашем проекте, включая заголовок, номер версии и зависимости. Также он содержит скрипты, которые вы можете использовать для запуска проекта.

      Откройте файл package.json в предпочитаемом текстовом редакторе:

      Открыв файл, вы увидите объект JSON, содержащий все метаданные. Если посмотреть на объект scripts, вы увидите, что он содержит четыре разных скрипта: start, build, test и eject.

      Эти скрипты перечислены в порядке важности. Первый скрипт запускает локальную среду разработки, к чему мы перейдем на следующем шаге. Второй скрипт выполняет сборку вашего проекта. Вы узнаете об этом более подробно на шаге 4, но лучше запустить его сейчас и посмотреть, что произойдет.

      Скрипт build

      Для запуска любого скрипта npm нужно просто ввести в терминале команду npm run script_name. Существует несколько особых скриптов, где можно опустить run в составе команды, но вводить команду полностью никогда не будет ошибкой. Чтобы запустить скрипт build, введите в терминале следующую команду:

      Вы немедленно увидите следующее сообщение:

      Output

      > digital-ocean-tutorial@0.1.0 build your_file_path/digital-ocean-tutorial > react-scripts build Creating an optimized production build... ...

      Это покажет вам, что приложение Create React App компилирует ваш код в пригодный для использования пакет.

      После завершения вы увидите следующее:

      Output

      ... Compiled successfully. File sizes after gzip: 39.85 KB build/static/js/9999.chunk.js 780 B build/static/js/runtime-main.99999.js 616 B build/static/js/main.9999.chunk.js 556 B build/static/css/main.9999.chunk.css The project was built assuming it is hosted at the server root. You can control this with the homepage field in your package.json. For example, add this to build it for GitHub Pages: "homepage" : "http://myname.github.io/myapp", The build folder is ready to be deployed. You may serve it with a static server: serve -s build Find out more about deployment here: bit.ly/CRA-deploy

      Выведите содержимое проекта, и вы увидите несколько новых директорий:

      Output

      build/ node_modules/ public/ src/ .gitignore README.md package-lock.json package.json

      Теперь у вас появилась директория build. Если вы открывали файл .gitignore, вы могли заметить, что директория build игнорируется git. Это связано с тем, что директория build просто представляет собой минифицированную и оптимизированную версию других файлов. Контроль версий не требуется, поскольку вы можете в любое время запустить команду build. О результатах выполнения этого скрипта мы поговорим чуть позже, а пока что перейдем к скрипту test.

      Скрипт test

      Скрипт test — один из специальных скриптов, для которых не требуется ключевое слово run, однако он будет работать и с этим ключевым словом. Этот скрипт запускает программу тестирования Jest. Программа тестирования ищет в проекте файлы с расширением .spec.js или .test.js, а затем запускает эти файлы.

      Для запуска скрипта test введите следующую команду:

      После запуска этого скрипта на вашем терминале будут выведены результаты тестирования, а командная строка терминала будет скрыта. Он будет выглядеть примерно так:

      Output

      PASS src/App.test.js ✓ renders learn react link (67ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 4.204s Ran all test suites. Watch Usage › Press f to run only failed tests. › Press o to only run tests related to changed files. › Press q to quit watch mode. › Press p to filter by a filename regex pattern. › Press t to filter by a test name regex pattern. › Press Enter to trigger a test run.

      Здесь нужно обратить внимание на несколько вещей. Во-первых, как говорилось выше, тест автоматически обнаруживает все файлы с тестовыми расширениями, включая .test.js и .spec.js. В нашем случае у нас имеется только один тестовый набор, то есть только один файл с расширением .test.js, и этот набор содержит только один тест. Jest может обнаруживать тесты в иерархии кода, то есть вы можете размещать тесты в директории, и Jest найдет их там.

      Во-вторых, Jest не просто запускает тест один раз и закрывается. Он продолжает работать в терминале. Если вы внесете изменения в исходный код, он проведет тесты снова.

      Также вы можете ограничить состав запускаемых тестов, использовав одну из опций с клавиатуры. Например, если вы наберете o, тесты будут выполняться только с файлами, в которые были внесены изменения. Это поможет вам сэкономить много времени при увеличении объемов тестовых наборов.

      Для выхода из системы тестирования следует ввести q. Сделайте это сейчас, чтобы вернуться в командную строку.

      Скрипт eject

      Последний скрипт называется npm eject. Этот скрипт копирует зависимости и файлы конфигурации в ваш проект, обеспечивая полный контроль над кодом, но при этом извлекая проект из интегрированной системы инструментов приложения Create React App. Сейчас мы не будем запускать этот скрипт, поскольку это действие нельзя отменить, а при его запуске вы потеряете все будущие обновления приложения Create React App.

      Ценность приложения Create React App заключается в том, что вам не нужно беспокоиться о значительном количестве аспектов настройки конфигурации. Для создания современных приложений JavaScript требуется множество разных инструментов, от Webpack и других сборочных систем до Babel и других средств компиляции. Приложение Create React App выполняет за вас все задачи по настройке конфигурации, поэтому извлечение проекта из приложения означает, что вам придется вносить все сложные настройки самостоятельно.

      Минус приложения Create React App заключается в том, что вы не можете полностью персонализировать проект. Для большинства проектов это неважно, однако если вы захотите полностью контролировать все аспекты процесса сборки, вам нужно будет выполнить извлечение кода. Однако, как мы уже говорили выше, после извлечения кода вы не сможете обновлять его с новыми версиями приложения Create React App, и вам придется вручную добавлять все улучшения.

      На данный момент вы выполнили скрипты для сборки и тестирования вашего кода. На следующем шаге мы запустим проект на рабочем сервере.

      Шаг 3 — Запуск сервера

      На этом шаге вы инициализируете локальный сервер и запустите проект в своем браузере.

      Для запуска проекта используется еще один скрипт npm. Как и скрипт npm test, этот скрипт не требует использования команды run. Этот скрипт запускает локальный сервер, выполняет код проекта, запускает программу отслеживания изменений кода и открывает проект в браузере.

      Запустите проект, введя следующую команду в корневой директории проекта. В данном обучающем руководстве в качестве корневой директории проекта выступает директория digital-ocean-tutorial. Откройте ее на отдельном терминале или вкладке, поскольку этот скрипт будет работать все время, пока вы это разрешаете:

      Перед запуском сервера вы ненадолго увидите замещающий текст, а потом появится следующий экран:

      Output

      Compiled successfully! You can now view digital-ocean-tutorial in the browser. http://localhost:3000 Note that the development build is not optimized. To create a production build, use npm run build.

      Если вы запускаете скрипт в локальной системе, он откроет проект в окне браузера и переключит фокус с терминала на браузер.

      Если этого не произойдет, вы можете открыть URL-адрес http://localhost:3000/, чтобы увидеть сайт в работе. Если на порту 3000 уже запущен другой сервер, это не представляет проблемы. Приложение Create React App найдет следующий доступный порт и запустит сервер на нем. Другими словами, если у вас уже запущен проект на порту 3000, новый проект будет запущен на порту 3001.

      При запуске с удаленного сервера вы все равно сможете увидеть свой сайт без дополнительной настройки. Он будет иметь адрес http://your_server_ip:3000. Если у вас включен и настроен брандмауэр, вам нужно будет открыть данный порт на удаленном сервере.

      В браузере вы увидите следующий шаблон проекта React:

      Шаблон проекта React

      Пока скрипт работает, у вас будет активный локальный сервер. Для остановки скрипта следует закрыть окно или вкладку терминала или ввести CTRL+C или ⌘-+c в окне или на вкладке терминала, где выполняется ваш скрипт.

      Вы запустили сервер, и ваш первый код React уже выполняется. Прежде чем вносить любые изменения в код React JavaScript, вам нужно увидеть рендеринг React на странице.

      Шаг 4 — Изменение главной страницы

      На этом шаге мы изменим код в директории public/. В директории public содержится ваша базовая страница HTML. Эта страница будет выступать в качестве корневой для вашего проекта. В будущем вам редко придется изменять эту директорию, однако она представляет собой основу запуска проекта и является ключевой частью проекта React.

      Если вы отключили сервер, запустите его с помощью команды npm start, а затем откройте public/ в предпочитаемом текстовом редакторе в новом окне терминала:

      Также вы можете вывести список файлов с помощью команды ls:

      Вы увидите список файлов следующего вида:

      Output

      favicon.ico logo192.png manifest.json index.html logo512.png robots.txt

      favicon.ico, logo192.png и logo512.png — это значки, которые пользователь будет видеть на вкладке браузера или в телефоне. Браузер автоматически выберет значок подходящего размера. Впоследствии вы можете заменить их на другие значки, которые лучше подойдут для вашего проекта. Пока же вы можете использовать их как есть.

      Файл manifest.json содержит структурированный набор метаданных, описывающий ваш проект. Помимо прочего, в нем указывается, какие значки следует использовать для разных размеров экрана.

      Файл robots.txt содержит информацию для поисковых роботов. Он указывает роботам, какие страницы можно индексировать, а какие нельзя. Вам не нужно изменять ни один из этих файлов, если у вас нет на это важных причин. Например, если вы хотите дать некоторым пользователям URL для доступа к особому контенту, который не должен быть общедоступным, вы можете добавить этот URL в файл robots.txt, и он останется общедоступным, но не будет индексироваться поисковыми системами.

      Файл index.html представляет собой корневую часть вашего приложения. Именно этот файл считывает сервер, и именно его отображает ваш браузер. Откройте файл в текстовом редакторе и посмотрите на него.

      Если вы работаете из командной строки, вы можете использовать следующую команду:

      Вот что вы увидите:

      digital-ocean-tutorial/public/index.html

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8" />
          <link rel="icon" href="https://www.digitalocean.com/%PUBLIC_URL%/favicon.ico" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <meta name="theme-color" content="#000000" />
          <meta
            name="description"
            content="Web site created using create-react-app"
          />
          <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
          <!--
            manifest.json provides metadata used when your web app is installed on a
            user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
          -->
          <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
          <!--
            Notice the use of %PUBLIC_URL% in the tags above.
            It will be replaced with the URL of the `public` folder during the build.
            Only files inside the `public` folder can be referenced from the HTML.
      
            Unlike "https://www.digitalocean.com/favicon.ico" or "favicon.ico", "https://www.digitalocean.com/%PUBLIC_URL%/favicon.ico" will
            work correctly both with client-side routing and a non-root public URL.
            Learn how to configure a non-root public URL by running `npm run build`.
          -->
          <title>React App</title>
        </head>
        <body>
          <noscript>You need to enable JavaScript to run this app.</noscript>
          <div id="root"></div>
          <!--
            This HTML file is a template.
            If you open it directly in the browser, you will see an empty page.
      
            You can add webfonts, meta tags, or analytics to this file.
            The build step will place the bundled scripts into the <body> tag.
      
            To begin the development, run `npm start` or `yarn start`.
            To create a production bundle, use `npm run build` or `yarn build`.
          -->
        </body>
      </html>
      

      Сам файл довольно короткий. В части <body> нет изображений или слов. Это связано с тем, что React самостоятельно строит всю структуру HTML и вставляет ее с помощью JavaScript. Однако React нужно знать, куда вставлять код, и для этого и используется файл index.html.

      В текстовом редакторе измените значение тега <title> с React App на Sandbox:

      digital-ocean-tutorial/public/index.html

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8" />
          <link rel="icon" href="https://www.digitalocean.com/%PUBLIC_URL%/favicon.ico" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <meta name="theme-color" content="#000000" />
          ...
          <title>Sandbox</title>
        </head>
        <body>
          <noscript>You need to enable JavaScript to run this app.</noscript>
          <div id="root"></div>
          <!--
            This HTML file is a template.
            If you open it directly in the browser, you will see an empty page.
      
            You can add webfonts, meta tags, or analytics to this file.
            The build step will place the bundled scripts into the <body> tag.
      
            To begin the development, run `npm start` or `yarn start`.
            To create a production bundle, use `npm run build` or `yarn build`.
          -->
        </body>
      </html>
      
      

      Сохраните изменения и закройте текстовый редактор. Откройте файл в браузере. Заголовок отображается на вкладке браузера и должен обновиться автоматически. Если этого не произойдет, обновите страницу и посмотрите на изменения.

      Теперь вернитесь в текстовый редактор. Каждый проект React начинается с корневого элемента. На странице может быть несколько корневых элементов, но один должен присутствовать обязательно. Так React узнает, куда поместить сгенерированный код HTML. Найдите элемент <div id="root">. Этот элемент div будет использоваться React для всех будущих обновлений. Измените id с root на base:

      digital-ocean-tutorial/public/index.html

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8" />
          ...
        <body>
          <noscript>You need to enable JavaScript to run this app.</noscript>
          <div id="base"></div>
          <!--
            This HTML file is a template.
            If you open it directly in the browser, you will see an empty page.
      
            You can add webfonts, meta tags, or analytics to this file.
            The build step will place the bundled scripts into the <body> tag.
      
            To begin the development, run `npm start` or `yarn start`.
            To create a production bundle, use `npm run build` or `yarn build`.
          -->
        </body>
      </html>
      

      Сохраните изменения.

      В браузере вы увидите сообщение об ошибке:

      Сообщение об ошибке гласит «Target container is not a DOM element» (целевой контейнер не является элементом DOM)

      React искал элемент с id root. Теперь этого элемента нет, и React не может запустить проект.

      Измените имя с base на root:

      digital-ocean-tutorial/public/index.html

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8" />
          ...
        <body>
          <noscript>You need to enable JavaScript to run this app.</noscript>
          <div id="root"></div>
          <!--
            This HTML file is a template.
            If you open it directly in the browser, you will see an empty page.
      
            You can add webfonts, meta tags, or analytics to this file.
            The build step will place the bundled scripts into the <body> tag.
      
            To begin the development, run `npm start` or `yarn start`.
            To create a production bundle, use `npm run build` or `yarn build`.
          -->
        </body>
      </html>
      

      Сохраните и закройте файл index.html.

      Вы запустили сервер и внесли небольшое изменение в корневую страницу HTML. Пока еще вы не меняли код JavaScript. В следующем разделе мы начнем изменять код React JavaScript.

      Шаг 5 — Изменение тега заголовка и стилей

      На этом шаге вы внесете первое изменение в компонент React в директории src/. Вы внесете небольшое изменение в код CSS и JavaScript, который будет автоматически обновляться в браузере с помощью встроенной функции горячей перезагрузки.

      Если вы остановили сервер, обязательно перезапустите его с помощью команды npm start. Познакомьтесь с содержимым директории src/. Вы можете открыть полную директорию в предпочитаемом текстовом редакторе или вывести проект на терминал с помощью следующей команды:

      Вы увидите в терминале или текстовом редакторе следующие файлы.

      Output

      App.css App.js App.test.js index.css index.js logo.svg serviceWorker.js setupTests.js

      Рассмотрим каждый из этих файлов по отдельности.

      Вначале вы не будете тратить много времени на файл serviceWorker.js, но он может оказаться важным, когда вы начнете создавать прогрессивные веб-приложения. Сервисный рабочий может выполнять много разных задач, в том числе отправлять push-уведомления и обеспечивать кэширование в автономном режиме, но пока что мы не будем его трогать.

      Далее взглянем на файлы setupTests.js и App.test.js. Они используются для тестовых файлов. При запуске npm test на шаге 2 скрипт уже запускал эти файлы. Файл setupTests.js небольшой и содержит несколько настраиваемых методов expect. Вы узнаете о них больше в следующих обучающих руководствах этой серии.

      Откройте файл App.test.js:

      Когда вы откроете этот файл, вы увидите простой тест:

      digital-ocean-tutorial/src/App.test.js

      import React from 'react';
      import { render } from '@testing-library/react';
      import App from './App';
      
      test('renders learn react link', () => {
        const { getByText } = render(<App />);
        const linkElement = getByText(/learn react/i);
        expect(linkElement).toBeInTheDocument();
      });
      

      Этот тест проверяет наличие в документе фразы learn react. Если вы вернетесь в браузер, где запущен ваш проект, вы увидите фразу на странице. Тестирование React отличается от большинства блочных тестов. Поскольку компоненты могут содержать и визуальную информацию (например разметку), и логику управления данными, традиционные блочные тесты могут не сработать. Тестирование React скорее является формой функционального тестирования или тестирования интеграции.

      Далее вы видите несколько файлов стилей: App.css, index.css и logo.svg. Существует много вариантов работы со стилями в React, но проще всего написать простой код CSS, не требующий дополнительной настройки.

      Здесь имеется несколько файлов CSS, поскольку вы можете импортировать стили в компонент, как если бы они представляли собой другой файл JavaScript. Поскольку у вас имеется возможность импортировать CSS в компонент напрямую, вы также можете разделить файл CSS для его применения к отдельному компоненту. Так вы разделяете области беспокойства. Вы не храните все файлы CSS отдельно от JavaScript. Вместо этого все элементы CSS, JavaScript, разметки и изображений сгруппированы вместе.

      Откройте файл App.css в предпочитаемом текстовом редакторе. Если вы работаете из командной строки, вы можете использовать следующую команду:

      Вы увидите следующий код:

      digital-ocean-tutorial/src/App.css

      .App {
        text-align: center;
      }
      
      .App-logo {
        height: 40vmin;
        pointer-events: none;
      }
      
      @media (prefers-reduced-motion: no-preference) {
        .App-logo {
          animation: App-logo-spin infinite 20s linear;
        }
      }
      
      .App-header {
        background-color: #282c34;
        min-height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        font-size: calc(10px + 2vmin);
        color: white;
      }
      
      .App-link {
        color: #61dafb;
      }
      
      @keyframes App-logo-spin {
        from {
          transform: rotate(0deg);
        }
        to {
          transform: rotate(360deg);
        }
      }
      

      Это стандартный файл CSS без специальных инструментов предварительной обработки CSS. Если хотите, вы можете добавить их позднее, но вначале у вас будут только простые файлы CSS. Создатели приложения Create React App старались не делать его безапелляционным, но при этом предоставить полностью готовую среду.

      Вернемся к файлу App.css. Одно из преимуществ приложения Create React заключается в том, что оно наблюдает за всеми файлами, и при внесении изменения вы увидите его в браузере без перезагрузки.

      Чтобы увидеть это, внесем небольшое изменение в параметр background-color в файле App.css. Измените его с #282c34 на blue, а затем сохраните файл. Окончательный стиль будет выглядеть следующим образом:

      digital-ocean-tutorial/src/App.css

      .App {
        text-align: center;
      }
      ...
      .App-header {
        background-color: blue
        min-height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        font-size: calc(10px + 2vmin);
        color: white;
      }
      ...
      
      @keyframes App-logo-spin {
        from {
          transform: rotate(0deg);
        }
        to {
          transform: rotate(360deg);
        }
      }
      

      Проверьте браузер. Вот как это выглядело раньше:

      Приложение React с темным фоном

      Вот как это будет выглядеть после изменения:

      Приложение React с синим фоном

      Измените значение background-color обратно на #282c34.

      digital-ocean-tutorial/src/App.css

      .App {
        text-align: center;
      
      ...
      
      .App-header {
        background-color: #282c34
        min-height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        font-size: calc(10px + 2vmin);
        color: white;
      }
      
      ...
      
      @keyframes App-logo-spin {
        from {
          transform: rotate(0deg);
        }
        to {
          transform: rotate(360deg);
        }
      }
      

      Сохраните и закройте файл.

      Вы внесли небольшое изменение в файл CSS. Теперь внесем изменения в код React JavaScript. Для начала откройте файл index.js.

      Вы увидите следующее:

      digital-ocean-tutorial/src/index.js

      import React from 'react';
      import ReactDOM from 'react-dom';
      import './index.css';
      import App from './App';
      import * as serviceWorker from './serviceWorker';
      
      ReactDOM.render(<App />, document.getElementById('root'));
      
      // If you want your app to work offline and load faster, you can change
      // unregister() to register() below. Note this comes with some pitfalls.
      // Learn more about service workers: https://bit.ly/CRA-PWA
      serviceWorker.unregister();
      

      Прежде всего, вы импортируете React, ReactDOM, index.css, App и serviceWorker. Импортируя React, вы фактически извлекаете код для конвертации JSX в JavaScript. JSX — это элементы в стиле HTML. Обратите внимание, что при использовании App вы обращаетесь с ним как с элементом HTML <App />. Вы узнаете об этом подробнее из следующих обучающих руководств этой серии.

      ReactDOM — это код, который связывает ваш код React с базовыми элементами, такими как страница index.html, которую мы увидели в public/. Посмотрите на следующую выделенную строку:

      digital-ocean-tutorial/src/index.js

      ...
      import * as serviceWorker from './serviceWorker';
      
      ReactDOM.render(<App />, document.getElementById('root'));
      ...
      serviceWorker.unregister();
      

      Этот код предписывает React найти элемент с id root и вставить в него код React. <App/> — это корневой элемент, от которого идут все ответвления. Это исходная точка для всего будущего кода React.

      Вверху файла имеется несколько операций импорта. Мы импортируем index.css, но ничего не делаем с этим файлом. Импортируя его, мы предписываем Webpack через скрипты React включить этот код CSS в окончательную скомпилированную версию пакета. Если его не импортировать, он не будет отображаться.

      Выйдите из файла src/index.js.

      Пока что вы еще не видели ничего, что вы видите в браузере. Чтобы увидеть это, откройте файл App.js:

      Код в этом файле выглядит как набор стандартных элементов HTML. Вы увидите следующее:

      digital-ocean-tutorial/src/App.js

      import React from 'react';
      import logo from './logo.svg';
      import './App.css';
      
      function App() {
        return (
          <div className="App">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <p>
                Edit <code>src/App.js</code> and save to reload.
              </p>
              <a
                className="App-link"
                href="https://reactjs.org"
                target="_blank"
                rel="noopener noreferrer"
              >
                Learn React
              </a>
            </header>
          </div>
        );
      }
      
      export default App;
      

      Измените содержимое тега <p> с Edit <code>src/App.js</code> and save to reload. на Hello, world и сохраните изменения.

      digital-ocean-tutorial/src/App.js

      ...
      
      function App() {
        return (
          <div className="App">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <p>
                  Hello, world
              </p>
              <a
                className="App-link"
                href="https://reactjs.org"
                target="_blank"
                rel="noopener noreferrer"
              >
                Learn React
              </a>
            </header>
          </div>
        );
      }
      ...
      

      Переключитесь в браузер, и вы увидите изменения:

      Приложение React с текстом "Hello, world" в теге абзаца

      Вы внесли первое изменение в компонент React.

      Прежде чем заканчивать, обратите внимание еще на несколько вещей. В этом компоненте мы импортируем файл logo.svg и назначаем его переменной. Затем в элементе <img> мы добавляем этот код как src.

      Здесь происходит еще несколько вещей. Посмотрите на элемент img:

      digital-ocean-tutorial/src/App.js

      ...
      function App() {
        return (
          <div className="App">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <p>
                  Hello, world
              </p>
      ...
      

      Обратите внимание, как вы передаете logo в фигурных скобках. Каждый раз, когда вы передаете атрибуты, которые не являются строками или числами, вам нужно будет использовать фигурные скобки. React обрабатывает их как элементы JavaScript, а не как строки. В этом случае вы не импортируете образ, а ссылаетесь на него. Когда Webpack выполняет сборку проекта, он обрабатывает образ и задает для источника соответствующее место.

      Закройте текстовый редактор.

      Если вы посмотрите на элементы DOM в браузере, вы увидите, что он добавляет путь. Если вы используете Chrome, вы можете просмотреть элемент, щелкнув его правой кнопкой мыши и выбрав пункт Inspect.

      Вот как это будет выглядеть в браузере:

      Инспектирование элемента с помощью инструментов chrome для разработчиков

      В DOM содержится следующая строка:

      <img src="https://www.digitalocean.com/static/media/logo.5d5d9eef.svg" class="App-logo" alt="logo">
      

      Ваш код будет немного отличаться, поскольку у логотипа другое имя. Webpack нужно убедиться, что путь изображения уникальный. Так что даже если вы импортируете изображения с одинаковым именем, они будут сохраняться на разных путях.

      Вы внесли небольшое изменение в код React JavaScript. На следующем шаге мы используем команду build для минификации кода в небольшой файл, который можно будет развернуть на сервере.

      Шаг 6 — Сборка проекта

      На этом шаге мы выполним сборку проекта в пакет, который можно будет развернуть на внешних серверах.

      Вернитесь в терминал и выполните сборку проекта. Вы уже запускали эту команду, но напомним, что она запускает скрипт build. В результате будет создан новая директория с комбинированными и минифицированными файлами. Для выполнения сборки запустите следующую команду из корневой директории проекта:

      Возможна небольшая задержка, пока код будет компилироваться, а после завершения компиляции будет создана новая директория build/.

      Откройте build/index.html в текстовом редакторе.

      Вы увидите примерно следующее:

      digital-ocean-tutorial/build/index.html

      <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="https://www.digitalocean.com/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="http://www.digitalocean.com/logo192.png"/><link rel="manifest" href="http://www.digitalocean.com/manifest.json"/><title>React App</title><link href="http://www.digitalocean.com/static/css/main.d1b05096.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,a,p=r[0],l=r[1],c=r[2],i=0,s=[];i<p.length;i++)a=p[i],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,c||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,p=1;p<t.length;p++){var l=t[p];0!==o[l]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/";var p=this["webpackJsonpdo-create-react-app"]=this["webpackJsonpdo-create-react-app"]||[],l=p.push.bind(p);p.push=r,p=p.slice();for(var c=0;c<p.length;c++)r(p[c]);var f=l;t()}([])</script><script src="/static/js/2.c0be6967.chunk.js"></script><script src="/static/js/main.bac2dbd2.chunk.js"></script></body></html>
      

      В директории сборки весь код компилируется и минифицируется до наименьшего полезного состояния. Читаемость кода неважна, поскольку этот код не предназначен для чтения человеком. При такой минификации код занимает намного меньше места, но при этом работает. В отличие от таких языков как Python, пробел не меняет интерпретацию кода компьютером.

      Заключение

      В этом обучающем руководстве вы создали свое первое приложение React и настроили проект с помощью инструментов сборки JavaScript без необходимости вдаваться в технические детали. В этом и заключается польза приложения Create React App: вам не нужно знать все, чтобы начать работу. Приложение позволяет игнорировать сложные этапы сборки и сосредоточиться исключительно на коде React.

      Вы изучили команды для запуска, тестирования и сборки проекта. Вы будете использовать эти команды регулярно, так что запомните их для будущих обучающих руководств. Не менее важно, что вы изменили свой первый компонент React.

      Если вы хотите увидеть React в действии, пройдите обучающее руководство Отображение данных из DigitalOcean API с помощью React.



      Source link

      Создание приложения с вдохновляющими цитатами с помощью AdonisJs и MySQL


      Автор выбрал Tech Education Fund для получения пожертвования в рамках программы Write for DOnations.

      Введение

      AdonisJs — это веб-инфраструктура Node.js, написанная на простом языке JavaScript, поддерживаемом всеми основными операционными системами. Она использует популярную схему MVC (модель — представление — контроллер) и предлагает стабильную экосистему для написания серверной части веб-приложений. Инфраструктура поддерживает удобную аутентификацию, SQL ORM (реляционные карты объектов), миграцию и пополнение баз данных. Архитектура AdonisJs похожа на архитектуру веб-инфраструктуры Laravel для приложений PHP и имеет такую же структуру папок и несколько сходных концепций настройки.

      По умолчанию AdonisJs использует систему шаблонов Edge, разработанную для интуитивно простого использования. Как и в Laravel, в AdonisJs имеется система ORM под названием Lucid, служащая интерфейсом для взаимодействия между моделями приложения и базой данных. С помощью AdonisJs разработчики могут создавать комплексные приложения, где серверная часть отвечает за применение бизнес-логики, маршрутизацию и рендеринг всех страниц приложения. Также можно создать API веб-служб для возврата ответов JSON от контроллера. Эти веб-службы можно использовать с помощью клиентских инфраструктур, таких как Vue.js, React и Angular.

      В этом обучающем руководстве мы создадим приложение с помощью AdonisJs, используя CLI. Мы создадим маршруты, контроллеры, модели и представления приложения, а также проведем проверки форм. В качестве примера для этого обучающего руководства мы выбрали приложение, в которое пользователь может входить для создания вдохновляющих цитат. Это демонстрационное приложение позволит выполнять операции создания, чтения, обновления и удаления (CRUD).

      Предварительные требования

      Для прохождения этого обучающего руководства вам потребуется следующее:

      • Локальная установка Node.js (версия не ниже 8) и npm (версия не ниже 3.0). Node.js — это среда исполнения на базе JavaScript, позволяющая выполнять код за пределами браузера. Она содержит предустановленный диспетчер пакетов npm, позволяющий устанавливать и обновлять пакеты. Чтобы установить его в macOS или Ubuntu 18.04, следуйте указаниям руководства Установка Node.js и создание локальной среды разработки в macOS или раздела Установка с помощью PPA руководства Установка Node.js в Ubuntu 18.04.
      • Установленная на компьютере СУБД MySQL. Следуйте приведенным здесь инструкциям для ее загрузки и установки в выбранной операционной системе. Для успешной установки MySQL можно использовать Homebrew для Mac или следовать указаниям руководства Установка MySQL в Ubuntu 18.04 для установки этой СУБД в Ubuntu 18.04.
      • Понимание основных принципов JavaScript; ознакомьтесь с нашей серией Программирование на JavaScript.
      • Установленный текстовый редактор, например Visual Studio Code, Atom или Sublime Text.

      Примечание. Для разработки в этом обучающем руководстве будет использоваться компьютер под управлением macOS. Если вы используете другую операционную систему, вам может потребоваться использовать права sudo для выполнения команд npm на первых шагах.

      Шаг 1 — Установка Adonis CLI

      В этом разделе мы установим Adonis CLI и все его требуемые пакеты на наш локальный компьютер. CLI позволяет создать структуру нового проекта AdonisJs, а также создать и сгенерировать шаблоны контроллеров, связующих элементов и моделей в вашем приложении. Также вы создадите базу данных для проекта.

      Выполните следующую команду для глобальной установки AdonisJs CLI на компьютере с помощью npm:

      После завершения процесса установки введите в терминал следующую команду для подтверждения установки AdonisJs и просмотра текущей версии:

      Вы увидите вывод с указанием текущей версии AdonisJs:

      Output

      4.1.0

      Мы успешно установили AdonisJs CLI и теперь можем использовать команду adonis для установки новых проектов AdonisJs, управления проектами и генерирования требуемых файлов, в том числе контроллеров, моделей и т. д.

      Теперь мы можем перейти к созданию нового проекта AdonisJs, используя команду adonis, как показано здесь:

      • adonis new adonis-quotes-app

      Приведенная выше команда создаст приложение adonis-quotes-app в новой директории с тем же именем внутри директории локального проекта, используя соответствующую структуру AdonisJs MVC.

      Перейдите в папку нового приложения:

      Запустите приложенеи с помощью следующей команды:

      Эта команда запустит сервер разработки на порту по умолчанию 3333, как указано внутри файла root .env для вашего приложения. Введите адрес http://localhost:3333 для просмотра приветственной страницы AdonisJs.

      Приветственная страница AdonisJs

      Теперь мы завершим настройку базы данных. Здесь вы установите драйвер mysql для подключения к вашему серверу MySQL из вашего приложения Node.js с помощью npm. Для начала вернитесь в терминал, где запущено приложение, остановите процесс нажатием CTRL + C и запустите следующую команду:

      Вы успешно установили драйвер MySQL Node.js для этого приложения, и теперь вам нужно создать базу данных приложения и настроить подключение к ней.

      Последняя версия MySQL, установленная согласно указаниям предварительных требований обучающего руководства, использует плагин аутентификации по умолчанию под названием caching_sha2_password. Этот плагин в настоящее время не поддерживается драйверами Node.js для MySQL. Чтобы избежать проблем при подключении вашего приложения к базе данных, вам нужно будет создать нового пользователя MySQL и использовать поддерживаемый плагин аутентификации mysql_native_password.

      Для начала откройте клиент MySQL, используя учетную запись root:

      В диалоге введите пароль учетной записи root, заданный во время установки MySQL.

      Затем создайте пользователя и пароль, используя плагин mysql_native_password:

      • CREATE USER 'sammy'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';

      Результат будет выглядеть следующим образом:

      Output

      Query OK, 0 rows affected (0.02 sec)

      Создайте базу данных приложения с помощью следующей команды:

      Результат будет выглядеть следующим образом:

      Output

      Query OK, 1 row affected (0.03 sec)

      Вы успешно создали базу данных для своего приложения.

      Теперь активируйте доступ к созданной базе данных для нового пользователя MySQL. Запустите следующую команду для предоставления всех привилегий пользователю в базе данных:

      • GRANT ALL PRIVILEGES ON adonis.* TO 'sammy'@'localhost';

      Перезагрузите таблицы grant, запустив следующую команду для применения внесенных изменений:

      Результат будет выглядеть следующим образом:

      Output

      Query OK, 0 rows affected (0.00 sec)

      Закройте клиент MySQL с помощью следующей команды:

      Мы успешно установили AdonisJs CLI, создали новый проект AdonisJs и выполнили установку mysql с помощью npm. Также мы создали базу данных для этого приложения и настроили пользователя MySQL с соответствующими правами доступа к нему. Базовая конфигурация приложения готова, и на следующем шаге мы начнем создавать необходимые представления для вашего приложения.

      Шаг 2 — Использование системы шаблонов Edge

      AdonisJs поставляется с собственной системой шаблонов Edge. Это позволяет создать многоразовый шаблон HTML и внести в приложение логику клиентской части с минимальным объемом кода. Edge дает разработчикам приложений JavaScript инструменты для создания схемы на базе компонентов, написания условных выражений, использования итераций и создания уровней представлений для хранения логики. Все файлы шаблонов с расширением .edge хранятся в директории resources/views.

      Далее указаны представления, необходимые приложению для надлежащей работы:

      • Генеральный макет. С помощью Edge вы можете создать страницу, содержащую таблицы CSS, общие файлы JavaScript, jQuery и части пользовательского интерфейса, которые будут едиными для всего приложения, в том числе панель навигации, логотип, заголовок и т. д. После создания генерального макета он будет наследоваться другими представлениями (страницами) вашего приложения.
      • Представление указателя. Эта страница будет использовать генеральный макет для наследования общих файлов, а также выполнять рендеринг содержимого для главной страницы приложения.
      • Страница входа. Эта страница также будет использовать генеральный макет, а также будет выполнять рендеринг формы с полями ввода имени пользователя и пароля для входа пользователей в систему.
      • Страница регистрации. Здесь пользователи найдут форму для регистрации и сохранения своих реквизитов в базе данных.
      • Страница создания цитаты. Пользователи будут использовать эту страницу для создания вдохновляющих цитат.
      • Страница редактирования цитаты. Пользователи будут использовать эту страницу для редактирования цитат.
      • Страница просмотра цитаты. Пользователи будут использовать эту страницу для просмотра определенных цитат.

      Для начала используйте команду adonis для создания страницы генерального макета, как показано здесь:

      • adonis make:view layouts/master

      Результат будет выглядеть примерно так:

      Output

      ✔ create resources/views/layouts/master.edge

      Эта команда автоматически создаст файл master.edge в папке resources/views/layouts. Откройте новый файл:

      • nano resources/views/layouts/master.edge

      Добавьте в него следующий код:

      /resources/views/layouts/master.edge

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>adonis-quotes-app</title>
          {{ style('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css') }}
          {{ style('style') }}
          {{ script('https://code.jquery.com/jquery-3.3.1.slim.min.js') }}
      </head>
      <body>
          <div class="container-fliud">
              @include('navbar')
              @!section('content')
          </div>
          {{ script('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js') }}
      
      </body>
      </html>
      

      В этот файл добавляются файлы CDN для Bootstrap CSS, Bootstrap JavaScript и jQuery. Также добавляется имя глобального файла CSS style.css, а в div добавляется частичный файл с именем navbar. Для повторного использования требуемых фрагментов кода HTML (например, nav или footer) на разных страницах приложения можно использовать частичные файлы. Это небольшие файлы, содержащие повторяющийся код и позволяющие быстро обновлять код этих элементов в одном месте, а не на каждой странице по отдельности. Файл navbar содержит разметку для кнопок Вход и Регистрация, логотип и ссылку на главную страницу.

      С этим файлом все последующие страницы этого приложения смогут использовать генеральный макет и выводить панель навигации без написания соответствующего кода для каждой страницы. Мы создадим этот файл navbar на следующих шагах этого обучающего руководства.

      В заключение мы определим тэг раздела @! section(), чтобы включить контент других страниц и обеспечить их рендеринг в генеральном макете. Чтобы эта система работала ожидаемым образом, все новые страницы на основе генерального макета должны также определять тег раздела с одним и тем же именем (т. е. @section('content')).

      Сохраните и закройте файл, когда закончите его редактирование.

      Далее мы используем команду adonis для создания панели навигации:

      Результат будет выглядеть примерно так:

      Output

      ✔ create resources/views/navbar.edge

      Откройте созданный файл:

      • nano resources/views/navbar.edge

      Затем добавьте в него следующий код:

      /resources/views/navbar.edge

      <nav class="navbar navbar-expand-lg navbar-dark text-white">
          <a class="navbar-brand" >LOGO</a>
          <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
              <span class="navbar-toggler-icon"></span>
          </button>
      
          <div class="collapse navbar-collapse" id="navbarNav">
              <ul class="navbar-nav">
                  <li class="nav-item active ">
                      <a class="btn text-white" href="https://www.digitalocean.com/">Home</a>
                  </li>
              </ul>
          </div>
          <div class="navbar-right" id="navbarNav">
              @loggedIn
                  <ul class="navbar-nav">
                          <li>
                              <div class="text-right">
                                   <a href="{{route('create.quote')}}" class="btn btn-outline-primary">Create Quote</a>
                              </div>
                          </li>
      
                      <li class="nav-item dropdown">
                          <a class="nav-link dropdown-toggle" href="https://www.digitalocean.com/#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                             {{ auth.user.username}}
                          </a>
                          <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                              <form method="POST" action="{{route('logout')}}">
                                  {{ csrfField() }}
                                    <button  type="submit" class="dropdown-item" href="">logout</button>
                              </form>
                          </div>
                      </li>
                  </ul>
              @else
                  <ul class="navbar-nav">
                      <li class="nav-item active pr-2">
                          <a href="{{route('login.create')}}" class="btn btn-outline-danger">
                            login
                          </a>
                      </li>
                      <li class="nav-item active pr-2">
                          <a href="{{route('register.create')}}" class="btn btn-outline-primary">
                              Register
                          </a>
                      </li>
                  </ul>
              @endloggedIn
          </div>
      </nav>
      

      В дополнение к определениям ссылок на главную страницу и кнопок для регистрации и входа мы добавим тег @loggedIn. С этим тегом мы можем написать условное выражение для прошедшего аутентификацию пользователя и выводить соответствующее содержание, когда это требуется. Для прошедшего аутентификацию пользователя приложение отображает имя пользователя и кнопку создания новой цитаты. Если пользователь не прошел аутентификацию, приложение будет отображать кнопку для входа или регистрации. Эта страница будет добавляться как часть каждой другой страницы, как и в случае с генеральным макетом приложения.

      Сохраните и закройте файл.

      Теперь мы создадим страницу указателя, которую используем в качестве главной страницы приложения. Она выполняет рендеринг и выводит список всех вдохновляющих цитат, написанных пользователями:

      Вы увидите примерно следующий результат:

      Output

      ✔ create resources/views/index.edge

      Созданный нами файл будет располагаться в директории resources/views/index.edge. Откройте файл:

      • nano resources/views/index.edge

      Добавьте следующий код:

      /resources/views/index.edge

      @layout('layouts/master')
      @section('content')
      
      <div class="container">
          <div class="text-center">
              @if(flashMessage('successmessage'))
                  <span class="alert alert-success p-1">{{ flashMessage('successmessage') }}</span>
              @endif
          </div>
          <div class="row">
              @each(quote in quotes)
                  <div class="col-md-4 mb-4 quote-wrapper">
                      <a href="https://www.digitalocean.com/view-quote/{{quote.id}}" class="w-100">
                          <div class="card shadow-lg bg-dark text-white">
                              <div class="card-body">
                                  <blockquote class="blockquote mb-0">
                                      <p>{{quote.body}}</p>
                                      <footer class="blockquote-footer">
                                          <cite title="Source Title"> {{quote.username}}</cite>
                                      </footer>
                                  </blockquote>
                                  @if(auth.user.id == quote.user_id)
                                    <div>
                                      <a  href="http://www.digitalocean.com/edit-quote/{{quote.id}}" class="btn btn-primary">edit</a>
                                      <a href="http://www.digitalocean.com/delete-quote/{{quote.id}}" class="btn btn-danger">delete</a>
                                    </div>
                                  @endif
                              </div>
                          </div>
                      </a>
                  </div>
              @else
               <div class="col-md-12 empty-quote text-center">
                      <p>No inspirational quote has been created</p>
               </div>
              @endeach
          </div>
      </div>
      @endsection
      

      Здесь вы указываете, что это представление будет использовать макет master посредством его расширения. Теперь эта страница имеет доступ ко всем библиотекам, таблицам стилей и файлу navbar в составе макета master. Далее мы выполним итерацию по массиву цитат, используя встроенный тег @each. Массив quotes будет передаваться в это представление из модуля QuoteController, который мы создадим на следующих шагах этого обучающего руководства. В случае отсутствия цитат будет выведено соответствующее сообщение.

      Сохраните и закройте файл.

      Для создания страницы входа запустите в терминале следующую команду:

      • adonis make:view auth/login

      Вы увидите примерно следующий результат:

      Output

      ✔ create resources/views/auth/login.edge

      Система автоматически создаст папку auth в директории resources/views, а также создаст в ней файл login.edge. Откройте файл login.edge:

      • nano resources/views/auth/login.edge

      Добавьте следующее содержимое:

      /resources/views/auth/login.edge

      @layout('layouts/master')
      @section('content')
        <div class="container">
          <div class="row">
            <div class="col-md-4 shadow bg-white mt-5 rounded offset-md-4">
              <form method="POST" action="{{route('login.store')}}">
                {{ csrfField() }}
                  <div>
                    @if(flashMessage('successmessage'))
                      <span class="alert alert-success p-1">{{ flashMessage('successmessage') }}</span>
                    @endif
                  </div>
                  <div class="form-group">
                    <label for="email">Email address</label>
                    <input type="email" class="form-control" id="email" name="email" value="{{old('email','')}}"  placeholder="Enter email">
                    {{ elIf('<span class=text-danger>$self</span>', getErrorFor('email'), hasErrorFor('email')) }}
                  </div>
                  <div class="form-group">
                    <label for="pasword">Password</label>
                    <input type="password" class="form-control" id="password" name="password" value="{{old('password','')}}" placeholder="Password">
                    {{ elIf('<span class=text-danger>$self</span>', getErrorFor('password'), hasErrorFor('password')) }}
                  </div>
      
                  <div class="text-center">
                    <button type="submit" class="btn btn-primary">Submit</button>
                  </div>
              </form>
            </div>
          </div>
        </div>
      @endsection
      

      В этом файле хранится форма, содержащая элементы ввода, которые вы будете использовать для получения имени пользователя и пароля зарегистрированного пользователя, прежде чем он сможет пройти аутентификацию и начать создавать цитаты. Еще один важный элемент на этой странице — {{ csrfField() }}. Это глобальная переменная, которую AdonisJs будет использовать для передачи токена доступа CSRF при отправке запросов POST, PUT и DELETE из приложения.

      Она размещена для защиты вашего приложения от атак методом подделки межсайтовых запросов (CSRF). Она работает посредством генерирования для каждого посещающего сайт пользователя уникального секрета CSRF. При отправке пользователями запроса HTTP через клиент для этого секрета генерируется соответствующий токен, передаваемый вместе с запросом. Это позволяет связующему элементу, создаваемому для этого запроса в AdonisJs, проверять корректность токена и секрета CSRF и их принадлежность пользователю, прошедшему аутентификацию.

      Сохраните и закройте файл после завершения.

      Далее мы создадим страницу регистрации, используя следующую команду:

      • adonis make:view auth/register

      Вы увидите примерно следующий вывод:

      Output

      ✔ create resources/views/auth/register.edge

      Найдите и откройте созданный файл в директории resources/views/auth/register.edge:

      • nano resources/views/auth/register.edge

      Добавьте следующий код:

      resources/views/auth/register.edge

      @layout('layouts/master')
      @section('content')
        <div class="container ">
          <div class="row">
              <div class="col-md-4  bg-white p-3 mt-5 shadow no-border rounded offset-md-4">
                <form method="POST" action="{{route('register.store')}}">
                  {{ csrfField() }}
                    <div class="form-group">
                      <label for="name">Fullname</label>
                      <input type="text" class="form-control" id="name" name="name"  value="{{old('name','')}}" placeholder="Enter Fullname">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('name'), hasErrorFor('name')) }}
                    </div>
                    <div class="form-group">
                      <label for="email">Email address</label>
                      <input type="email" class="form-control" id="email"  name="email" value="{{old('email','')}}" placeholder="Enter email">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('email'), hasErrorFor('email')) }}
                    </div>
                    <div class="form-group">
                      <label for="pasword">Password</label>
                      <input type="password" class="form-control" id="password" name="password" placeholder="Password">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('password'), hasErrorFor('password')) }}
                    </div>
                    <div class="text-center">
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </div>
                </form>
              </div>
          </div>
        </div>
      @endsection
      

      Как и в случае со страницей входа, этот файл содержит форму HTML с полями ввода имени, электронной почты и пароля пользователя при регистрации. Также здесь присутствует переменная {{ csrfField() }}, поскольку она требуется для каждого запроса post для приложения AdonisJs.

      Сохраните и закройте файл.

      Теперь мы сгенерируем новый файл для создания вдохновляющей цитаты, запустив следующую команду из терминала:

      • adonis make:view quotes/create-quote

      Вы увидите примерно следующее:

      Output

      ✔ create resources/views/quotes/create-quote.edge

      Откройте resources/views/quotes/create-quote.edge:

      • nano resources/views/quotes/create-quote.edge

      Добавьте следующее содержание:

      /resources/views/quotes/create-quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-3"></div>
              <div class="col-md-6 shadow bg-white mt-5 rounded p-3">
                  <div class="float-right">
                      <a href="https://www.digitalocean.com/" class="btn btn-outline-dark ">back</a>
                  </div>
                      <br>
      
                  <div class="clear-fix"></div>
                      <form method="POST" action="{{route('store.quote')}}">
                          {{ csrfField() }}
                          <div class="form-group">
                              <label for="quote">Create Quote</label>
                              <textarea type="text" rows="5"  name='body' id="body" class="form-control" id="quote" placeholder="Write an inspirational quote"></textarea>
                          </div>
      
                          <div class="text-center">
                              <button type="submit" class="btn btn-primary">Submit</button>
                          </div>
                      </form>
                  </div>
              </div>
              <div class="col-md-3"></div>
          </div>
      </div>
      @endsection
      

      Эта страница расширяет генеральный макет и содержит форму HTML с элементом текстовой области, позволяющим пользователю вводить текст в нескольких строках, после чего этот текст отправляется и обрабатывается по заданному маршруту.

      Сохраните и закройте файл после завершения.

      Далее мы создадим страницу для редактирования конкретной цитаты. Запустите в терминале следующую команду:

      • adonis make:view quotes/edit-quote

      Результат будет выглядеть следующим образом:

      Output

      ✔ create resources/views/quotes/edit-quote.edge

      Откройте файл с помощью следующей команды:

      • nano resources/views/quotes/edit-quote.edge

      Добавьте следующее содержание в файл resources/views/quotes/edit-quote:

      /resources/views/quotes/edit-quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-6 shadow bg-white rounded p-3 offset-md-3">
                  <div class="float-right">
                      <a href="https://www.digitalocean.com/" class="btn btn-outline-dark ">back</a>
                  </div>
                  <br>
      
                  <div class="clear-fix"></div>
                  <form method="POST" action="/update-quote/{{quote.id}}">
                      {{ csrfField() }}
                      <div class="form-group">
                          <label for="pasword">Edit Quote</label>
                          <textarea type="text" rows="5"  name='body' id="body" class="form-control" id="quote" placeholder="write the inspirational quote">{{quote.body}}</textarea>
                      </div>
                      <div class="text-center">
                          <button type="submit" class="btn btn-primary">Update</button>
                      </div>
      
                  </form>
              </div>
          </div>
      </div>
      @endsection
      

      Содержание этой страницы похоже на содержание файла create-quote.edge. Отличие заключается в том, что она содержит данные конкретной цитаты, которую нужно отредактировать: <form method="POST" action="/update-quote/{{quote.id}}">.

      Сохраните и закройте файл.

      В заключение мы сгенерируем страницу для просмотра одной вдохновляющей цитаты:

      • adonis make:view quotes/quote

      Вы увидите примерно следующий вывод:

      Output

      ✔ create resources/views/quotes/quote.edge

      Откройте файл с помощью следующей команды:

      • nano resources/views/quotes/quote.edge

      Добавьте следующий код:

      /resources/views/quotes/quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-6 offset-md-3">
                  <div class="card shadow-lg bg-dark text-white">
                      <div class="card-body">
                          <div class="float-right">
                              <a href="https://www.digitalocean.com/" class="btn btn-outline-primary ">back</a>
                          </div>
                              <br>
                          <div class="clear-fix"></div>
                          <blockquote class="blockquote mb-0">
                              <p>{{quote.body}}</p>
                              <footer class="blockquote-footer">
                                  <cite title="Source Title">{{quote.username}}</cite>
                              </footer>
                          </blockquote>
                      </div>
                  </div>
              </div>
          </div>
      </div>
      @endsection
      

      Эта страница выполняет рендеринг деталей конкретной цитаты, включая тело цитаты quote.body и пользователя, создавшего цитату, quote.username.

      После завершения работы с этим файлом сохраните и закройте его.

      Вы создали все требуемые страницы для вашего приложения, используя систему шаблонов Edge. Далее мы настроим и создадим подключение к базе данных нашего приложения.

      Шаг 3 — Создание схемы баз данных

      Если мы запустим приложение сейчас, оно выдаст ошибку, поскольку мы не подключили его к базе данных. В этом разделе мы настроим подключение к базе данных, а затем используем команду adonis для генерирования файла миграции, который будет использоваться для создания таблиц для нее.

      В комплект AdonisJs входит модель ORM под названием Lucid ORM, обеспечивающая реализацию активных записей для работы с базой данных. Эта модель избавляет от необходимости писать запросы SQL, извлекающие данные из базы данных в реальном времени. Это особенно полезно при работе над сложными приложениями, для которых требуется большое количество запросов. Например, мы можем получить все цитаты из нашего приложения с помощью следующей команды:

      const quotes = await Quote.all()
      

      Чтобы продолжить настройку базы данных приложения, необходимо убедиться, что вы все еще находитесь в корневой директории вашего приложения, и создать в ней файл .env:

      Откройте созданный файл и добавьте в него следующее содержание:

      .env

      HOST=127.0.0.1
      PORT=3333
      NODE_ENV=development
      APP_URL=http://${HOST}:${PORT}
      CACHE_VIEWS=false
      APP_KEY=bTVOEgUvmTCfkvgrK8gEBC3Qxt1xSYr0
      DB_CONNECTION=mysql
      DB_HOST=127.0.0.1
      DB_PORT=3306
      DB_USER=sammy
      DB_PASSWORD=password
      DB_DATABASE=adonis
      SESSION_DRIVER=cookie
      HASH_DRIVER=bcrypt
      

      По умолчанию для подключения приложений AdonisJs к базе данных используется СУБД SQLite, которую мы здесь заменим на MySQL. Также мы укажем PORT для приложения, среду приложения и учетные данные для входа в базу данных. Замените DB_USER, DB_PASSWORD и DB_DATABASE своими учетными данными для базы данных.

      Далее мы создадим модель и файл миграции для Quote, используя Adonis CLI. Для этого нужно запустить следующую команду:

      • adonis make:model Quote --migration

      Результат будет выглядеть примерно так:

      Output

      ✔ create app/Models/Quote.js ✔ create database/migrations/1568209992854_quote_schema.js

      Эта команда создаст модель Quote в папке app/Models и файл схемы в папке database/migrations. Созданный файл схемы будет иметь префикс с указанием текущей временной метки. Откройте файл схемы с помощью следующей команды:

      • nano database/migrations/1568209992854_quote_schema.js

      Обновите его содержимое с помощью следующего кода:

      database/migrations/…quote_schema.js

      'use strict'
      /** @type {import('@adonisjs/lucid/src/Schema')} */
      const Schema = use('Schema')
      class QuoteSchema extends Schema {
        up () {
          this.create('quotes', (table) => {
            table.increments()
            table.integer('user_id').notNullable()
            table.string('username', 80).notNullable()
            table.string('body').notNullable()
            table.timestamps()
          })
        }
        down () {
          this.drop('quotes')
        }
      }
      module.exports = QuoteSchema
      

      Для файла схемы в AdonisJs требуются два разных метода:

      • up: используется для создания новых таблиц и изменения существующих.
      • down: используется для отмены изменений, примененных с помощью метода up.

      В дополнение к полям timestamps() и increments() мы обновим содержание файла схемы, указав атрибуты полей user_id, username и body для создаваемой цитаты. В полях user_id и username указываются данные пользователя, создавшего определенную цитату. Файл построен по принципу отношения одного к многим. Это означает, что пользователю может принадлежать бесконечное количество цитат, а цитата может принадлежать только одному пользователю.

      Сохраните и закройте файл.

      В AdonisJs по умолчанию установлены модель User и ее файл миграции. В связи с этим требуется лишь небольшое изменение для установки отношения между моделями User и Quote.

      Откройте модель User в app/Models/User.js:

      Добавьте этот метод сразу же после метода tokens():

      app/Models/User.js

      ...
      class User extends Model {
        ...
        tokens () {
          return this.hasMany('App/Models/Token')
        }
      
        quote () {
          return this.hasMany('App/Models/Quote')
        }
      }
      
      module.exports = User
      

      Эта команда устанавливает отношение «один ко многим» с таблицей Quote, используя user_id как посторонний ключ.

      Сохраните и закройте файл.

      В завершение этого раздела мы используем для проведения миграции следующую команду, которая выполнит метод up() для всех файлов миграции:

      Вы увидите примерно следующий результат:

      Output

      migrate: 1503248427885_user.js migrate: 1503248427886_token.js migrate: 1568209992854_quote_schema.js Database migrated successfully in 3.42 s

      Мы настроили и защитили соединение с базой данных. Также мы создали модель Quote и соответствующий файл схемы и создали отношение один ко многим между моделями User и Quote. Далее мы сгенерирурем маршруты и создадим контроллеры для обработки запросов HTTP и бизнес-логики для создания, изменения и удаления вдохновляющей цитаты.

      Шаг 4 — Создание контроллеров и настройка маршрутов

      В этом разделе мы начнем с создания контроллеров для обработки всей логики приложения, а затем прикрепим эти контроллеры к определенному маршруту, чтобы пользователи могли использовать URL-адрес для получения доступа к ним.

      Для начала мы используем Adonis CLI для создания нового контроллера запросов HTTP для обработки всех процессов аутентификации нашего приложения, выполнив следующую команду:

      • adonis make:controller Auth --type http

      Эта команда создаст файл AuthController.js и сохранит его в папке app/Controllers/Http. Используйте флаг --type, чтобы указать, что этот контроллер должен быть контроллером HTTP.

      Вы увидите примерно следующий результат:

      Output

      ✔ create app/Controllers/Http/AuthController.js

      Затем откройте созданный файл контроллера:

      • nano app/Controllers/Http/AuthController.js

      Добавьте в него следующее содержание:

      app/Controllers/Http/AuthController.js

      'use strict'
      const User = use('App/Models/User')
      class AuthController {
      
          loginView({ view }) {
              return view.render('auth.login')
          }
          registrationView({ view }) {
              return view.render('auth.register')
          }
      
          async postLogin({ request, auth, response}) {
              await auth.attempt(request.input('email'), request.input('password'))
              return response.route('index')
          }
      
          async postRegister({ request, session, response }) {
              const user = await User.create({
                  username: request.input('name'),
                  email: request.input('email'),
                  password: request.input('password')
              })
              session.flash({ successmessage: 'User have been created successfully'})
              return response.route('login.create');
          }
      
          async logout ({ auth, response }) {
              await auth.logout()
              return response.route("https://www.digitalocean.com/")
          }
      }
      module.exports = AuthController
      

      В этом файле мы импортируем модель User и создаем два метода с именами loginView() и registerView() для рендеринга страниц входа в систему и регистрации соответственно. В заключение мы создадим следующие асинхронные методы:

      • postLogin(): этот метод получает значения email и password, опубликованные посредством встроенного метода request в AdonisJs, а затем сверяет эти учетные данные пользователя с базой данных. Если такой пользователь существует в базе данных и ввел правильные учетные данные, пользователь возвращается на главную страницу как прошедший аутентификацию и может создать новую цитату. В ином случае появится сообщение о том, что учетные данные введены неверно.
      • postRegister(): этот метод получает значения username, email и password для создания учетной записи пользователя в базе данных. В сеанс приложения передается сообщение об успешном создании пользователя, а пользователь перенаправляется на страницу входа в систему для прохождения аутентификации, после чего он может создать цитату.
      • logout(): этот метод выполняет функцию выхода из системы и возвращает пользователя на главную страницу.

      Сохраните и закройте файл.

      Мы настроили контроллер для регистрации и аутентификации пользователей. Теперь мы создадим контроллер запросов HTTP для управления всеми операциями с цитатами.

      Вернитесь в терминал и запустите следующую команду для создания контроллера QuoteController:

      • adonis make:controller Quote --type http --resource

      Используйте флаг --resource для создания контроллера с заданными методами ресурсов для операций создания, чтения, обновления и удаления (CRUD).

      Вы увидите следующее:

      Output

      ✔ create app/Controllers/Http/QuoteController.js

      Найдите этот файл в папке app/Controllers/Http/QuoteController.js:

      • nano app/Controllers/Http/QuoteController.js

      Добавьте в него следующее содержание:

      app/Controllers/Http/QuoteController.js

      'use strict'
      const Quote = use('App/Models/Quote')
      
      class QuoteController {
      
        async index ({ view }) {
          const quote = await Quote.all()
          return view.render('index', {
            quotes: quote.toJSON()
          })
        }
      
        async create ({ view }) {
          return view.render('quotes.create-quote')
        }
      
        async store ({ request,auth,session, response }) {
          const quote = await Quote.create({
            user_id: auth.user.id,
            username: auth.user.username,
            body: request.input('body')
          })
          session.flash({ 'successmessage': 'Quote has been created'})
          return response.redirect("https://www.digitalocean.com/")
        }
      
        async show ({ params, view }) {
          const quote = await Quote.find(params.id)
          return view.render('quotes.view-quote', {
            quote: quote.toJSON()
          })
        }
      
        async edit ({ params, view }) {
          const quote = await Quote.find(params.id)
          return view.render('quotes.edit-quote', {
            quote: quote.toJSON()
          })
        }
      
        async update ({ params, request, response, session }) {
          const quote = await Quote.find(params.id)
          quote.body = request.input('body')
          await quote.save()
          session.flash({'successmessage': 'Quote has been updated'})
          return response.redirect("https://www.digitalocean.com/")
        }
      
        async destroy ({ params, response, session }) {
          const quote = await Quote.find(params.id)
          await quote.delete()
          session.flash({'successmessage': 'Quote has been deleted'})
          return response.redirect("https://www.digitalocean.com/")
        }
      }
      module.exports = QuoteController
      

      В этом контроллере мы импортировали модель Quote и обновили следующие методы, которые были автоматически созданы с помощью AdonisJs CLI:

      • index(): доставка всех цитат из базы данных и их рендеринг на главной странице приложения.
      • create(): рендеринг страницы для создания цитат.
      • store(): сохранение созданной цитаты в базе данных и вывод соответствующего ответа.
      • show(): получение идентификатора определенной цитаты, ее извлечение из базы данных и рендеринг на странице редактирования цитаты.
      • edit(): получение деталей определенной цитаты из базы данных и ее рендеринг для редактирования.
      • update(): обработка любых изменений цитаты и возвращение пользователя на главную страницу.
      • destroy(): удаление определенной цитаты и ее полное удаление из базы данных.

      Сохраните и закройте файл.

      После создания всех необходимых контроллеров для этого приложения мы можем настроить маршруты, чтобы пользователи могли легко взаимодействовать с приложением. Для начала перейдите в файл start/routes.js.

      Замените его содержание на следующее:

      start/routes.js

      'use strict'
      const Route = use('Route')
      
      Route.get("https://www.digitalocean.com/",'QuoteController.index').as('index')
      Route.get('/register','AuthController.registrationView').as('register.create')
      Route.post('/register-store','AuthController.postRegister').as('register.store').validator('Register')
      Route.get('/login','AuthController.loginView').as('login.create')
      Route.post('/login-store','AuthController.postLogin').as('login.store')
      Route.get('/view-quote/:id','QuoteController.show').as('view.quote')
      
      Route.group(() => {
          Route.get('/create-quote','QuoteController.create').as('create.quote')
          Route.post('/store-quote','QuoteController.store').as('store.quote')
          Route.get('/edit-quote/:id','QuoteController.edit').as('edit.quote')
          Route.post('/update-quote/:id','QuoteController.update').as('update.quote')
          Route.get('/delete-quote/:id','QuoteController.destroy').as('delete.quote')
          Route.post('/logout','AuthController.logout').as('logout')
      }).middleware(['auth'])
      

      Здесь мы определяем путь к каждому маршруту нашего приложения, задаем глаголы HTTP для каждого действия и привязываем маршрут к определенному методу в каждом контроллере. Также мы присвоим имена каждому из маршрутов, поскольку контроллеры и представления ссылаются на них.

      Чтобы обеспечить доступ ко всем маршрутам цитат только для пользователей, прошедших аутентификацию, мы назначим соответствующую группу middleware. В заключение мы прикрепим метод проверки к маршруту register.store для проверки вводимых пользователем данных.

      Сохраните и закройте файл.

      Мы создали контроллеры и настроили маршруты приложения. Далее мы создадим метод проверки, определяемый на этом шаге.

      Шаг 5 — Проверка вводимых пользователем данных

      AdonisJs не имеет встроенных по умолчанию средств проверки. Поэтому средство проверки для вашего приложения нужно установить и зарегистрировать вручную.

      Запустите следующую команду для его установки:

      Откройте следующий файл для регистрации поставщика средства проверки:

      Зарегистрируйте поставщика средства проверки, добавив его в список поставщиков, как показано далее:

      start/app.js

      ...
      const providers = [
         ...
         '@adonisjs/cors/providers/CorsProvider',
         '@adonisjs/shield/providers/ShieldProvider',
         '@adonisjs/session/providers/SessionProvider',
         '@adonisjs/auth/providers/AuthProvider',
         '@adonisjs/validator/providers/ValidatorProvider'
      ]
      

      Мы установили и зарегистрировали поставщика средства проверки в нашем приложении. Теперь мы создадим собственное средство проверки ввода данных пользователем при регистрации с помощью следующей команды:

      • adonis make:validator Register

      Эта команда создаст файл Register.js в директории App/validators. Откройте файл с помощью следующей команды:

      • nano app/Validators/Register.js

      Добавьте в файл следующий код:

      app/Validators/Register.js

      'use strict'
      class Register {
        get rules () {
          return {
            name:'required',
            email:'required|email|unique:users',
            password:'required|min:8'
          }
        }
      
        get messages(){
          return{
            'name.required':'Full name is required',
            'email.required':'email is required',
            'email.unique':'email already exists',
            'password.required':'password is required',
            'password.min':'password should be at least 8 characters'
          }
        }
      }
      module.exports = Register
      

      Для определенных полей в приложении можно определять правила. Если проверка не будет пройдена на любом этапе, средство проверки автоматически выведет всплывающее сообщение об ошибке и возвратит пользователя в форму.

      Сохраните и закройте файл после завершения редактирования.

      Для добавление стилей в ваше приложение откройте следующий файл:

      Замените его содержание на следующее:

      /public/style.css

      @import url('https://fonts.googleapis.com/css?family=Montserrat:300');
      
      html, body {
        height: 100%;
        width: 100%;
      }
      
      body {
        font-family: 'Montserrat', sans-serif;
        font-weight: 300;
        background-image: url("/splash.png");
        background-color: #220052;
      }
      
      * {
        margin: 0;
        padding: 0;
      }
      
      a {
        color: inherit;
        text-decoration: underline;
      }
      
      p {
        margin: 0.83rem 0;
      }
      
      .quote-wrapper {
        margin-top: 20px;
      }
      
      .quote-wrapper a {
        text-decoration: none;
      }
      
      .quote-wrapper a:hover {
        color: #ffffff;
      }
      
      .empty-quote {
        color: #ffffff;
      }
      
      form {
        padding: 20px;
      }
      

      В этом файле мы обновляем стили CSS нашего приложения в файле style.css.

      Мы установили и зарегистрировали поставщика средства проверки с целью проверки данных, вводимых пользователями при регистрации. Также мы обновили содержание таблицы стилей, добавив в приложение дополнительные стили. На последнем шаге мы проведем тестирование нашего приложения.

      Шаг 6 — Выполнение приложения

      На этом шаге мы запустим наше приложение и создадим пользователя и пароль для тестирования аутентификации. Также мы добавим в приложение цитату и просмотрим ее на главной странице.

      Чтобы протестировать приложение, запустите сервер разработки, выполнив следующую команду в корневой директории вашего приложения:

      Приложение будет запущено на порту, заданном в файле root .env, а именно на порту 3333. Откройте в браузере адрес http://localhost:3333.

      Главная страница приложения с цитатами

      Сейчас главная страница пустая, поскольку мы не создали никаких цитат. Нажмите кнопку Регистрация.

      Страница регистрации

      Введите свои данные и нажмите кнопку Отправить, чтобы завершить процедуру регистрации. Вы будете перенаправлены на страницу входа. Введите свой адрес электронной почты и пароль для аутентификации.

      Страница входа

      После аутентификации нажмите кнопку Создать цитату.

      Страница создания цитаты

      Введите цитату и перейдите на страницу Показать все для ее просмотра.

      Страница просмотра всех цитат

      Мы протестировали приложение, создав пользователя, пройдя аутентификацию и написав цитату.

      Заключение

      В этом обучающем руководстве мы создали веб-приложение с помощью AdonisJs. Мы настроили приложение с помощью AdonisJs CLI и использовали CLI для создания других важных файлов, в том числе контроллеров, моделей и представлений.

      В этой инфраструктуре вы можете создавать веб-приложения любого размера и сложности. Исходный код проекта можно загрузить на GitHub здесь. Дополнительную информацию можно найти в официальной документации.

      Если вы хотите посмотреть наши другие обучающие руководства по инфраструктуре JavaScript, обратите внимание на следующие:



      Source link

      Упаковка и публикация приложения Snap в Ubuntu 18.04


      Автор выбрал фонд Electronic Frontier Foundation для получения пожертвований в рамках программы Write for DOnations.

      Введение

      Одной из самых крупных проблем при разработке приложений является конечный шаг, предусматривающий предоставление готового продукта вашим пользователям или клиентам. Многие существующие методологии развертывания приложений не отличаются удобством для пользователя и безопасностью, либо же не предоставляют возможности для автоматического обновления приложения после его установки.

      Snap — это современный формат упаковки приложений с мощными опциями для песочницы и обеспечения безопасности, включая изоляцию файловой системы, автоматические обновления и комплексное управление зависимостями. Приложения Snap, или «снапы», могут загружаться и устанавливаться с помощью программы командной строки, такой как apt или yum. Snap предоставляется в комплекте с Ubuntu, что означает, что у приложений Snap есть самая широкая аудитория.

      В этом обучающем руководстве вы создадите приложение Snap и опубликуете его в Snap Store.

      Предварительные требования

      Для данного обучающего руководства вам потребуется следующее:

      • Один сервер Ubuntu 18.04, настроенный в соответствии с инструкциями по начальной настройке сервера с Ubuntu 18.04, а также пользователь sudo без прав root.

      • Приложение, которое вы хотите упаковать и выпустить в качестве снапа. Это может быть сложное приложение, которое вы создали, общий проект с открытым исходным кодом, или просто приложение «Hello, world!». Если у вас еще нет приложения, в шаге 1 данного руководства описано, как создать программу Hello World в Go.

      • Учетная запись в Snapcraft Developer Dashboard.

      Подготовив все вышеперечисленное, войдите на сервер без привилегий root, чтобы начать подготовку.

      Шаг 1 — Подготовка вашего приложения к упаковке

      Во-первых, вы подготовите приложение к упаковке в качестве приложения Snap, обеспечив наличие всего необходимого в одной директории.

      Начнем с создания новой директории для вашего снапа, после чего вам нужно перейти в эту директорию:

      • mkdir ~/your-snap
      • cd ~/your-snap

      Затем, если у вас уже есть приложение, поместите полную копию исходного кода вашего приложения в только что созданную вами директорию. Данный процесс в значительной степени зависит от конкретного приложения, которое вы упаковываете, но если ваш исходный код хранится в репозитории Git, вы можете воспользоваться командой git init​​​, чтобы инициализировать репозиторий для директории и загрузить весь соответствующий код.

      Если у вас еще нет приложения, которое вы хотите упаковать, вы можете создать программу Hello World и использовать ее. Если вам потребуется добавить дополнительный контекст при написании этой программы на языке Go, ознакомьтесь с руководством Написание вашей первой программы на Go.

      Вы можете сделать это, создав новый файл Go и открыв его в предпочитаемом вами текстовом редакторе:

      Добавьте в файл следующий код:

      helloworld.go

      package main
      import "fmt"
      func main() {
        fmt.Println("Hello, world!")
      }
      

      Сохраните и закройте файл.

      Если у вас не установлен Go, вы можете сделать это с помощью следующей команды:

      • sudo apt install golang-go

      После установки Go вы можете запустить вашу новую программу, чтобы проверить ее работу:

      Вывод должен выглядеть так:

      Output

      Hello, world!

      Вы успешно подготовили приложение для упаковки в качестве снапа. Далее вы установите программное обеспечение, необходимое для начала процесса упаковки.

      Шаг 2 — Установка Snapcraft

      На этом шаге вы загрузите и установите Snapcraft, официальный инструмент для упаковки приложений Snap. Snapcraft доступен в Snap Store, встроенный в Ubuntu по умолчанию. Это означает, что вы можете установить Snapcraft из командной строки с помощью команды snap.

      Команда snap является эквивалентом команды apt, но вы можете использовать ее для установки программного обеспечения из Snap Store вместо пакетов из репозиториев Apt.

      Чтобы установить Snapcraft, запустите следующую команду:

      • sudo snap install snapcraft --classic

      Воспользуйтесь аргументом команды --classic, чтобы установить Snapcraft без строгих функций песочницы, которые обычно используются снапами. Snapcraft требует наличие этого аргумента, поскольку он подразумевает более безопасный доступ к системе для более надежной упаковки приложений.

      После установки Snapcraft вы увидите следующее:

      Output

      snapcraft 3.9.8 from Canonical✓ installed

      После этого вы можете еще раз проверить корректность установки Snapcraft с помощью следующей команды:

      В результате будет выведено примерно следующее:

      Output

      snapcraft, version 3.9.8

      После того как вы установили Snapcraft, вы можете приступать к определению конфигурации и метаданных для вашего приложения Snap.

      Шаг 3 — Определение конфигурации и метаданных для вашего снапа

      На этом шаге вы начнете определять конфигурацию, структуру и метаданные для вашего приложения Snap.

      Сначала нужно убедиться, что вы до сих пор работаете в директории приложения Snap:

      Затем создайте и отредактируйте файл snapcraft.yaml в вашем предпочитаемом текстовом редакторе:

      Вы будете использовать файл snapcraft.yaml для хранения всех элементов конфигурации для вашего приложения Snap, включая имя, описание и версию, а также настройки, связанные с управлением зависимостями и песочницей.

      Начните с определения имени, резюме, описания и номера версии вашего приложения:

      snapcraft.yaml

      name: your-snap
      summary: A summary of your application in 78 characters or less.
      description: |
        A detailed description of your application.
        The description can have multiple lines.
      version: '1.0'
      

      Имя вашего снапа должно быть уникальным, если вы хотите опубликовать его в Snap Store — выполните поиск других приложений с таким же именем, чтобы убедиться, что имя еще не занято.

      Далее вы можете определить команду (команды) для связи с вашим приложением. Это позволит использовать ваш снап напрямую из командной строки Bash в качестве обычной команды.

      Добавьте следующее в файл snapcraft.yaml​​​:

      snapcraft.yaml

      . . .
      apps:
        your-snap-command:
          command: your-snap
      

      your-snap-command — это имя команды, которую вы хотите определить. Например, вы сможете использовать команду helloworld для запуска вашей программы Hello World.

      Воспользуйтесь command: your-snap, чтобы сообщить Snapcraft, что нужно делать, когда команда приложения запущена. В случае программы Hello World вы будете использовать значение helloworld для ссылки на файл helloworld.go, что позволит Snapcraft успешно запускать вашу программу.

      В результате вы получите следующий пример конфигурации:

      snapcraft.yaml

      apps:
        helloworld:
          command: helloworld
      

      Если имя команды совпадает с именем снапа, вы сможете запустить его напрямую из командной строки. Если команда не соответствует имени снапа, к команде будет автоматически добавлен префикс с именем снапа. Например, helloworld.command1.

      В заключение вы можете определить части, которые составляют приложение Snap. Приложения Snap состоят из нескольких частей, которые являются компонентами, которые составляют приложение. Во многих случаях существует только одна часть, т. е. само приложение.

      Каждая часть имеет соответствующий плагин. Например, для компонентов вашего приложения, написанного на Ruby, используется плагин ruby, а для компонентов, написанных на Go, используется плагин go.

      Вы можете использовать команду Snapcraft list-plugins, чтобы определить надлежащий плагин (плагины) для вашего приложения:

      В результате вы получите примерно следующий список:

      Output

      ant catkin-tools conda dump gradle make nil python rust autotools cmake crystal go kbuild maven nodejs qmake scons catkin colcon dotnet godeps kernel meson plainbox-provider ruby waf

      Наиболее распространенные плагины — это плагины для распространенных языков программирования, таких как Go, Rust, Ruby или Python.

      После того как вы определили надлежащие плагины для вашего приложения, вы можете переходить к добавлению конфигурации частей для вашего файла snapcraft.yaml​​​:

      snapcraft.yaml

      . . .
      parts:
        your-snap:
          plugin: plugin-name
          source: .
      

      Вы используете параметр конфигурации source, чтобы задать относительный путь к исходному коду вашего приложения. Обычно это будет та же директория, где расположен сам файл snapcraft.yaml, поэтому значение source будет просто точка (.).

      Примечание. Если компонент вашего приложения имеет любые зависимости, необходимые для сборки или запуска, вы можете задать их с помощью атрибутов build-packages и stage-packages. Указанные названия зависимостей автоматически будут подбираться диспетчером пакетов по умолчанию для вашей системы.

      Например:

      snapcraft.yaml

      parts:
        your-snap:
        plugin: plugin-name
        source: .
        build-packages:
        - gcc
        - make
        stage-packages:
        - libcurl4
      

      Некоторые плагины Snapcraft имеют собственные конкретные опции, которые могут потребоваться вашему приложению, поэтому полезно изучить соответствующие страницы руководства для вашего плагина:

      • snapcraft help plugin-name

      В случае с приложениями Go вы также можете указать go-importpath. Для конфигурации Hello World вы получите следующий пример конфигурации:

      snapcraft.yaml

      parts:
        helloworld:
          plugin: go
          source: .
          go-importpath: helloworld
      

      Вы можете оставить ваш файл snapcraft.yaml открытым, чтобы внести дальнейшие изменения в конфигурацию на следующем шаге.

      Вы определили базовую конфигурацию для вашего приложения Snap. Далее вы настроите аспекты безопасности и песочницы для вашего приложения.

      Шаг 4 — Защита приложения Snap

      Приложения Snap разрабатываются для запуска в изолированной среде, поэтому в этом шаге вы настроите песочницу для вашего снапа. Во-первых, вам нужно будет активировать песочницу для вашего приложения, известную в Snapcraft как ограждение.

      Добавьте следующее в файл snapcraft.yaml​​​:

      snapcraft.yaml

      . . .
      confinement: strict
      

      Это позволит организовать песочницу для вашего приложения, предотвращая возможность доступа через Интернет, из других запущенных снапов или самой хост-системы. Однако в большинстве случаев приложения должны иметь возможность передавать данные за пределы своей песочницы, например, когда им требуется получить доступ к Интернету или выполнить чтение/запись в файловой системе.

      Эти разрешения, известные в Snapcraft как интерфейсы, могут быть предоставлены вашему приложению Snap с помощью плагов. С помощью плагов вы можете организовать детальный контроль песочницы для вашего приложения, чтобы предоставить ей доступ к тому, что нужно, и ничего более (принцип «минимум полномочий»).

      Конкретные интерфейсы, которые могут потребоваться, будут варьироваться в зависимости от вашего приложения. Ниже представлен ряд наиболее распространенных интерфейсов:

      • audio-playback — разрешает вывод аудио/проигрывание звуков.
      • audio-record — разрешает ввод/запись аудио.
      • camera — разрешает доступ к подключенным веб-камерам.
      • home — разрешает доступ к нескрытым файлам внутри домашней директории.
      • network — разрешает доступ к сети/Интернету.
      • network-bind — разрешает привязку портов для работы в качестве сетевой службы.
      • system-files — разрешает доступ ко всей файловой системе хост-компьютера.

      Полный список доступных интерфейсов можно найти в документации Snapcraft в разделе Поддерживаемые интерфейсы.

      После того как вы определили все требуемые интерфейсы для вашего приложения, вы можете начать присвоение плагов внутри вашего файла snapcraft.yaml.

      Следующий пример конфигурации позволит приложению получить доступ к сети и домашнему пространству пользователей:

      snapcraft.yaml

      . . .
      plugs:
        your-snap-home:
          interface: home
        your-snap-network:
          interface: network
      

      Сохраните и закройте файл.

      Имя плага должно быть описательным, чтобы пользователи могли понять, для чего нужен плаг.

      Вы активировали песочницу для вашего снапа и настроили несколько плагов для предоставления ограниченного доступа к системным ресурсам. Далее вы сможете завершить процесс сборки приложения Snap.

      Шаг 5 — Сборка и тестирование приложения Snap

      Теперь, когда вы создали всю необходимую конфигурацию для вашего снапа, вы можете перейти к его сборке и локальному тестированию пакета Snap.

      Если вы выполняли инструкции, используя в качестве приложения программу Hello World, ваш итоговый файл snapcraft.yaml будет выглядеть примерно следующим образом:

      snapcraft.yaml

      name: helloworld
      summary: A simple Hello World program.
      description: |
        A simple Hello World program written in Go.
        Packaged as a Snap application using Snapcraft.
      version: '1.0'
      confinement: strict
      
      apps:
        helloworld:
          command: helloworld
      
      parts:
        helloworld:
          plugin: go
          source: .
          go-importpath: helloworld
      
      plugs:
        helloworld-home:
          interface: home
        helloworld-network:
          interface: network
      

      Чтобы выполнить сборку приложения Snap, запустите команду snapcraft внутри директории вашего снапа:

      Snapcraft будет автоматически запускать виртуальную машину (VM) и начинать сборку снапа. После завершения процесса Snapcraft будет закрыт, а вы увидите примерно следующее:

      Output

      Snapped your-snap_1.0_amd64.snap

      Теперь вы можете выполнить установку вашего снапа локально, чтобы проверить его работоспособность:

      • sudo snap install your-snap.snap --dangerous

      Аргумент команды --dangerous требуется, поскольку вы выполняете установку локального снапа, который не подписан.

      Output

      your-snap 1.0 installed

      После завершения процесса установки вы можете запустить ваш снап с помощью связанной команды. Например:

      В случае используемой в качестве примера программы Hello World вы увидите следующее:

      Output

      Hello, world!

      Также вы можете просмотреть политику песочницы для вашего снапа, чтобы убедиться, что присвоенные разрешения были получены нормально:

      • snap connections your-snap

      В результате будет выведен примерно следующий список плагов и интерфейсов:

      Output

      snap connections your-snap Interface Plug Slot Notes home your-snap:your-snap-home :home - network your-snap:your-snap-network :network -

      На этом шаге вы выполнили сборку вашего снапа и установили его локально для проверки его работы. Далее вы опубликуете ваш снап в Snap Store.

      Шаг 6 — Публикация вашего приложения Snap

      Теперь, когда вы выполнили сборку и тестирование приложения Snap, пришло время опубликовать его в Snap Store.

      Начните со входа в учетную запись разработчика Snap с помощью приложения командной строки Snapcraft:

      Следуйте указаниям и введите ваш адрес электронной почты и пароль.

      Далее вам нужно зарегистрировать имя приложения в Snap Store:

      • snapcraft register your-snap

      После того как вы зарегистрируете имя снапа, вы сможете загрузить созданный пакет приложения Snap в магазин:

      • snapcraft push your-snap.snap

      Результат будет выглядеть примерно так:

      Output

      Preparing to push 'your-snap_1.0_amd64.snap'. Install the review-tools from the Snap Store for enhanced checks before uploading this snap. Pushing 'your-snap_1.0_amd64.snap' [===================================================================================================] 100% Processing...| Ready to release! Revision 1 of 'your-snap' created.

      Каждый раз, когда вы выполняете загрузку в Snap Store, номер версии увеличивается, начиная с 1. Это полезно, так как помогает определить различные сборки вашего снапа.

      Наконец, вы можете опубликовать ваш снап:

      • snapcraft release your-snap revision-number channel

      Если вы впервые загружаете снап в Snap Store, версия будет иметь номер 1. Также вы можете выбрать каналы stable, candidate, beta и edge, если у вас есть несколько версий приложения на разных этапах разработки.

      Например, следующая команда будет публиковать версию 1 снапа Hello World на канале stable:

      • snapcraft release helloworld 1 stable

      Результат будет выглядеть примерно так:

      Output

      Track Arch Channel Version Revision latest amd64 stable 1.0 1 candidate ^ ^ beta ^ ^ edge ^ ^ The 'stable' channel is now open.

      Теперь вы можете выполнить поиск приложения в Snap Store и установить его на любом из ваших устройств.

      Snap Store с приложением HelloWorld, которое отображается в результатах поиска

      На данном заключительном шаге вы загрузили созданный вами пакет в Snap Store и опубликовали его.

      Заключение

      В этой статье вы настроили и выполнили сборку приложения Snap, а затем опубликовали его в Snap Store. Теперь у вас есть базовые знания, необходимые для поддержания вашего приложения и сборки новых приложений.

      Если вы хотите продолжить изучение снапов, просмотрите весь магазин Snap Store. Также вы можете ознакомиться со Справочником по Snapcraft YAML, чтобы узнать о нем подробнее и определить дополнительные атрибуты для вашей конфигурации снапа.

      Наконец, если вы хотите продолжить дальнейшее изучение разработки приложений Snap, вы можете прочитать о реализации исполняемых файлов в Snap, которые позволяют Snap динамически реагировать на изменения системы, например, обновления или изменения политики безопасности.



      Source link