NativeScript-Vue с Vuex и Vue Devtools (нет, правда)

Борьба одного человека со стопкой

Итак, вы слышали о NativeScript? Уже одно это несколько впечатляет, учитывая длинную тень, которую отбрасывают подобные React Native (но это уже другая история).

И где-то по пути вы влюбились в VueJS и его до боли простое хранилище Vuex и привязку данных. А как насчет этих вездесущих инструментов разработки? Ах, настоящая любовь. Я был там. В тот момент, когда вы впервые обнаружили, что на самом деле можете использовать фреймворк Vue поверх NativeScript, это было похоже на первый раз, когда кто-то вручил вам миску ванильного мороженого с шоколадным сиропом. Из-за этого трудно вернуться. Кроме того, NativeScript-Vue не вызовет диабета или обострит непереносимость лактозы.

Но потом вы двое начали проводить больше времени вместе. Возможно, вы думали, что интегрируете vue-devtools, чтобы посмотреть, что происходит в вашем магазине. Возможно, вы хотели использовать одну из готовых тем, по крайней мере, в качестве отправной точки. Вы хотите использовать Vue Router? Хорошо, просто успокойся. Может быть, кто-то из вас не снимал колпачок с зубной пасты.

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

Ну не волнуйся. Я здесь, чтобы помочь. Я здесь, чтобы закрыть всех. Давайте начнем с самого начала, ладно?

TL;DR

ПРИМЕЧАНИЕ. Несмотря на то, что эта статья не была протестирована / одобрена FDA, в ходе ограниченных испытаний было показано, что она помогает пользователям заснуть.

Более чем один способ снять шкуру с кошки

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

А теперь давайте познакомимся с Вещью 1 и Вещью два ...

Вариант 1 - Создание проекта стандартного интерфейса командной строки NativeScript¹

Если вы уже настроили создание проектов NativeScript из командной строки, то это должно быть вам знакомо. Если нет, рекомендую быстро прочитать Быстрый старт. В любом случае убедитесь, что вы используете последнюю версию интерфейса командной строки, которая на данный момент является v6.2.0, поскольку более старые версии будут делать… старые вещи.

tns create thing-one

После этого вам будет представлен список типов проектов, в который входит Vue.js. Для сегодняшних целей я выбрал этот и «пустой» проект.

Вариант 2 - Создание проекта CLI NativeScript-Vue²

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

npm install -g @vue/cli @vue/cli-init

Это устанавливает Vue CLI и инструмент Vue CLI Init соответственно. Как только это будет сделано, мы теперь можем использовать Vue CLI, в отличие от NativeScript CLI, для создания проекта NativeScript-Vue с использованием шаблона Vue:

vue init nativescript-vue/vue-cli-template thing-two

Это происходит аналогично варианту 1. Однако на этот раз вас спросят, хотите ли вы создать проект JavaScript или TypeScript. В последнее время я довольно сильно увлекся TypeScript. Но в этой статье уже достаточно переменных, чтобы у кого-то закружилась голова, поэтому я не буду навязывать вам другую, а просто будем придерживаться обычного старого JavaScript. Я также выбрал «простой» проект (аналогичный «пустому» выше). При появлении запроса я решил установить Vuex и Vue Devtools. Для цветовой гаммы я выбрал «синий». Не стесняйтесь выбирать, что хотите, если только вы не выбираете «ничего» (я обещаю, что все это будет иметь смысл).

Итак, в чем разница?

Большой. Итак, теперь у нас есть два проекта NativeScript Vue. И вы, вероятно, задаетесь вопросом: «Почему мы это сделали?» Так рада, что вы спросили.

Первое, что вы, вероятно, заметили, это то, что в Варианте 2 было еще несколько вопросов о том, как вы хотите настроить свой проект. Если вы откроете два проекта бок о бок, следующее, что вы заметите, это то, что их файловая структура сразу же будет совершенно иной. Также обратите внимание, что, несмотря на указание «JavaScript», мы получили /typesfolder и tsconfig.jsonfile в Thing Two. А пока давайте просто тяжело вздохнем и притворимся, что их нет. Важно отметить, что мы создали два проекта NativeScript-Vue, и они очень сильно отличаются.

Давайте немного познакомимся с нашими новорожденными. Во-первых, давайте запустим пару команд для каждого готовящегося проекта:

npm install
tns install

Я подозреваю, что вы уже сбились со счета, сколько раз набирали npm install за свою короткую жизнь, поэтому я предполагаю, что вы знаете, в чем дело. tns install устанавливает /platforms каталоги и настраивает нас для сборки как для Android, так и для iOS. Почему их нет по умолчанию? Потому что на самом деле можно создавать веб-приложения с помощью NativeScript (но не сегодня).

После выполнения вышеуказанных команд наши два проекта выглядят немного более похожими, но определенно не одинаковыми. Давайте посмотрим, что произойдет, когда мы попытаемся запустить каждый из них. В данный момент я использую Mac. Однако, если некоторые из вас работают на ПК, я остановлюсь на эмуляторе Android на сегодня и просто укажу на любые проблемы, связанные с iOS.

Вещь первая:

Поскольку при создании проекта с помощью интерфейса командной строки NativeScript у нас не было этой возможности, у нас нет ни Vue Devtools для запуска, ни хранилища Vuex. Итак, все, что нужно сделать, это запустить то, что у нас есть:

tns run android --emulator

Ничего особенного. Получается очень простое пустое приложение.

Вещь вторая:

ПРИМЕЧАНИЕ. Прежде чем двигаться дальше, вам нужно остановить любой запущенный процесс и очистить эмулятор. Не переходите ручьи (вы когда-нибудь видели Реаниматор?)

Теперь, в этом случае, у нас ДЕЙСТВИТЕЛЬНО есть магазин Vuex и Vue Devtools, поэтому давайте начнем с запуска автономной версии Electron инструментов разработки:

npx vue-devtools

А потом, как и раньше:

tns run android --emulator

Vue Devtools появляются без проблем. Однако, выполнив на этот раз ту же команду запуска, мы получим:

OMGPWNDKTHXBYE!!!

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

ReferenceError: HTMLElement is not defined

Ради экономии времени я просто пропущу этот рассказ до конца и испорчу его вам; Vue Devtools использует ловушку, чтобы узнать, когда Vuex инициализируется. Когда это происходит, он пытается создать копию состояния магазина. Частью этого процесса является процедура, которая выполняет некоторую проверку типов для каждого объекта в магазине. И одна из вещей, которые он проверяет, - является ли данный объект экземпляром HTMLElement. Конечно, поскольку это NativeScript, а не веб-сайт, у нас нет DOM. И отсутствие DOM означает отсутствие элементов HTML. А это означает большой толстый кусок undefined угля на Рождество. Таким образом, приложение просто заканчивается дизентерией, ужасно портит вашу консоль и плачет до сна (или что-то в этом роде).

Быстрое [временное] исправление⁷, которое, как я видел, использовали несколько человек, - это изменить порядок, в котором библиотеки импортируются в /app/main.js, таким образом, чтобы store импортировался ДО того, как мы импортируем nativescript-vue-devtools. Это быстрое изменение действительно избавляет от ошибки. К сожалению, это также означает, что мы не можем подключиться к магазину Vuex. К тому же на Android вообще ничего не происходит. Vue Devtools просто зависают, ожидая подключения. Это очень похоже на… отсутствие… инструментов разработчика. Но мы вернемся к этому чуть позже.

Вы также могли заметить ошибку о невозможности загрузки ~nativescript-theme-core/scss/blue. Так что наша тема тоже борется. Не то чтобы мы действительно добавили что-то «тематическое». В конце концов, мы тоже разберемся с этим.

Вы здесь

Не знаю, как вы, но я не сильно люблю ни одного из этих двух детей. У нас есть два проекта NativeScript-Vue. Они оба [сейчас] по крайней мере работают, и мы можем начать писать приложение. Но Thing One требует дополнительной работы по добавлению зависимостей и настройке вещей, чтобы они соответствовали Thing Two. Инструменты разработчика Thing Two не работают, и наша тема не загружается. Если вы посмотрите на соответствующие package.json файлы в каждом проекте, вы заметите несколько вещей.

  1. У них есть разные версии, перечисленные для одних и тех же зависимостей.
  2. Thing Two не использует текущие версии зависимостей NativeScript или Vue.

В целом, Thing Two гораздо более тщательно настроен для разработки Vue (не считая всей неработающей вещи). Но зависимости в Thing One, по крайней мере, для NativeScript, гораздо более актуальны. Честно говоря, поддержание и обновление зависимостей в любой цепочке инструментов - это рутинная работа. Часто безопаснее не быть в курсе последних событий. А обновление одной зависимости может легко повлиять на остальную часть стека. Кроме того, усилия сообщества по развитию в основном бесплатны и выполняются, когда у людей появляется свободное время. Так что я не могу указать пальцем на [мерзавца] виноватого и сказать, что любой из этих вариантов «неправильный». При этом давайте все равно обновим их.

AoTM

Ниже приведен список зависимостей и их текущая версия на сегодня [15.11.2019]. И да, я с болью осознаю, что этот список вполне может устареть еще до того, как я его закончу. Помимо самостоятельной проверки различных репозиториев, tns doctor также предупредит вас, если технология продвигается без вас, по крайней мере, в том, что касается NativeScript, и предложит вам запустить tns update.

Кроме того, с этого момента мы сделаем Вещь Один сиротой и оставим ее на обочине (не надо было называть ее). Но прежде чем выбросить его в холод, взгляните на файл .gitignore. Это одна вещь, которая намного надежнее, чем та, которую мы получили с Вещью Два, так что давайте оставим ее (она ему больше не понадобится).

Обновления зависимостей

В разделе nativescript документа package.json и Android, и iOS должны иметь версию 6.2.0.

“tns-android”: {
  “version”: “6.2.0”
},
“tns-ios”: {
  “version”: “6.2.0”
}

dependencies

Обратите внимание, что nativescript-theme-core был заменен на @nativescript/theme (подробнее об этом чуть позже).

“@nativescript/theme”: “^2.2.0”,
“vuex”: “3.1.2”,
“nativescript-socketio”: “^3.3.1”,
“nativescript-toasty”: “^2.0.1”,
“nativescript-vue”: “^2.4.0”,
“tns-core-modules”: “^6.2.1”

devDependencies

Мы не только обновим Vue Devtools, но и переместим их с dependencies на devDependencies (потому что мы не хотим встраивать их в производственные нативные приложения). Похожая история для nativescript-vue-devtools. Здесь у меня возникла небольшая путаница: и в созданном проекте, и в NPM самая последняя версия nativescript-vue-devtools указана как v1.2.0. И это несмотря на то, что последняя версия на GitHub - v1.1.0. Так что я просто пойду вместе со всеми здесь.

“@babel/core”: “^7.0.0”,
“@babel/preset-env”: “^7.0.0”,
“@vue/devtools”: “^5.3.2”,
“nativescript-vue-devtools”: “^1.2.0”,
“babel-loader”: “^8.0.2”,
“nativescript-dev-webpack”: “^1.3.0”,
“nativescript-vue-template-compiler”: “^2.0.0”,
“nativescript-worker-loader”: “~0.9.5”,
“node-sass”: “^4.9.2”,
“vue-loader”: “^15.7.2”

Растущая боль

По мере того, как NativeScript продолжает развиваться, он уходит от tns-core-modules и переходит в ограниченное пространство имен @nativescript. По крайней мере, в ближайшем будущем tns-core-modules также поддерживается для обратной совместимости. К сожалению, функции и обновления, как правило, опережают документацию. Итак, у нас есть некоторые документы, указывающие на одно соглашение, а некоторые - на другое. А наличие устаревших зависимостей приводит к тому, что код, указывающий на разные соглашения, делает такие вещи, как нарушение вашей * кашляющей * темы³. Имея это в виду и обновив стек, давайте вылечим то, что вас беспокоит.

Вариации на тему

В пределах /app/app.scss просто удалите… все. Затем замените его на это, чтобы оно соответствовало нашей обновленной зависимости⁸:

@import “~@nativescript/theme/core”;
@import “~@nativescript/theme/blue”;

Получите Android на условиях разговора с помощью Devtools

Чтобы Android работал и работал нормально с инструментами разработки, нам нужно будет провести несколько амбулаторных операций⁶. Готовый? Вот так…

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

Перейдите к файлу манифеста Android:

/app/App_Resources/Android/src/main/AndroidManifest.xml

Затем в блоке <application> добавьте:

android:usesCleartextTraffic=”true”

Теперь мы можем, по крайней мере, заставить и iOS, и Android подключиться к Vue Devtools, но только пока действует наш временный обходной путь, оставляющий нас без представления в магазине. И мне очень нужен шоколадный сироп.

Комната без Vue

Vue Devtools был разработан с учетом веб-среды. Из-за этого вполне вероятно, что кто-то может хранить один или несколько повторно используемых HTML-элементов в хранилище Vuex. Итак, когда devtools клонирует store.state, ему необходимо перебрать то, что он получил, и выяснить, что представляют собой различные типы объектов, чтобы он знал, как с ними бороться, прежде чем заполнять их через соединение с сокетом. Простые типы - это нормально, но все более сложное нужно будет глубоко скопировать, создать экземпляры или проигнорировать.

Но в NativeScript нет HTMLElement типов (или даже DOM). Поэтому, когда инструменты разработчика пытаются проверить объект на instanceof HTMLElement, он взрывается с undefined⁷ (а try/catch нет).

Хотя технически это не ошибка, для нас это определенно проблема. Итак, каковы некоторые из наших возможных вариантов / обходных путей? В порядке от наиболее до наименее инвазивного:

  • Измените исходный код Vue Devtools в node_modules: просто закомментировав 3 строки ошибочного кода, вы эффективно решите проблему. Однако в первый раз, когда вы чистите, строите или обновляете зависимости, изменение не будет заметным.
  • Разверните vue-devtools и измените эти 3 строки: Gross. Просто нет.
  • Перегрузить весь метод installHook() в @vue/devtools/build/hook.js: Хотя это возможно, это кажется немного ... тупым.
  • Создать поддельный тип HTMLElement: это действительно кажется потенциально жизнеспособным вариантом. Это даже не обязательно должен быть правильный / пригодный для использования тип. Он просто должен позволить условию [безопасно] выйти из строя, чтобы можно было двигаться дальше.

Подделка, пока {{кто-то}} не добьется успеха {{лучше}}

Во-первых, давайте переместим import строку для nativescript-vue-devtools обратно в начало main.js (что немедленно приведет к поломке нашего приложения).

import VueDevtools from 'nativescript-vue-devtools'
import Vue from 'nativescript-vue'
import store from './store'
import App from './components/App'

Затем в вашем webpack.config.js перейдите в раздел plugins. В частности, раздел webpack.DefinePlugin()⁹. Здесь определяются глобальные значения для приложения. Внутри этого блока добавьте нижнюю строку:

new webpack.DefinePlugin({
  "global.TNS_WEBPACK": "true",
  "TNS_ENV": JSON.stringify(mode),
  "process": "global.process",
  "HTMLElement": function(){return false},
}),

Ага. Вот и все. Вам придется повторно запустить приложение, поскольку обновления конфигурации WebPack не запускают Watchman. Но это фактически создает глобальный тип HTMLElement, предотвращая условие undefined. Когда Vue Devtools анализирует предметы в вашем магазине, он никогда не вернет true при тестировании с instanceof HTMLElement. И это совершенно нормально, потому что у вас его никогда не будет. Если, конечно, вы не решите определить свой собственный HTMLElement тип, который также возвращает только false, а затем вы также решите сохранить его экземпляры в своем магазине. Но если вы сделаете это, вы как бы заслужите все, что получите. Но даже тогда это не приведет к сбою приложения из-за ошибки JavaScript. Он просто вернет object.cloneNode(false)… что мы и хотели в первую очередь.

Победа, победа.

Надеть лук

И вот мы здесь! Теперь у нас есть полностью функциональная, надежная и современная основа для разработки приложения NativeScript-Vue нашей мечты. Это просто показывает, что если вы потратите время, чтобы прочитать документы, почистить Интернет, проанализировать исходный код, отследить, казалось бы, случайные и непоследовательные ошибки и сделать пару удачных предположений ... это просто работает. Мы живем в действительно удивительное время.

Летите безопасно, друзья мои.

использованная литература

  1. Краткое руководство по NativeScript - https://docs.nativescript.org/angular/start/quick-setup
  2. Краткое руководство по NativeScript-Vue - https://nativescript-vue.org/en/docs/getting-started/quick-start/
  3. Документация по теме NativeScript - https://docs.nativescript.org/ui/theme
  4. Vue Devtools - https://github.com/vuejs/vue-devtools
  5. NativeScript Vue Devtools - https://nativescript-vue.org/en/docs/getting-started/vue-devtools/
  6. NativeScript Vue Devtools и Android - https://stackoverflow.com/questions/55407201/nativescript-vue-devtools-does-not-connect
  7. Сбой NativeScript Vue Devtools - https://stackoverflow.com/questions/58672942/htmlelement-is-not-defined-nativescript-vue
  8. Тема NativeScript на GitHub - https://github.com/NativeScript/theme
  9. WebPack и глобальные переменные - https://discourse.nativescript.org/t/webpack-and-global-variables/7857