Snippet, ekstensi untuk VSCode dan CLI. Bagian 2





Selamat siang teman!



Saat mengembangkan Template Pemula HTML Modern, saya berpikir untuk memperluas kegunaannya. Pada saat itu, opsi penggunaannya terbatas pada kloning repositori dan mengunduh arsip. Beginilah cuplikan dan ekstensi HTML untuk Kode Microsoft Visual Studio - Template HTML , serta antarmuka baris perintah - buat-modern-template muncul . Tentu saja, alat-alat ini jauh dari sempurna dan saya akan menyempurnakannya semampu saya. Namun, dalam proses pembuatannya, saya mempelajari beberapa hal menarik yang ingin saya bagikan kepada Anda.



Cuplikan dan perluasan dibahas di bagian pertama . Pada bagian ini, kita akan melihat CLI.



Jika Anda hanya tertarik pada kode sumbernya, berikut ini tautan ke repositori .



Oclif



Oclif adalah framework Heroku untuk membangun antarmuka baris perintah.



Mari kita gunakan untuk membuat trik yang memberikan kemampuan untuk menambah, memperbarui, menghapus tugas, dan melihat daftarnya.



Kode sumber proyek ada di sini . Ada juga CLI untuk memeriksa fungsionalitas situs dengan URL.



Instal oclif secara global:



npm i -g oclif / yarn global add oclif

      
      





Oclif menyediakan kemampuan untuk membuat CLI perintah tunggal dan multi-perintah. Kami membutuhkan opsi kedua.



Kami membuat proyek:



oclif multi todocli

      
      





  • argumen multi memberitahu oclif untuk membuat antarmuka multi-perintah
  • todocli - nama proyek






Tambahkan perintah yang diperlukan:



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

      
      





File src / commands / hello.js bisa dihapus.



Kami akan menggunakan lowdb sebagai database lokal . Kami juga akan menggunakan kapur untuk menyesuaikan pesan yang ditampilkan di terminal . Instal perpustakaan ini:



npm i chalk lowdb / yarn add chalk lowdb

      
      





Buat file db.json kosong di direktori root. Ini akan menjadi tempat penyimpanan tugas kita.



Di direktori src, buat file db.js dengan konten berikut:



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

      
      





Mengedit file src / commands / 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

      
      





Mengedit file src / commands / 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

      
      





File src / commands / remove.js terlihat seperti ini:



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

      
      





Terakhir, edit file src / commands / 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

      
      





Berada di direktori root proyek, jalankan perintah berikut:



npm link / yarn link

      
      









Selanjutnya, kami melakukan beberapa operasi.







Baik. Semuanya bekerja seperti yang diharapkan. Yang tersisa hanyalah mengedit package.json dan README.md, dan Anda dapat menerbitkan paket ke registri npm.



CLI DIY



CLI kami akan menyerupai fungsi create-react-app atau vue-cli . Pada perintah create, itu akan membuat proyek di direktori target yang berisi semua file yang diperlukan agar aplikasi berfungsi. Selain itu, ini akan memberikan kemampuan untuk menginisialisasi git dan menginstal dependensi secara opsional.



Kode sumber proyek ada di sini .



Buat direktori dan inisialisasi proyek:



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

      
      





Instal perpustakaan yang diperlukan:



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

      
      





  • arg - alat untuk mengurai argumen baris perintah
  • clear - alat untuk membersihkan terminal
  • esm adalah alat yang menyediakan dukungan modul ES6 di Node.js
  • execa adalah alat untuk secara otomatis melakukan beberapa operasi umum (kita akan menggunakannya untuk menginisialisasi git)
  • figlet - alat untuk mengeluarkan teks yang disesuaikan ke terminal
  • Inquirer - alat untuk bekerja dengan baris perintah, khususnya, memungkinkan Anda untuk mengajukan pertanyaan kepada pengguna dan mengurai jawabannya
  • listr - alat untuk membuat daftar tugas dan memvisualisasikan pelaksanaannya di terminal
  • ncp - alat untuk menyalin file dan direktori
  • pkg-install - alat untuk menginstal dependensi proyek secara terprogram


Di direktori root, buat bin / buat file (tanpa ekstensi) dengan konten berikut:



#!/usr/bin/env node

require = require('esm')(module)

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

      
      





Mengedit package.json:



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

      
      





Perintah buat terdaftar.



Buat direktori src / template dan letakkan file proyek di sana, yang akan disalin ke direktori target.



Buat file src / cli.js dengan konten berikut:



//   
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)
}

      
      





File src / main.js terlihat seperti ini:



//   
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
}

      
      





Kami menghubungkan CLI (berada di direktori root):



yarn link

      
      





Buat direktori dan proyek target:



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

      
      













Sempurna. CLI siap untuk dipublikasikan.



Menerbitkan paket ke registri npm



Untuk dapat menerbitkan paket, Anda harus membuat akun di registri npm terlebih dahulu .



Kemudian Anda harus masuk dengan menjalankan perintah login npm dan menentukan email dan kata sandi Anda.



Setelah itu kita mengedit package.json dan membuat file .gitignore, .npmignore, LICENSE dan README.md (lihat repositori proyek).



Kami mengemas file proyek menggunakan perintah paket npm. Kami mendapatkan file create-modern-template.tgz. Kami menerbitkan file ini dengan menjalankan perintah npm publish create-modern-template.tgz.



Mendapat kesalahan saat menerbitkan paket biasanya berarti bahwa paket dengan nama yang sama sudah ada di registri npm. Untuk memperbarui paket, Anda perlu mengubah versi proyek di package.json, membuat file TGZ lagi dan mengirimkannya untuk publikasi.



Setelah sebuah paket diterbitkan, itu dapat diinstal seperti paket lainnya yang menggunakan npm i / yarn add.







Seperti yang Anda lihat, membuat CLI dan menerbitkan paket ke registri npm sangatlah mudah.



Saya harap Anda menemukan sesuatu yang menarik untuk diri Anda sendiri. Terima kasih atas perhatian Anda.



All Articles