Meteor and standard lint
Tags: meteor, standard, lint, javascript
Published: 2020-12-23 13:44:30

It is a great out-of-the-box experience to integrate [standard](https://standardjs.com/) with [Meteor](https://www.meteor.com/). Simply install it as dev dependency, then add the NPM script to run the linter:

```bash
$ meteor npm install --save-dev standard
```

The npm script in the `package.json` could look like the following:

```json
{
  "scripts": {
    "lint": "standard",
    "lint:fix": "standard --fix"
  }
}
```

Super easy and powerful. However, you might at some point encounter parsing errors, because in Meteor you can actually do the following:

```javascript
import '../some/module' // valid

export const somefunction = function () {
  import { dependency } from '../some/dependency' // this will cause trouble
  // ...
}
```

You Meteor app will run fine but your linter will simply crash when parsing the file. It will throw the error, that imports are only allowed at top-level and then skip scanning the file for any further issues.

## What you could do to solve this

You could of course change all non-top-level imports to dynamic imports (supported since Meteor 1.5) but this would also require to change all the respective functions to be `async` or handle the return values from the `Promise`.

You could also rewrite all these imports to the node `require` style and the linter is happy again.

However, you could just keep your code as it is and do some slight changes with `standard`.

## `standardx` to the rescue

With standardx you can override the default eslint rules for standard and declare `allowImportExportEverywhere` to be `true`. Furthermore, you can integrate eslint plugins, like `eslint-plugin-security` (which we will use in the upcoming examples).

The following guide will show you how it's done in a few steps.

## 1. Replace standard with standardx

This is done in two lines. Note, that we will also install an additional plugin in order to use babel to transpile our code, so we will always be ready for the newest ES-Next features.

```bash
$ meteor npm uninstall --save-dev standard
$ meteor npm install --save-dev standardx @babel/eslint-parser @babel/core eslint-plugin-security
```

## 2. Update the `package.json`

Since `standard` is no longer available the scripts also need to be updated to call `standardx`:

```json
{
  "scripts": {
    "lint": "standardx",
    "lint:fix": "standardx --fix"
  }
}
```

Additionally, if you encounter any Babel related issues, then  may try to add an empty `"babel"` Object:

```json
{
  "scripts": {
    "lint": "standardx",
    "lint:fix": "standardx --fix"
  },
  "babel": {}
}
```

This solves errors related to missing Babel configurations, required by `@babel/core`.

If you use tools like istanbul then you might already have a `babel` entry in your `package.json`.

## 3. Define a custom `eslintConfig`

The last step is to configure eslint to support imports anywhere. If you ask yourself why now eslint, then you may take a look at the `standard` repos to see, it's based on eslint.

There is the config in the `package.json`:

```json
{
  "eslintConfig": {
    "parser": "@babel/eslint-parser",
    "parserOptions": {
      "sourceType": "module",
      "allowImportExportEverywhere": true
    },
    "plugins": [
      "security"
    ],
    "extends": [
      "plugin:security/recommended"
    ]
  }
}
```

With this you have now full support for your Meteor environment plus integrated a plugin that extends standard by a few rules.

On top of that you can also define custom rules:

```json
{
  "eslintConfig": {
    "parser": "@babel/eslint-parser",
    "parserOptions": {
      "sourceType": "module",
      "allowImportExportEverywhere": true
    },
    "plugins": [
      "security"
    ],
    "extends": [
      "plugin:security/recommended"
    ],
    "rules": {
      "brace-style": [
        "error",
        "stroustrup",
        {
          "allowSingleLine": true
        }
      ]
    }
  }
}
```

The above code is just an example, that would allow to write the following code

```javascript
if (condition) {
  // action a
} else {
  // action b
}
```

in the following format

```javascript
if (condition) {
  // action a
} 

else {
  // action b
}
```

## Summary

With these few steps you can actually benefit from standard linter, while circumventing the need to change your import structure. Additional plugins will also improve your code quality, depending on the use case. The parser should prevent the need to constantly update rules in the future, in case Meteor integrates a new edge ES-next feature as they ever did already.

Please leave a comment, in case you encounter any issue.