Principio y configuración del complemento Pettier de VSCode

Recientemente escribí un complemento Prettier que puede lograr este efecto:

Cada vez que un colega guarda el código, el orden de las declaraciones de importación cambiará aleatoriamente.

Pero no pudo encontrar nada en el archivo de configuración más bonito.

Así que te quedarás boquiabierto.

Entonces, ¿cómo descubrió este colega el complemento más bonito que te impactará?

Cómo funciona Más bonito

Las herramientas de compilación front-end son todas conversiones de código fuente a código fuente, por lo que hay tres pasos: analizar, transformar y generar:

analizar es convertir la cadena de código fuente en un árbol de objetos AST, transformar es agregar, eliminar y modificar AST, y generar (o imprimir) es imprimir recursivamente el AST convertido en código de destino.

En realidad, Prettier se implementa en función de la compilación, pero no realiza una conversión intermedia, solo analiza e imprime (también llamado generar), por lo que se divide en dos pasos:

Sus principales funciones de formateo se realizan en la fase de impresión.

Todo el proceso es relativamente simple, entonces, ¿cómo admite tantos idiomas?

Por supuesto, ¡cada idioma tiene su propio analizador e impresora!

Por ejemplo, ha incorporado estos analizadores:

Se admiten ts, js, css, scss, html, etc., porque diferentes sufijos habilitarán diferentes analizadores e impresoras.

Además, admite complementos, puede usar complementos más bonitos para lograr el formato en cualquier idioma.

Es fácil pensar que el complemento es naturalmente un archivo que especifica el nombre del sufijo, qué analizador e impresora usar, por lo que tiene este formato:

Veamos un complemento real, el complemento más bonito prettier-plugin-nginx que formatea los archivos de configuración de nginx:

La parte de idiomas es para especificar el nombre del idioma, qué extensión de archivo usar y qué analizador usar.

Luego, la parte del analizador es implementar el análisis de cadena a AST:

La parte de la impresora es imprimir el AST en código:

Por supuesto, la impresora en el complemento de prettier no imprime directamente una cadena, sino que la imprime en formato Doc, lo cual es conveniente para que prettier haga otra capa de control de formato.

En resumen, si desea extender el formato de un nuevo idioma, solo necesita implementar el analizador y la impresora.

Pero el complemento anterior que modifica las importaciones no es un lenguaje nuevo, ¿no es código js/ts? ¿Cómo escribir un complemento más bonito?

De hecho, el analizador también puede especificar un preprocesador:

Realice algunos cambios en el contenido antes de analizar:

Entonces, el proceso más bonito completo debería verse así:

Luego, escribimos un complemento más bonito y hacemos el mismo preprocesamiento en el código js/ts/vue/flow, ¿no podemos lograr el efecto de interrumpir aleatoriamente las importaciones?

Escribámoslo:

Solo necesita modificar el analizador predeterminado de babel y mecanografiado de prettier.

Otras configuraciones permanecen sin cambios, solo modifique la parte de preprocesamiento:

const babelParsers = require("prettier/parser-babel").parsers;
const typescriptParsers = require("prettier/parser-typescript").parsers;

function myPreprocessor(code, options) {
  return code + 'guangguangguang';
}

module.exports = {
  parsers: {
    babel: {
      ...babelParsers.babel,
      preprocess: myPreprocessor,
    },
    typescript: {
      ...typescriptParsers.typescript,
      preprocess: myPreprocessor,
    },
  },
};
复制代码

Agregué un guangguangguang después del código.

Introduzca este complemento en el archivo de configuración más bonito:

Luego bajamos más bonito:

¡Nuestro primer complemento más bonito funciona!

Y además de js y ts, también tendrá efecto en archivos vue:

Esto se debe a que al analizar el sfc de vue, la parte del script todavía usa babel o tsc.

Por supuesto, generalmente configuraremos vscode para llamar automáticamente al formato más bonito al guardar.

Esto requiere que se instale el complemento más bonito:

Luego siga su documentación para configurar los ajustes:

Solo hazlo coincidir así:

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true
}
复制代码

Luego se formatea automáticamente con más bonito cada vez que se guarda:

Luego comenzamos a implementar la función de barajar las importaciones.

Para encontrar el código de las importaciones y luego hacer algunas modificaciones, es natural pensar en pasar la api de babel.

Entonces podemos escribir:

Primero importe estos paquetes:

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generate = require("@babel/generator").default;
const types = require("@babel/types");

const _ = require("lodash");
复制代码

Los paquetes analizar, atravesar y generar son fáciles de entender y corresponden a los tres pasos de la compilación babel.

El paquete de tipos se utiliza para crear AST.

Debido a que esm exporta algunos paquetes, se requiere el atributo .default para importarlos en commonjs.

Luego introduzca lodash, algunas funciones de utilidad.

El primer paso es llamar a parser.parse para convertir el código en AST.

function myPreprocessor(code, options) {
  const ast = parser.parse(code, {
    plugins: ["typescript", "jsx"],
    sourceType: "module",
  });
}
复制代码

Si analiza los códigos ts y jsx, debe especificar los complementos mecanografiado y jsx respectivamente.

sourceType is module significa que es un código de módulo con importación o exportación.

El segundo paso es encontrar el nodo de importaciones.

const importNodes = [];

traverse(ast, {
    ImportDeclaration(path) {
      importNodes.push(_.clone(path.node));

      path.remove();
    }
});

复制代码

Recorre el AST, declarando la tramitación de declaraciones de importación.

Qué código específico es lo que AST se puede   visualizar en astexplorer.net :

Use la función de clonación de lodash para copiar el nodo AST y colocarlo en la matriz.

Luego elimine el nodo de importación del AST original.

El tercer paso es ordenar los nodos de importación.

Para este paso, solo use la función de reproducción aleatoria de lodash:

const newImports = _.shuffle(importNodes);
复制代码

El cuarto paso es imprimir el código objetivo.

Después de modificar el AST, simplemente imprímalo como el código de destino, pero ahora hay dos partes del código, que se generan por separado y luego se unen:

const newAST = types.file({
    type: "Program",
    body: newImports,
});

const newCode =  generate(newAST).code +
    "\n" +
    generate(ast, {
      retainLines: true,
    }).code;

复制代码

La declaración de importación debe envolver el nodo raíz de una capa de archivo, que se crea con la API del paquete @babel/types:

Al generar, puede agregar RetainLines a verdadero, es decir, la cantidad de líneas retenidas en el código fuente al imprimir, para que la cantidad de líneas no cambie después de la impresión.

Hasta ahora, hemos completado el complemento más bonito que cambia aleatoriamente el orden de las importaciones.

El código completo es el siguiente:

const babelParsers = require("prettier/parser-babel").parsers;
const typescriptParsers = require("prettier/parser-typescript").parsers;

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generate = require("@babel/generator").default;
const types = require("@babel/types");

const _ = require("lodash");

function myPreprocessor(code, options) {
  const ast = parser.parse(code, {
    plugins: ["typescript", "jsx"],
    sourceType: "module",
  });

  const importNodes = [];

  traverse(ast, {
    ImportDeclaration(path) {
      importNodes.push(_.clone(path.node));

      path.remove();
    },
  });

  const newImports = _.shuffle(importNodes);

  const newAST = types.file({
    type: "Program",
    body: newImports,
  });

  const newCode =  generate(newAST).code +
    "\n" +
    generate(ast, {
      retainLines: true,
    }).code;

  return newCode;
}

module.exports = {
  parsers: {
    babel: {
      ...babelParsers.babel,
      preprocess: myPreprocessor,
    },
    typescript: {
      ...typescriptParsers.typescript,
      preprocess: myPreprocessor,
    },
  },
};
复制代码

Vamos a intentarlo.

En el archivo js/ts:

En el archivo vue:

¡Todo está funcionando! (Debido a que el complemento más bonito tiene un caché, si no hace efecto, ciérrelo y abra el editor nuevamente)

¡Hasta ahora, nuestro colega ha descubierto el complemento que lo golpeará y está completo!

Algunos estudiantes dijeron, pero se introducirá en el archivo de configuración, esto es demasiado obvio.

En realidad no. De manera predeterminada, prettier cargará todos los complementos prettier-plugin-xx o @xxx/prettier-plugin-yy en node_modules, no es necesario especificar manualmente los complementos, esto solo es necesario para el desarrollo local.

Por ejemplo, la comunidad tiene un complemento llamado prettier-plugin-sort-import para la clasificación de importaciones:

Puede configurarlo directamente sin importarlo usted mismo:

Por lo tanto, siempre que instale la dependencia del complemento más bonito que interrumpe las importaciones, se aplicará automáticamente y será difícil para los colegas encontrarlo sin mirar el archivo package.json.

Resumir

Prettier se implementa en base a la tecnología de compilación. La compilación frontal es un proceso de tres pasos de analizar, transformar y generar, al igual que Prettier, pero no se requiere una transformación intermedia.

Solo incluye analizador e impresora, pero admite muchos idiomas. Cada idioma tiene su propio analizador e impresora.

Para escribir un complemento formateado más bonito que admita un nuevo idioma, solo necesita un archivo que exporte la configuración de idiomas, analizadores e impresoras:

  • La parte de idiomas especifica el nombre del idioma, la extensión del archivo, qué analizador usar, etc.
  • La parte de los analizadores realiza el análisis desde la cadena hasta el AST y también puede especificar el preprocesamiento de la función de preprocesamiento.
  • La parte de impresoras se da cuenta de la impresión de AST a doc. doc es un formato intermedio de prettier, lo cual es conveniente para prettier para hacer otra capa de control de formato unificado y luego imprimirlo como una cadena

El complemento más bonito que escribimos hoy no admite nuevos idiomas, por lo que solo usamos el preprocesamiento para preprocesar el código y usamos la API de babel para procesar las importaciones del código.

Por lo tanto, si conoce el complemento babel, escribirá un complemento más bonito para preprocesar js/ts. De manera similar, también puede usar postcss, posthtml, etc. para preprocesar css, scss, less, html, etc. al formatear el código. lógica personalizada.

Finalmente, el caso del complemento más bonito en el artículo es solo para aprender. No se recomienda introducir este complemento en el proyecto, de lo contrario, las consecuencias serán bajo su propio riesgo [Wang Chai].

Supongo que te gusta

Origin blog.csdn.net/weixin_46669844/article/details/128450156
Recomendado
Clasificación