Comparta un tutorial de andamiaje de 30.000 palabras escrito para niñas front-end de 5 años

d30913da244db37510a0ce8c3735ecb9.jpeg

En medio de la noche, un fuerte tono de llamada me despertó. Rápidamente puse el teléfono en silencio y miré la pantalla. Era una llamada telefónica de una chica que llevé conmigo hace unos años. Mirando a mi esposa dormida y niño, caminé de puntillas hasta la cocina está al teléfono.

Tan pronto como se conectó, hubo un estallido de llanto: "Maestro, no puedo encontrar trabajo. ¡He estado buscando durante mucho tiempo!".

Me pregunté y pregunté: "Tienes 5 años de experiencia laboral front-end, ¿por qué no puedes encontrar trabajo?"

"Maestro, después de que usted se fue, me quedé en esta empresa. Todo lo que hago es agregar, eliminar, modificar y verificar negocios. No les interesa cuando escuchan esto durante la entrevista. No sé cómo presentar mi proyecto. experiencia."

En este punto, también entendí a grandes rasgos lo que estaba pasando, la consolé por un momento, le dije que pensara en una manera para ti más tarde y colgué el teléfono.

No pude conciliar el sueño durante mucho tiempo cuando volví a la cama, recordando que encontré el mismo problema cuando cambié de trabajo por primera vez. En ese momento, acababa de trabajar durante tres años y, al comienzo de la entrevista, también describí secamente algunas experiencias del proyecto sobre cómo agregar, eliminar, modificar y verificar. Después de varias entrevistas fallidas, comencé a hablar sobre la experiencia de desarrollo de algunas formas y tablas complejas, y tuve la suerte de cambiar de trabajo y obtener un aumento de salario.

Pero con 5 años de experiencia laboral, estos no son adecuados. Esta niña de 5 años debería mostrar las mejores prácticas para agregar, eliminar, modificar y verificar negocios en la entrevista, y el front-end de 5 años debería tener algo de front-end. capacidades de ingeniería.

Entonces, al día siguiente, llamé y le dije a mi hermana: "Primero resumes los 5 años de experiencia en desarrollo agregando, eliminando, modificando y verificando el negocio en una plantilla de desarrollo de mejores prácticas, y luego te enseñaré a escribir un andamio y coloque estas plantillas de desarrollo en el andamio. Otros proyectos utilizan estas plantillas a través del andamio para mejorar la eficiencia del desarrollo ".

La niña preguntó vacilante: "Andamio, es difícil de oír, ¿es bueno aprender?"

"No se preocupe, el scaffolding es muy simple. Scaffolding es en realidad una herramienta de línea de comandos (CLI) de Node.js escrita en js, que también está llena de código js, ​​pero se ejecuta con Node.js y se utilizan algunas API de nodo. "Eso es todo, primero organiza las plantillas de mejores prácticas y yo te enseñaré a escribir el andamio y te enseñaré cómo hacerlo".

Que aprenderás

De hecho, no se ha implementado el andamiaje y la dificultad radica en la disposición y precipitación de las mejores prácticas. Este artículo no abordará el contenido de las mejores prácticas, solo le enseñará cómo implementar un andamio básico como soporte para demostrar las mejores prácticas.

Debido a que se trata de enseñar a las niñas a escribir andamios a mano, este artículo es muy detallado y tiene muchas palabras, unas 30.000 palabras, después de leerlo aprenderás:

  • Cómo construir un proyecto de andamio

  • Cómo desarrollar y depurar un andamio

  • Cómo recibir y procesar parámetros de comando en andamios

  • Cómo interactuar con los usuarios en andamios

  • Cómo copiar una carpeta o archivo en scaffolding

  • Cómo generar dinámicamente un archivo en scaffolding

  • Cómo afrontar los problemas de trayectoria en los andamios

  • Cómo instalar automáticamente dependencias de plantillas en scaffolding

Todo el código de este artículo se ha subido a GitHub [1] .

1. Construya un proyecto de andamio estilo monorepo

1.1 Cómo ejecutar js con Node.js

Para evitar problemas extraños causados ​​por las diferencias de versión de Node.js, se recomienda instalar Node.js versión 16 o superior.

Simplemente busque un lugar para crear un archivo index.js y agregue el siguiente código al archivo:

console.log('Welcome to Mortal World');

Salida en la barra de direcciones del archivo cmdAbra la ventana de la línea de comando, ingrese node index.jsel comando y presione Entrar para ejecutar el comando.

395839902fb98f2d32cd83abc06b6d5d.jpeg
imagen.png

Puede ver la impresión en la ventana de línea de comando  Welcome to Mortals World.

1.2 Declara tus propios comandos

Si está familiarizado con Vue , debe tener cierta comprensión del andamio vue-cli , como ejecutar vue create myappcomandos para crear un proyecto Vue .

Si no instalamos npm install \-g vue-cliel scaffolding vue-cli y lo ejecutamos directamente en la ventana de línea de comando vue create myapp, se informará un error, como se muestra en la siguiente figura:

06d7a3a098b79c656caf399f063394dd.jpeg
imagen.png

Se puede ver vueque no es un comando del sistema, vuesino un comando declarado mediante el scaffolding vue-cli.

Entonces, cómo declarar un comando para andamios es realmente muy simple, sígueme para operar.

Encuentre un lugar para crear una carpeta mortal-cli , ingrese la carpeta, envíela a su barra de direcciones para cmdabrir la ventana de línea de comando,

8f197c68312190afca35d896dfed990c.jpeg
imagen.png

Ejecute el comando para inicializar un proyecto de scaffolding. Después de ejecutarlo correctamente, npm initse generará un archivo packageage.json en esta carpeta.

Agregamos un campo en pakeage.jsonbin para declarar un comando. El código agregado es el siguiente:

{
 "name": "mortal-cli",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
 "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "",
 "license": "ISC",
 "bin":{
 "mortal": "./bin/index.js"
 }
}

De esta manera, hemos declarado un mortalcomando y ./bin/index.jses mortalla ruta relativa del archivo js que se ejecutará después de ejecutar el comando.

Luego creamos una carpeta bin en la carpeta mortal-cli , creamos un archivo index.js en la carpeta bin y agregamos el siguiente código al archivo:

js

copiar código

#!/usr/bin/env node console.log('Welcome to Mortal World');

Preste atención a agregarlo al principio del archivo #!/usr/bin/env node; de lo contrario, se informará un error después de ejecutarlo. ! !

De esta manera, se completa el proyecto de andamio más básico y luego ingresa mortalel comando en la ventana de la línea de comando para ejecutar el comando.

f0dff1d79295fd0f490b4a3ce9240e8b.jpeg
imagen.png

Se encontrará que todavía se informa un error, lo que indica que mortalel comando no es un comando del sistema y, por supuesto, no es una forma incorrecta de declarar el comando.

Suponga que publica este andamio en npm. Dado que el valor en mortal-cli/pakeage.json es, ejecutamos para instalar el andamio localmente y luego ejecutamos el comando, y descubriremos que la operación se realizó correctamente.namemortal-clinpm install \-g mortal-climortal

Es imposible hacer esto en el desarrollo real de andamios, por lo que también necesitamos implementar la capacidad de depurar andamios localmente, que también es muy simple de implementar y se puede hacer con un solo comando.

Este comando es npm link, jaja, no se me ocurre, así que no explicaré su principio aquí, si lo necesitas puedes dejar un mensaje y abriré un solo capítulo para explicarlo.

Después de ingresar npm linkel comando para ejecutar, ingrese mortalel comando nuevamente, presione Entrar para ejecutar y el resultado que ve se muestra en la siguiente figura.

58047f869510713cb36351bfa02d49bb.jpeg
imagen.png

Hasta ahora, hemos declarado un mortalcomando con éxito.

1.3 Desventajas del enlace npm

Existe una desventaja de utilizarlo npm linkpara la depuración local. Por ejemplo, existen varias versiones del almacén de andamios localmente. Después de modificar el código en el almacén A y ejecutar mortalel comando, se descubre que el código modificado no surte efecto. Esto se debe a que ya se está ejecutando en el proyecto de andamiaje del almacén B npm link, lo que hace mortalque después de ejecutar el comando ejecutemos el código en el almacén B. Es extraño que el código modificado en el almacén A pueda surtir efecto. Después de ejecutar primero el proyecto de andamio en el almacén B npm unlinky luego ejecutar el proyecto de andamio en el almacén A npm link, el código modificado en el almacén A entrará en vigor.

Para resolver esta desventaja, utilizamos pnpm para construir proyectos de andamios estilo monorepo .

Un proyecto de estilo monorepo puede contener múltiples subproyectos, y cada subproyecto se puede compilar y empaquetar de forma independiente para enviar el producto en un paquete npm , por lo que monorepo también se denomina proyecto de paquetes múltiples.

Dado que el nombre del paquete del andamio lanzado a npm es mortal-cli , modifique el código en el archivo package.json del subproyecto de depuración . La parte de modificación del código es la siguiente:

{
 "scripts": {
 "mortal": "mortal --help"
 },
 "dependencies": {
 "mortal-cli": "workspace:*"
 }
}

Tenga en cuenta que la versión del paquete dependiente de mortal-clidependencies declarada en el campo debe definirse por , no por un número de versión específico.workspace:*

Cuando se utiliza el protocolo workspace: en pnpm para definir un número de versión de un paquete dependiente, pnpm solo resolverá los paquetes dependientes en el espacio de trabajo y no descargará ni resolverá los paquetes dependientes en npm.

Introduzca el paquete de dependencia mortal-cli y ejecute pnpm ila dependencia de instalación. El efecto es el mismo que la ejecución , excepto que no se instala globalmente. El andamiaje mortal-cli npm install \-g mortal-clisolo se instala en el subproyecto de depuración . Luego, el subproyecto de depuración se refiere directamente al producto compilado y empaquetado localmente del proyecto de andamio, en lugar del producto lanzado a npm, para lograr completamente la depuración local.

Además, el proyecto de andamiaje y el subproyecto de depuración están en el mismo proyecto, por lo que se realiza una depuración uno a uno, resolviendo así las npm linkdesventajas del uso para lograr la depuración local.

Al mismo tiempo, el comando del script se define en, el comando se ejecuta scriptsen el proyecto de depuración y el comando se puede ejecutar sin ejecutarse en el proyecto de andamio .pnpm mortalmortalnpm linkmortal

1.4 Proyecto de andamio estilo monorepo

Comencemos a usar pnpm para construir un proyecto de andamio estilo monorepo . Primero, ingrese el siguiente código en la ventana de línea de comando para ejecutar la instalación de pnpm .

iwr https://get.pnpm.io/install.ps1 -useb | iex

Luego busque otro lugar para crear una carpeta mortal y, después de ingresar a la carpeta, escriba cmd en su barra de direcciones para abrir la ventana de línea de comando.

Ingrese pnpm inital proyecto de inicialización, pnpm usa el espacio de trabajo (espacio de trabajo) para construir un proyecto de estilo monorepo .

Por lo tanto, debemos crear el archivo de configuración del espacio de trabajo pnpm-workspace.yaml en la carpeta mortal y agregar el siguiente código de configuración al archivo.

packages: 
 - 'packages/*' 
 - 'examples/*'

Después de la configuración, se declara que los subproyectos en las carpetas de paquetes y ejemplos pertenecen al mismo espacio de trabajo, y otros subproyectos pueden hacer referencia a los productos compilados y empaquetados de los subproyectos en el espacio de trabajo.

Cree una nueva carpeta mortal-cli en la carpeta de paquetes y envíela a su barra de direcciones para abrir una ventana de línea de comando.cmd

Ingrese el comando y ejecútelo para inicializar un proyecto. Después de una ejecución exitosa, pnpm initse generará un archivo packageage.json en esta carpeta.

Agregamos el campo en pakeage.jsonbin para declarar mortalel comando, el código agregado es el siguiente:

{
 "name": "mortal-cli",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
 "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "",
 "license": "ISC",
 "bin":{
 "mortal": "./bin/index.js"
 }
}

Cree una nueva carpeta bin en la carpeta paquetes/mortal-cli, cree un nuevo archivo index.js en la carpeta bin y agregue el siguiente código al archivo:

#!/usr/bin/env node
console.log('Welcome to Mortal World');

Cree una nueva carpeta de aplicación en la carpeta de ejemplos, ingrese cmd en su barra de direcciones para abrir la ventana de línea de comando y ejecute el comando para inicializar un proyecto. Después de ejecutarlo exitosamente, se generará un archivo packageage.json en la carpeta.pnpm init

Agregamos un campo en pakeage.jsondependencies para agregar la dependencia de mortal-cli . Agregue scriptsotro comando de script personalizado a . El código agregado se ve así:

{
 "name": "app",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
 "mortal": "mortal"
 },
 "author": "",
 "license": "ISC",
 "dependencies": {
 "mortal-cli": "workspace:*"
 }
}

Luego ejecute el comando en el directorio raíz más externo pnpm ipara instalar las dependencias. Después de que la instalación sea exitosa, ejecútela en el directorio de la carpeta de la aplicación pnpm mortaly encontrará que se imprime la ventana de línea de comando Welcome to Mortal World, lo que indica que su proyecto de andamio estilo monorepo se ha creado con éxito.

15b56e48554bac267ea465bfdd585c31.jpeg
imagen.png

En este punto, la estructura de directorios de todo el proyecto es la siguiente

  |-- mortal
      |-- package.json
      |-- pnpm-lock.yaml
      |-- pnpm-workspace.yaml
      |-- examples
      |   |-- app
      |       |-- package.json
      |-- packages
          |-- mortal-cli
              |-- package.json
              |-- bin
                  |-- index.js


1.5 Módulos necesarios para andamios

Uno de los andamios más simples consta de los siguientes módulos.

  • módulo de parámetros de comando

  • módulo de interacción del usuario

  • módulo de copia de archivos

  • Módulo de generación dinámica de archivos.

  • Instalar automáticamente módulos dependientes

Implementémoslos uno por uno.

2. Módulo de parámetros de comando

2.1 Obtener parámetros de comando

El módulo de proceso en Node.js proporciona información del entorno global relacionada con el proceso actual de Node.js , como parámetros de comando, variables de entorno, ruta de ejecución de comandos, etc.

const process = require('process');
// 获取命令参数
console.log(process.argv);

Los parámetros también se pueden configurar después de los comandos proporcionados por scaffolding mortal. Los parámetros de comando de scaffolding estándar deben admitir dos formatos, por ejemplo:

mortal --name=orderPage
mortal --name orderPage

Si se process.argvobtiene a través de, es inconveniente tratar adicionalmente con dos formatos de parámetros de comando diferentes.

Aquí se recomienda la biblioteca de código abierto yargs para analizar los parámetros del comando. Ejecute el siguiente comando para instalar yargs :

pnpm add yargs --F mortal-cli

pnpm addes el comando para instalar paquetes dependientes en pnpm--F mortal-cli y especifica las dependencias que se instalarán en el subproyecto mortal-cli .

Cabe señalar aquí que mortal-clise toma el valor del campo en package.json en el subproyecto mortal-cli en lugar del nombre de la carpeta del subproyecto mortal-cli .name

El uso de yargs es muy simple y el atributo que proporciona argves el resultado del procesamiento de los parámetros del comando en dos formatos.

Agregue el siguiente código en bin/index.js :

#!/usr/bin/env node
const yargs = require('yargs');
console.log('name', yargs.argv.name);

Tenga en cuenta que el código anterior se ejecuta en el entorno Node.js y los módulos de Node.js siguen la especificación CommonJS. Si desea depender de un módulo, debe utilizar la función del sistema integrada de Node.js para hacer referencia al módulo require.

Ejecutar en el directorio de la carpeta de la aplicaciónpnpm mortal \-- \--name=orderPage ,

Tenga en cuenta que pnpm mortaldebe agregar dos guiones (--) después de , lo cual indica a pnpm que los siguientes parámetros se pasan al comando mortalen sí, no a pnpm.

El resultado se muestra en la siguiente figura:

0ae012fdd97839ac74eb5b0aed186964.jpeg
imagen.png

yargs.argv.nameEl valor del parámetro del comando se puede obtener mediante name.

2.2 Establecer subcomandos

Si el andamio necesita proporcionar múltiples funciones externas, no todas las funciones se pueden mortalimplementar en el comando.

Puede configurar algunos subcomandos mediante el método proporcionado por yargs , de modo que cada subcomando corresponda a su propia función y realice sus tareas.command

yargs.commandEl uso es **yargs.command(cmd, desc, builder, handler)**.

  • cmd: también se puede pasar una cadena, el nombre del subcomando y una matriz, por ejemplo ['create', 'c'], significa que se llama al subcomando createy su alias es c;

  • desc: Cadena, información de descripción del subcomando;

  • builder: Una función que devuelve una matriz, configuración de información de parámetros de subcomando, por ejemplo, se pueden configurar parámetros:

    • alias: alias;

    • demand: ¿Es necesario?

    • default:Valores predeterminados;

    • describe:Descripción;

    • type: tipo de parámetro, string | boolean | number.

  • handler: función, el parámetro del subcomando se puede procesar especialmente en esta función.

Configuremos un subcomando para generar una plantilla y nombremos este subcomando como create.

Modifique el código en el archivo bin/index.js de la siguiente manera:

#!/usr/bin/env node
const yargs = require('yargs');
yargs.command(
 ['create', 'c'],
 '新建一个模板',
 function (yargs) {
   return yargs.option('name', {
     alias: 'n',
     demand: true,
     describe: '模板名称',
     type: 'string'
   })
 },
 function (argv) {
   console.log('argv', argv);
 }
).argv;

Ejecute los comandos y respectivamente en el directorio de la carpeta de la aplicación y los resultados de la ejecución se muestran en la siguiente figura:pnpm mortal create \-- \--name=orderPagepnpm mortal c \-- \--name=orderPage

1578700bba0d3ba52084a16fb242ad93.jpeg
imagen.png

En lo anterior configuramos cierta información de parámetros de createlos parámetros del subcomando. name¿Cómo mostrárselos al usuario? De hecho, siempre que los parámetros del subcomando que ingresamos sean incorrectos, la información del parámetro se mostrará en la ventana de la línea de comando.

Ejecute el comando en el directorio de la carpeta de la aplicación pnpm mortal c \-- \--abcy el resultado de la ejecución se muestra en la siguiente figura:

d2b0eaa4a6fcef2890497ec3884cbaeb.jpeg
imagen.png

Hasta ahora, hemos logrado la interacción más simple entre andamios y usuarios, pero si hay demasiados parámetros personalizados, el método de interacción de los parámetros de la línea de comandos es muy hostil para los usuarios. Por lo tanto, también necesitamos implementar un módulo de interacción del usuario. Consulte la siguiente sección para saber cómo implementarlo.

3. Módulo de interacción del usuario

Creo que un mejor método de interacción con el usuario es la interacción interrogativa. Por ejemplo, estamos ejecutando y el contenido del archivo package.jsonnpm init se completa mediante la interacción interrogativa .

04f591798e8989933875f8b8e27b597a.jpeg
imagen.png

Se recomienda utilizar la biblioteca de código abierto de Investigar para lograr la interacción interrogativa. Ejecute el siguiente comando para instalar Investigar :

js

copiar código

pnpm add [email protected] --F mortal-cli

Para utilizar Inquirerrequire , se debe utilizar la versión 8.2.5 de Inquirer .

Aquí utilizamos principalmente las capacidades de tres aspectos de la biblioteca de código abierto del investigador :

  • hacer preguntas a los usuarios

  • Obtener y analizar la entrada del usuario

  • Comprueba si la respuesta del usuario es válida.

Se logra principalmente inquirer.prompt()a través de . promptLa función recibe una matriz y cada elemento de la matriz es un elemento de consulta. El elemento de consulta tiene muchos parámetros de configuración. Los siguientes son elementos de configuración de uso común.

  • type: Los tipos de preguntas que se utilizan comúnmente son

    • cuadro de entrada: input;

    • Confirmar: confirm;

    • Grupo de radio: list;

    • Grupo de opción múltiple: checkbox;

  • name: Una variable que almacena la respuesta a la pregunta actual;

  • message: Descripción del problema;

  • default:Valores predeterminados;

  • choices: opción de lista, typedisponible en algunos;

  • validate: Verificar la respuesta del usuario;

  • filter: filtra la respuesta del usuario y devuelve el valor procesado.

Por ejemplo, cuando creamos un archivo de plantilla, probablemente le preguntaremos al usuario: nombre del archivo de plantilla, tipo de plantilla, qué marco usar para el desarrollo, qué biblioteca de componentes usar para el marco a desarrollar, etc. Implementemos esta función a continuación.

Cree una nueva carpeta requester.js en la carpeta bin y agregue el siguiente código en ella:

const inquirer = require('inquirer');

function inquirerPrompt(argv) {
  const { name } = argv;
  return new Promise((resolve, reject) => {
    inquirer.prompt([
      {
        type: 'input',
        name: 'name',
        message: '模板名称',
        default: name,
        validate: function (val) {
          if (!/^[a-zA-Z]+$/.test(val)) {
            return "模板名称只能含有英文";
          }
          if (!/^[A-Z]/.test(val)) {
            return "模板名称首字母必须大写"
          }
          return true;
        },
      },
      {
        type: 'list',
        name: 'type',
        message: '模板类型',
        choices: ['表单', '动态表单', '嵌套表单'],
        filter: function (value) {
          return {
            '表单': "form",
            '动态表单': "dynamicForm",
            '嵌套表单': "nestedForm",
          }[value];
        },
      },
      {
        type: 'list',
        message: '使用什么框架开发',
        choices: ['react', 'vue'],
        name: 'frame',
      }
    ]).then(answers => {
      const { frame } = answers;
      if (frame === 'react') {
        inquirer.prompt([
          {
            type: 'list',
            message: '使用什么UI组件库开发',
            choices: [
              'Ant Design',
            ],
            name: 'library',
          }
        ]).then(answers1 => {
          resolve({
            ...answers,
            ...answers1,
          })
        }).catch(error => {
          reject(error)
        })
      }

      if (frame === 'vue') {
        inquirer.prompt([
          {
            type: 'list',
            message: '使用什么UI组件库开发',
            choices: [ 'Element'],
            name: 'library',
          }
        ]).then(answers2 => {
          resolve({
            ...answers,
            ...answers2,
          })
        }).catch(error => {
          reject(error)
        })
      }
    }).catch(error => {
      reject(error)
    })
  })

}

exports.inquirerPrompt = inquirerPrompt;

Entre ellos inquirer.prompt(), devuelve una Promesa, que podemos usar thenpara obtener la respuesta a la consulta anterior y luego iniciar el contenido correspondiente de acuerdo con la respuesta.

Introducido en bin /index.jsinquirerPrompt .

#!/usr/bin/env node

const yargs = require('yargs');
const { inquirerPrompt } = require("./inquirer");

yargs.command(
  ['create', 'c'],
  '新建一个模板',
  function (yargs) {
    return yargs.option('name', {
      alias: 'n',
      demand: true,
      describe: '模板名称',
      type: 'string'
    })
  },
  function (argv) {
    inquirerPrompt(argv).then(answers =>{
      console.log(answers)
    })
  }
).argv;

Ejecute el comando en el directorio de la carpeta de la aplicación pnpm mortal c \-- \--n Inputy el resultado de la ejecución se muestra en la siguiente figura:

00e2b16cefd13c911d8bb5977bb7a52f.jpeg
imagen.png
3d3f00eec2fded5452d9f9c57ec95157.jpeg
imagen.png

Se puede ver claramente que la respuesta a la pregunta de "qué marco se usa para el desarrollo" es diferente, y las opciones para la siguiente pregunta de "qué biblioteca de componentes de UI usar para el desarrollo" son diferentes.

Una vez completada la respuesta, el formato de la respuesta se puede ver claramente en la imagen a continuación.

772eea23cf4fbe5749f00fe0ab88e3db.jpeg
imagen.png

4. Módulo de copia de carpetas

Para generar un archivo de plantilla, la forma más sencilla es copiar el archivo de plantilla en el andamio al lugar correspondiente después de ejecutar el comando proporcionado por el andamio. Un archivo de plantilla puede ser un solo archivo o una carpeta. Esta sección presenta primero cómo copiar el archivo de plantilla cuando es una carpeta.

Copiar carpetas en Node.js no es fácil y se requiere recursividad. Aquí, se recomienda utilizar la biblioteca de código abierto copy - dir para copiar archivos.

Ejecute el siguiente comando para instalar copy-dir .

pnpm add copy-dir --F mortal-cli

Cree un nuevo archivo copy.js en la carpeta bin y agregue el siguiente código:

const copydir = require('copy-dir');
const fs = require('fs');
function copyDir(from, to, options) {
 copydir.sync(from, to, options);
}
function checkMkdirExists(path) {
 return fs.existsSync(path)
};
exports.checkMkdirExists = checkMkdirExists;
exports.copyDir = copyDir;

copyDirLa implementación del método es muy simple, pero la dificultad es cómo usarlo, creemos una escena para presentar cómo usarlo.

Creamos una nueva carpeta de plantilla en la carpeta bin para almacenar archivos de plantilla. Por ejemplo, creamos una carpeta de formulario en la carpeta de plantilla para almacenar plantillas de formulario. El contenido de la plantilla de formulario no se presenta aquí. Creamos una en la carpeta de formulario en will._index.js_, simplemente escribe algo en él. Su estructura de directorios es la siguiente:

  |-- mortal
      |-- package.json
      |-- pnpm-lock.yaml
      |-- pnpm-workspace.yaml
      |-- examples
      |   |-- app
      |       |-- package.json
      |-- packages
          |-- mortal
              |-- package.json
              |-- bin
                  |-- template
                      |-- form
                          |-- index.js
                  |-- copy.js
                  |-- index.js
                  |-- inquirer.js

A continuación, copie la carpeta paquetes/mortal/bin/template/form a ejemplos/app/src/pages/OrderPage .

Modifique el código en bin/index.js , el código modificado es el siguiente:

#!/usr/bin/env node

const yargs = require('yargs');
const path = require('path');
const { inquirerPrompt } = require("./inquirer");
const { copyDir, checkMkdirExists } = require("./copy");

yargs.command(
  ['create', 'c'],
  '新建一个模板',
  function (yargs) {
    return yargs.option('name', {
      alias: 'n',
      demand: true,
      describe: '模板名称',
      type: 'string'
    })
  },
  function (argv) {
    inquirerPrompt(argv).then(answers => {
      const { name, type } = answers;
      const isMkdirExists = checkMkdirExists(
        path.resolve(process.cwd(),`./src/pages/${name}`)
      );
      if (isMkdirExists) {
        console.log(`${name}文件夹已经存在`)
      } else {
        copyDir(
          path.resolve(__dirname, `./template/${type}`),
          path.resolve(process.cwd(), `./src/pages/${name}`)
        )
      }
    })
  }
).argv;

La dificultad de utilizar el método de copiar archivo copyDires la asignación de parámetros fromy to. Entre ellos from, representa la ruta del archivo que se copiará y torepresenta la ruta donde se copiará el archivo. La ruta aquí es mejor usar una ruta absoluta, porque surgirán una serie de problemas extraños al usar una ruta relativa en Node.js.

4.1 Procesamiento de caminos en andamios

Podemos usar el método proporcionado por el módulo de ruta en Node.js para convertir la ruta en una ruta absoluta, que consiste en unir los parámetros en una ruta absoluta. Es un elemento opcional y se pueden establecer varias rutas. Por ejemplo , Las reglas de empalme de rutas a las que se debe prestar atención al usarpath.resolve( [from…], to )to[from … ]path.resolve('./aaa', './bbb', './ccc')path.resolve

  • Coser caminos de atrás hacia adelante;

  • Si tocomienza /con, no se unirá a la ruta anterior;

  • Si tocomienza ../con , empalme las rutas anteriores y no incluya la última ruta;

  • Si tocomienza ./con o no tiene símbolo, se concatenará la ruta anterior.

De las reglas de empalme anteriores, path.resolvecuando se utiliza, se debe prestar especial atención toa la configuración del parámetro.

Introduzcamos copyDircómo configurar los parámetros al usar el método:

  • Establezca copyDirel parámetro de en ,frompath.resolve(__dirname, `./template/${type}`)

Entre ellos __dirnamese encuentra la ruta absoluta utilizada para obtener dinámicamente el directorio al que pertenece el módulo de archivo actual. Por ejemplo, si se usa en el archivo bin/index.js__dirname , __dirnamesignifica la ruta absoluta del directorio al que pertenece el archivo bin/index.jsD:\mortal\packages\mortal-cli\bin .

Debido a que el archivo de plantilla se almacena en la carpeta bin/template y copyDirse usa en bin/index.js , la ruta de la carpeta _bin/template_ es relativa al archivo bin/index.js./template , así que establezca path.resolveel parámetro toen ./template/${type}, ¿dónde typeestá el usuario seleccionado El tipo de plantilla.

Suponiendo typeque el tipo de plantilla es form, entonces path.resolve(__dirname, `./template/form`)la ruta absoluta obtenida por es D:\mortal\packages\mortal-cli\bin\template\form.

  • Establezca copyDirel parámetro de en ,topath.resolve(process.cwd(), `${name}`)

Entre ellos, la ruta absoluta del directorio al que pertenece el archivo cuando se ejecuta process.cwd()el proceso actual de Node.js. Por ejemplo, cuando se ejecuta en el directorio de la carpeta binnode index.js , process.cwd()lo que obtiene es D:\mortal\packages\mortal-cli\bin.

Ejecute node index.jsel mortalcomando en lugar de ejecutar. En la ingeniería front-end moderna,  los comandos de script se definen en el archivo package.json , de la siguiente manera:scripts

{
  "name": "app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "mortal": "mortal"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "mortal-cli": "workspace:*"
  }
}

Ejecutar pnpm mortales equivalente a ejecutar mortalel comando, por lo que pnpm mortalal ejecutar, el archivo cuando se ejecuta el proceso actual de Node.js es el archivo package.json . Bueno, process.cwd()consíguelo D:\mortal\examples\app.

Debido a que la carpeta paquetes/mortal/bin/template/form debe copiarse en ejemplos/app/src/pages/OrderPage y process.cwd()el valor de es , la ruta de D:\mortal\examples\appla carpeta _src/pages_ relativa a ejemplos/aplicación./src/pages es , por lo que path.resolveparámetro de toEstablecer en ./src/pages/${name}, donde nameestá el nombre de la plantilla ingresado por el usuario.

4.2 Guardia de directorio

Ejecútelo en el directorio de la carpeta de la aplicación pnpm mortal create \-- \--name=OrderPagepara ver si puede copiar correctamente la carpeta paquetes/mortal/bin/template/form a ejemplos/app/src/pages/OrderPage .

93f8722d65b42174d423c8ad87672a39.jpeg
imagen.png

Se informó un error que indica que la carpeta ejemplos/app/src/pages no existe. Para evitar tales errores, necesitamos implementar un método de protección de directorio mkdirGuard. Por ejemplo, si la carpeta ejemplos/app/src/pages no existe, cree una carpeta ejemplos/app/src/pages .

En el archivo bin/copy.js , modifique el código de la siguiente manera:

const copydir = require('copy-dir');
const fs = require('fs');
const path = require('path');

function mkdirGuard(target) {
  try {
    fs.mkdirSync(target, { recursive: true });
  } catch (e) {
    mkdirp(target)
    function mkdirp(dir) {
      if (fs.existsSync(dir)) { return true }
      const dirname = path.dirname(dir);
      mkdirp(dirname);
      fs.mkdirSync(dir);
    }
  }
}

function copyDir(form, to, options) {
  mkdirGuard(to);
  copydir.sync(form, to, options);
}

function checkMkdirExists(path) {
  return fs.existsSync(path)
};

exports.checkMkdirExists = checkMkdirExists;
exports.mkdirGuard = mkdirGuard;
exports.copyDir = copyDir;

fs.mkdirSyncEl formato de sintaxis: fs.mkdirSync(path[, options]), para crear un directorio de carpetas.

  • path: ruta del directorio de la carpeta;

  • options: recursiveindica si se debe crear un directorio principal, truesí.

fs.existsSyncEl formato de sintaxis es:, fs.existsSync(pach)verifique si el directorio existe, regrese si el directorio existe  true y regrese si el directorio no existe false.

  • path: Ruta del directorio de carpetas.

path.dirnameEl formato de sintaxis de: path.dirname(path)se utiliza para obtener el nombre del directorio de la ruta dada.

  • path:ruta de archivo.

Dentro del método, cuando el directorio principal del mkdirGuarddirectorio que se va a crear no existe, la llamada informará un error y seguirá parte de la lógica, en la que el directorio principal se crea de forma recursiva y el directorio principal se utiliza para determinar si el directorio principal se crea de forma recursiva. El directorio principal existe para finalizar la recursividad. Aquí se debe prestar especial atención a la creación de un directorio principal antes de llamar para formar una secuencia de creación correcta; de lo contrario, el proceso de creación de un directorio principal informará un error porque el directorio principal del directorio principal no existe.targetfs.mkdirSync(target)catchfs.existsSync(dir)fs.mkdirSync(dir)mkdirp(dirname)

Ejecutemos nuevamente en el directorio de la carpeta de la aplicación pnpm mortal create \-- \--name=OrderPagepara ver si podemos copiar con éxito la carpeta paquetes/mortal/bin/template/form a ejemplos/app/src/pages/OrderPage esta vez .

Agregado exitosamente, el resultado agregado es el siguiente:

8512f985241699c3d4c1219771f1f6ad.jpeg
imagen.png

Luego ejecute pnpm mortal create \-- \--name=OrderPageel comando nuevamente y encontrará que la consola imprime que la plantilla ya existe y le pregunta.

6f3b2653c127507b073fb023e69b3b47.jpeg
imagen.png

Esto es para evitar que el archivo de plantilla modificado por el usuario se sobrescriba al estado inicial después de ejecutar el comando. checkMkdirExistsEntonces introducimos un método para verificar si el archivo de plantilla existe , que se implementa internamente fs.existsSync.

5. Módulo de copia de archivos

La copia de archivos se implementa en tres pasos: use para fs.readFileSyncleer el contenido del archivo copiado, luego cree un archivo y luego use para fs.writeFileSyncescribir el contenido del archivo.

En el archivo bin/copy.js , agregue el siguiente código dentro:

function copyFile(from, to) {
 const buffer = fs.readFileSync(from);
 const parentPath = path.dirname(to);
 mkdirGuard(parentPath)
 fs.writeFileSync(to, buffer);
}
exports.copyFile = copyFile;

A continuación, utilizamos copyFileel método para modificar el código en bin/index.js , el código modificado es el siguiente:

#!/usr/bin/env node

const yargs = require('yargs');
const path = require('path');
const { inquirerPrompt } = require("./inquirer");
const { copyDir } = require("./copy");

yargs.command(
  ['create', 'c'],
  '新建一个模板',
  function (yargs) {
    return yargs.option('name', {
      alias: 'n',
      demand: true,
      describe: '模板名称',
      type: 'string'
    })
  },
  function (argv) {
    inquirerPrompt(argv).then(answers => {
      const { name, type } = answers;
      const isMkdirExists = checkMkdirExists(
        path.resolve(process.cwd(),`./src/pages/${name}/index.js`)
      );
      if (isMkdirExists) {
        console.log(`${name}/index.js文件已经存在`)
      } else {
        copyFile(
          path.resolve(__dirname, `./template/${type}/index.js`),
          path.resolve(process.cwd(), `./src/pages/${name}/index.js`),
          {
            name,
          }
        )
      }
    })
  }
).argv;

copyFileLa diferencia entre usar y copyDirusar está en los parámetros, copyFileque requieren que tanto los parámetros fromcomo los parámetros tosean precisos en la ruta del archivo.

Ejecútelo en el directorio de la carpeta de la aplicación pnpm mortal create \-- \--name=OrderPagey el resultado de la ejecución se muestra en la siguiente figura:

1500c9a1cf62c4da11e8da104fb449e7.jpeg
imagen.png

6. Módulo de generación dinámica de archivos.

Supongamos que parte de la información en el archivo de plantilla proporcionado en el andamio necesita generar dinámicamente el archivo de plantilla correspondiente de acuerdo con los parámetros de comando ingresados ​​por el usuario.

Por ejemplo, en el archivo de plantilla siguiente , ¿cómo Appreemplazar dinámicamente el valor del parámetro de comando ingresado por el usuario ?name

import React from 'react';
const App = () => {
 return (
 <div></div>
 );
};
export default App;

Se recomienda utilizar la biblioteca de código abierto bigote para implementarlo, ejecute el siguiente comando para instalar copy-dir .

pnpm add mustache --F mortal-cli

Creamos un archivo index.tpl en la carpeta paquetes/mortal-cli/bin/template/form con el siguiente contenido:

import React from 'react';
const { {name}} = () => {
 return (
 <div></div>
 );
};
export default { {name}};

Primero escriba un readTemplatemétodo para leer el contenido del archivo de plantilla dinámica index.tpl . En el archivo bin/copy.js , agregue el siguiente código dentro:

const Mustache = require('mustache');
function readTemplate(path, data = {}) {
 const str = fs.readFileSync(path, { encoding: 'utf8' })
 return Mustache.render(str, data);
}
exports.readTemplate = readTemplate;

readTemplateEl método recibe dos parámetros, pathla ruta relativa del archivo de plantilla dinámica y datalos datos de configuración del archivo de plantilla dinámica.

Úselo para Mustache.render(str, data)generar el contenido del archivo de plantilla y devolverlo, debido a que Mustache.renderel primer tipo de parámetro es una cadena, por lo que al llamar, fs.readFileSyncespecifique encodingel tipo como utf8; de lo contrario fs.readFileSync, devuelva datos de tipo búfer.

Escribir un copyTemplatemétodo para copiar el archivo de plantilla en el lugar correspondiente es copyFilemuy similar al método. En el archivo bin/copy.js , agregue el siguiente código dentro:

function copyTemplate(from, to, data = {}) {
 if (path.extname(from) !== '.tpl') {
   return copyFile(from, to);
 }
 const parentToPath = path.dirname(to);
 mkdirGuard(parentToPath);
 fs.writeFileSync(to, readTemplate(from, data));
}

path.extname(from)Devuelve la extensión del archivo, por ejemplo, path.extname(index.tpl)return .tpl.

Modifique el código en bin/index.js , el código modificado es el siguiente:

#!/usr/bin/env node

const yargs = require('yargs');
const path = require('path');
const { inquirerPrompt } = require("./inquirer");
const { copyTemplate } = require("./copy");

yargs.command(
  ['create', 'c'],
  '新建一个模板',
  function (yargs) {
    return yargs.option('name', {
      alias: 'n',
      demand: true,
      describe: '模板名称',
      type: 'string'
    })
  },
  function (argv) {
    inquirerPrompt(argv).then(answers => {
      const { name, type } = answers;
      const isMkdirExists = checkMkdirExists(
        path.resolve(process.cwd(),`./src/pages/${name}/index.js`)
      );
      if (isMkdirExists) {
        console.log(`${name}/index.js文件已经存在`)
      } else {
        copyTemplate(
          path.resolve(__dirname, `./template/${type}/index.tpl`),
          path.resolve(process.cwd(), `./src/pages/${name}/index.js`),
          {
            name,
          }
        )
      }
    })
  }
).argv;

Ejecútelo en el directorio de la carpeta de la aplicación pnpm mortal create \-- \--name=OrderPagey el resultado de la ejecución se muestra en la siguiente figura:

91dad5d26d75ecb852a102978b6b5995.jpeg
imagen.png

6.1 Introducción al bigote

El caso anterior es el uso más simple de bigote . A continuación se presentan algunos escenarios de uso comunes.

Primero, familiaricémonos con la gramática del bigote , introduzcamos algunos escenarios para usar estas gramáticas.

  • { {clave}}

  • { {#clave}} { {/clave}}

  • { {^clave}} { {/clave}}

  • { {.}}

  • { {&clave}}

6.1.1, enlace simple

Utilice { {key}}la sintaxis, keyque debe ser Mustache.rendercoherente con el nombre de propiedad del segundo parámetro (un objeto) del método.

Por ejemplo:

Mustache.render('<span>{ {name}}</span>',{name:'张三'})

producción:

<span>张三</span>

6.1.2 Subpropiedades vinculantes

Por ejemplo:

Mustache.render('<span>{ {ifno.name}}</span>', { ifno: { name: '张三' } })

producción:

<span>张三</span>

6.1.3, renderizado en bucle

Si keyel valor del atributo es una matriz, puede usar { {#key}} { {/key}}la sintaxis para mostrarlo en un bucle. La { {#}}marca indica que todo el contenido después de esta marca se mostrará en un bucle y { {/}}la marca indica el final del ciclo.

Por ejemplo:

Mustache.render(
 '<span>{ {#list}}{ {name}}{ {/list}}</span>',
 {
   list: [
     { name: '张三' },
     { name: '李四' },
     { name: '王五' },
   ]
 }
)

producción:

<span>张三李四王五</span>

Si listel valor de es ['张三','李四','王五'], debe { {name}}reemplazarlo { {.}}por para renderizar.

Mustache.render(
 '<span>{ {#list}}{ {.}}{ {/list}}</span>',
 {
   list: ['张三','李四','王五']
 }
)

6.1.4 Procesamiento de datos secundarios en el bucle

Mustache.renderEl segundo parámetro en el método es un objeto y su valor de atributo puede ser una función. Al renderizar, la función se ejecutará para generar el valor de retorno. En la función, puede usarlo para obtener el contexto del segundo parámetro this.

Por ejemplo:

Mustache.render(
 '<span>{ {#list}}{ {info}}{ {/list}}</span>',
 {
   list: [
     { name: '张三' },
     { name: '李四' },
     { name: '王五' },
   ],
   info() {
     return this.name + ',';
   }
 }
)

producción:

<span>张三,李四,王五,</span>

6.1.5, renderizado condicional

Utilice { {#key}} { {/key}}sintaxis y { {^key}} { {/key}}sintaxis para lograr la representación condicional. Cuando keyes false,,,,, y es verdadero, el contenido empaquetado no se 0representa y el contenido empaquetado sí se representa.[]{}nullkey == false{ {#key}} { {/key}}{ {^key}} { {/key}}

Por ejemplo:

Mustache.render(
 '<span>{ {#show}}显示{ {/show}}{ {^show}}隐藏{ {/show}}</span>',
 {
 show: false
 }
)

producción:

<span>隐藏</span>

6.1.6 No escapar de las etiquetas HTML

Utilice { {&key}}la sintaxis para hacerlo.

Por ejemplo:

Mustache.render(
 '<span>{ {&key}}</span>',
 {
 key: '<span>标题</span>'
 }
)

producción:

<span><span>标题</span></span>

7. Instalar automáticamente módulos dependientes

Supongamos que la plantilla es así:

import React from 'react';
import { Button, Form, Input } from 'antd';

const App = () => {
  const onFinish = (values) => {
    console.log('Success:', values);
  };
  return (
    <Form onFinish={onFinish} autoComplete="off">
      <Form.Item label="Username" name="username">
        <Input />
      </Form.Item>
      <Form.Item>
        <Button type="primary" htmlType="submit">提交</Button>
      </Form.Item>
    </Form>
  );
};
export default App;

Puede ver que las dos dependencias de terceros reactse utilizan en la plantilla . Si estas dos dependencias no están instaladas en el proyecto usando la plantilla, debemos realizar la instalación automática de estas dos dependencias durante el proceso de generación de la plantilla.antd

Usamos el módulo de subproceso child_process en Node para lograr esto.

La sintaxis más común en child_process es :

child_process.exec(command, options, callback)

  • command: comando, comopnpm install

  • options:parámetro

    • cwd: establece la ruta del entorno de ejecución del comando

    • env:Variable ambiental

    • timeout:ejecutar ejecutar ahora

  • callback: La devolución de llamada al final de la ejecución del comando, (error, stdout, stderr) =>{ }después de una ejecución exitosa errores nully después de una ejecución fallida errores una instancia de error, stdoutes stderruna salida estándar, un error estándar y su formato es una cadena de forma predeterminada.

Cree una nueva carpeta requester.js en la carpeta bin y agregue el siguiente código en ella:

const path = require('path');
const { exec } = require('child_process');

const LibraryMap = {
  'Ant Design': 'antd',
  'iView': 'view-ui-plus',
  'Ant Design Vue': 'ant-design-vue',
  'Element': 'element-plus',
}

function install(cmdPath, options) {
  const { frame, library } = options;
  const command = `pnpm add ${frame} && pnpm add ${LibraryMap[library]}`
  return new Promise(function (resolve, reject) {
    exec(
      command,
      {
        cwd: path.resolve(cmdPath),
      },
      function (error, stdout, stderr) {
        console.log('error', error);
        console.log('stdout', stdout);
        console.log('stderr', stderr)
      }
    )
  })
}

exports.install = install;

El parámetro en installel método es el comando de dependencia de instalación pnpm y el empalme se utiliza al instalar múltiples dependencias. El parámetro es la ruta del archivo package.json del proyecto dependiente instalado , que podemos usar para obtenerlo. Como se mencionó anteriormente, es la ruta absoluta del directorio al que pertenece el archivo cuando se ejecuta el proceso actual de Node.js.execcommand&&cwdprocess.cwd()process.cwd()

El próximo uso, modifique el código en bin/index.js , el código modificado es el siguiente:

#!/usr/bin/env node

const yargs = require('yargs');
const path = require('path');
const { inquirerPrompt } = require("./inquirer");
const { copyTemplate, checkMkdirExists } = require("./copy");
const { install } = require('./manager');

yargs.command(
  ['create', 'c'],
  '新建一个模板',
  function (yargs) {
    return yargs.option('name', {
      alias: 'n',
      demand: true,
      describe: '模板名称',
      type: 'string'
    })
  },
  function (argv) {
    inquirerPrompt(argv).then(answers => {
      const { name, type } = answers;
      const isMkdirExists = checkMkdirExists(
        path.resolve(process.cwd(),`./src/pages/${name}/index.js`)
      );
      if (isMkdirExists) {
        console.log(`${name}/index.js文件已经存在`)
      } else {
        copyTemplate(
          path.resolve(__dirname, `./template/${type}/index.tpl`),
          path.resolve(process.cwd(), `./src/pages/${name}/index.js`),
          {
            name,
          }
        )
        install(process.cwd(), answers);
      }
    })
  }
).argv;

Después de ejecutar el método, copyTemplatese ejecutarán install(process.cwd(), answers)las dependencias requeridas en la plantilla de instalación automática .

Ejecútelo en el directorio de la carpeta de la aplicación pnpm mortal create \-- \--name=OrderPagepara ver si las dependencias se pueden instalar automáticamente.

Después de ejecutar el comando, verifique si las dependencias y se agregan al valor en el archivo ejemplos\app\package.json .dependenciesantdreact

952d8d8acf673228440455d84b74ba9c.jpeg
imagen.png

Además, cuando ejecutamos el comando, encontraremos que, como se muestra en la figura siguiente, el cursor sigue parpadeando, como si estuviera atascado, y las dependencias se están instalando. Aquí vamos a presentar una animación de carga para resolver este fenómeno hostil.

a86180b007a160db733a39da05068873.jpeg
imagen.png

Se recomienda utilizar la biblioteca de código abierto ora para realizar la animación de carga.

Ejecute el siguiente comando para instalar ora .

pnpm add [email protected] --F mortal-cli

Modifique el código en bin/inquirer.js , el código modificado es el siguiente:

const path = require('path');
const { exec } = require('child_process');
const ora = require("ora");

const LibraryMap = {
  'Ant Design': 'antd',
  'iView': 'view-ui-plus',
  'Ant Design Vue': 'ant-design-vue',
  'Element': 'element-plus',
}

function install(cmdPath, options) {
  const { frame, library } = options;
  const command = `pnpm add ${frame} && pnpm add ${LibraryMap[library]}`
  return new Promise(function (resolve, reject) {
    const spinner = ora();
    spinner.start(
      `正在安装依赖,请稍等`
    );
    exec(
      command,
      {
        cwd: path.resolve(cmdPath),
      },
      function (error) {
        if (error) {
          reject();
          spinner.fail(`依赖安装失败`);
          return;
        }
        spinner.succeed(`依赖安装成功`);
        resolve()
      }
    )
  })
}

exports.install = install;

Ejecútelo en el directorio de la carpeta de la aplicación pnpm mortal create \-- \--name=OrderPagepara ver el efecto de ejecución.

49fa4e92229836dc32b7d14ef92607b4.jpeg
imagen.png
99bf2d0831fdd9d303536c082abcc234.jpeg
imagen.png

8. Publicar e instalar

Ejecute en el directorio de la carpeta paquetes/mortal , ejecute el siguiente comando para instalar y publicar el scaffolding en npm .

js

copiar código

pnpm publish --F mortal-cli

Después de un lanzamiento exitoso. En cualquier proyecto, podemos ejecutar el comando en el proyecto después de pnpm add mortal-cli \-Dinstalar correctamente las dependencias de scaffolding de mortal-clipnpm mortal create \-- \--name=OrderPage .

epílogo

Lo anterior sólo le enseña a realizar el andamio más simple. Su función sólo la genera un archivo de plantilla. Aunque simples, estas son las habilidades introductorias del andamio. El código se ha subido a GitHub [2] , puedes descargarlo y practicarlo tú mismo. Nunca lo aprenderás si no lo practicas.

Después de aprender, podrá resumir algunos códigos comerciales habituales, formular las mejores prácticas y utilizar andamios como soporte para mostrarlos y mejorar su competitividad en el lugar de trabajo.

Referencias

[1]

https://github.com/532pyh/mortal-cli: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2F532pyh%2Fmortal-cli

[2]

https://github.com/532pyh/mortal-cli: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2F532pyh%2Fmortal-cli

Acerca de este artículo

Autor: Hongchen Lianxin

https://juejin.cn/post/7260144602471776311

Beneficios para los fanáticos

Comparta el código fuente de una plantilla de fondo de NodeJs basada en Tailwind Css. Si desea aprender sobre nodejs y tailwindcss, no se pierda este código fuente.

Supongo que te gusta

Origin blog.csdn.net/Ed7zgeE9X/article/details/132484927
Recomendado
Clasificación