Bonne journée, mes amis!
Lors du développement du modèle de démarrage HTML moderne, j'ai pensé à en étendre la convivialité. À cette époque, les options pour son utilisation se limitaient au clonage du référentiel et au téléchargement de l'archive. C'est ainsi que le fragment de code HTML et l'extension pour Microsoft Visual Studio Code - HTML Template , ainsi que l'interface de ligne de commande - create-modern-template sont apparus . Bien sûr, ces outils sont loin d'être parfaits et je vais les affiner autant que possible. Cependant, en les créant, j'ai appris quelques choses intéressantes que je souhaite partager avec vous.
Dans cette partie, nous examinerons l'extrait et l'extension, ainsi que la CLI dans la prochaine.
Si vous n'êtes intéressé que par le code source, voici le lien vers le référentiel .
Fragment
Qu'est-ce qu'un extrait? En bref, un extrait de code est un modèle que l'éditeur utilise pour la saisie semi-automatique (complétion de code).
VSCode a intégré Emmet ( site officiel , Emmet dans Visual Studio Code ), qui utilise de nombreux extraits de code HTML, CSS et JS pour vous aider à écrire votre code. Nous tapons dans l'éditeur (en .html) !, Appuyez sur Tab ou Entrée, nous obtenons le balisage html5 terminé. On tape nav> ul> li * 3> a.link> img, on appuie sur Tab, on obtient:
<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>
etc.
En plus des extraits intégrés, VSCode offre la possibilité d'utiliser des extraits de code personnalisés. Pour les créer, allez dans Fichier -> Préférences -> Extraits d'utilisateurs (ou cliquez sur le bouton Gérer dans le coin inférieur gauche et sélectionnez Extraits d'utilisateurs). Les paramètres de chaque langue sont stockés dans un fichier JSON correspondant (pour HTML dans html.json, pour JavaScript dans javascript.json, etc.).
Entraînons-nous à créer des extraits JS. Recherchez le fichier javascript.json et ouvrez-le.
Nous voyons des commentaires décrivant brièvement les règles de création d'extraits de code. Pour plus d'informations sur la création d'extraits de code personnalisés dans VSCode, cliquez ici .
Commençons par quelque chose de simple. Créons un extrait pour console.log (). Voici à quoi ça ressemble:
"Print to console": {
"prefix": "log",
"body": "console.log($0)",
"description": "Create console.log()"
},
- Imprimer vers la console - clé d'objet, nom de l'extrait (obligatoire)
- préfixe - raccourci pour l'extrait (obligatoire)
- body - l'extrait de code lui-même (obligatoire)
- $ number - position du curseur après la création de l'extrait de code; $ 1 - première position, $ 2 - deuxième, etc., $ 0 - dernière position (facultatif)
- description - description de l'extrait (facultatif)
Nous sauvegardons le fichier. Nous tapons log dans le script, appuyez sur Tab ou Entrée, nous obtenons console.log () avec le curseur entre les crochets.
Créons un extrait de code pour la boucle for-of:
"For-of loop": {
"prefix": "fo",
"body": [
"for (const ${1:item} of ${2:arr}) {",
"\t$0",
"}"
]
},
- Les extraits de code multiligne sont créés à l'aide d'un tableau
- $ {nombre: valeur}; $ {1: item} signifie la première position du curseur avec la valeur par défaut de l'élément; cette valeur est mise en évidence après la création d'un extrait de code, ainsi qu'après le passage à la position suivante du curseur pour une édition rapide
- \ t - un retrait (la quantité d'espace est déterminée par les paramètres de l'éditeur correspondants ou, dans mon cas, l'extension Prettier ), \ t \ t - deux retraits, etc.
Nous tapons fo dans le script, appuyez sur Tab ou Entrée, nous obtenons:
for (const item of arr) {
}
avec l'élément en surbrillance. Appuyez sur Tab, arr est mis en surbrillance. Appuyez à nouveau sur Tabulation, passez à la deuxième ligne.
Voici quelques exemples supplémentaires:
"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}",
"}"
]
}
Les extraits de code HTML suivent le même principe. Voici à quoi ressemble le modèle HTML:
{
"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"
}
}
Nous tapons HTML, appuyez sur Tab ou Entrée, nous obtenons le balisage. Les positions du curseur sont définies dans l'ordre suivant: nom de l'application (titre), description (description), auteur (auteur), mots-clés (mots-clés), adresse (url).
Extension
Le site VSCode a une excellente documentation sur la création d'extensions .
Nous allons créer deux options pour l'extension: le formulaire d'extrait de code et le formulaire CLI. Nous publierons la deuxième option dans Visual Studio Marketplace .
Exemples d'extensions sous forme d'extraits de code:
- Extraits de code JavaScript (ES6)
- Extraits de code ES7 React / Redux / GraphQL / React-Native
- Extraits de vue VSCode
Les extensions de formulaire CLI sont moins populaires, probablement parce qu'il existe de «vraies» CLI.
Extension sous forme d'extraits
Pour développer des extensions pour VSCode, outre Node.js et Git , nous avons besoin de quelques bibliothèques supplémentaires, plus précisément d'une bibliothèque et d'un plugin, à savoir: yeoman et générateur-code . Installez-les globalement:
npm i -g yo generator-code
//
yarn global add yo generator-code
Nous exécutons la commande yo code, sélectionnons de nouveaux extraits de code, répondons aux questions.
Il reste à copier l'extrait de code HTML que nous avons créé précédemment dans le fichier snippets / snippets.code-snippets (les fichiers d'extrait de code peuvent également avoir l'extension json), éditer le package.json et README.md, et vous pouvez publier l'extension sur le marché. Comme vous pouvez le voir, tout est très simple. Trop simple, j'ai pensé, et j'ai décidé de créer une extension sous la forme d'une CLI.
Extension CLI
Exécutez à nouveau la commande yo code. Cette fois, nous sélectionnons Nouvelle extension (TypeScript) (n'ayez pas peur, il n'y aura presque pas de TypeScript dans notre code, et là où il se trouve, je donnerai les explications nécessaires), répondez aux questions.
Pour vous assurer que l'extension fonctionne, ouvrez le projet dans l'éditeur:
cd htmltemplate code .
Appuyez sur F5 ou sur le bouton Exécuter (Ctrl / Cmd + Maj + D) sur la gauche et sur le bouton Démarrer le débogage en haut. Parfois, vous obtenez une erreur au démarrage. Dans ce cas, nous annulons le lancement (Cancel) et répétons la procédure.
Dans l'éditeur qui s'ouvre, cliquez sur Affichage -> Palette de commandes (Ctrl / Cmd + Maj + P), tapez bonjour et sélectionnez Hello World.
Nous recevons un message d'information de VSCode et un message correspondant (félicitations) dans la console.
De tous les fichiers du projet, nous sommes intéressés par package.json et src / extension.ts. Le répertoire src / test et le fichier vsc-extension-quickstart.md peuvent être supprimés.
Jetons un coup d'œil à extension.ts (commentaires supprimés pour plus de lisibilité):
// VSCode
import * 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() {}
Point important: 'extension.command' dans extension.ts doit correspondre aux valeurs des champs activationEvents et command dans package.json:
"activationEvents": [
"onCommand:htmltemplate.helloWorld"
],
"contributes": {
"commands": [
{
"command": "htmltemplate.helloWorld",
"title": "Hello World"
}
]
},
- commandes - liste des commandes
- activationEvents - fonctions à appeler pendant l'exécution de la commande
Commençons par développer l'extension.
Nous voulons que notre extension ressemble à create-react-app ou vue-cli dans la fonctionnalité , c'est-à-dire sur la commande create créé un projet contenant tous les fichiers nécessaires dans le répertoire cible.
Tout d'abord, éditons package.json:
"displayName": "HTML Template",
"activationEvents": [
"onCommand:htmltemplate.create"
],
"contributes": {
"commands": [
{
"command": "htmltemplate.create",
"title": "Create Template"
}
]
},
Créez un répertoire src / components pour stocker les fichiers de projet qui seront copiés dans le répertoire cible.
Nous créons des fichiers de projet sous forme de modules ES6 (VSCode utilise les modules ES6 par défaut (export / import), mais prend en charge les modules CommonJS (module.exports / require)): index.html.js, css / style.css.js , script.js, etc. Le contenu du fichier est exporté par défaut:
// index.html.js
export default `
<!DOCTYPE html>
<html
lang="en"
dir="ltr"
itemscope
itemtype="https://schema.org/WebPage"
prefix="og: http://ogp.me/ns#"
>
...
</html>
`
Notez qu'avec cette approche, toutes les images (dans notre cas, les icônes) doivent être encodées en Base64: voici un outil en ligne adapté . La présence de la ligne "data: image / png; base64," au début du fichier converti n'a pas d'importance fondamentale.
Nous utiliserons fs-extra pour copier (écrire) des fichiers . La méthode outputFile de cette bibliothèque fait la même chose que la méthode intégrée Node.js writeFile, mais crée également un répertoire pour le fichier en cours d'écriture s'il n'existe pas: par exemple, si nous avons spécifié create css / style.css, et que le répertoire css n'existe pas, outputFile le créera et y écrira style.css (writeFile lancera une exception s'il n'y a pas de répertoire).
Le fichier extension.ts ressemble à ceci:
import * as vscode from 'vscode'
// fs-extra
const 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() {}
Pour empêcher TypeScript de prêter attention au manque de types de fichiers de modules importés, créez src / global.d.ts avec le contenu suivant:
declare module '*'
Testons l'extension. Ouvrez-le dans l'éditeur:
cd htmltemplate code .
Démarrez le débogage (F5). Accédez au répertoire cible (test-dir, par exemple) et exécutez la commande create dans la palette de commandes.
Nous recevons un message d'information sur la création réussie de fichiers. Hourra!
Publication d'une extension sur Visual Studio Marketplace
Pour pouvoir publier des extensions pour VSCode, vous devez effectuer les opérations suivantes:
- Créez un compte sur la place de marché (rappelez-vous la valeur du champ éditeur)
- Installer la bibliothèque vsce globalement
Modification de 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"
}
]
},
...
}
Modification de README.md.
Exécutez la commande vsce package dans le répertoire d'extension pour créer un package publié avec l'extension vsix. Nous obtenons le fichier htmltemplate-1.0.0.vsix.
Sur la page de gestion des extensions de la place de marché, cliquez sur le bouton Nouvelle extension et sélectionnez Visual Studio Code. Transférez ou chargez le fichier VSIX dans la fenêtre modale. Nous attendons la fin de la vérification.
Une fois qu'une coche verte apparaît à côté du numéro de version, l'extension devient disponible pour l'installation dans VSCode.
Pour mettre à jour l'extension, vous devez changer le numéro de version dans package.json, générer un fichier VSIX et le télécharger sur le marché en cliquant sur le bouton Plus d'actions et en sélectionnant Mettre à jour.
Comme vous pouvez le voir, la création et la publication d'extensions pour VSCode n'ont rien de surnaturel. Sur ce, laissez-moi prendre congé.
Dans la partie suivante, nous allons créer une interface de ligne de commande à part entière, en utilisant d'abord le framework Heroku - oclif , puis sans lui. Notre Node.js-CLI sera très différent de l'extension, il aura une certaine visualisation, la possibilité d'initialiser éventuellement git et d'installer des dépendances.
J'espère que vous avez trouvé quelque chose d'intéressant pour vous-même. Merci de votre attention.