Snippet, eine Erweiterung für VSCode und CLI. Teil 2





Guten Tag, Freunde!



Bei der Entwicklung der Modern HTML Starter Template habe ich darüber nachgedacht, die Benutzerfreundlichkeit zu erweitern. Zu diesem Zeitpunkt beschränkten sich die Optionen für die Verwendung auf das Klonen des Repositorys und das Herunterladen des Archivs. Auf diese Weise wurden das HTML-Snippet und die Erweiterung für Microsoft Visual Studio-Code - HTML-Vorlage sowie die Befehlszeilenschnittstelle - create-modern-template angezeigt . Natürlich sind diese Werkzeuge alles andere als perfekt und ich werde sie so weit wie möglich verfeinern. Während der Erstellung habe ich jedoch einige interessante Dinge gelernt, die ich mit Ihnen teilen möchte.



Snippet und Erweiterung wurden im ersten Teil behandelt . In diesem Teil werfen wir einen Blick auf die CLI.



Wenn Sie nur am Quellcode interessiert sind, finden Sie hier den Link zum Repository .



Oclif



Oclif ist ein Heroku-Framework zum Erstellen von Befehlszeilenschnittstellen.



Wir werden damit einen Trick erstellen, mit dem Sie Aufgaben hinzufügen, aktualisieren, löschen und deren Liste anzeigen können.



Der Quellcode des Projekts ist hier . Es gibt auch eine CLI zum Überprüfen der Funktionalität der Site anhand der URL.



Installieren Sie oclif global:



npm i -g oclif / yarn global add oclif

      
      





Oclif bietet die Möglichkeit, CLIs mit einem oder mehreren Befehlen zu erstellen. Wir brauchen eine zweite Option.



Wir erstellen ein Projekt:



oclif multi todocli

      
      





  • Das Argument multi weist oclif an, eine Schnittstelle mit mehreren Befehlen zu erstellen
  • todocli - Projektname






Fügen Sie die erforderlichen Befehle hinzu:



oclif command add
oclif command update
oclif command remove
oclif command show

      
      





Die Datei src / command / hello.js kann gelöscht werden.



Wir werden lowdb als lokale Datenbank verwenden . Wir werden auch Kreide verwenden , um die im Terminal angezeigten Nachrichten anzupassen . Installieren Sie diese Bibliotheken:



npm i chalk lowdb / yarn add chalk lowdb

      
      





Erstellen Sie eine leere Datei db.json im Stammverzeichnis. Dies wird unser Aufgaben-Repository sein.



Erstellen Sie im Verzeichnis src eine Datei db.js mit folgendem Inhalt:



const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync('db.json')
const db = low(adapter)

//   todos        db.json
db.defaults({ todos: [] }).write()

//    
const Todo = db.get('todos')

module.exports = Todo

      
      





Bearbeiten der Datei src / command / add.js:



//   
const { Command } = require('@oclif/command')
const Todo = require('../db')
const chalk = require('chalk')

class AddCommand extends Command {
  async run() {
    //     
    const { argv } = this.parse(AddCommand)
    try {
      //     
      await Todo.push({
        id: Todo.value().length,
        //       ,
        //  
        task: argv.join(' '),
        done: false
      }).write()
      //    
      this.log(chalk.green('New todo created.'))
    } catch {
      //    
      this.log(chalk.red('Operation failed.'))
    }
  }
}

//  
AddCommand.description = `Adds a new todo`

//      
AddCommand.strict = false

//  
module.exports = AddCommand

      
      





Bearbeiten der Datei src / command / update.js:



const { Command } = require('@oclif/command')
const Todo = require('../db')
const chalk = require('chalk')

class UpdateCommand extends Command {
  async run() {
    //   
    const { id } = this.parse(UpdateCommand).args
    try {
      //    id   
      await Todo.find({ id: parseInt(id, 10) })
        .assign({ done: true })
        .write()
      this.log(chalk.green('Todo updated.'))
    } catch {
      this.log('Operation failed.')
    }
  }
}

UpdateCommand.description = `Marks a task as done by id`

//     
UpdateCommand.args = [
  {
    name: 'id',
    description: 'todo id',
    required: true
  }
]

module.exports = UpdateCommand

      
      





Die Datei src / command / remove.js sieht folgendermaßen aus:



const { Command } = require('@oclif/command')
const Todo = require('../db')
const chalk = require('chalk')

class RemoveCommand extends Command {
  async run() {
    const { id } = this.parse(RemoveCommand).args
    try {
      await Todo.remove({ id: parseInt(id, 10) }).write()
      this.log(chalk.green('Todo removed.'))
    } catch {
      this.log(chalk.red('Operation failed.'))
    }
  }
}

RemoveCommand.description = `Removes a task by id`

RemoveCommand.args = [
  {
    name: 'id',
    description: 'todo id',
    required: true
  }
]

module.exports = RemoveCommand

      
      





Bearbeiten Sie abschließend die Datei src / command / show.js:



const { Command } = require('@oclif/command')
const Todo = require('../db')
const chalk = require('chalk')

class ShowCommand extends Command {
  async run() {
    //        id
    const res = await Todo.sortBy('id').value()
    //        
    //    
    if (res.length) {
      res.forEach(({ id, task, done }) => {
        this.log(
          `[${
            done ? chalk.green('DONE') : chalk.red('NOT DONE')
          }] id: ${chalk.yellowBright(id)}, task: ${chalk.yellowBright(task)}`
        )
      })
    //     
    } else {
      this.log('There are no todos.')
    }
  }
}

ShowCommand.description = `Shows existing tasks`

module.exports = ShowCommand

      
      





Führen Sie im Stammverzeichnis des Projekts den folgenden Befehl aus:



npm link / yarn link

      
      









Als nächstes führen wir mehrere Operationen durch.







Fein. Alles funktioniert wie erwartet. Sie müssen lediglich package.json und README.md bearbeiten, und Sie können das Paket in der npm-Registrierung veröffentlichen.



DIY CLI



Unsere CLI-Funktionalität ähnelt der Create-React -App oder der Vue-Cli . Mit dem Befehl create wird ein Projekt im Zielverzeichnis erstellt, das alle Dateien enthält, die für die Arbeit der Anwendung erforderlich sind. Darüber hinaus bietet es die Möglichkeit, git optional zu initialisieren und Abhängigkeiten zu installieren.



Der Quellcode des Projekts ist hier .



Erstellen Sie ein Verzeichnis und initialisieren Sie das Projekt:



mkdir create-modern-template
cd create-modern-template
npm init -y / yarn init -y

      
      





Installieren Sie die erforderlichen Bibliotheken:



yarn add arg chalk clear esm execa figlet inquirer listr ncp pkg-install

      
      





  • arg - Tool zum Parsen von Befehlszeilenargumenten
  • clear - ein Tool zum Löschen des Terminals
  • esm ist ein Tool, das ES6- Modulunterstützung in Node.js bietet
  • execa ist ein Tool zum automatischen Ausführen einiger gängiger Operationen (wir werden es verwenden, um git zu initialisieren).
  • figlet - ein Werkzeug zur Ausgabe von benutzerdefiniertem Text an das Terminal
  • Anfragender - ein Tool zum Arbeiten mit der Befehlszeile, mit dem Sie dem Benutzer Fragen stellen und seine Antworten analysieren können
  • listr - ein Tool zum Erstellen einer Liste von Aufgaben und zum Visualisieren ihrer Ausführung im Terminal
  • ncp - Tool zum Kopieren von Dateien und Verzeichnissen
  • pkg-install - ein Tool zum programmgesteuerten Installieren von Projektabhängigkeiten


Erstellen Sie im Stammverzeichnis eine bin / create-Datei (ohne Erweiterung) mit folgendem Inhalt:



#!/usr/bin/env node

require = require('esm')(module)

require('../src/cli').cli(process.argv)

      
      





Package package.json:



"main": "src/main.js",
"bin": "bin/create"

      
      





Der Befehl create ist registriert.



Erstellen Sie ein src / template-Verzeichnis und platzieren Sie dort die Projektdateien, die in das Zielverzeichnis kopiert werden.



Erstellen Sie eine src / cli.js-Datei mit folgendem Inhalt:



//   
import arg from 'arg'
import inquirer from 'inquirer'
import { createProject } from './main'

//    
// --yes  -y    git   
// --git  -g   git
// --install  -i   
const parseArgumentsIntoOptions = (rawArgs) => {
  const args = arg(
    {
      '--yes': Boolean,
      '--git': Boolean,
      '--install': Boolean,
      '-y': '--yes',
      '-g': '--git',
      '-i': '--install'
    },
    {
      argv: rawArgs.slice(2)
    }
  )

  //    
  return {
    template: 'template',
    skipPrompts: args['--yes'] || false,
    git: args['--git'] || false,
    install: args['--install'] || false
  }
}

//   
const promptForMissingOptions = async (options) => {
  //     --yes  -y
  if (options.skipPrompts) {
    return {
      ...options,
      git: false,
      install: false
    }
  }

  // 
  const questions = []

  //      git
  if (!options.git) {
    questions.push({
      type: 'confirm',
      name: 'git',
      message: 'Would you like to initialize git?',
      default: false
    })
  }

  //      
  if (!options.install) {
    questions.push({
      type: 'confirm',
      name: 'install',
      message: 'Would you like to install dependencies?',
      default: false
    })
  }

  //   
  const answers = await inquirer.prompt(questions)

  //    
  return {
    ...options,
    git: options.git || answers.git,
    install: options.install || answers.install
  }
}

//        
export async function cli(args) {
  let options = parseArgumentsIntoOptions(args)

  options = await promptForMissingOptions(options)

  await createProject(options)
}

      
      





Die Datei src / main.js sieht folgendermaßen aus:



//   
import path from 'path'
import chalk from 'chalk'
import execa from 'execa'
import fs from 'fs'
import Listr from 'listr'
import ncp from 'ncp'
import { projectInstall } from 'pkg-install'
import { promisify } from 'util'
import clear from 'clear'
import figlet from 'figlet'

//        
const access = promisify(fs.access)
const copy = promisify(ncp)

//  
clear()

//     HTML - 
console.log(
  chalk.yellowBright(figlet.textSync('HTML', { horizontalLayout: 'full' }))
)

//   
const copyFiles = async (options) => {
  try {
    // templateDirectory -    ,
    // targetDirectory -  
    await copy(options.templateDirectory, options.targetDirectory)
  } catch {
    //    
    console.error('%s Failed to copy files', chalk.red.bold('ERROR'))
    process.exit(1)
  }
}

//   git
const initGit = async (options) => {
  try {
    await execa('git', ['init'], {
      cwd: options.targetDirectory,
    })
  } catch {
    //    
    console.error('%s Failed to initialize git', chalk.red.bold('ERROR'))
    process.exit(1)
  }
}

//   
export const createProject = async (options) => {
  //     
  options.targetDirectory = process.cwd()

  //     
  const fullPath = path.resolve(__filename)

  //       
  const templateDir = fullPath.replace('main.js', `${options.template}`)

  options.templateDirectory = templateDir

  try {
    //     
    //  R_OK -    
    await access(options.templateDirectory, fs.constants.R_OK)
  } catch {
    //    
    console.error('%s Invalid template name', chalk.red.bold('ERROR'))
    process.exit(1)
  }

  //   
  const tasks = new Listr(
    [
      {
        title: 'Copy project files',
        task: () => copyFiles(options),
      },
      {
        title: 'Initialize git',
        task: () => initGit(options),
        enabled: () => options.git,
      },
      {
        title: 'Install dependencies',
        task: () =>
          projectInstall({
            cwd: options.targetDirectory,
          }),
        enabled: () => options.install,
      },
    ],
    {
      exitOnError: false,
    }
  )

  //  
  await tasks.run()

  //    
  console.log('%s Project ready', chalk.green.bold('DONE'))

  return true
}

      
      





Wir verbinden die CLI (im Stammverzeichnis):



yarn link

      
      





Zielverzeichnis und Projekt erstellen:



mkdir test-dir
cd test-dir
create-modern-template && code .

      
      













Perfekt. CLI bereit zur Veröffentlichung.



Veröffentlichen eines Pakets in der npm-Registrierung



Um Pakete veröffentlichen zu können, müssen Sie zunächst ein Konto in der npm-Registrierung erstellen .



Anschließend müssen Sie sich anmelden, indem Sie den Befehl npm login ausführen und Ihre E-Mail-Adresse und Ihr Kennwort angeben.



Danach bearbeiten wir package.json und erstellen die Dateien .gitignore, .npmignore, LICENSE und README.md (siehe Projekt-Repository).



Wir packen die Projektdateien mit dem Befehl npm package. Wir erhalten die Datei create-modern-template.tgz. Wir veröffentlichen diese Datei, indem wir den Befehl npm Publish create-modern-template.tgz ausführen.



Ein Fehler beim Veröffentlichen eines Pakets bedeutet normalerweise, dass ein Paket mit demselben Namen bereits in der npm-Registrierung vorhanden ist. Um ein Paket zu aktualisieren, müssen Sie die Version des Projekts in package.json ändern, die TGZ-Datei erneut erstellen und zur Veröffentlichung senden.



Sobald ein Paket veröffentlicht wurde, kann es wie jedes andere Paket mit npm i / yarn add installiert werden.







Wie Sie sehen, ist das Erstellen der CLI und das Veröffentlichen des Pakets in der npm-Registrierung unkompliziert.



Ich hoffe, Sie haben etwas Interessantes für sich gefunden. Danke für die Aufmerksamkeit.



All Articles