Add Prettier
Summary
This RFC proposes adding Prettier to the blueprints
that back ember new and ember addon.
Motivation
Using Prettier removes the ever present and ongoing stylistic debates that tend
to happen on teams. Prettier is incredibly freeing for both developers and
reviewers of a codebase. The developer can author in whatever format they find
easiest to type out, avoiding needless wasted time trying to get that
indentation just right, and either setup an automated "format on save"
operation in their editor or use a quick command line invocation to --fix all
files at once.
This dove tails very nicely with Embers deeply ingrained goal of using shared solutions to solve common problems, and aligns very well with the general trend to play better with the general JavaScript ecosystem.
Detailed design
Due to the pre-existing design (and improvements added to the blueprints in
ember-cli/rfcs#121)
implementation is very straight forward. The general idea is that we will
update the app and addon blueprints to add a few Prettier related packages
to the package.json, update the linting configuration to enforce Prettier
styles, and update the other blueprint code to ensure that its output is
Prettier compatible.
Packages
The following packages will be added to the package.json of both app and addon blueprints:
- prettier - The main package (used by the other packages).
- eslint-config-prettier - Disables stylistic ESLint rules that would conflict with the Prettier output.
- eslint-plugin-prettier - Enables
eslint-config-prettiersrecommendedset, and adds theprettier/prettierrule to enforce styles.
Configuration Changes
ESLint
The .eslintrc.js that is generated will be updated to add:
{
extends: ['plugin:prettier/recommended'],
}
Prettier
A .prettierrc.js will be added with the following contents:
module.exports = {
singleQuote: true,
};
There is a small number of configuration options that can be used in this file, but we are intentionally avoiding modifying the default values for things that are not nearly universally agreed on in the Ember ecosystem.
A .prettierignore will be added to match the .eslintignore contents:
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
/node_modules/
# misc
/coverage/
!.*
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try
Git
The .gitignore will be updated to add .eslintcache so that when using
eslint --cache the cache file itself won't be added to the repositories
history.
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, ember-source, and ember-data will
be updated to ensure that they satisfy these new linting rules requirements.
In order to ensure blueprint output follows each individual projects custom
stylistic linting settings as much as possible. The following will be updated
to run lint:fix (when available) after their existing functionality:
ember generateember initember-cli-update
package.json scripts
The app and addon blueprints will be updated to add the following
additional entries to scripts:
{
"scripts": {
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel 'lint:!(fix)'",
"lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
"lint:js": "eslint . --cache",
"lint:js:fix": "eslint . --fix",
"lint:hbs:fix": "ember-template-lint . --fix"
}
}
A few callouts here:
- The
lint:fix,lint:js:fix,lint:hbs:fixscripts are new (introduced with this RFC) - The
lintscript will be updated to ensure that it avoids running the newlint:fixscript - The
lint:jsscript will be updated to add caching
This configuration is specifically intending to allow users to add additional
linters (e.g. stylelint or markdownlint) by adding scripts for them, and
they would automatically be rolled up into lint:fix.
Codemod
In order to make the migration as simple as possible, a codemod will be created: ember-cli-prettier-codemod.
The codemod will do the following:
- Install the new/required dependencies
- Migrate an application / addon to the new linting configuration
- Commit just the configuration changes.
- Run the new
lint:fixscript to update all files to the new format. - Commit just the auto-fixed output.
While this seems quite simple (and in fact it is pretty easy), leveraging a codemod will make it much easier to deal with rebasing large Prettier migration pull requests. If one of those pull requests gets out of date (e.g. due to a conflict in one of the files) you can simply re-run the codemod on the branch and it will replace the previously created commits.
How we teach this
We do not currently discuss linting or stylistic formatting in either guides.emberjs.com or cli.emberjs.com.
This RFC proposes adding a new subsection that discusses linting under Basic
Use section of the CLI guides. In
addition, when this RFC is implemented we should do a throughough audit of the
cli.emberjs.com and guides.emberjs.com content to ensure that all code
snippets are formatted correctly (e.g. using the Prettier specific formatting
introduced here).
Drawbacks
The largest drawback is generally the cost of the initial migration to Prettier. That migration tends to be quick, but it can cause pain for folks maintaining long lived branches.
Alternatives
Why not adopt standard instead of Prettier?
Prettier is much more popular with 9,249,847 weekly
downloads vs 265,658 weekly
downloads (we all know these download
numbers don't mean a ton, but the order of magnitude can tell us something),
and (aside from the defaulting of singleQuotes) is much more aligned with the
Ember ecosystems inherent preferences.
Additionally, a very large number of the Ember ecosystem
projects are already using Prettier internally. These include ember-source,
ember-cli, ember-data, @ember/test-helpers, eslint-plugin-ember, the
various packages composing the rendering engine, @glimmer/component,
ember-template-lint, and many more. Additionally a large number of community
maintained addons are also using it already (here is a
listing
using EmberObservers awesome code search feature).
Unresolved questions
In general, users of
yarncould be perfectly happy withyarn lint:js --fix/yarn lint:hbs --fix(which works today). Should we still add thelint:js:fix/lint:hbs:fixscripts?
I went with "yes" here in the initial RFC prose, as I'd general prefer to reduce the differences between users of npm and yarn over time.