In the previous post, Improving Your DX on Ember, Part 1: Quick Wins, we saw some quick best practices for improving our DX in Ember. In this post, we will replace a few add-ons with other tools. Specifically, we will be removing ember-cli-eslint
, ember-cli-stylelint
and ember-cli-template-lint
while keeping our project completely linted.
Adding Husky
The husky project lets your team share and version your git hooks. We will be using two hooks:
pre-commit
, where we will lint and fix all staged files.pre-push
, where we will prevent the push if our linters fail.
Adding husky is as easy as installing any other npm dependency: do npm install husky --save-dev
.
Husky can store its configuration in the same package.json
, but I prefer it in its own file; and usually, I prefer a js file. Create the following .huskyrc.js
with the content:
/* eslint-env node */
module.exports = {
hooks: {
"pre-commit": "lint-staged",
"pre-push": "npm run lint"
}
};
In this configuration, we are asking husky to run lint-staged
before committing any change, and npm run lint
before pushing. We don’t need to do ./node_modules/.bin/lint-staged
in husky, it will find the executable in our project.
Talking about lint-staged
, let’s install that now.
Install Lint-Staged
lint-staged
let us run commands on staged files. We will be using it to fix linting errors in files before committing.
Install it with npm install lint-staged --save-dev
, and create a lint-staged.config.js
file:
/* eslint-env node */
module.exports = {
"**/*.js": ["eslint --fix", "git add"],
"app/styles/**/*.{scss,css}": ["stylelint --fix", "git add"],
"app/templates/**/*.hbs": "ember-template-lint"
};
With this configuration, we are asking lint-staged
to run eslint --fix
and git add
on any JavaScript file in our project. This will check those JS files and fix them before they are committed. Notice that for executing several commands, we don’t need to use &&
between them and can instead use an array of strings.
The file also contains similar configuration for linting CSS and SCSS files with stylelint, and templates with ember-template-lint.
Preventing jsconfig.json from Changing
As stated in the Part 1 post, the extension Ember CLI in Visual Studio Code overwrites jsconfig.json
every time VSCode is launched. A configuration option to prevent this was added in September 2018, but, as the time of this writing, it has not been released.
With our new setup, reversing these changes is a simple task. A new rule that only matches jsconfig.json
and that reverts the changes would make our lint-staged.config.js
file look like this:
/* eslint-env node */
module.exports = {
"jsconfig.json": [
"git reset HEAD", // Remove from staged area
"git checkout --" // Revert changes
],
"**/*.js": ["eslint --fix", "git add"],
"app/styles/**/*.{scss,css}": ["stylelint --fix", "git add"],
"app/templates/**/*.hbs": "ember-template-lint"
};
If you need to make any changes to your jsconfig.json
file, you can still commit them using the --no-verify
option of git commit
, which would prevent the hooks from running.
Updating Scripts
So far, we have set up husky
and lint-staged
. There is one thing left: define the npm script lint
. For this, we will use concurrently
, which let us run several npm scripts concurrently rather than serially like
the &&
shell operator would do (npm run lint.hbs && npm run lint.js && npm run lint.styles
). This can reduce script run time significantly, especially in big applications.
First, install it with npm install concurrently --save-dev
. Then add the following lint
script to your package.json
:
{
"scripts": {
"lint": "node_modules/.bin/concurrently \"npm:lint.*\""
}
}
This script runs all tasks in scripts that start with lint.
. Let’s define them!
{
"scripts": {
"lint.hbs": "node_modules/.bin/ember-template-lint app/templates/**/*",
"lint.js": "node_modules/.bin/eslint app config scripts server/index.js server/mocks tests *.js",
"lint.styles": "./node_modules/.bin/stylelint app/styles/**/*.scss"
}
}
Given we are writing scripts in npm, we do need to prepend the node_modules/.bin/
path to our executables.
One more piece to change in scripts: run the lint
script as part of your CI process. If you don’t have a specific script, it might be a good time to add one:
{
"scripts": {
"test.ci": "npm run lint && npm run test"
}
}
If you are adding a new one, don’t forget to update your CI configuration to run it.
That’s it! We are done almost entirely with set up. There is only one thing left.
Uninstall Dependencies
We no longer need ember-cli-eslint
, ember-cli-stylelint
nor ember-cli-template-lint
.
These addons run the linters during tests, but do increase start up time in a noticeable way in big applications.
Let’s just get rid of them:
npm uninstall ember-cli-eslint ember-cli-stylelint ember-cli-template-lint --save-dev
After removing these, we might not have eslint
, stylelint
, and ember-template-lint
in our project. Let’s add these tools back:
npm install eslint stylelint ember-template-lint --save-dev
So that’s it!
Recap
In part II we have removed ember-cli-eslint
, ember-cli-stylelint
, and ember-cli-template-lint
. Instead, we are using eslint
, stylelint
, and ember-template-lint
without losing any coverage. This also removes some weight from our ember server
command.
Furthermore, we have setup husky
and lint-staged
so we can autofix our linting errors whenever possible before committing the code, and we won’t be able to push if our linters error.
What’s Next?
For the next and final part, we will be announcing something we’ve been working on lately that will improve the quality of your software code. Stay tuned.
DockYard is a digital product agency offering custom software, mobile, and web application development consulting. We provide exceptional professional services in strategy, user experience, design, and full stack engineering using Ember.js and Elixir. With staff nationwide, we’ve got consultants in key markets across the United States, including San Francisco, San Diego, Phoenix, Houston, Detroit, Miami, Pittsburgh, Baltimore, Boston, and New York.