Awesome
blade-formatter
An opinionated blade template formatter for Laravel that respects readability
This project aims to provide a formatter for blade templates, as there is no official blade template formatter.
Features
-
Automatically Indents markup inside directives
-
Automatically add spacing to blade templating markers
-
PHP 8 support (null safe operator, named arguments) 🐘
-
PSR-2 support (format inside directives)
-
Automatic Tailwind CSS Class Sorting. see Options
-
Custom Directive support
Example
Input
@extends('frontend.layouts.app')
@section('title') foo
@endsection
@section('content')
<section id="content">
<div class="container mod-users-pd-h">
<div class="pf-user-header">
<div></div>
<p>@lang('users.index')</p>
</div>
<div class="pf-users-branch">
<ul class="pf-users-branch__list">
@foreach($users as $user)
<li>
<img src="{{ asset('img/frontend/icon/branch-arrow.svg') }}" alt="branch_arrow">
{{ link_to_route("frontend.users.user.show",$users["name"],$users['_id']) }}
</li>
@endforeach
</ul>
<div class="pf-users-branch__btn">
@can('create', App\Models\User::class)
{!! link_to_route("frontend.users.user.create",__('users.create'),[1,2,3],['class' => 'btn']) !!}
@endcan
</div>
</div>
</div>
</section>
@endsection
@section('footer')
@stop
Output
@extends('frontend.layouts.app')
@section('title') foo
@endsection
@section('content')
<section id="content">
<div class="container mod-users-pd-h">
<div class="pf-user-header">
<div></div>
<p>@lang('users.index')</p>
</div>
<div class="pf-users-branch">
<ul class="pf-users-branch__list">
@foreach ($users as $user)
<li>
<img src="{{ asset('img/frontend/icon/branch-arrow.svg') }}" alt="branch_arrow">
{{ link_to_route('frontend.users.user.show', $users['name'], $users['_id']) }}
</li>
@endforeach
</ul>
<div class="pf-users-branch__btn">
@can('create', App\Models\User::class)
{!! link_to_route('frontend.users.user.create', __('users.create'), [1, 2, 3], ['class' => 'btn']) !!}
@endcan
</div>
</div>
</div>
</section>
@endsection
@section('footer')
@stop
Installation
$ npm install --save-dev blade-formatter
$ node_modules/.bin/blade-formatter -h
yarn
$ yarn add --dev blade-formatter
global
$ npm install -g blade-formatter
$ yarn global add blade-formatter
docker
$ docker run -it -v $(pwd):/app -w /app shufo/blade-formatter resources/**/*.blade.php
Usage
- Basic
# This outputs formatted result to stdout
$ blade-formatter resources/**/*.blade.php
$ blade-formatter resources/layouts/app.blade.php
- Check if template is formatted or not (makes no change)
$ blade-formatter app/** -d -c
Check formatting...
app/index.blade.php
Above file(s) are formattable. Forgot to run formatter? Use --write option to overwrite.
$ echo $?
1
- Format files and overwrite
$ blade-formatter --write resources/**/*.blade.php
- Show diffs
$ blade-formatter -c -d resources/**/*.blade.php
Options
Options:
--version Show version number [boolean]
-c, --check-formatted Only checks files are formatted or not [boolean] [default: false]
-w, --write Write to file [boolean] [default: false]
-d, --diff Show diffs [boolean] [default: false]
-e, --end-with-newline End output with newline [boolean] [default: true]
--end-of-line End of line character(s). [string] [choices: "LF", "CRLF"]
-i, --indent-size Indentation size [default: 4]
--wrap-line-length, --wrap The length of line wrap size [default: 120]
--wrap-attributes, --wrap-atts The way to wrap attributes.
[auto|force|force-aligned|force-expand-multiline|aligned-multiple|preserve|preserve-aligned] [string] [default: "auto"]
-M, --wrap-attributes-min-attrs Minimum number of html tag attributes for force wrap attribute options. Wrap the first attribute only if 'force-expand-multiline' is specified in wrap attributes [default: "2"]
-I, --indent-inner-html Indent <head> and <body> sections in html. [boolean] [default: false]
--sort-tailwindcss-classes Sort tailwindcss classes [boolean] [default: false]
--tailwindcss-config-path Specify path of tailwind config [string] [default: null]
--sort-html-attributes Sort HTML attributes. [string] [choices: "none", "alphabetical", "code-guide", "idiomatic", "vuejs", "custom"] [default: none]
--custom-html-attributes-order Comma separated custom HTML attributes order. To enable this you must specify sort html attributes option as `custom`. You can use regex for attribute names. [string] [default: null]
--no-single-quote Use double quotes instead of single quotes for php expression. [boolean] [default: false]
-E, --extra-liners Comma separated list of tags that should have an extra newline before them. [string] [default: "head,body,/html"]
--no-multiple-empty-lines Merge multiple blank lines into a single blank line [boolean] [default: false]
--no-php-syntax-check Disable PHP syntax checking [boolean] [default: false]
--no-trailing-comma-php If set to true, no trailing commas are printed for php expression. [boolean] [default: false]
-p, --progress Print progress [boolean] [default: false]
--stdin Format code provided on <STDIN> [boolean] [default: false]
--config Use this configuration, overriding .bladeformatterrc config options if present [string] [default: null]
--ignore-path Specify path of ignore file [string] [default: null]
-h, --help Show help [boolean]
Examples:
blade-formatter "resources/views/**/*.blade.php" --write Format all files in views directory
Configuring blade-formatter
To configure project wide settings, put .bladeformatterrc.json
or .bladeformatterrc
in your repository root, blade-formatter will treat them as settings files.
e.g.
{
"indentSize": 4,
"wrapAttributes": "auto",
"wrapLineLength": 120,
"wrapAttributesMinAttrs": 2,
"indentInnerHtml": true,
"endWithNewLine": true,
"endOfLine": "LF",
"useTabs": false,
"sortTailwindcssClasses": true,
"sortHtmlAttributes": "none",
"noMultipleEmptyLines": false,
"noPhpSyntaxCheck": false,
"noSingleQuote": false,
"noTrailingCommaPhp": false,
"extraLiners": []
}
blade-formatter will search up the directory structure until it reaches the root directory.
Ignore Files
To ignore a specific file, put a `.bladeignore' in the root of your repository and the blade formatter will treat it as an ignored file.
e.g.
resources/views/users/index.blade.php
resources/views/products/*
resources/views/books/**/*
Disabling format in file
To disable formatting in your file, you can use blade comments in the following format:
{{-- blade-formatter-disable --}}
{{ $foo }}
{{ $bar }}
{{-- blade-formatter-enable --}}
To disable formatiing on a specific line, you can use comment in the following format:
{{-- blade-formatter-disable-next-line --}}
{{ $foo }}
To disable formatting for an entire file, put a {{-- blade-formatter-disable --}}
comment at the beginning of the file:
{{-- blade-formatter-disable --}}
{{ $foo }}
API
You can also use the blade formatter via API.
const { BladeFormatter } = require('blade-formatter');
const input = `
<html>
<body>
<p>foo</p>
</body>
</html>
`;
const options = {
indentSize: 4,
wrapAttributes: "auto",
wrapLineLength: 120,
endWithNewLine: true,
useTabs: false,
sortTailwindcssClasses: true,
};
new BladeFormatter(options).format(input).then((formatted) => {
console.log(formatted);
});
ESModule
import { Formatter } from "blade-formatter";
const input = `
<html>
<body>
<p>foo</p>
</body>
</html>
`;
const options = {
indentSize: 2,
};
new Formatter(options).formatContent(input).then((formatted) => {
console.log(formatted);
});
Extensions
- vscode-blade-formatter - VSCode Extension
- coc-blade - coc.nvim Extension by @yaegassy
- prettier-plugin-blade - Prettier plugin for Blade
- null-ls.nvim - Extension by @jose-elias-alvarez
Troubleshoot
- If you encounter the following error during installation
$ npm install -g blade-formatter
~~
current user ("nobody") does not have permission to access the dev dir
~~
Try setting the global user as root
$ npm -g config set user root
- If you encounter the following message like below when sorting TailwindCss class sorting enabled
message: 'module is not defined in ES module scope\n' +
// or
export default {
^^^^^^
SyntaxError: Unexpected token 'export'
then you should check your nodejs module type is matched with tailwindcss.config.js
.
ESM
package.json
"type": "module"
tailwind.config.js
export default {
~~~
}
CommonJS
tailwind.config.js
module.exports = {
~~~
}
TODO
- custom directives
-
@for
directive support - ignore formatting in blade comment
- automatically add new line after directive
Development
$ yarn install
$ yarn run watch # watch changes
You can use local docker image for development. It might help if the host OS is not an amd64 architecture.
$ make build
$ make run example.php
Testing
$ yarn install
$ yarn run test
You can use local docker image for testing. It might help if the host OS is not an amd64 architecture.
$ make build
$ make test
$ make debug # attach
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
Contributors
<!-- readme: collaborators,contributors -start --> <table> <tr> <td align="center"> <a href="https://github.com/shufo"> <img src="https://avatars.githubusercontent.com/u/1641039?v=4" width="100;" alt="shufo"/> <br /> <sub><b>Shuhei Hayashibara</b></sub> </a> </td> <td align="center"> <a href="https://github.com/wheesnoza"> <img src="https://avatars.githubusercontent.com/u/45123151?v=4" width="100;" alt="wheesnoza"/> <br /> <sub><b>Null</b></sub> </a> </td> <td align="center"> <a href="https://github.com/claytonrcarter"> <img src="https://avatars.githubusercontent.com/u/1420419?v=4" width="100;" alt="claytonrcarter"/> <br /> <sub><b>Null</b></sub> </a> </td> <td align="center"> <a href="https://github.com/slovenianGooner"> <img src="https://avatars.githubusercontent.com/u/1257629?v=4" width="100;" alt="slovenianGooner"/> <br /> <sub><b>SlovenianGooner</b></sub> </a> </td> <td align="center"> <a href="https://github.com/yaegassy"> <img src="https://avatars.githubusercontent.com/u/188642?v=4" width="100;" alt="yaegassy"/> <br /> <sub><b>Yaegassy</b></sub> </a> </td> <td align="center"> <a href="https://github.com/schelmo"> <img src="https://avatars.githubusercontent.com/u/47602?v=4" width="100;" alt="schelmo"/> <br /> <sub><b>Schelmo</b></sub> </a> </td></tr> <tr> <td align="center"> <a href="https://github.com/Dave-iFour"> <img src="https://avatars.githubusercontent.com/u/110526667?v=4" width="100;" alt="Dave-iFour"/> <br /> <sub><b>Dave</b></sub> </a> </td> <td align="center"> <a href="https://github.com/notdian"> <img src="https://avatars.githubusercontent.com/u/4225509?v=4" width="100;" alt="notdian"/> <br /> <sub><b>Null</b></sub> </a> </td> <td align="center"> <a href="https://github.com/garrettboone"> <img src="https://avatars.githubusercontent.com/u/47018474?v=4" width="100;" alt="garrettboone"/> <br /> <sub><b>Garrett Boone</b></sub> </a> </td> <td align="center"> <a href="https://github.com/gagansday"> <img src="https://avatars.githubusercontent.com/u/25811413?v=4" width="100;" alt="gagansday"/> <br /> <sub><b>Gagandeep Singh</b></sub> </a> </td> <td align="center"> <a href="https://github.com/hjanos1"> <img src="https://avatars.githubusercontent.com/u/3355793?v=4" width="100;" alt="hjanos1"/> <br /> <sub><b>Janos Horvath</b></sub> </a> </td> <td align="center"> <a href="https://github.com/joshuachp"> <img src="https://avatars.githubusercontent.com/u/43700905?v=4" width="100;" alt="joshuachp"/> <br /> <sub><b>Joshua Chapman</b></sub> </a> </td></tr> <tr> <td align="center"> <a href="https://github.com/jtanaka"> <img src="https://avatars.githubusercontent.com/u/1379640?v=4" width="100;" alt="jtanaka"/> <br /> <sub><b>Jumpei Tanaka</b></sub> </a> </td> <td align="center"> <a href="https://github.com/ldommer"> <img src="https://avatars.githubusercontent.com/u/65616313?v=4" width="100;" alt="ldommer"/> <br /> <sub><b>Lennart Dommer</b></sub> </a> </td></tr> </table> <!-- readme: collaborators,contributors -end -->LICENSE
MIT