Tern - отличный инструмент для Javascript, но иногда мне трудно рассуждать о нем, что ведет меня к черным дырам несогласованной настройки конфигурации, пока он не сработает волшебным образом. Недавно я более глубоко погрузился в понимание этого и хотел поделиться с вами (и со своим будущим, когда я вернусь к поиску в Google)

Tern:

  • Http-сервер, который принимает почтовые запросы JSON.
  • Обычно запускают в редакторе через плагин (vim, atom и т. Д.)
  • Читает из .tern-project файла в корне проекта
  • При запуске создает файл .tern-port, чтобы ваш редактор знал, к какому порту подключаться.
  • Считывает серию файлов из вашего проекта в память и по запросу возвращает тип / автозаполнение и другую полезную информацию.
  • См. Больше на https://ternjs.net/doc/manual.html

Проблема, с которой я обычно сталкиваюсь, заключается в том, что он, кажется, время от времени не может завершить [некоторые] вещи. Это можно продемонстрировать, создав конфигурацию и вручную запустив сервер с установленной опцией --verbose. В приложении stockcreate-react-app добавьте в корень проекта следующий файл

.tern-project

{
  "libs": [
    "browser"
  ],
  "loadEagerly": [],
  "dontLoad": [],
  "plugins": {
    "modules": {},
    "es_modules": {},
    "requirejs": {},
    "commonjs": {}
  }
}

Установите и запустите двоичный файл в другом терминале

# if you haven't installed tern already
$ yarn global add tern
$ cd project-dir
$ tern --verbose
# Outputs: Listening on port [port#]

теперь, когда у вас есть сервер, работающий в каталоге проекта, ваш редактор (у которого должен быть плагин tern https://ternjs.net/doc/manual.html#editor) должен выбрать файл .tern-port и знать, что там - это запущенный сервер, и ему не нужно запускать новый.

Если я открою новый файл с именем autocompleteme.js в каталоге src и попробую что-то завершить, я увижу следующее…

Так крачка ... работает? ¯_ (ツ) _ / ¯

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

Если вы вернетесь к терминалу, на котором запущен сервер, вы должны увидеть несколько поступивших запросов и ответов (это много JSON, поэтому просто прокрутите мимо, если вам нужно только объяснение).

Request: {
  "query": {
    "type": "completions",
    "types": true,
    "depths": true,
    "docs": false,
    "filter": true,
    "caseInsensitive": true,
    "guess": true,
    "sort": false,
    "expandWordForward": true,
    "omitObjectPrototype": false,
    "includeKeywords": false,
    "inLiteral": true,
    "file": "#0",
    "end": {
      "line": 2,
      "ch": 0
    },
    "lineCharPositions": true
  },
  "files": [
    {
      "type": "full",
      "name": "src/autocompleteme.js",
      "text": "import React, { Component } from \"react\";\n\nRea\n"
    }
  ]
}
Response: {
  "start": {
    "line": 2,
    "ch": 0
  },
  "end": {
    "line": 2,
    "ch": 3
  },
  "isProperty": false,
  "isObjectKey": false,
  "completions": [
    {
      "name": "React",
      "type": "?",
      "depth": 0
    }
  ]
}

Вы можете видеть, что он отправляет текущий файл, а также позицию курсора и запрашивает параметры завершения. Ближе к концу получается один ... `React` с типом ?, который мы видели в поле автозаполнения.

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

Request: {
  "query": {
    "type": "completions",
    "types": true,
    "depths": true,
    "docs": false,
    "filter": true,
    "caseInsensitive": true,
    "guess": true,
    "sort": false,
    "expandWordForward": true,
    "omitObjectPrototype": false,
    "includeKeywords": false,
    "inLiteral": true,
    "file": "#0",
    "end": {
      "line": 2,
      "ch": 6
    },
    "lineCharPositions": true
  },
  "files": [
    {
      "type": "full",
      "name": "src/autocompleteme.js",
      "text": "import React, { Component } from 'react';\n\nReact.\n"
    }
  ]
}
Response: {
  "start": {
    "line": 2,
    "ch": 6
  },
  "end": {
    "line": 2,
    "ch": 6
  },
  "isProperty": true,
  "isObjectKey": false,
  "completions": []
}

И есть варианты нулевой доработки… хммм. Заглянув в документацию (https://ternjs.net/doc/manual.html#req_files), я вижу, что есть конечная точка для получения файлов, проанализированных сервером, в основном всех файлов, которые tern может рисовать. доработки из. Примерного запроса нет, поэтому, немного поработав, я смог придумать curl запрос, который был принят ...

# get the port number from the `.tern-port` file
$ curl -X POST https://localhost:57242 -d '{"query": {"type": "files"}}'
# OUTPUT: {"files":[]}

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

По умолчанию локальные файлы загружаются на сервер Tern при выполнении запросов в редакторе. Http://ternjs.net/doc/manual.html#configuration

Это могло бы объяснить, почему он иногда работает, а иногда нет, даже с одним и тем же кодом ... Если у вас был запущен tern server, и он читает файл, то он запомнит его и извлечет из него автозаполнения. Так что, если ваш редактор был открыт долгое время и было открыто много файлов, он мог бы, казалось бы, завершить все, только чтобы вернуться позже в тот же день, не касаясь конфигурации, и все кажется сломанным.

Как это исправить

Чтобы исправить это, убедитесь, что у вас есть правильные строки в конфигурации, которые могут указать серверу, где искать файлы и загружать их сразу при запуске. Для своих целей при написании javascript я обычно использую create-react-app, который использует веб-пакет, поэтому я сосредоточусь на этом плагине, но есть и другие [здесь] (https://ternjs.net/doc/manual.html#plugins)

При использовании create-react-app конфигурация веб-пакета входит в node_modules, поэтому мы должны использовать путь к этому файлу.

{
  "libs": [
    "browser"
  ],
  "loadEagerly": [],
  "dontLoad": [],
  "plugins": {
    "modules": {},
    "webpack": {
      "configPath": "./node_modules/react-scripts/config/webpack.config.dev.js"
    }
  }
}

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

Единственный способ, которым я мог это увидеть, - это создать сценарий оболочки, который устанавливает переменную и вызывает tern

custom-tern

#!/bin/bash
# while debugging and experimenting, add the pipe to a log file
NODE_ENV=dev tern --persistent --verbose | tee /tmp/tern.log

Как только я добавил это в свой ~/bin и изменил свой редактор, чтобы использовать мой custom-tern в качестве tern исполняемого файла, я смог увидеть доработки во всей их красе. Если мы запросим файлы с curl, можно будет убедиться, что несколько файлов были загружены в память при запуске ...

$ curl -X POST https://localhost:60662 -d '{"query": {"type": "files"}}'
{"files":
["src/autocompleteme.js","node_modules/react/index.js","node_modules/react/cjs/react.production.min.js","node_modules/react/cjs/react.development.js","node_modules/object-assign/index.js","node_modules/fbjs/lib/emptyObject.js","node_modules/fbjs/lib/emptyFunction.js","node_modules/fbjs/lib/invariant.js","node_modules/fbjs/lib/warning.js","node_modules/prop-types/checkPropTypes.js","node_modules/prop-types/lib/ReactPropTypesSecret.js"]}

Эта статья больше о внутренней работе tern, а не о настройке вашего редактора, но если вы хотите увидеть мой vimrc, вы можете проверить мою настройку

На что следует обратить внимание:

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

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

Как только все заработает, вы можете удалить перенаправление в скрипте custom-tern. (Если вам нужно снова устранить неполадки, обязательно используйте tee вместо >, потому что перенаправление stdout с >, похоже, все ломает)

Я думаю, что есть много путаницы в том, как работает tern и почему он ломается, потому что большая часть работы абстрагируется в npm пакетах и ​​подключаемых модулях редактора, но место, где необходимо устранить проблему (сервер), часто скрыто в некоторых фоновый процесс. Итак, чтобы понять, что именно нужно исправить, людям нужно

  1. Вручную запустить сервер в оболочке
  2. Откройте другую оболочку или инструмент и отправьте ему пользовательские запросы JSON для проверки состояния сервера.
  3. Вернитесь и прочтите документацию, выясните, где у вас неправильная конфигурация, и попробуйте еще раз, пока не получите правильный ответ.

Я надеюсь, что любой, кто найдет свой путь к этому, будет лучше понимать, что делать, и, надеюсь, я сэкономил вам время! Спасибо