Админка магазина на vue.js. Урок 6. Vue-cli и vue-компоненты
До этого урока мы писали код просто и сурово. Здоровенный index.html, внешние библиотеки с CDN-a, javascript-код в одном файле. Для учебного проекта сгодится, но мы же хотим быть серьезными ребятами.
Так мы приходим к пониманию, что пора делать окружение для локальной разработки, бить код на отдельные файлы-модули и настраивать сборку. Здесь у нас есть выбор. Первое: взять вебпак или другой сборщик и врукопашную настроить все, что нужно. Второе: взять готовый инструмент, который всю эту рутину сделает за нас.
Я выбираю второй вариант. Грамотные люди уже написали все сборщики и подготовили основу проектов vue, на которой мы и будем развивать наше приложение.
Инструмент называется vue-cli и работает он очень просто. Можете посмотреть документацию vue-cli, а если неохота, то я кратко расскажу, как его установить и в чем его смысл.
Ставим vue-cli как глобальный npm-пакет
npm install -g @vue/cli-init
Замечу, что он работает на ноде от версии 8.9 и выше. У меня стояла древняя 6.9, поэтому пришлось обновлять. Если вам край нужна старая версия, то воспользуйтесь nvm - инструмент для управления разными версиями nodejs.
Так, vue-cli поставили, пора развернуть приложение. Нам доступно несколько вариантов: от webpack с тестами и хот-релоадерами до простейшего приложения из пары файлов наподобие того, что мы делали в предыдущих пяти уроках. Подробнее почитать и узнать все варианты можно по этой ссылке.
Мы выберем шаблон webpack-simple. На ютубе все его разбирают, а мы чем хуже? webpack-simple - это шаблон на базе вебпака, там настроена сборка и hot reload, но исключены совсем уж хитрые штуки типа тестов и линтинга. То есть сначала разберемся с простым вариантом, а потом полезем дальше.
Не беспокойтесь, если вы не имели дела с вебпаком. Я в нем тоже не шарю, но это и не потребовалось. Пока все, что нужно знать - это то, что vue-cli дает нам окружение для локальной разработки и сборку для режима production, не углубляясь в детали. Но давайте посмотрим на практике.
Создание проекта с vue-cli
Зайдем в папку admin нашего проекта и переименуем папку vue во ___vue. В конце урока мы ее удалим, но пока она нужна для копирования из нее старого кода. Теперь создадим vue-приложение через vue-cli
vue init webpack-simple vue // Если не сработало, то vue-cli init webpack-simple vue
vue - это название папки с проектом, то есть в итоге приложение останется на старом месте - в /admin/vue/.
vue-cli при установке задаст пару простых вопросов, можно оставить ответы по дефолту. Только когда спросит, использовать ли scss, говорите да. После установки в папке vue появится десяток файлов. Быстро пробежимся, что нагенерил нам vue-cli
package.json - там можно посмотреть все зависимости. Кстати, запустим сразу npm install, а пока пакеты ставятся, смотрим сгенеренные файлы дальше.
.babelrc - настройки для babel, логично. Ничего там не правим.
.editorconfig - в нем заменил одну настройку, indent_size поставил 4 вместо 2 - это сколько пробелов будет использоваться вместо таба
.gitignore оставляем как есть
readme.md тоже ничего особенного
webpack.config.js - я для интереса заглянул, но как и говорил, в вебпаке не шарю. Поэтому посмотрел и закрыл :-)
Дальше идут файлы самого приложения, рассмотрим их чуть позже. А пока, если npm install отработал, можно запустить приложение. Делается это командой
npm run dev
При этом в браузере откроется вкладка localhost:8080, где и будет крутиться приложение. Сейчас там тестовое приоложение с логотипом vue и ссылками.
Отличная новость - в режиме разработки dev запущен hot reload, то есть мы можем менять код, а браузер будет сам перезагружать страницу. Особенно удобно, особенно если у вас 2 монитора, в одном IDE, в другом браузер. В любом случае не нужно постоянно жать на F5.
Вторая и последняя команда, которая нам пригодится - это
npm run build
Команда соберет все файлы и компоненты в кучу, сожмет js-код и стили. То есть даст на выходе файл, готовый к заливке на production - dist/build.js. Вот и все. Всего две команды и заметьте, без знания вебпака - он работает под капотом, удобно.
А теперь смотрим код, относящийся уже непосредственно к приложению.
index.html
Он очень простой - один пустой div#app и подключение скрипта ./dist/build.js - именно с точкой - чтобы файл брался из текущей папки. Никаких vue, axios и lodash - все будет собираться в файл build.js. Нам нужно лишь подключить отдельно стили mini.css в head, вот такой файлик
https://cdnjs.cloudflare.com/ajax/libs/mini.css/3.0.1/mini-default.css
main.js
Файл, с которого стартует все приложение. Содержимое такое
import Vue from 'vue' import App from './App.vue' new Vue({ el: '#app', render: h => h(App) })
Мы уже работаем по-взрослому, импортируем файлы и компоненты через import, а не тащим их в одном файле. В один файл их пусть собирает сборщик. Наш код уже разбит на компоненты в предыдущем уроке, давайте разберемся, как это сделать красиво через специальные .vue-файлы. Главный компонент App.vue оставим напоследок, а начнем с самого простого.
Разбираемся с компонентами
Компонент .vue состоит из трех разделов: шаблон template, js-код script и стили style. Эти элементы необязательны, у нас будут компоненты и без стилей, и без js-кода. Вот как выглядит компонент AppHeader.
Webdevkin
В секцию template мы полностью скопировали код из бывшего компонента Header. Секция script немного отличается. Там экспортируются параметры компонента, в нашем случае только props. Но экспортируемое содержимое точно такое же, как и раньше.
Идем дальше, смотрим на подвал AppFooter.
Здесь вообще один шаблон. Оно и верно: никакой логики у компонента нет. Теперь страницы брендов и категорий
Brands.vue
Бренды
Categories.vue
Категории
Ну тут вообще незатейливо. Дальше чуть сложнее - ProductsItem
{{ product.id }} {{ product.title }} {{ product.brand }} {{ product.price }} {{ product.rating }}
Здесь уже прокидывается свойство 'product', поэтому имеется секция script.
А теперь посмотрим на самый большой компонент - Products.vue
Список товаров
Id Название Бренд Цена Рейтинг
Кода много, но это опять копипаста из старого компонента. Стоит обратить внимание только на одну вещь - секция style. Можно догадаться, что атрибут lang указывает, какой использовать препроцессор. И использовать ли вообще.
Самое интересное здесь - атрибут scoped. Пишите просто scoped, без ="" - это кривой парсер так отображает :-(
Атрибут scoped крут тем, что ограничивает область видимости стилей текущим компонентом.
То есть в нашем примере max-height: 1000px будет только у таблиц в компоненте Products. В других - нет. Если уберем scoped, то указанный стиль распространится на все таблицы.
Советую для всех стилей использовать scoped. Это позволит делать компоненты изолированными и заодно избавит от необходимости писать страшные названия классов вида .product-item__description. Конечно, если вы не ярый поклонник БЭМ, тогда вам можно :-)
Классы, однако ж, все равно прописывать стоит по причине скорости. Браузер ищет стили по классам быстрее, чем по атрибутам. Поэтому вместо table вы можете написать table class="products" и соответственно
Мне уже лень, но надеюсь на вашу сознательность.
Да, еще одно. В компоненте Products используются lodash и axios, раньше мы их подключали глобально, но сейчас их удалили в самом начале урока. Нужно заново подтянуть все нужные библиотеки, только не внешними скриптами, а через npm
npm install --save lodash npm install --save axios
Почему именно --save? Напомню, что --save - это для библиотек, которые включаются в сборку, а --save-dev - для библиотек, нужных для разработки. По-человечески: lodash или jquery вам нужен для непосредственной работы кода, поэтому --save. А вебпак или hot-reload только для удобства разработки - поэтому --save-dev.
После установки lodash и axios глобально недоступны, их нужно подключать по необходимости. Вот и в Products в начале script мы подключаем библиотеки плюс нужный компонент ProductsItem
import axios from 'axios' import _ from 'lodash' import ProductsItem from './ProductsItem'
Почти все, осталось собрать все компоненты в кучу - а это компонент App. Вот его код
Много, но тоже ничего необычного. Шаблон скопирован, js-код тоже. Только опять добавились импорты нужных компонентов в script
import AppHeader from './AppHeader.vue' import AppFooter from './AppFooter.vue' import Products from './Products.vue' import Categories from './Categories.vue' import Brands from './Brands.vue'
И на этом бы закончить урок, но есть один момент, сейчас расскажу.
Проблема с ajax-запросами при локальной разработке
Если вы исправно выполняли предыдущие уроки, то сейчас приложение не запустится, даже если вы все сделаете строго по инструкции. Причина в том, что vue-приложение через "npm run dev" запускается на localhost:8080. И запросы на бекенд сейчас отвалятся. Почему это?
Потому что раньше мы или настраивали веб-сервер, или запускали через встроенный веб-сервер в IDE. Например, у меня был настроен nginx и на хосте w-shop.lc крутилось приложение.
Сама админка запускалась из папки
Сейчас же ajax-запросы за товарами и категориями будут долбиться в
Как выходить из этого положения? Можно было сразу установить vue в корневую папку приложения. Можно отключить в конфиге вебпака hot reload и открывать в браузере не localhost:8080, а по-старому w-shop.lc/admin/vue. А еще можно для режима режима разработки переопределять в конфиге axios базовый путь к апишным запросам.
Делается это через хитрый объект process.env и его поле NODE_ENV в main.js - вот его полный код.
import Vue from 'vue' import App from './App.vue' import axios from 'axios' const debug = process.env.NODE_ENV !== 'production'; // Для dev-режима if (debug) { axios.defaults.baseURL = 'http://w-shop.lc'; } new Vue({ el: '#app', render: h => h(App) })
Сначала определяется debug, которая определяет, запустили ли мы приложение в dev-режиме. И если это так, то задается новый axios.defaults.baseURL. У меня это http://w-shop.lc, вы же подставите свое.
Так, одну проблему решили, но это еще не все. Попробуйте запустить и браузер нам скажет, ага, кроссдоменный запрос. Логично же, у нас localhost:8080, а мы лезем на какой-то w-shop.lc.
Нужно ходить как положено. Или включить поддержку кроссдоменных запросов.
Для этого в
header('Access-Control-Allow-Origin: *');
Подробнее про кроссдоменные запросы можете почитать в статье Кроссдоменные запросы и причем здесь php
По-хорошему, заголовок "Access-Control-Allow-Origin: *" тоже нужно проставлять только в dev-режиме, но /admin/api/ у нас не под вебпаком и я пока не придумал, как это сделать адекватно. Если у вас есть мысли на этот счет, поделитесь в коментах.
Вот такие 2 момента. Не думаю, что это прямо большая неприятность, но немножко жмет. Наверно поэтому умные люди сразу изучают какой-нибудь laravel с встроенной поддержкой vue.js. Думаю, там таких приколов нет.
Впрочем, как я и говорил еще в первом уроке, я изучаю vue вместе с вами и поэтому наступаю на подобные грабли :-)
Но как иначе мы что-то сделаем, если не будем пробовать и ошибаться, правильно?
На этом все, 6-й урок закончен, осталось только отдать ссылку на исходники
До встречи! В следующий раз будем разбираться с vuex.
Все уроки админки на vue.js
- Урок 1. Список товаров
- Урок 2. Фильтры и сортировки
- Урок 3. Новое REST API на чистом PHP
- Урок 4. Правим клиентский код под новое REST API и находим багу
- Урок 5. Разбиваем приложение на компоненты
- Урок 6. Инструмент vue-cli и vue-компоненты
- Урок 7. Flux и Vuex - общие вопросы
- Урок 8. Vuex на практике
- Урок 9. Перерабатываем фильтры
- Урок 10. Добавляем и удаляем бренды
- Урок 11. Обрабатываем ошибки на клиенте и сервере
- Урок 12. Редактируем бренды
- Урок 13. Роутинг
- Урок 14. Карточка товара
Истории из жизни айти и обсуждение кода.