1 | <div align="center">
|
2 | <img src="media/logo.svg" width="150" height="150">
|
3 | <h1>eslint-plugin-html</h1>
|
4 | <a href="https://www.npmjs.com/package/eslint-plugin-html"><img alt="NPM version" src="https://img.shields.io/npm/v/eslint-plugin-html"></a>
|
5 | <a href="https://github.com/BenoitZugmeyer/eslint-plugin-html/actions/workflows/tests.yml"><img alt="Tests Status" src="https://img.shields.io/github/actions/workflow/status/BenoitZugmeyer/eslint-plugin-html/tests.yml"></a>
|
6 | <p>A <a href="http://eslint.org">ESLint</a> plugin to lint and fix inline scripts contained in HTML files.</p>
|
7 | </div>
|
8 |
|
9 | - [Usage](#usage)
|
10 | - [Disabling ESLint](#disabling-eslint)
|
11 | - [Linting HTML](#linting-html)
|
12 | - [Multiple scripts tags in a HTML file](#multiple-scripts-tags-in-a-html-file)
|
13 | - [History](#history)
|
14 | - [XML support](#xml-support)
|
15 | - [Settings](#settings)
|
16 | - [`html/html-extensions`](#htmlhtml-extensions)
|
17 | - [`html/xml-extensions`](#htmlxml-extensions)
|
18 | - [`html/indent`](#htmlindent)
|
19 | - [`html/report-bad-indent`](#htmlreport-bad-indent)
|
20 | - [`html/javascript-tag-names`](#htmljavascript-tag-names)
|
21 | - [`html/javascript-mime-types`](#htmljavascript-mime-types)
|
22 | - [`html/ignore-tags-without-type`](#htmlignore-tags-without-type)
|
23 | - [Troubleshooting](#troubleshooting)
|
24 | - [No file linted when running `eslint` on a directory](#no-file-linted-when-running-eslint-on-a-directory)
|
25 | - [Linting templates (or PHP)](#linting-templates-or-php)
|
26 | - [Linting VUE files](#linting-vue-files)
|
27 | - [Migration from older versions](#migration-from-older-versions)
|
28 | - [To v4](#to-v4)
|
29 | - [To v3](#to-v3)
|
30 | - [Credits](#credits)
|
31 |
|
32 | ## Usage
|
33 |
|
34 | Simply install via `npm install --save-dev eslint-plugin-html` and add the plugin to your ESLint
|
35 | configuration. See
|
36 | [ESLint documentation](http://eslint.org/docs/user-guide/configuring#configuring-plugins).
|
37 |
|
38 | Example:
|
39 |
|
40 | ```javascript
|
41 | {
|
42 | "plugins": [
|
43 | "html"
|
44 | ]
|
45 | }
|
46 | ```
|
47 |
|
48 | ## Disabling ESLint
|
49 |
|
50 | To temporarily disable ESLint, use the `<!-- eslint-disable -->` HTML comment. Re-enable it with
|
51 | `<!-- eslint enable -->`. Example:
|
52 |
|
53 | ```html
|
54 | <!-- eslint-disable -->
|
55 | <script>
|
56 | var foo = 1
|
57 | </script>
|
58 | <!-- eslint-enable -->
|
59 | ```
|
60 |
|
61 | To disable ESLint for the next script tag only, use the `<!-- eslint-disable-next-script -->` HTML
|
62 | comment. Example:
|
63 |
|
64 | ```html
|
65 | <!-- eslint-disable-next-script -->
|
66 | <script>
|
67 | var foo = 1
|
68 | </script>
|
69 | ```
|
70 |
|
71 | Disabled script tags are completely ignored: their content will not be parsed as JavaScript. You can
|
72 | use this to disable script tags containing template syntax.
|
73 |
|
74 | ## Linting HTML
|
75 |
|
76 | This plugin focuses on applying ESLint rules on inline scripts contained in HTML. It does not
|
77 | provide any rule related to HTML. For that, you can use other plugins like
|
78 | [`@eslint-html`](https://yeonjuan.github.io/html-eslint/) or
|
79 | [@angular-eslint](https://github.com/angular-eslint/angular-eslint). `eslint-plugin-html` is
|
80 | compatible with those plugins and can be used along them.
|
81 |
|
82 | ## Multiple scripts tags in a HTML file
|
83 |
|
84 | When linting a HTML with multiple script tags, this plugin tries to emulate the browser behavior by
|
85 | sharing the global scope between scripts by default. This behavior doesn't apply to "module"
|
86 | scripts (ie: `<script type="module">` and most transpiled code), where [each script tag gets its own
|
87 | top-level scope](http://exploringjs.com/es6/ch_modules.html#_modules).
|
88 |
|
89 | ESLint has already [an
|
90 | option](https://eslint.org/docs/user-guide/configuring#specifying-parser-options) to tell the parser
|
91 | if the script are modules. `eslint-plugin-html` will use this option as well to know if the scopes
|
92 | should be shared (the default) or not. To change this, just set it in your ESLint configuration:
|
93 |
|
94 | ```
|
95 | {
|
96 | "parserOptions": {
|
97 | "sourceType": "module"
|
98 | }
|
99 | }
|
100 | ```
|
101 |
|
102 | To illustrate this behavior, consider this HTML extract:
|
103 |
|
104 | ```html
|
105 | <script>
|
106 | var foo = 1
|
107 | </script>
|
108 |
|
109 | <script>
|
110 | alert(foo)
|
111 | </script>
|
112 | ```
|
113 |
|
114 | This is perfectly valid by default, and the ESLint rules `no-unused-vars` and `no-undef` shouldn't
|
115 | complain. But if those scripts are considerated as ES modules, `no-unused-vars` should report an
|
116 | error in the first script, and `no-undef` should report an error in the second script.
|
117 |
|
118 | ### History
|
119 |
|
120 | In `eslint-plugin-html` v1 and v2, script code were concatenated and linted in a single pass, so
|
121 | the scope were always shared. This caused [some issues](MIGRATION_TO_V3.md), so in v3 all scripts
|
122 | were linted separately, and scopes were never shared. In v4, the plugin still lint scripts
|
123 | separately, but makes sure global variables are declared and used correctly in the non-module case.
|
124 |
|
125 | ## XML support
|
126 |
|
127 | This plugin parses HTML and XML markup slightly differently, mainly when considering `CDATA`
|
128 | sections:
|
129 |
|
130 | - in XML, any data inside a `CDATA` section will be considered as raw text (not XML) and the `CDATA`
|
131 | delimiter will be droped ;
|
132 | - in HTML, there is no such thing for `<script>` tags: the `CDATA` delimiter is considered as normal
|
133 | text and thus, part of the script.
|
134 |
|
135 | ## Settings
|
136 |
|
137 | > Note: all settings can be written either as `"html/key": value` or in a nested object `"html": { "key": value }`
|
138 |
|
139 | ### `html/html-extensions`
|
140 |
|
141 | By default, this plugin will only consider files ending with those extensions as HTML: `.erb`,
|
142 | `.handlebars`, `.hbs`, `.htm`, `.html`, `.mustache`, `.nunjucks`, `.php`, `.tag`, `.twig`, `.we`.
|
143 | You can set your own list of HTML extensions by using this setting. Example:
|
144 |
|
145 | ```javascript
|
146 | {
|
147 | "plugins": [ "html" ],
|
148 | "settings": {
|
149 | "html/html-extensions": [".html", ".we"], // consider .html and .we files as HTML
|
150 | }
|
151 | }
|
152 | ```
|
153 |
|
154 | ### `html/xml-extensions`
|
155 |
|
156 | By default, this plugin will only consider files ending with those extensions as XML: `.xhtml`,
|
157 | `.xml`. You can set your own list of XML extensions by using this setting. Example:
|
158 |
|
159 | ```javascript
|
160 | {
|
161 | "plugins": [ "html" ],
|
162 | "settings": {
|
163 | "html/xml-extensions": [".html"], // consider .html files as XML
|
164 | }
|
165 | }
|
166 | ```
|
167 |
|
168 | ### `html/indent`
|
169 |
|
170 | By default, the code between `<script>` tags is dedented according to the first non-empty line. The
|
171 | setting `html/indent` allows to ensure that every script tags follow an uniform indentation. Like
|
172 | the `indent` rule, you can pass a number of spaces, or `"tab"` to indent with one tab. Prefix this
|
173 | value with a `+` to be relative to the `<script>` tag indentation. Example:
|
174 |
|
175 | ```javascript
|
176 | {
|
177 | "plugins": [ "html" ],
|
178 | "settings": {
|
179 | "html/indent": "0", // code should start at the beginning of the line (no initial indentation).
|
180 | "html/indent": "+2", // indentation is the <script> indentation plus two spaces.
|
181 | "html/indent": "tab", // indentation is one tab at the beginning of the line.
|
182 | }
|
183 | }
|
184 | ```
|
185 |
|
186 | ### `html/report-bad-indent`
|
187 |
|
188 | By default, this plugin won't warn if it encounters a problematic indentation (ex: a line is under
|
189 | indented). If you want to make sure the indentation is correct, use the `html/report-bad-indent` in
|
190 | conjunction with the `indent` rule. Pass `"warn"` or `1` to display warnings, `"error"` or `2` to
|
191 | display errors. Example:
|
192 |
|
193 | ```javascript
|
194 | {
|
195 | "plugins": [ "html" ],
|
196 | "settings": {
|
197 | "html/report-bad-indent": "error",
|
198 | }
|
199 | }
|
200 | ```
|
201 |
|
202 | ### `html/javascript-tag-names`
|
203 |
|
204 | By default, the code between `<script>` tags is considered as JavaScript. You can customize which
|
205 | tags should be considered JavaScript by providing one or multiple tag names.
|
206 |
|
207 | Example:
|
208 |
|
209 | ```javascript
|
210 | {
|
211 | "plugins": [ "html" ],
|
212 | "settings": {
|
213 | "html/javascript-tag-names": ["script", "customscript"],
|
214 | }
|
215 | }
|
216 | ```
|
217 |
|
218 | ### `html/javascript-mime-types`
|
219 |
|
220 | By default, the code between `<script>` tags is considered as JavaScript code only if there is no
|
221 | `type` attribute or if its value matches the pattern
|
222 | `(application|text)/(x-)?(javascript|babel|ecmascript-6)` or `module` (case insensitive). You can
|
223 | customize the types that should be considered as JavaScript by providing one or multiple MIME types.
|
224 | If a MIME type starts with a `/`, it will be considered as a regular expression. Example:
|
225 |
|
226 | ```javascript
|
227 | {
|
228 | "plugins": [ "html" ],
|
229 | "settings": {
|
230 | "html/javascript-mime-types": ["text/javascript", "text/jsx"], // also use script tags with a "text/jsx" type attribute
|
231 | "html/javascript-mime-types": "/^text\\/(javascript|jsx)$/", // same thing
|
232 | }
|
233 | }
|
234 | ```
|
235 |
|
236 | ### `html/ignore-tags-without-type`
|
237 |
|
238 | By default, the code between `<script>` tags is considered JavaScript if there is no `type`
|
239 | attribute. You can set this setting to `true` to ignore script tags without a `type` attribute.
|
240 | Example:
|
241 |
|
242 | ```javascript
|
243 | {
|
244 | "plugins": [ "html" ],
|
245 | "settings": {
|
246 | "html/ignore-tags-without-type": true,
|
247 | }
|
248 | }
|
249 | ```
|
250 |
|
251 | ## Troubleshooting
|
252 |
|
253 | ### No file linted when running `eslint` on a directory
|
254 |
|
255 | By default, when executing the `eslint` command on a directory, only `.js` files will be linted. You
|
256 | will have to specify extra extensions with the `--ext` option. Example: `eslint --ext .html,.js src`
|
257 | will lint both `.html` and `.js` files in the `src` directory. See [ESLint
|
258 | documentation](http://eslint.org/docs/user-guide/command-line-interface#ext).
|
259 |
|
260 | ### Linting templates (or PHP)
|
261 |
|
262 | `eslint-plugin-html` won't evaluate or remove your template markup. If you have template markup in
|
263 | your script tags, the resulting script may not be valid JavaScript, so `ESLint` will fail to parse
|
264 | it. Here are some workarounds:
|
265 |
|
266 | - You can use [HTML comments to disable ESLint](#disabling-eslint) for specific script tags.
|
267 |
|
268 | - For PHP, you can use
|
269 | [`eslint-plugin-php-markup`](https://github.com/tengattack/eslint-plugin-php-markup) to lint php
|
270 | files, it use a same way to process php markup like `eslint-plugin-html`.
|
271 |
|
272 | - Another possible hacky workaround to make sure the code is valid JavaScript is to put your
|
273 | template markup inside a comment. When the template is rendered, the generated JS code must start
|
274 | with a new line, so it will be written below the comment. PHP example:
|
275 |
|
276 | ```html
|
277 | <script>
|
278 | var mydata
|
279 | // <?= "\n mydata = " . json_encode($var) . ";" ?>
|
280 | console.log(mydata)
|
281 | </script>
|
282 | ```
|
283 |
|
284 | ### Linting VUE files
|
285 |
|
286 | Initially, [`eslint-plugin-vue`](https://github.com/vuejs/eslint-plugin-vue) was using
|
287 | `eslint-plugin-html` to lint code inside script tags. Since v3, `eslint-plugin-vue` is using its
|
288 | own parser, so it is _incompatible_ with `eslint-plugin-html`. You should use `eslint-plugin-vue`
|
289 | exclusively and remove `eslint-plugin-html` from your dependencies if you still have it.
|
290 |
|
291 | ## Migration from older versions
|
292 |
|
293 | ### To v4
|
294 |
|
295 | `eslint-plugin-html` v4 requires at least ESLint v4.7. This is because a lot of internal changes
|
296 | occured in ESLint v4.7, including a [new API to support autofixing in
|
297 | preprocessors](https://eslint.org/docs/developer-guide/working-with-plugins#processors-in-plugins).
|
298 | If you are still using an older version of ESLint, please consider upgrading, or keep using
|
299 | `eslint-plugin-html` v3.
|
300 |
|
301 | The big feature (and breaking change) in `eslint-plugin-html` v4 is the ability to choose how [scopes
|
302 | are shared between script tags in the same HTML file](#multiple-scripts-tags-in-a-html-file).
|
303 |
|
304 | ### To v3
|
305 |
|
306 | If you are considering upgrading to v3, please read [this guide](MIGRATION_TO_V3.md).
|
307 |
|
308 | ## Credits
|
309 |
|
310 | A big thank you to [@kuceb](https://github.com/kuceb) for the logo image!
|