Start Date Release Date Release Versions PR link Tracking Link Stage Teams
4/19/2022
Accepted
  • CLI

Add stylelint to Ember blueprints

Summary

This RFC proposes adding stylelint to the blueprints that back ember new and ember addon.

Motivation

Ember app and addons already come with a broad variety of linting plugins targeting various areas of our codebases:

With all these amazing tools in place, however, we still have a major aspect of our Ember codebases that are not benefiting from mature tooling to enforce best practices and automate code styling: CSS.

Stylelint is a modern linter for stylesheets that ships with over 170 built-in rules, sane default configs, and robust plugin support.

Detailed design

The general idea is that we will update the app and addon blueprints to add a few Stylelint-related packages to the package.json, add config files to enable this tooling by default, and add commands to the scripts section of package.json to expose easy access to this tool consistent with our existing linters.

Packages

The following packages will be added to the devDependencies section of both blueprints:

Prettier itself is already included in the Ember blueprints by default.

Configuration Changes

A .stylelintrc.js file will be added with the following contents:

'use strict';

module.exports = {
  extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'],
};

There are many rules, configs, and plugins available for stylelint and prettier, but we are intentionally avoiding being prescriptive on anything that isn't nearly universally agreed upon by the stylelint, prettier, and Ember communities.

Lint Ignores

A .stylelintignore file will be added with the following contents:

# unconventional js
/blueprints/*/files/
/vendor/

# compiled output
/dist/
/tmp/

# dependencies
/bower_components/
/node_modules/

# misc
/coverage/
!.*
.*/
.eslintcache
.lint-todo/

# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/npm-shrinkwrap.json.ember-try
/package.json.ember-try
/package-lock.json.ember-try
/yarn.lock.ember-try

These contents are based on the existing .eslintignore and .prettierignore files for consistency.

Blueprint Changes

In general, it is recommended that all blueprints provided by addons should satisfy the default linting configuration of a new Ember application. As such, the blueprints provided by ember-cli will be updated as needed to ensure that they satisfy these new linting requirements.

package.json scripts

The app and addon blueprints will be updated to add style-related linting scripts:

{
  "scripts": {
    "lint:css": "stylelint \"**/*.{css}\"",
    "lint:css:fix": "npm-run-all \"lint:css --fix\"",
  }
}

Linting Stylelint's Config

.stylelintrc.js should be linted as a node file in eslint's config.

npmignore

/.stylelintrc.js should be added to the addon blueprint's npmignore file.

How we teach this

We do not currently discuss linting or stylistic formatting in either guides.emberjs.com or cli.emberjs.com.

However, previous linting RFCs have proposed adding a subsection to the CLI guides to discuss linting. As that is implemented, we can include basic information about style linting as well.

Documentation for the new rules can be found within the Doc sites & READMEs for the packages being added by this RFC.

Drawbacks

For those introducing stylelint to an existing codebase, the largest drawback is generally the initial cost of fixing linting violations. This can be mitigated by individually disabling noisy lint rules and working to fix violations overtime, or by extending the lint-todo functionality available for ember-template-lint and eslint to support stylelint as well. However, note that this RFC is more likely to impact newly-generated applications where there will be no existing lint violations to fix as opposed to existing applications.

Alternatives

Ember applications may choose to use CSS, SCSS, LESS, or other approaches for styling. How do we reconcile our default linting config?

Today, the de facto default for Ember apps via the blueprints is CSS, so our default configuration should strive to support that use-case. stylelint has readily-available support for popular preprocessors built-in, and there are plugins like stylelint-scss that add rules specific to those ecosystems for teams to opt into.

Why name the scripts lint:css instead of something more universal like lint:style?

With CSS being the default in Ember applications, this is consistent with our existing linting strategy. While teams may choose to adopt a preprocessor like SASS in the same way they could adopt TypeScript over JavaScript, we still default to lint:js and lint:hbs to match the standard file types of a new Ember application.

Why use stylelint-config-standard over stylelint-config-recommended?

The standard config intentional extends the recommended config, which is just a smaller subset of rules. The README for the standard config talks briefly about the philosophy behind the additional rules it adds. If there is a strong case for the standard config being a divergence from how the Ember community would commonly author stylesheets, we could fall back to the recommended config instead. However, the standard config appears to provide sane defaults for new applications.

Unresolved questions

This RFC will be updated as such questions are posed, until we have an answer.