Feb 23, 2024

How to set up Prettier On a Laravel App, Linting Tailwind Class Order and More

It may seem silly, but it's important to me that my Tailwind classes are orderedly consistently, and I don't want to have to manage that manually. Frustratingly, I've never found a solution that gives me exactly what I want—until now.

Here's my must-have list:

  • Works in CLI/Continuous Integration (Rustywind would work here, but not Headwind)
  • Works in all IDEs (so Headwind doesn't cut it, and Rustywind would require work to adapt)
  • Uses Tailwind's official ordering specifications (again, Headwind/Rustywind would require work to get here)
  • Works on Laravel Blade files

I've asked on Twitter multiple times, and the most recent time I asked, I got a response from my friend Jason Beggs suggesting I should look into prettier-plugin-blade.

So I set out, with Jason's help, to get it working on a new Laravel app, later receiving some help from the tools' creator, John.

What I found is that the ideal solution to my wish list above is using prettier-plugin-blade together with Tailwind's official Prettier plugin. It works on CI and the CLI, has IDE integrations, works in Blade files, and uses Tailwind's official class ordering.

Let's dig in!

The installation

  1. Install prettier, prettier-plugin-tailwindcss, and prettier-plugin-blade with npm install
npm install --save-dev prettier-plugin-blade@^2 prettier prettier-plugin-tailwindcss
  1. Add a .prettierrc config file to your project root

Here is the most basic file you'll start with, before you start actually configuring Prettier:

{
  "plugins": ["prettier-plugin-blade", "prettier-plugin-tailwindcss"],
  "overrides": [
    {
      "files": [
        "*.blade.php"
      ],
      "options": {
        "parser": "blade"
      }
    }
  ]
}

On top of this, you can add your own lines to configure Prettier; here are those I've added, but you can find more here.

{
    "printWidth": 120,
    "semi": true,
    "singleQuote": true,
    "tabWidth": 4,
    "trailingComma": "all",
    "plugins": ["prettier-plugin-blade", "prettier-plugin-tailwindcss"],
    "overrides": [
        {
            "files": [
                "*.blade.php"
            ],
            "options": {
                "parser": "blade"
            }
        }
    ]
}
  • printWidth: Defines the width (in characters) you'd like your lines to reach; this is not a hard limit, but a general guideline to Prettier. Prettier recommends 80. I'm not sure what I'll land on; I'm using 120 for now because that's what was in Jason's original config file.
  • semi: Adds semicolons at the end of all lines in JavaScript
  • singleQuote: Uses single quotes when possible in JavaScript
  • tabWidth: Sets the number of spaces in each level of indentation.
  • trailingComma: Defines when to put trailing commas in multiline structures
  1. Add a .prettierignore file

I hacked this together using Jason's and some other references online, but I can't say this is perfect. Like .gitignore, everyone will have their own way of doing it.

node_modules
dist
.env*
vendor/
/vendor
public/
.git
**/.git
package-lock.json
composer.lock

Using the package manually

Now that we have the package installed, let's take a look at what we can do with it.

First, if you want to run Prettier, you have a few options. The most common is to fix your issues. You'll run npx prettier --write and pass the directory you're fixing. I'm only using Prettier for frontend code, so I'll pass it the resources/ directory:

npx prettier --write resources/

If you want to check whether your code passes, but not actually format anything (most common in CI), you can instead pass the --check flag, which will return a failing code if your code isn't formatted correctly:

npx prettier --check resources/

So let's take a project where I have a single file with a Tailwind-styled div, living at resources/file.html:

<html><body>
    <div class="mb-2 font-bold p-2">
        Content!
    </div>
</body></html>

If I run npx prettier --check resources/file.html, it'll fail:

± npx prettier --check resources/file.html
Checking formatting...
[warn] resources/file.html
[warn] Code style issues found in the above file. Run Prettier to fix.

And if I run npx prettier --write resources/file.html, it'll fix it:

± npx prettier --write resources/file.html
resources/file.html 257ms

And now we've got a fixed file:

<html>
    <body>
        <div class="mb-2 p-2 font-bold">Content!</div>
    </body>
</html>

That's it!

Other benefits of this package

One of the benefits of using this package specifically is that it understands Laravel-specific contexts. For example, if you have strings inside of Blade, it'll fix them as well. As you can see, it'll re-order the classes here even when they're inside a Blade string, turning this:

<div class="{{ 'mb-2 font-bold p-2' }}">Content!</div>

to this:

<div class="{{ 'mb-2 p-2 font-bold' }}">Content!</div>

You can learn more about the specific benefits of this package, and how to customize some of its unique settings, on its documentation site.

Using Pint with Prettier

At Tighten, we use Duster, which includes Pint, so this isn't a feature I use, but if you use Pint on your projects, you can also hook that into your Prettier runs.

You can learn more in the documentation, but you'll essentially set useLaravelPint to true in your .blade.format.json configuration file, and then the Prettier plugin will run Pint as a part of any calls to it.

Other options for using the package

There are a few other ways you can use this package other than running it manually on the command line.

Create an NPM script to run Prettier

If you want to make it easier to manually (or programatically) run your format commands, or to give directions to future devs how and where to run it, you can add a script to your package.json file:

{
    // ...
    "scripts": {
        // ...
        "format": "npx prettier --write resources/",
    }
    // ...
}

You can now run npm run format to trigger your run.

Trigger Prettier on Git actions with Husky

Husky is a popular JavaScript package that makes it easy to manage your Git hooks. At Tighten, we often use it to ensure everyone on the project remembers to run code formatting tooling with each commit.

For a tutorial on how to set up Husky, check out Tower's guide to installing Husky. Once you have Husky set up, you can add a step to run Prettier as a part of your Git workflow; here's my lint-staged.config.js (which I should probably tweak to only run on files in resources/):

export default {
    '**/*': 'prettier --write --ignore-unknown',
};

Format files in VS Code with Prettier

If you want to set up VS Code to correctly parse your Prettier config with this plugin, you have to do a tiny bit of configuration. I've seen a few folks online saying you have to trick VS Code into treating Blade like HTML, but the plugin's author, John, told me this is the correct answer: Open up your VS Code configuration and add the following configuration items:

{
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "[blade]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "prettier.documentSelectors": [
        "**/*.blade.php"
    ]
}

This, of course, requires you to have the Prettier VS Code plugin installed. Once you have the plugin installed, you can run Prettier by triggering "Format Document" from the command palette, or you can set the editor.formatOnSave setting to true and then it'll run Prettier every time you save a file.

Run Prettier in GitHub Actions

If you want to set up Prettier in your GitHub actions workflow, you have two options: Fail the action if it's not correctly formatted, or just format it on the server.

If you want to format your code as a part of your GitHub Actions workflow, check out this tutorial.

If you want your Prettier step to fail if the Prettier check fails, check out this tutorial.

Conclusion

That's everything!

Do you have any questions, or any preferences for how you like to set up your Prettier? Let me know on Twitter!


Comments? I'm @stauffermatt on Twitter

Subscribe

For quick links to fresh content, and for more thoughts that don't make it to the blog.