VSCode の Pettier プラグインの原理と設定

最近、この効果を実現できる Prettier プラグインを作成しました。

同僚がコードを保存するたびに、インポート ステートメントの順序がランダムに変更されます。

しかし、よりきれいな構成ファイルには何も見つかりませんでした。

だからあなたは唖然とするでしょう。

では、この同僚はどのようにして、より魅力的なプラグインを見つけたのでしょうか?

Pretier の仕組み

フロントエンド コンパイル ツールはすべてソース コードからソース コードへの変換であるため、解析、変換、生成の 3 つの手順があります。

parse はソース コード文字列を AST オブジェクト ツリーに変換すること、transform は AST を追加、削除、変更すること、generate (または printer) は変換された AST をターゲット コードに再帰的に出力することです。

Prettier は実際にはコンパイルに基づいて実装されますが、中間の変換は行わず、単に解析して出力 (生成とも呼ばれます) するため、次の 2 つのステップに分けられます。

その主なフォーマット機能は、印刷フェーズで実行されます。

全体のプロセスは比較的単純ですが、なぜこれほど多くの言語をサポートしているのでしょうか?

もちろん、各言語には独自のパーサーとプリンターがあります。

たとえば、次のパーサーが組み込まれています。

ts、js、css、scss、html などはすべてサポートされています。これは、サフィックスが異なれば、異なるパーサーとプリンターが有効になるためです。

さらに、プラグインをサポートしているため、よりきれいなプラグインを使用して、任意の言語でフォーマットを実現できます。

プラグインは当然、サフィックス名、使用するパーサーとプリンターを指定するファイルであると考えるのは簡単なので、次の形式になります。

実際のプラグイン、nginx 構成ファイルをフォーマットする prettier プラグイン prettier-plugin-nginx を見てみましょう。

言語部分は、言語の名前、使用するファイル拡張子、および使用するパーサーを指定することです。

次に、パーサー部分は、文字列から AST への解析を実装することです。

プリンター部分は、AST をコードに出力することです。

もちろん、prettier プラグインのプリンターは文字列を直接出力するのではなく、doc 形式で出力します。これは、prettier がフォーマット制御の別のレイヤーを実行するのに便利です。

つまり、新しい言語のフォーマットを拡張したい場合は、パーサーとプリンターを実装するだけで済みます。

しかし、インポートを変更する以前のプラグインは新しい言語ではなく、js/ts コードではありませんか? よりきれいなプラグインを作成するには?

実際、パーサーはプリプロセッサーも指定できます。

解析前にコンテンツにいくつかの変更を加えます。

したがって、よりきれいなプロセス全体は次のようになります。

次に、よりきれいなプラグインを作成し、js/ts/vue/flow コードで同じ前処理を行います。インポートをランダムに中断する効果を実現できませんか?

書きましょう:

prettier のデフォルトのバベルと typescript パーサーを変更するだけです。

他の構成は変更されません。前処理部分を変更するだけです。

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,
    },
  },
};
复制代码

コードの後に​​ guangguangguang を追加しました。

prettier 構成ファイルにこのプラグインを導入します。

次に、よりきれいに実行します。

私たちの最初のきれいなプラグインが動作します!

js と ts に加えて、vue ファイルでも有効になります。

これは、vue の sfc を解析するときに、スクリプト部分が引き続き babel または tsc を使用するためです。

もちろん、通常は、保存時に自動的に prettyer を呼び出してフォーマットするように vscode を構成します。

これには、よりきれいなプラグインをインストールする必要があります。

次に、ドキュメントに従って設定を構成します。

次のように一致させるだけです:

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

次に、保存するたびに自動的にきれいにフォーマットされます。

次に、インポートをシャッフルする機能の実装を開始しました。

インポートのコードを見つけて、いくつかの変更を加えるには、babel の api を渡すことを考えるのが自然です。

したがって、次のように記述できます。

最初にこれらのパッケージをインポートします。

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");
复制代码

パッケージ parser、traverse、および generate は理解しやすく、babel コンパイルの 3 つのステップに対応しています。

types パッケージは、AST の作成に使用されます。

一部のパッケージは esm によってエクスポートされるため、それらを commonjs にインポートするには .default 属性が必要です。

次に、いくつかのユーティリティ関数である lodash を紹介します。

最初のステップは、parser.parse を呼び出してコードを AST に変換することです。

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

ts および jsx コードを解析する場合は、typescript および jsx プラグインをそれぞれ指定する必要があります。

sourceType is module は、インポートまたはエクスポートを伴うモジュール コードであることを意味します。

2 番目のステップは、インポート ノードを見つけることです。

const importNodes = [];

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

      path.remove();
    }
});

复制代码

import ステートメントの処理を宣言して、AST をウォークします。

astexplorer.netで 視覚化できるAST の特定のコードは次のとおりです 。

lodash のクローン機能を使用して AST ノードをコピーし、配列に配置します。

次に、元の AST のインポート ノードを削除します。

3 番目のステップは、インポート ノードをソートすることです。

このステップでは、lodash のシャッフル機能を使用します。

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

4 番目のステップは、ターゲット コードを出力することです。

AST を変更した後、それをターゲット コードとして出力するだけですが、コードには 2 つの部分があり、別々に生成されてから結合されます。

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

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

复制代码

import ステートメントは、 @babel/types パッケージの API で作成されたファイルのレイヤーのルート ノードをラップする必要があります。

生成時にretainLinesをtrue、つまり印刷時にソースコードに保持する行数に追加することで、印刷後に行数が変わらないようにすることができます。

これで、インポートの順序をランダムにシャッフルする、よりきれいなプラグインが完成しました。

完全なコードは次のとおりです。

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,
    },
  },
};
复制代码

試してみよう。

js/ts ファイル内:

vue ファイルで:

それはすべて働いています!(きれいなプラグインはキャッシュがあるので、効かない場合は一度閉じてエディタを開き直してください)

これまでのところ、私たちの同僚があなたにヒットするプラグインを発見し、完成しました!

何人かの学生が言ったが、それは設定ファイルで導入されるだろう、これはあまりにも明白です。

実際にはありません。デフォルトでは、prettier はすべての prettier-plugin-xx または @xxx/prettier-plugin-yy プラグインを node_modules の下にロードします。手動でプラグインを指定する必要はありません。これはローカル開発にのみ必要です。

たとえば、コミュニティには、インポートの並べ替え用の prettier-plugin-sort-import というプラグインがあります。

自分でインポートせずに直接構成できます。

したがって、インポートを中断する prettier プラグインの依存関係をインストールする限り、prettier は自動的に適用され、同僚が package.json を見ずにそれを見つけることは困難です。

要約する

Prettier はコンパイル技術に基づいて実装されています. フロントエンドのコンパイルは、prettier と同様に解析、変換、生成の 3 ステップのプロセスですが、中間の変換は必要ありません。

パーサーとプリンターのみが含まれていますが、多くの言語をサポートしています。各言語には、独自のパーサーとプリンターがあります。

新しい言語をサポートするフォーマット済みのよりきれいなプラグインを作成するには、言語、パーサー、およびプリトナー構成をエクスポートするファイルのみが必要です。

  • 言語部分は、言語の名前、ファイル拡張子、使用するパーサーなどを指定します。
  • パーサー部分は文字列からASTへのパースを実現し、前処理関数preprocessも指定できます。
  • printers 部分は AST から doc への印刷を実現します. doc は prettier の中間フォーマットであり、prettier が統一されたフォーマット制御の別のレイヤーを実行し、文字列として出力するのに便利です

今日書いたよりきれいなプラグインは新しい言語をサポートしていないため、コードの前処理には preprocess のみを使用し、コードのインポートの処理には babel API を使用します。

したがって、babel プラグインを知っている場合は、よりきれいなプラグインを作成して js/ts を前処理します. 同様に、postcss、posthtml などを使用して、コードをフォーマットするときに css、scss、less、html などを前処理することもできます。カスタムロジック。

最後に、この記事のよりきれいなプラグインのケースは、学習のためのものであり、このプラグインをプロジェクトに導入することはお勧めしません。

おすすめ

転載: blog.csdn.net/weixin_46669844/article/details/128450156