🛁

Rust製のコードフォーマッターdprintの導入手順

2023/09/25に公開

dprintとは

https://dprint.dev/

公式ドキュメントには以下のように書かれていました

Formatting is very fast.
Plugins are WebAssembly files that may be imported from a URL or file path.
Official plugins are highly configurable enabling you to auto format code closer to your preferences.
Configuration may be imported from URLs for reuse and sharing.

これを含めるとdprintには以下のような特徴があります

  • Rust製のコードフォーマッター
  • 高速に動作する
  • 細かいフォーマットの設定が可能
  • JavaScript, Typescript, JSON, Markdown, TOMAL, Dockerfileなどのファイルが対象

インストール

様々な導入方法がありますが、ここではnpmパッケージを使用します
他のインストール方法は公式ドキュメントに載っています
https://dprint.dev/install/

npm i dprint --save-dev
or
yarn add -D dprint
or
pnpm add -D dprint

scriptに追加します

package.json
{
  ...
  "scripts": {
    ...
+   "fmt": "pnpm dprint fmt",
  },

初期設定

https://dprint.dev/setup/
dprint initを実行します

pnpm dprint init

spaceで選択をし、Enterで決定します
ここでは、typescriptとjsonを選択しました

> pnpm dprint init
Select plugins (use the spacebar to select/deselect and then press enter when finished):
> [x] dprint-plugin-typescript
  [x] dprint-plugin-json
  [ ] dprint-plugin-markdown
  [ ] dprint-plugin-toml
  [ ] dprint-plugin-dockerfile

設定ファイルであるdprint.jsonがプロジェクト直下に生成されます

dprint.json
{
  "typescript": {
  },
  "json": {
  },
  "excludes": [
    "**/node_modules",
    "**/*-lock.json"
  ],
  "plugins": [
    "https://plugins.dprint.dev/typescript-0.87.1.wasm",
    "https://plugins.dprint.dev/json-0.17.4.wasm"
  ]
}

私のプロジェクトがNext.jsだったので.next内のファイルを除外します

dprint.json
{
  "typescript": {
  },
  "json": {
  },
  "excludes": [
    "**/node_modules",
    "**/*-lock.json",
+   "**/.next"
  ],
  "plugins": [
    "https://plugins.dprint.dev/typescript-0.87.1.wasm",
    "https://plugins.dprint.dev/json-0.17.4.wasm"
  ]
}

動かしてみる

dprint fmtで対象ファイルのフォーマットを実行します

pnpm dprint fmt

フォーマットされました。体感すごい速かったです🎉

計測している方の記事では、小規模のプロジェクトでPrettierの2倍の速度で動いているようです
速いですね
https://sosukesuzuki.dev/posts/dprint-is-fast/

vscodeで保存時にフォーマットさせる

  1. vscodeの拡張機能を入れます

https://marketplace.visualstudio.com/items?itemName=dprint.dprint

  1. .vscode/settings.jsonにdprintの設定を追加します
    これで、保存した時にフォーマットがされるようになります
.vscode/settings.json
{
  "editor.defaultFormatter": "dprint.dprint",
  "editor.formatOnSave": true
}

Ctrl+Sで保存すると、ちゃんとフォーマットされました🎉

  1. .vscode/extensions.jsonに追加
    vscodeの拡張機能を他の人にオススメする
.vscode/extensions.json
{
  "recommendations": [
    "dprint.dprint"
  ]
}

フォーマットの細かい設定

https://dprint.dev/config/

設定ファイルは型が効くので嬉しいです

playgroundにTypescriptの設定一覧が載っています
https://dprint.dev/playground/#code/Q/language/typescript

フォーマットの設定を細かく設定することが出来ます

Typescriptの設定項目一覧
{
  "lineWidth": 80,
  "indentWidth": 2,
  "useTabs": false,
  "semiColons": "prefer",
  "quoteStyle": "alwaysDouble",
  "quoteProps": "preserve",
  "newLineKind": "lf",
  "useBraces": "whenNotSingleLine",
  "bracePosition": "sameLineUnlessHanging",
  "singleBodyPosition": "maintain",
  "nextControlFlowPosition": "sameLine",
  "trailingCommas": "onlyMultiLine",
  "operatorPosition": "nextLine",
  "preferHanging": false,
  "preferSingleLine": false,
  "arrowFunction.useParentheses": "maintain",
  "binaryExpression.linePerExpression": false,
  "jsx.bracketPosition": "nextLine",
  "jsx.forceNewLinesSurroundingContent": false,
  "jsx.quoteStyle": "preferDouble",
  "jsx.multiLineParens": "prefer",
  "memberExpression.linePerExpression": false,
  "typeLiteral.separatorKind": "semiColon",
  "enumDeclaration.memberSpacing": "maintain",
  "spaceAround": false,
  "spaceSurroundingProperties": true,
  "objectExpression.spaceSurroundingProperties": true,
  "objectPattern.spaceSurroundingProperties": true,
  "typeLiteral.spaceSurroundingProperties": true,
  "binaryExpression.spaceSurroundingBitwiseAndArithmeticOperator": true,
  "commentLine.forceSpaceAfterSlashes": true,
  "constructor.spaceBeforeParentheses": false,
  "constructorType.spaceAfterNewKeyword": false,
  "constructSignature.spaceAfterNewKeyword": false,
  "doWhileStatement.spaceAfterWhileKeyword": true,
  "exportDeclaration.spaceSurroundingNamedExports": true,
  "forInStatement.spaceAfterForKeyword": true,
  "forOfStatement.spaceAfterForKeyword": true,
  "forStatement.spaceAfterForKeyword": true,
  "forStatement.spaceAfterSemiColons": true,
  "functionDeclaration.spaceBeforeParentheses": false,
  "functionExpression.spaceBeforeParentheses": false,
  "functionExpression.spaceAfterFunctionKeyword": false,
  "getAccessor.spaceBeforeParentheses": false,
  "ifStatement.spaceAfterIfKeyword": true,
  "importDeclaration.spaceSurroundingNamedImports": true,
  "jsxSelfClosingElement.spaceBeforeSlash": true,
  "jsxExpressionContainer.spaceSurroundingExpression": false,
  "method.spaceBeforeParentheses": false,
  "setAccessor.spaceBeforeParentheses": false,
  "taggedTemplate.spaceBeforeLiteral": false,
  "typeAnnotation.spaceBeforeColon": false,
  "typeAssertion.spaceBeforeExpression": true,
  "whileStatement.spaceAfterWhileKeyword": true,
  "ignoreNodeCommentText": "dprint-ignore",
  "ignoreFileCommentText": "dprint-ignore-file"
}

今までPrettierを使っていたので、以下のPrettierの設定に近づけてカスタマイズしてみます

.prettierrc
{
  "semi": false,
  "singleQuote": true,
  "jsxSingleQuote": true,
  "trailingComma": "all",
  "arrowParens": "avoid"
}

この時のdprint.jsonは以下になりました(コメントは消してください)

dprint.json
{
  "lineWidth": 80, // 折り返しの横幅
  "indentWidth": 2, // インデントの幅
  "typescript": {
    "quoteStyle": "alwaysSingle", // シングルクォーテーションを使用
    "semiColons": "asi", // セミコロンを使わない
    "arrowFunction.useParentheses": "force", // アロー関数の引数が1つの時()を省略しない
    "binaryExpression.linePerExpression": false, // 二項演算で折り返すとき、全ての項を折り返す
  },
  "json": {},
  "excludes": [
    "**/node_modules",
    "**/*-lock.json",
    "**/.next"
  ],
  "plugins": [
    "https://plugins.dprint.dev/typescript-0.87.1.wasm",
    "https://plugins.dprint.dev/json-0.17.4.wasm"
  ]
}

他にも良さそうな設定があったので、プロジェクトに合わせて設定しても良いと思います

useBraces

  • 説明: 単一行ステートメントのブレース(中括弧)の使用を指定します。

  • 例:

    "useBraces": "whenNotSingleLine"(規定値)

    if (true) console.log('Inside if block')
    

    "useBraces": "always"

    if (true) { console.log('Inside if block') }
    

bracePosition

  • 説明: ブレースの位置を指定します。

  • 例:

    "bracePosition": "sameLineUnlessHanging"(規定値)

    function myFunction() {
      return "Indented text.";
    }
    

    "bracePosition": "nextLine"

    function myFunction()
    {
      return "Indented text.";
    }
    

singleBodyPosition

  • 説明: 単一行関数のボディの位置を指定します。

  • 例:

    "singleBodyPosition": "maintain"(規定)

    if (true) console.log('Inside if block')
    

    "singleBodyPosition": "nextLine"

    if (true) {
      console.log('Inside if block')
    }
    

trailingCommas

  • 説明: 配列やオブジェクトリテラルの最後の要素の後にカンマを使用するかどうかを指定します。"onlyMultiLine"を指定すると、複数行の場合のみカンマが挿入されます。

  • 例:

    "trailingCommas": "onlyMultiLine"(規定値)

    const obj = {
      'key': 'value',
      'a-2': '',
      '0-22': '',
    }
    

    "trailingCommas": ”never"

    const obj = {
      'key': 'value',
      'a-2': '',
      '0-22': ''
    }
    

jsx.forceNewLinesSurroundingContent

  • 説明: JSX要素の内容の周りに新しい行を強制的に挿入するかどうかを指定します。trueに設定すると、内容の周りに新しい行が挿入されます。

  • 例:

    "jsx.forceNewLinesSurroundingContent": false(規定値)

    const element = <div><p>Hello, world!</p></div>;
      const element1 = (
        <div>
          <p>Hello, world!</p>
        </div>
      )
    

    "jsx.forceNewLinesSurroundingContent": true

    const element = (
      <div>
        <p>
          Hello, world!
        </p>
      </div>
    )
    const element1 = (
      <div>
        <p>
          Hello, world!
        </p>
      </div>
    )
    

参考

https://zenn.dev/riya_amemiya/articles/3cfb09104804be

Discussion