Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2021: Lint ALL The Things!

2021: Lint ALL The Things!

Ember applications come with linting built-in and you’ve probably encountered linting in action when it reminded you about unused variables in your code or that you were using deprecated Ember constructs like mixins or observers. But there’s a whole world to linting beyond the default setup, and when used properly, it can become a superpower for modernizing your application and maximizing your team’s productivity. We’ll look at the state of linting with Ember, the different kinds of linters available and actual bugs caught with them, and even how you can write your own lint rules.

Presented by Bryan Mishkin at EmberConf 2021.

EmberConf

March 24, 2021
Tweet

More Decks by EmberConf

Other Decks in Programming

Transcript

  1. Taking advantage of Linting with Ember Bryan Mishkin “Stop nitting,

    start linting” “Ship better code faster!”
  2. My story • Worked on a variety product teams at

    Microsoft and now Square • Switched over to infrastructure to tackle many of the recurring problems I encountered • Linting, a rule-based static code analysis tool, turned out to be a superpower for solving problems Bryan Mishkin github.com/bmish linked.com/in/bmish
  3. Outline • Real bugs caught and examples • Linting +

    Ember • Writing our own lint rule
  4. How does Ember use linting? • eslint • eslint-plugin-ember •

    eslint-plugin-node • eslint-plugin-qunit (new in ember-cli 3.26!) • ember-template-lint • prettier (new in ember-cli 3.24!)
  5. What’s new in eslint-plugin-ember • Comprehensive set of ~65 recommended

    rules • v10 released in December ◦ Ember Octane linting now comes by default ▪ no-actions-hash ▪ no-classic-classes ▪ no-classic-components ▪ no-component-lifecycle-hooks ▪ no-computed-properties-in-native-classes ▪ require-tagless-components ◦ Improved robustness ▪ Better import validation to reduce false positives ▪ Support for newer JavaScript syntaxes (native classes, spread syntax, optional chaining)
  6. What’s new in ember-template-lint • Comprehensive set of ~65 recommended

    rules • v3 released this month (March), the first major release in a year ◦ Ember Octane linting now comes by default ▪ no-action ▪ no-curly-component-invocation ▪ no-implicit-this ◦ Ability to set due dates on violations (“todos”) ◦ Linting arbitrary file extensions like HTML files
  7. Test cases disallowed: [ "this.get('myProperty');" // i.e. accessing a property

    in an Ember component ], allowed: [ "this.foo('bar');", not the `get` function "foo.get('bar');", // might not be an Ember Object "this.get('foo.bar');" // more complex to deal with nested paths ] Writing your own lint rule
  8. Writing your own lint rule Rule implementation CallExpression(node) { if

    ( node.callee.type === 'MemberExpression' && ... ) { report(node, "Use ES5 getters"); } }
  9. Writing your own lint rule Rule implementation CallExpression(node) { if

    ( node.callee.type === 'MemberExpression' && node.callee.object.type === 'ThisExpression' && ... ) { report(node, "Use ES5 getters"); } }
  10. Writing your own lint rule Rule implementation CallExpression(node) { if

    ( node.callee.type === 'MemberExpression' && node.callee.object.type === 'ThisExpression' && node.callee.property.type === 'Identifier' && ... ) { report(node, "Use ES5 getters"); } }
  11. Writing your own lint rule Rule implementation CallExpression(node) { if

    ( node.callee.type === 'MemberExpression' && node.callee.object.type === 'ThisExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'get' && ... ) { report(node, "Use ES5 getters"); } }
  12. Writing your own lint rule Rule implementation CallExpression(node) { if

    ( node.callee.type === 'MemberExpression' && node.callee.object.type === 'ThisExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'get' && node.arguments.length === 1 && ... ) { report(node, "Use ES5 getters"); } }
  13. Writing your own lint rule Rule implementation CallExpression(node) { if

    ( node.callee.type === 'MemberExpression' && node.callee.object.type === 'ThisExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'get' && node.arguments.length === 1 && node.arguments[0].type === 'Literal' && ... ) { report(node, "Use ES5 getters"); } }
  14. Writing your own lint rule Rule implementation CallExpression(node) { if

    ( node.callee.type === 'MemberExpression' && node.callee.object.type === 'ThisExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'get' && node.arguments.length === 1 && node.arguments[0].type === 'Literal' && typeof node.arguments[0].value === 'string' && !node.arguments[0].value.includes('.') ) { report(node, "Use ES5 getters"); } }
  15. Publishing • If needed, create eslint-plugin-your-application • Or ideally contribute

    back to an open source linting project! • Hopefully now you and other developers can clear your mind of this issue for good! Writing your own lint rule
  16. Next steps • Pick a nit you have seen in

    code reviews and try writing a lint rule for it! • Make sure your IDE is highlighting and autofixing linting violations • Check for additional linting plugins that may be relevant to your application
  17. Other linters to check out • @typescript-eslint/eslint-plugin ◦ Linting and

    TypeScript go great together • eslint-plugin-eslint-plugin ◦ Even lint your own linting plugins • eslint-plugin-import ◦ Ensure imports can be resolved, avoid import cycles • eslint-plugin-markdown ◦ Hold the JavaScript code samples in your documentation to high standards (valid syntax, no violations) too • eslint-plugin-unicorn ◦ Help adopt modern JavaScript (flatMap, sets, newer string/array functions, for-of loops) • markdownlint ◦ Consistent documentation formatting • stylelint ◦ All kinds of CSS best practices