Working with ReactJS in WebStorm: Linting, refactoring and compiling

We recently explored coding assistance that WebStorm provides for React and JSX. Now we would like to talk a bit about the tools in the React ecosystem. In this area it’s not easy to provide a complete overview as tools are developing at a crazy pace. So right now we’ll focus on linters (code quality tools), refactoring and tools that can help us compile code.

Code analysis

As you may know, WebStorm has a wide range of built-in inspections for JavaScript and HTML, and these inspections also work for JSX code.

For example, WebStorm alerts you in case of unused variables and functions, missing closing tags, missing statements and much more. For some inspections WebStorm provides quick-fixes, like add a missing semicolon:

react-inspection

You can customize the list of inspections in Preferences | Editor | Inspections. Disable those you don’t want to see, or change severity level from warning to error or vice versa.

On top of such inspections, you can also use linters like ESLint and JSCS for the JSX code. Let’s talk about these in more detail.

ESLint

ESLint is a linting utility that provides a wide range of linting rules, which can also be extended with plugins. WebStorm integrates with ESLint and allows you to see warnings and errors reported by ESLint right in the editor, as you type.

While ESLint itself understands JSX syntax, authors recommend using eslint-plugin-react if you are working with React. To get started, add eslint and eslint-plugin-react modules to your project via npm, then add an ESLint configuration file .eslintrc.

Here’s what .eslint file structure looks like when using ESLint 1.x and react plugin:

In ecmaFeatures object you can specify additional language features you’d like to use, for example ES6 classes, modules, etc.

In rules object you can list ESLint built-in rules that you would like to enable, as well as rules available via the react plugin.

For example, thanks to ESLint with react plugin we can get warnings when the display name is not set for React component, or when some dangerous JSX properties are used. Here’s how it looks in the editor, if you have ESLint integration enabled in WebStorm:

eslint-react

To enable ESLint, go to Preferences | Languages & Frameworks | JavaScript | Code quality | ESLint (or simply search for ESLint in Preferences) and check the Enable checkbox. WebStorm will automatically locate ESLint in your project’s node_modules folder and then use .eslintrc configuration by default.

eslint-enable

Refactoring

WebStorm offers lots of different refactorings to modify and maintain your code. For example, when you rename a file with Refactor -> Rename, all the references will be renamed automatically. Or, you can easily rename a variable, class or method throughout your whole project.

For React applications, WebStorm can also help you rename components. Place the cursor on the component name and press Ctrl+T to open the Refactor This popup. Select Rename…, type the new name and press Enter. Done!

Here’s an example of renaming a component that is defined and used in only one file:

rename-component

In the same way, you can rename components defined in one file and then imported using a named export to another file:

rename-component-import

Compiling the code

You can set up a build process for your React app in multiple ways. The React Getting started page suggests using Browserify or Webpack which are CommonJS module systems. You will also need Babel and, if using Babel 6 and ES6 code, babel-preset-react and babel-preset-es2015 to compile your code. You can find lots of articles and tutorials with recommendations for the build process using various tools.

As the Getting started tutorial suggests, install the following modules via npm:

npm install --save react react-dom browserify babelify babel-preset-es2015 babel-preset-react

To automate the build process a little bit, let’s add the command suggested in the tutorial to the scripts section of the project’s package.json file:

where main.js is the main app file and bundle.js is the output file.

WebStorm displays npm tasks listed in package.json in a separate tool window. Just double-click on the task name to run it. No need to run commands in the terminal.

npm-build

In a similar way you can start Gulp or Grunt tasks in WebStorm.

You can also set up a File watcher for Babel and Browserify in WebStorm to execute similar tasks (you can read about it here), but running tasks via npm scripts or Gulp gives you more flexibility if you add more steps.

More on using React in WebStorm:

– JetBrains WebStorm Team

About Ekaterina Prigara

Ekaterina Prigara is WebStorm product marketing manager at JetBrains. She's passionate about new technologies, UX and coffee.
This entry was posted in Tutorials and tagged , , . Bookmark the permalink.

16 Responses to Working with ReactJS in WebStorm: Linting, refactoring and compiling

  1. A java architect trying to learn React and Node. says:

    Hi. I’m new to Webstorm. Have been trying to get an example React application with server-side rendering and Flux to work. It’s a nice tutorial blog, uses Gulp, Babel, Webpack among others. It works fine from the command line, but for some reason, I’m getting errors from Webstorm. Googling, if I change the version of Babel in one place (for example), it causes an error in another place. Wonder what I’m doing wrong. The said tutorial code is at https://github.com/zen-js-code/react-universal-web-apps/tree/flux+ssr+context+promises , and is explained here: https://www.smashingmagazine.com/2016/03/server-side-rendering-react-node-express/

    Don’t expect you or your team to spend too much time on this, but fyi, it’s a good example, and will be great for your product if it could work for it.

    • Ekaterina Prigara says:

      Can you please let us know what kind of errors you get from WebStorm? Thanks!

    • Ekaterina Prigara says:

      As for me, I’m just enable to start the app with npm start with either Node.js v4, 5 or 6 :(

      • A java architect trying to learn React and Node says:

        Hi. This is what is happening for me.

        1.
        If I run npm start from within Webstorm (without trying to enable babel presets for react or es6 via a .babelrc), it works. But breakpoints aren’t working (running debug on npm start, or npm start:debug). Trying to debug results in the process to stop. Also, the jsx stuff is marked with syntax errors.

        2.
        Adding the following in .babelrc

        {
        “presets”: [“react”]
        }

        or

        {
        “presets”: [“react”, “es2015” ]
        }

        and running npm start from within Webstorm is giving the errors below. I’m also investigating in parallel.

        3.
        One thing to note is that the code from git needs a minor massaging before it will run (versioning issue):

        git clone -b

        npm install

        then run this to force an older version of node-dev. else things will fail (TypeError)

        npm i node-dev@3.0.0 –save-dev

        npm start

        4.
        The error message after adding a .babelrc in (2) above is:

        error { [ModuleBuildError: Module build failed: ReferenceError: [BABEL] /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js: Unknown option: /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/.babelrc.presets
        at Logger.error (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/logger.js:58:11)
        at OptionManager.mergeOptions (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:126:29)
        at OptionManager.addConfig (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:107:10)
        at OptionManager.findConfigs (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:168:35)
        at OptionManager.init (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:229:12)
        at File.initOptions (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/index.js:147:75)
        at new File (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/index.js:137:22)
        at Pipeline.transform (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/pipeline.js:164:16)
        at transpile (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-loader/index.js:12:22)
        at /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-loader/lib/fs-cache.js:140:16]
        name: ‘ModuleBuildError’,
        message: ‘Module build failed: ReferenceError: [BABEL] /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js: Unknown option: /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/.babelrc.presets\n at Logger.error (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/logger.js:58:11)\n at OptionManager.mergeOptions (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:126:29)\n at OptionManager.addConfig (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:107:10)\n at OptionManager.findConfigs (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:168:35)\n at OptionManager.init (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:229:12)\n at File.initOptions (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/index.js:147:75)\n at new File (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/index.js:137:22)\n at Pipeline.transform (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/pipeline.js:164:16)\n at transpile (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-loader/index.js:12:22)\n at /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-loader/lib/fs-cache.js:140:16’,
        module:
        DependenciesBlock {
        dependencies: [],
        blocks: [],
        variables: [],
        context: ‘/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app’,
        reasons: [],
        debugId: 1000,
        lastId: -1,
        id: 0,
        index: null,
        index2: null,
        chunks: [],
        warnings: [],
        dependenciesWarnings: [],
        errors: [],
        dependenciesErrors: [],
        request: ‘/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-loader/index.js?{“compact”:false,”cacheDirectory”:true}!/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/eslint-loader/index.js!/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js’,
        userRequest: ‘/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js’,
        rawRequest: ‘/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js’,
        parser: Parser { _plugins: [Object], options: undefined },
        resource: ‘/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js’,
        loaders:
        [ ‘/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-loader/index.js?{“compact”:false,”cacheDirectory”:true}’,
        ‘/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/eslint-loader/index.js’ ],
        fileDependencies: [ ‘/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js’ ],
        contextDependencies: [],
        error:
        { [ModuleBuildError: Module build failed: ReferenceError: [BABEL] /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js: Unknown option: /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/.babelrc.presets
        at Logger.error (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/logger.js:58:11)
        at OptionManager.mergeOptions (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:126:29)
        at OptionManager.addConfig (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:107:10)
        at OptionManager.findConfigs (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:168:35)
        at OptionManager.init (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:229:12)
        at File.initOptions (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/index.js:147:75)
        at new File (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/index.js:137:22)
        at Pipeline.transform (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/pipeline.js:164:16)
        at transpile (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-loader/index.js:12:22)
        at /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-loader/lib/fs-cache.js:140:16]
        name: ‘ModuleBuildError’,
        message: ‘Module build failed: ReferenceError: [BABEL] /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/app/client.js: Unknown option: /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/.babelrc.presets\n at Logger.error (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/logger.js:58:11)\n at OptionManager.mergeOptions (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:126:29)\n at OptionManager.addConfig (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:107:10)\n at OptionManager.findConfigs (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:168:35)\n at OptionManager.init (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/babel-core/lib/transformation/file/options/option-manager.js:229:12)\n at File.initOptions /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/webpack-core/lib/NormalModuleMixin.js:151
        throw e;
        ^

        TypeError: Cannot read property ‘toString’ of null
        at printReport (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/tools/build/webpack.js:15:33)
        at Watching.handler (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/tools/build/webpack.js:43:9)
        at Watching._done (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/webpack/lib/Compiler.js:81:7)
        at Watching. (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/webpack/lib/Compiler.js:47:24)
        at Compiler. (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/webpack/lib/Compiler.js:395:18)
        at /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/tapable/lib/Tapable.js:99:11
        at Compilation. (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/webpack/lib/Compilation.js:433:11)
        at errorAndCallback (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/webpack/lib/Compilation.js:340:3)
        at Compilation. (/Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/webpack/lib/Compilation.js:400:12)
        at /Users/am/workspaces/sandbox/universal-web-app-root/test-react3/node_modules/webpack/lib/Compilation.js:123:4

        npm ERR! Darwin 15.4.0
        npm ERR! argv “/usr/local/bin/node” “/usr/local/bin/npm” “run-script” “gulp”
        npm ERR! node v5.7.1
        npm ERR! npm v3.6.0
        npm ERR! code ELIFECYCLE
        npm ERR! react-ssr-example@0.0.1 gulp: gulp
        npm ERR! Exit status 1
        npm ERR!
        npm ERR! Failed at the react-ssr-example@0.0.1 gulp script ‘gulp’.
        npm ERR! Make sure you have the latest version of node.js and npm installed.
        npm ERR! If you do, this is most likely a problem with the react-ssr-example package,
        npm ERR! not with npm itself.
        npm ERR! Tell the author that this fails on your system:
        npm ERR! gulp
        npm ERR! You can get information on how to open an issue for this project with:
        npm ERR! npm bugs react-ssr-example
        npm ERR! Or if that isn’t available, you can get their info via:
        npm ERR! npm owner ls react-ssr-example
        npm ERR! There is likely additional logging output above.

        Thanks!

      • A java architect trying to learn React and Node says:

        Update: enabling JSX Harmony makes the earlier errors go away!

        In the “run” mode, it works fine now. Trying to figure out the debug mode where the process is exiting, but just wanted to let you know so you don’t waste time on the previous path.

        • Ekaterina Prigara says:

          The way npm scripts are written in the app you’ve sent makes it very hard to debug it with WebStorm – there’s quite a lot of various tools and utilities that wrapped around the build and serve processes.
          The WebStorm built-in node debugger works only with the node processes started with –debug-brk= option.

          The start, debug and serve tasks in this projects’ package.json use node-dev tool as a wrapper – the node process is started by this tool then. There’s no way for WebStorm to know what happens inside this node-dev process. It can’t add the required –debug-brk option itself.

          You might try to run the gulp task to build the app, then create a new Node.js debug configuration, specify the JS file you need to start to start the app and then start the debug process. As long as you have source maps generated, WebStorm should be able to stop on the breakpoints put in the original source files. (Haven’t tested that myself, I still can’t even build the app).

  2. am says:

    Thank you. I’ll try that.

    fyi, the build fails because one of the dependencies in package.json pulls a later version.
    After npm insall, one needs to do this:

    npm i node-dev@3.0.0 –save-dev

    as explained here: http://stackoverflow.com/questions/37259608/getting-typeerror-cannot-read-property-filename-of-undefined-when-calling/37259794#37259794

    Thank you so much for all your help!

  3. Greg Sandell says:

    I am using React extended with Babel “do expressions” (see https://babeljs.io/docs/plugins/syntax-do-expressions/)

    I have set my parser to babel-eslint which is supposed to accept the do expressions. It does when I eslint from the command line, but not in Webstorm. (Everything else is correctly parsed, so I’m confident I have the Webstorm config correct.)

    Here is my .eslintrc:
    {
    “extends”: “”,
    “parser”: “babel-eslint”,
    “rules”: {
    “react/jsx-no-bind”: 1,
    “jsx-quotes”: [“warn”, “prefer-single”]
    }
    }

  4. Greg Sandell says:

    I might not have been clear in my post, here is my eslint config in Webstorm: http://imgur.com/a/0Zerc

    So I am pointing to the nodeJs eslint package. I assume that overrides the Webstorm parser…correct me if I’m wrong. So if eslint is being configured with babel-eslint, I would expect Webstorm to accept the do syntax.

    • Ekaterina Prigara says:

      No, as I’ve said, that does not override the WebStorm parser and does not change the way WebStorm builds its AST to provide code completion, highlighting, refactorings, etc.
      Specifying the parser in the .eslintrc file only affects the way ESLint parses the file when reporting back to WebStorm the lines and columns with the errors. WebStorm then just shows those errors in addition to the errors it had found itself.

  5. A link is broken in the last line of the post.

    Correct link for Developing mobile apps with React Native link is https://blog.jetbrains.com/webstorm/2016/12/developing-mobile-apps-with-react-native-in-webstorm/ instead of https//blog.jetbrains.com/webstorm/2016/12/developing-mobile-apps-with-react-native-in-webstorm/

    Note missing colon after https

  6. Javier says:

    Hi, Im having issues while formatting the code with the props like:

    is turned into this after formatting:

    I ve tried around code style JS and Typescript but failed to fix it

    • Ekaterina Prigara says:

      Can you please use the code tag for the code samples, attach a screenshot or a link to a gist? Thank you!

Leave a Reply

Your email address will not be published. Required fields are marked *