Админка магазина на vue.js. Урок 6. Vue-cli и vue-компоненты

февраль 26 , 2019
Метки:
Предыдущая статья Следующая статья Исходники

До этого урока мы писали код просто и сурово. Здоровенный 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.

    
    
    

В секцию template мы полностью скопировали код из бывшего компонента Header. Секция script немного отличается. Там экспортируются параметры компонента, в нашем случае только props. Но экспортируемое содержимое точно такое же, как и раньше.

Идем дальше, смотрим на подвал AppFooter.

    

Здесь вообще один шаблон. Оно и верно: никакой логики у компонента нет. Теперь страницы брендов и категорий

Brands.vue

    

Categories.vue

    

Ну тут вообще незатейливо. Дальше чуть сложнее - ProductsItem

    
    
    

Здесь уже прокидывается свойство 'product', поэтому имеется секция script.

А теперь посмотрим на самый большой компонент - Products.vue

    
    
    
    
    

Кода много, но это опять копипаста из старого компонента. Стоит обратить внимание только на одну вещь - секция 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 крутилось приложение. Сама админка запускалась из папки http://w-shop.lc/admin/vue/, а запросы ходили на http://w-shop.lc/admin/api/v1/...

Сейчас же ajax-запросы за товарами и категориями будут долбиться в http://locahost:8080/admin/api/v1/... и конечно же ничего там не найдут. locahost:8080 не видит ничего вне корневой для него папки - /admin/vue/.

Как выходить из этого положения? Можно было сразу установить 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. Нужно ходить как положено. Или включить поддержку кроссдоменных запросов. Для этого в /admin/api/v1/index.php нужно отдавать определенный заголовок, то есть в самом начале этого файла поставить строку

    header('Access-Control-Allow-Origin: *');

Подробнее про кроссдоменные запросы можете почитать в статье Кроссдоменные запросы и причем здесь php

По-хорошему, заголовок "Access-Control-Allow-Origin: *" тоже нужно проставлять только в dev-режиме, но /admin/api/ у нас не под вебпаком и я пока не придумал, как это сделать адекватно. Если у вас есть мысли на этот счет, поделитесь в коментах.

Вот такие 2 момента. Не думаю, что это прямо большая неприятность, но немножко жмет. Наверно поэтому умные люди сразу изучают какой-нибудь laravel с встроенной поддержкой vue.js. Думаю, там таких приколов нет.

Впрочем, как я и говорил еще в первом уроке, я изучаю vue вместе с вами и поэтому наступаю на подобные грабли :-)
Но как иначе мы что-то сделаем, если не будем пробовать и ошибаться, правильно?

На этом все, 6-й урок закончен, осталось только отдать ссылку на исходники

До встречи! В следующий раз будем разбираться с vuex.

Все уроки админки на vue.js

Предыдущая статья Следующая статья Исходники
Метки:
Заходите в группу в контакте - https://vk.com/webdevkin
Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
Истории из жизни айти и обсуждение кода.
Как Вам статья? Оцените!