¡Buen dia amigos!
Mientras desarrollaba la plantilla de inicio HTML moderna, pensé en ampliar su usabilidad. En ese momento, las opciones para su uso se limitaban a clonar el repositorio y descargar el archivo. Así es como apareció el fragmento de código HTML y la extensión para Microsoft Visual Studio Code - Plantilla HTML , así como la interfaz de línea de comandos - create-modern-template . Por supuesto, estas herramientas están lejos de ser perfectas y las perfeccionaré tanto como pueda. Sin embargo, en el proceso de crearlos, aprendí algunas cosas interesantes que quiero compartir con ustedes.
El fragmento y la expansión se trataron en la primera parte.... En esta parte, echaremos un vistazo a la CLI.
Si solo está interesado en el código fuente, aquí está el enlace al repositorio .
Oclif
Oclif es un marco de Heroku para construir interfaces de línea de comandos.
Lo usaremos para crear un truco que brinde la capacidad de agregar, actualizar, eliminar tareas y ver su lista.
El código fuente del proyecto está aquí . También hay una CLI para verificar la funcionalidad del sitio por URL.
Instale oclif globalmente:
npm i -g oclif / yarn global add oclif
Oclif ofrece la posibilidad de crear CLI de uno o varios comandos. Necesitamos una segunda opción.
Creamos un proyecto:
oclif multi todocli
- el argumento múltiple le dice a oclif que cree una interfaz de múltiples comandos
- todocli - nombre del proyecto
Agregue los comandos necesarios:
oclif command add oclif command update oclif command remove oclif command show
El archivo src / commands / hello.js se puede eliminar.
Usaremos lowdb como base de datos local . También usaremos tiza para personalizar los mensajes que se muestran en el terminal . Instale estas bibliotecas:
npm i chalk lowdb / yarn add chalk lowdb
Cree un archivo db.json vacío en el directorio raíz. Este será nuestro repositorio de tareas.
En el directorio src, cree un archivo db.js con el siguiente contenido:
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
Editando el archivo 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
Editando el archivo 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
El archivo src / commands / remove.js se ve así:
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
Finalmente, edite el archivo 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
Estando en el directorio raíz del proyecto, ejecute el siguiente comando:
npm link / yarn link
A continuación, realizamos varias operaciones.
Multa. Todo funciona como se esperaba. Todo lo que queda es editar package.json y README.md, y puede publicar el paquete en el registro npm.
CLI de bricolaje
Nuestra CLI en funcionalidad se parecerá a create-react-app o vue-cli . En el comando crear, creará un proyecto en el directorio de destino que contiene todos los archivos necesarios para que la aplicación funcione. Además, proporcionará la capacidad de inicializar opcionalmente git e instalar dependencias.
El código fuente del proyecto está aquí .
Cree un directorio e inicialice el proyecto:
mkdir create-modern-template cd create-modern-template npm init -y / yarn init -y
Instale las bibliotecas necesarias:
yarn add arg chalk clear esm execa figlet inquirer listr ncp pkg-install
- arg : herramienta para analizar los argumentos de la línea de comandos
- clear —
- esm — , ES6- Node.js
- execa — ( git)
- figlet —
- inquirer — , ,
- listr —
- ncp —
- pkg-install —
En el directorio raíz, cree un archivo bin / create (sin extensión) con el siguiente contenido:
#!/usr/bin/env node
require = require('esm')(module)
require('../src/cli').cli(process.argv)
Editando package.json:
"main": "src/main.js",
"bin": "bin/create"
El comando de creación está registrado.
Cree un directorio src / template y coloque los archivos del proyecto allí, que se copiarán en el directorio de destino.
Cree un archivo src / cli.js con el siguiente contenido:
//
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)
}
El archivo src / main.js se ve así:
//
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
}
Conectamos la CLI (estando en el directorio raíz):
yarn link
Cree el directorio y el proyecto de destino:
mkdir test-dir cd test-dir create-modern-template && code .
Perfectamente. CLI listo para publicar.
Publicar un paquete en el registro npm
Para poder publicar paquetes, primero debe crear una cuenta en el registro de npm .
Luego, debe iniciar sesión ejecutando el comando npm login y especificando su correo electrónico y contraseña.
Después de eso, editamos package.json y creamos los archivos .gitignore, .npmignore, LICENSE y README.md (ver el repositorio del proyecto).
Empaquetamos los archivos del proyecto usando el comando npm package. Obtenemos el archivo create-modern-template.tgz. Publicamos este archivo ejecutando el comando npm publish create-modern-template.tgz.
Obtener un error al publicar un paquete generalmente significa que ya existe un paquete con el mismo nombre en el registro de npm. Para actualizar un paquete, debe cambiar la versión del proyecto en package.json, crear el archivo TGZ nuevamente y enviarlo para su publicación.
Una vez que se ha publicado un paquete, se puede instalar como cualquier otro paquete usando npm i / yarn add.
Como puede ver, crear la CLI y publicar el paquete en el registro npm es sencillo.
Espero que hayas encontrado algo interesante para ti. Gracias por su atención.