Русский
Русский
English
Статистика
Реклама

Сниппет

Перевод 20 ES6-сниппетов для решения практических задач

11.11.2020 10:16:50 | Автор: admin


Доброго времени суток, друзья!

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

Предполагается, что вы имеете определенный опыт программирования на JavaScript.

1. Как скрыть все элементы определенного типа?


// вспомогательная функция для нахождения всех элементов определенного типаconst findAll = (parent, selector) => parent.querySelectorAll(selector)const hide = (...els) => [...els].forEach(el => el.style.display = 'none')// примерhide(findAll(document, 'img')) // находим и скрываем все элементы "img" на странице

2. Как проверить, что элемент имеет определенный класс?


// вспомогательная функция для нахождения одного элемента определенного типаconst findOne = (parent, selector) => parent.querySelector(selector)const hasClass = (el, className) => el.classList.contains(className)// примерhasClass(findOne(document, 'p'), 'special') // true

3. Как переключить классы элемента?


const toggleClass = (el, className) => el.classList.toggleClass(className)// примерtoggleClass(findOne('p'), 'special') // параграф больше не имеет класса "special"

4. Как получить величину прокрутки текущей страницы?


const getScrollPosition = (el = window) => ({  x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,  y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop})// примерgetScrollPosition() // { x: 0, y: 200 }

5. Как сделать плавную прокрутку в начало страницы?


const scrollToTop = () => {  const c = document.documentElement.scrollTop || document.body.scrollTop  if (c > 0) {    requestAnimationFrame(scrollToTop)    scrollTo(0, c - c / 8)  }}// илиscrollTo({  top: 0,  behavior: 'smooth'})// примерscrollToTop()

6. Как проверить, содержит ли один элемент другой?


const elementContains = (parent, child) => parent !== child && parent.contains(child)// примерelementContains(findOne(document, 'head'), findOne(document, 'title')) // trueelementContains(findOne(document, 'body'), findOne(document, 'body')) // false

7. Как определить, попадает ли элемент в область просмотра?


const elemIsVidibleInViewport = (el, partiallyVisible = false) => {  const { top, left, bottom, right } = el.getBoundingClientRect()  const { innerHeight, innerWidth } = window  return partiallyVisible    ? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&      ((left > 0 && left < innerWidth || right > 0 && right < innerWidth))    : top >= 0 & left >=0 && bottom <= innerHeight && rigth <= innerWidth}// примерelemIsVidibleInViewport(el) // элемент должен быть виден полностьюelemIsVidibleInViewport(el, true) // может быть виден частично

8. Как получить все изображения, находящиеся внутри определенного элемента?


const getImages = (el, includeDuplicates = false) => {  const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src'))  return includeDuplicates ? images : [...new Set(images)]}// примерgetImages(document, true) // получаем все изображения на страницеgetImages(document, false) // получаем только уникальные изображения

9. Как определить устройство пользователя?


const detectDeviceType = () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)    ? 'Mobile'    : 'Desktop'// ExampledetectDeviceType()

11. Как создать объект, содержащий параметры текущего URL?


const getURLParams = url => (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(  (a, v) => ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a),  {})// примерgetURLParams('http://url.com/page?f=John&l=Smith') // { f: 'John', l: 'Smith' }getURLParams('https://google.com') // { }

12. Как преобразовать элементы формы в объект?


const formToObject = form =>  Array.from(new FormData(form)).reduce(    (acc, [key, value]) => ({      ...acc,      [key]: value    }),    {}  )// примерformToObject(findOne(document, 'form')) // { name: 'John', email: "myemail@example.com" }

13. Как извлечь определенные свойства объекта?


const getProps = (from, ...selectors) =>  [...selectors].map(s =>    s      .replace(/\[([^\[\]]*)\]/g, '.$1.')      .split('.')      .filter(t => t !== '')      .reduce((prev, cur) => prev && prev[cur], from)  )const obj = { selector: { to: { value: 'value to select' } }, target: [ 1, 2, { a: 'test' } ] }// примерgetProps(obj, 'selector.to.value', 'target[0]', 'target[2].a') // [ 'value to select', 1, 'test' ]

14. Как вызвать функцию через определенное время (в миллисекундах)?


// вспомогательная функция для вывода сообщения в консольconst log = (value) => console.log(value)const delay = (fn, wait, ...rest) => setTimeout(fn, wait, ...rest)// примерdelay(  text => log(text),  1000,  'позже')// 'позже' через 1 секунду

16. Как удалить обработчик события, зарегистрированный на определенном элементе?


// вспомогательная функция для добавления обработчикаaddListener = (el, evt, cb) => el.addEventListener(evt, cb)const removeListener = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts)const fn = () => log('!')// пример;((B) => {  addListener(B, 'click', fn)  removeListener(B, 'click', fn) // сообщение "!" больше не выводится в консоль после клика})(document.body)

17. Как преобразовать миллисекунды в читаемый формат?


const formatDuration = ms => {  if (ms < 0) ms = -ms  const time = {    // ~~ = Math.floor    day: ~~(ms / 86400000),    hour: ~~(ms / 3600000) % 24,    minute: ~~(ms / 60000) % 60,    second: ~~(ms / 1000) % 60,    millisecond: ~~(ms) % 1000  }  return Object.entries(time)    .filter(val => val[1] !== 0)    .map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`)    .join(', ')}// примерformatDuration(1001); // 1 second, 1 millisecondformatDuration(34325055574); // 397 days, 6 hours, 44 minutes, 15 seconds, 574 milliseconds

18. Как получить разницу между двумя датами в днях?


const getDaysDiffBetweenDates = (dateInitial, dateFinal) => (dateFinal - dateInitial) / (1000 * 3600 * 24)// примерlog(  getDaysDiffBetweenDates(new Date('2020-11-01'), new Date('2020-11-09'))) // 8

19. Как сделать GET-запрос?


// XMLHttpRequestconst httpGet = (url, cb, err = console.error) => {  const req = new XMLHttpRequest()  req.open('GET', url, true)  req.onload = () => cb(req.responseText)  req.onerror = () => err(req)  req.send()}httpGet(  'https://jsonplaceholder.typicode.com/posts/1',  log) // { "userId": 1, "id": 1, "title": "some title", "body": "some text" }// fetchconst httpGet = (url, cb, err = console.error) =>  fetch(url)    .then(response => response.json())    .then(result => cb(result))    .catch(error => err(error))// async/awaitconst httpGet = async (url, cb, err = console.error) => {  try {    const response = await fetch(url);    const result = await response.json();    cb(result);  } catch (error) {    err(error)  }}

20. Как сделать POST-запрос?


// XMLHttpsRequestconst httpPost = (url, data, cb, err = console.error) => {  const req = new XMLHttpRequest()  req.open('POST', url, true)  req.setRequestHeader('Content-Type', 'application/json')  req.onload = () => cb(req.responseText)  req.onerror = () => err(req)  req.send(data)}const newPost = {  userId: 1234,  title: 'foo',  body: 'bar baz qux'}const data = JSON.stringify(newPost)httpPost(  'https://jsonplaceholder.typicode.com/posts',  data,  log) // { "id": 101, "userId": 1234, "title": "foo", "body": "bar baz qux" }// async/awaitconst httpPost = async (url, data, cb, err = console.error) => {  try {    const response = await fetch(url, {      method: 'POST',      headers: {        'Content-Type': 'application/json'      },      body: JSON.stringify(data)    })    const result = await response.json()    cb(result)  } catch (error) {    err(error)  }}httpPost(  'https://jsonplaceholder.typicode.com/posts',  newPost,  log)

21. Как создать счетчик с определенным диапазоном, шагом и продолжительностью?


const counter = (selector, start, end, step = 1, duration = 2000) => {  let current = start,    _step = (end - start) * step < 0 ? -step : step,    timer = setInterval(() => {      current += _step      findOne(document, selector).innerHTML = current      if (current >= end) findOne(document, selector).innerHTML = end      if (current >= end) clearInterval(timer)    }, Math.abs(~~(duration / (end - start))))    return timer}// примерcounter('#some_id', 1, 1000, 5, 2000) // создаем двухсекундный таймер для элемента с идентификатором "some_id"

22. Как скопировать строку в буфер обмена?


const copyToClipboard = str => {  const el = document.createElement('textarea')  el.value = str  el.setAttribute('readonly')  el.style.position = 'absolute'  el.style.left = '-999px'  document.body.append(el)  const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false  el.select()  document.execCommand('copy')  el.remove()  if (selected) {    document.getSelection().removeAllRanges()    document.getSelection().addRange(selected)  }}// примерcopyToClipboard('some text') // строка "some text" скопирована в буфер обмена

Надеюсь, вы нашли для себя что-нибудь интересное. Еще больше JavaScript в моем приложении. Благодарю за внимание.
Подробнее..

Сниппет, расширение для VSCode и CLI. Часть 1

04.12.2020 14:04:54 | Автор: admin


Доброго времени суток, друзья!

В процессе разработки Современного стартового HTML-шаблона я задумался о расширении возможностей его использования. На тот момент варианты его применения ограничивались клонированием репозитория и скачиванием архива. Так появились HTML-сниппет и расширение для Microsoft Visual Studio Code HTML Template, а также интерфейс командной строки create-modern-template. Конечно, указанные инструменты далеки от совершенства и я буду их дорабатывать по мере сил и возможностей. Однако, в процессе их создания я узнал несколько интересных вещей, которыми и хочу с вами поделиться.

В этой части мы рассмотрим сниппет и расширение, а CLI в следующей.

Если вас интересует лишь исходный код, вот ссылка на репозиторий.

Сниппет (Snippet)


Что такое сниппет? Если коротко, сниппет это заготовка, которую использует редактор для автозаполнения (автодополнения кода).

В VSCode встроен Emmet (официальный сайт, Emmet in Visual Studio Code), который использует многочисленные HTML, CSS и JS-сниппеты для помощи в написании кода. Набираем в редакторе (в .html) !, нажимаем Tab или Enter, получаем готовую html5-разметку. Набираем nav>ul>li*3>a.link>img, нажимаем Tab, получаем:

<nav>    <ul>      <li><a href="" class="link"><img src="" alt=""></a></li>      <li><a href="" class="link"><img src="" alt=""></a></li>      <li><a href="" class="link"><img src="" alt=""></a></li>    </ul>  </nav>

и т.д.

Кроме встроенных, VSCode предусматривает возможность использования пользовательских сниппетов. Для их создания необходимо перейти в File -> Preferences -> User Snippets (или нажать на кнопку Manage в левом нижнем углу и выбрать User Snippets). Настройки для каждого языка хранятся в соответствующем JSON-файле (для HTML в html.json, для JavaScript в javascript.json и т.д.).

Потренируемся создавать JS-сниппеты. Находим файл javascript.json и открываем его.



Видим комментарии, кратко описывающие правила создания сниппетов. Более подробную информацию о создании пользовательских сниппетов в VSCode можно найти здесь.

Начнем с чего-нибудь простого. Создадим сниппет для console.log(). Вот как он выглядит:

"Print to console": {  "prefix": "log",  "body": "console.log($0)",  "description": "Create console.log()"},

  • Print to console ключ объекта, название сниппета (обязательно)
  • prefix сокращение для сниппета (обязательно)
  • body сам сниппет (обязательно)
  • $число положение курсора после создания сниппета; $1 первое положение, $2 второе и т.д., $0 последнее положение (опционально)
  • description описание сниппета (опционально)

Сохраняем файл. Набираем log в скрипте, нажимаем Tab или Enter, получаем console.log() с курсором между скобками.

Создадим сниппет для цикла for-of:

"For-of loop": {  "prefix": "fo",  "body": [    "for (const ${1:item} of ${2:arr}) {",    "\t$0",    "}"  ]},

  • Сниппеты, состоящие из нескольких строк, создаются с помощью массива
  • ${число: значение}; ${1:item} означает первое положение курсора со значением item по умолчанию; данное значение выделяется после создания сниппета, а также после перехода к следующему положению курсора для быстрого редактирования
  • \t один отступ (величина оступа определяется соответствующими настройками редактора или, как в моем случае, расширения Prettier), \t\t два отступа и т.д.

Набираем в скрипте fo, нажимаем Tab или Enter, получаем:

for (const item of arr) {}

с выделенным item. Нажимаем Tab, выделяется arr. Еще раз нажимаем Tab, переходим на вторую строку.

Вот еще несколько примеров:

"For-in loop": {  "prefix": "fi",  "body": [    "for (const ${1:key} in ${2:obj}) {",    "\t$0",    "}"  ]},"Get one element": {  "prefix": "qs",  "body": "const $1 = ${2:document}.querySelector('$0')"},"Get all elements": {  "prefix": "qsa",  "body": "const $1 = [...${2:document}.querySelectorAll('$0')]"},"Add listener": {  "prefix": "al",  "body": [    "${1:document}.addEventListener('${2:click}', (${3:{ target }}) => {",    "\t$0",    "})"  ]},"Async function": {  "prefix": "af",  "body": [    "const $1 = async ($2) => {",    "\ttry {",    "\t\tconst response = await fetch($3)",    "\t\tconst data = await res.json()",    "\t\t$0",    "\t} catch (err) {",    "\t\tconsole.error(err)",    "\t}",    "}"  ]}

HTML-сниппеты строятся по такому же принципу. Вот как выглядит HTML Template:

{  "HTML Template": {    "prefix": "html",    "body": [      "<!DOCTYPE html>",      "<html",      "\tlang='en'",      "\tdir='ltr'",      "\titemscope",      "\titemtype='https://schema.org/WebPage'",      "\tprefix='og: http://ogp.me/ns#'",      ">",      "\t<head>",      "\t\t<meta charset='UTF-8' />",      "\t\t<meta name='viewport' content='width=device-width, initial-scale=1' />",      "",      "\t\t<title>$1</title>",      "",      "\t\t<meta name='referrer' content='origin' />",      "\t\t<link rel='canonical' href='$0' />",      "\t\t<link rel='icon' type='image/png' href='./icons/64x64.png' />",      "\t\t<link rel='manifest' href='./manifest.json' />",      "",      "\t\t<!-- Security -->",      "\t\t<meta http-equiv='X-Content-Type-Options' content='nosniff' />",      "\t\t<meta http-equiv='X-XSS-Protection' content='1; mode=block' />",      "",      "\t\t<meta name='author' content='$3' />",      "\t\t<meta name='description' content='$2' />",      "\t\t<meta name='keywords' content='$4' />",      "",      "\t\t<meta itemprop='name' content='$1' />",      "\t\t<meta itemprop='description' content='$2' />",      "\t\t<meta itemprop='image' content='./icons/128x128.png' />",      "",      "\t\t<!-- Microsoft -->",      "\t\t<meta http-equiv='x-ua-compatible' content='ie=edge' />",      "\t\t<meta name='application-name' content='$1' />",      "\t\t<meta name='msapplication-tooltip' content='$2' />",      "\t\t<meta name='msapplication-starturl' content='/' />",      "\t\t<meta name='msapplication-config' content='browserconfig.xml' />",      "",      "\t\t<!-- Facebook -->",      "\t\t<meta property='og:type' content='website' />",      "\t\t<meta property='og:url' content='$0' />",      "\t\t<meta property='og:title' content='$1' />",      "\t\t<meta property='og:image' content='./icons/256x256.png' />",      "\t\t<meta property='og:site_name' content='$1' />",      "\t\t<meta property='og:description' content='$2' />",      "\t\t<meta property='og:locale' content='en_US' />",      "",      "\t\t<!-- Twitter -->",      "\t\t<meta name='twitter:title' content='$1' />",      "\t\t<meta name='twitter:description' content='$2' />",      "\t\t<meta name='twitter:url' content='$0' />",      "\t\t<meta name='twitter:image' content='./icons/128x128.png' />",      "",      "\t\t<!-- IOS -->",      "\t\t<meta name='apple-mobile-web-app-title' content='$1' />",      "\t\t<meta name='apple-mobile-web-app-capable' content='yes' />",      "\t\t<meta name='apple-mobile-web-app-status-bar-style' content='#222' />",      "\t\t<link rel='apple-touch-icon' href='./icons/256x256.png' />",      "",      "\t\t<!-- Android -->",      "\t\t<meta name='theme-color' content='#eee' />",      "\t\t<meta name='mobile-web-app-capable' content='yes' />",      "",      "\t\t<!-- Google Verification Tag -->",      "",      "\t\t<!-- Global site tag (gtag.js) - Google Analytics -->",      "",      "\t\t<!-- Global site tag (gtag.js) - Google Analytics -->",      "",      "\t\t<!-- Yandex Verification Tag -->",      "",      "\t\t<!-- Yandex.Metrika counter -->",      "",      "\t\t<!-- Mail Verification Tag -->",      "",      "\t\t<!-- JSON-LD -->",      "\t\t<script type='application/ld+json'>",      "\t\t\t{",      "\t\t\t\t'@context': 'http://schema.org/',",      "\t\t\t\t'@type': 'WebPage',",      "\t\t\t\t'name': '$1',",      "\t\t\t\t'image': [",      "\t\t\t\t\t'$0icons/512x512.png'",      "\t\t\t\t],",      "\t\t\t\t'author': {",      "\t\t\t\t\t'@type': 'Person',",      "\t\t\t\t\t'name': '$3'",      "\t\t\t\t},",      "\t\t\t\t'datePublished': '2020-11-20',",      "\t\t\t\t'description': '$2',",      "\t\t\t\t'keywords': '$4'",      "\t\t\t}",      "\t\t</script>",      "",      "\t\t<!-- Google Fonts -->",      "",      "\t\t<style>",      "\t\t\t/* Critical CSS */",      "\t\t</style>",      "",      "\t\t<link rel='preload' href='./css/style.css' as='style'>",      "\t\t<link rel='stylesheet' href='./css/style.css' />",      "",      "<link rel='preload' href='./script.js' as='script'>",      "\t</head>",      "\t<body>",      "\t\t<!-- HTML5 -->",      "\t\t<header>",      "\t\t\t<h1>$1</h1>",      "\t\t\t<nav>",      "\t\t\t\t<a href='#' target='_blank' rel='noopener'>Link 1</a>",      "\t\t\t\t<a href='#' target='_blank' rel='noopener'>Link 2</a>",      "\t\t\t</nav>",      "\t\t</header>",      "",      "\t\t<main></main>",      "",      "\t\t<footer>",      "\t\t\t<p> 2020. All rights reserved</p>",      "\t\t</footer>",      "",      "\t\t<script src='./script.js' type='module'></script>",      "\t</body>",      "</html>"    ],    "description": "Create Modern HTML Template"  }}

Набираем html, нажимаем Tab или Enter, получаем разметку. Положения курсора определены в следующем порядке: название приложения (title), описание (description), автор (author), ключевые слова (keywords), адрес (url).

Расширение (Extension)


На сайте VSCode имеется отличная документация по созданию расширений.

Мы создадим два варианта расширения: в форме сниппетов и в форме CLI. Второй вариант опубликуем в Visual Studio Marketplace.

Примеры расширений в форме сниппетов:


Расширения в форме CLI менее популярны, вероятно, по той причине, что существуют настоящие CLI.

Расширение в форме сниппетов

Для разработки расширений для VSCode, нам, кроме Node.js и Git, потребуется еще парочка библиотек, точнее, одна библиотека и плагин, а именно: yeoman и generator-code. Устанавливаем их глобально:

npm i -g yo generator-code// илиyarn global add yo generator-code

Выполняем команду yo code, выбираем New Code Snippets, отвечаем на вопросы.



Осталось скопировать созданный нами ранее HTML-сниппет в файл snippets/snippets.code-snippets (файлы сниппетов также могут иметь расширение json), отредактировать package.json и README.md, и можно публиковать расширение в маркетплейсе. Как видите, все очень просто. Слишком просто, подумал я, и решил создать расширение в форме CLI.

Расширение в форме CLI

Снова выполняем команду yo code. На этот раз выбираем New Extension (TypeScript) (не бойтесь, TypeScript в нашем коде почти не будет, а там, где будет, я дам необходимые разъяснения), отвечаем на вопросы.



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

cd htmltemplatecode .

Нажимаем F5 или на кнопку Run (Ctrl/Cmd+Shift+D) слева и кнопку Start Debugging сверху. Иногда при запуске можно получить ошибку. В этом случае отменяем запуск (Cancel) и повторяем процедуру.

В открывшемся редакторе нажимаем View -> Command Palette (Ctrl/Cmd+Shift+P), набираем hello и выбираем Hello World.



Получаем информационное сообщение от VSCode и соответствующее сообщение (поздравление) в консоли.



Из всех файлов, имеющихся в проекте, нас интересуют package.json и src/extension.ts. Директорию src/test и файл vsc-extension-quickstart.md можно удалить.

Заглянем в extension.ts (комментарии удалены для удобочитаемости):

// импорт функционала VSCodeimport * as vscode from 'vscode'// функция, вызываемая при активации расширенияexport function activate(context: vscode.ExtensionContext) {  // сообщение, выводимое в консоль редактора,  // в котором запущена отладка расширения  console.log('Congratulations, your extension "htmltemplate" is now active!')  // функционал расширения  // команда - это свойство расширения  // htmltemplate - название расширения  // helloWorld - название команды  let disposable = vscode.commands.registerCommand(    'htmltemplate.helloWorld',    () => {      // информационное сообщение, отображаемое в редакторе      // при успешном выполнении команды      vscode.window.showInformationMessage('Hello World from htmltemplate!')    }  )  // регистрация команды  // судя по всему, здесь реализован паттерн проектирования "Подписка/Уведомление",  // один из вариантов паттерна "Наблюдатель"  context.subscriptions.push(disposable)}// функция, вызываемая при деактивации расширенияexport function deactivate() {}

Важный момент: 'расширение.команда' в extension.ts должно совпадать со значениями полей activationEvents и command в package.json:

"activationEvents": [  "onCommand:htmltemplate.helloWorld"],"contributes": {  "commands": [    {      "command": "htmltemplate.helloWorld",      "title": "Hello World"    }  ]},

  • commands список команд
  • activationEvents функции, вызываемые при выполнении команд

Приступаем к разработке расширения.

Мы хотим, чтобы наше расширение по функционалу напоминало create-react-app или vue-cli, т.е. по команде create создавало проект, содержащий все необходимые файлы, в целевой директории.

Для начала отредактируем package.json:

"displayName": "HTML Template","activationEvents": [  "onCommand:htmltemplate.create"],"contributes": {  "commands": [    {      "command": "htmltemplate.create",      "title": "Create Template"    }  ]},

Создаем директорию src/components для хранения файлов проекта, которые будут копироваться в целевую директорию.

Создаем файлы проекта в виде ES6-модулей (VSCode по умолчанию использует ES6-модули (export/import), но поддерживает и CommonJS-модули (module.exports/require)): index.html.js, css/style.css.js, script.js и т.д. Содержимое файлов экспортируется по умолчанию:

// index.html.jsexport default `<!DOCTYPE html><html  lang="en"  dir="ltr"  itemscope  itemtype="http://personeltest.ru/aways/schema.org/WebPage"  prefix="og: http://ogp.me/ns#">  ...</html>`

Обратите внимание, что при таком подходе все изображения (в нашем случае, иконки) должны быть закодированы в Base64: вот один из подходящих онлайн-инструментов. Наличие строки data:image/png;base64, в начале преобразованного файла принципиального значение не имеет.

Для копирования (записи) файлов мы будем использовать fs-extra. Метод outputFile данной библиотеки делает томе самое, что и встроенный Node.js-метод writeFile, но также создает директорию для записываемого файла при ее отсутствии: например, если мы указали создать css/style.css, а директории css не существует, outputFile создаст ее и запишет туда style.css (writeFile при отсутствии директории выбросит исключение).

Файл extension.ts выглядит следующим образом:

import * as vscode from 'vscode'// импорт библиотеки fs-extraconst fs = require('fs-extra')const path = require('path')// импорт файлов проекта, точнее, содержимого этих файловimport indexHTML from './components/index.html.js'import styleCSS from './components/css/style.css.js'import scriptJS from './components/script.js'import icon64 from './components/icons/icon64.js'// ...export function activate(context: vscode.ExtensionContext) {  console.log('Congratulations, your extension "htmltemplate" is now active!')  let disposable = vscode.commands.registerCommand(    'htmltemplate.create',    () => {      // мы хотим, чтобы файлы проекта хранились в директории html-template      // filename: string указывает TypeScript-компилятору,      // что типом аргумента, передаваемого функции,      // должна быть строка      const folder = (filename: string) =>        path.join(vscode.workspace.rootPath, `html-template/${filename}`)      // массив с контентом файлов      // files: string[] означает, что значением переменной files является массив строк      const files: string[] = [        indexHTML,        styleCSS,        scriptJS,        icon64,        ...      ]      // массив с названиями файлов      // обратите внимание, что индексы контента и названий файлов должны совпадать      const fileNames: string[] = [        'index.html',        'css/style.css',        'script.js',        'server.js',        'icons/64x64.png',        ...      ]      ;(async () => {        try {          // перебираем массив с контентом          for (let i = 0; i < files.length; i++) {            // метод outputFile принимает два обязательных и один опциональный параметр:            // путь к файлу (его название), содержимое файла и кодировку (по умолчанию UTF-8)            // если название файла включает png,            // значит, мы имеем дело с Base64-изображением:            // указываем соответствующую кодировку            if (fileNames[i].includes('png')) {              await fs.outputFile(folder(fileNames[i]), files[i], 'base64')            // иначе, используем кодировку по умолчанию            } else {              await fs.outputFile(folder(fileNames[i]), files[i])            }          }          // информационное сообщение об успехе операции          return vscode.window.showInformationMessage(            'All files created successfully'          )        } catch {          // сообщение об ошибке          return vscode.window.showErrorMessage('Failed to create files')        }      })()    }  )  context.subscriptions.push(disposable)}export function deactivate() {}

Для того, чтобы TypeScript не обращал внимания на отсутствие типов импортируемых файлов-модулей, создадим src/global.d.ts следующего содержания:

declare module '*'

Протестируем расширение. Открываем его в редакторе:

cd htmltemplatecode .

Запускаем отладку (F5). Переходим в целевую директорию (test-dir, например) и выполняем команду create в Command Palette.



Получаем информационное сообщение об успешном создании файлов. Ура!



Публикация расширения в Visual Studio Marketplace

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

  • Создать аккаунт в маркетплейсе (запомните значение поля publisher)
  • Глобально установить библиотеку vsce

Редактируем package.json:

{  "name": "htmltemplate",  "displayName": "HTML Template",  "description": "Modern HTML Starter Template",  "version": "1.0.0",  "publisher": "puslisher-name",  "license": "MIT",  "keywords": [    "html",    "html5",    "css",    "css3",    "javascript",    "js"  ],  "icon": "build/128x128.png",  "author": {    "name": "Author Name @githubusername"  },  "repository": {    "type": "git",    "url": "https://github.com/username/dirname"  },  "engines": {    "vscode": "^1.51.0"  },  "categories": [    "Snippets"  ],  "activationEvents": [    "onCommand:htmltemplate.create"  ],  "main": "./dist/extension.js",  "contributes": {    "commands": [      {        "command": "htmltemplate.create",        "title": "Create Template"      }    ]  },  ...}

Редактируем README.md.

Выполняем команду vsce package в директории расширения для создания публикуемого пакета с расширением vsix. Получаем файл htmltemplate-1.0.0.vsix.

На странице управления расширениями маркетплейса нажимаем кнопку New extension и выбираем Visual Studio Code. Переносим или загружаем в модальное окно VSIX-файл. Ждем завершения проверки.



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



Для обновления расширения необходимо изменить номер версии в package.json, сгенерировать VSIX-файл и загрузить его в маркетплейс, нажав на кнопку More actions и выбрав Update.

Как видите, в создании и публикации расширений для VSCode нет ничего сверхестественного. На этом позвольте откланяться.

В следующей части мы создадим полноценный интерфейс командной строки сначала с помощью фреймворка от Heroku oclif, затем без него. Наш Node.js-CLI будет сильно отличаться от расширения, в нем будет присутствовать некоторая визуализация, возможность опциональной инициализации git и установки зависимостей.

Надеюсь, вы нашли для себя что-нибудь интересное. Благодарю за внимание.
Подробнее..

Из песочницы Отображение emoji в результатах поиска

24.06.2020 14:16:49 | Автор: admin


Со временем в результатах поиска попадается все больше emoji и эта тенденция продолжится до тех пор пока поисковые системы не начнут их фильтровать. Присутствие заметного emoji в сниппете способно значительно повысить его CTR. Например, на моем статейном сайте средний CTR в Google вырос на 5,5% после включения emoji в title, description и микроразметку хлебных крошек.


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



Но, у многих пользователей это будет выглядеть так:


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


Как определить поддерживаемость


Для определения уровня поддерживаемости были объединены данные о популярности операционных систем за май 2020 и наличие в этих операционных системах поддержки emoji (включаемых с новыми версиями юникода).


Unicode 6.0 и ниже



Наилучшая поддерживаемость у первой значимой интеграции emoji в юникод. Все символы, попавшие в Unicode 6.0 здесь.


Unicode 7.0



Список символов Unicode 7.0 здесь. Но, начиная с emoji Page они отображаются лишь на устройствах LG.


Unicode 8.0



Список символов Unicode 8.0 здесь.


Unicode 9.0



Список символов Unicode 9.0 здесь.


Unicode 10.0



Список символов Unicode 10.0 здесь. Последний символ Bitcoin не отображается во многих версиях Windows.


Unicode 11.0



Список символов Unicode 11.0 здесь.


Unicode 12.0



Список символов Unicode 12.0 здесь.


Unicode 13.0



Да, у тебя они тоже не отображаются можешь проверить. Стоит отметить, что в будущем поддерживаемость всех версий продолжит расти в том числе из-за снижения популярности старых операционных систем. Через год-два ситуация станет заметно лучше.


Особенности отображения


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




Что поддерживают поисковые системы


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


  • символы выглядят слишком спамными;
  • символы являются неуместными;
  • символы вводят пользователей в заблуждение.

Заключение


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

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru