Setting Up A JavaScript Development Environment: Part One

32yllwbi8q4-sergey-zolkin

Setting up a JavaScript development environment is the easiest thing ever. Said no one ever. Setting up a solid JavaScript development environment is quite some work and is hectic for those starting out. Even those who aren’t beginners get tired of starting from scratch for every new project and therefore build/use starter-kits.

JavaScript Development Environment, starter project, boilerplate, starter-kit all mean the same thing.


JavaScript has so many packages and frameworks and this can result to it being overwhelming and complex and does make it hard to make a decision. It is tempting to overlook some things but we all know the value of having a rapid feedback environment. A solid environment that supports automated testing, linting, bundling, error logging, transpiling, package management, continuous integration etc should be every developer’s goal.

Having the same robust environment used across the team on different projects increases consistency, wipes out repetitive work, reduces chances of forgetting important details, increases quality and fosters productivity.

This article will guide you to setting up your own JS dev environment 

Editors

The first thing you need is a JavaScript editor. The following are things to look for in an editor:

  • Should offer strong support of the latest JavaScript features. Some ways you can identify this is autocomplete support, report unused imports, framework intelligence
  • Built-in terminal. This keeps you in a single window.

Options:

To be used in demo: VS Code

Editor Config

One way to maintain consistency across the different IDEs is through editorconfig. Creating a file named .editorconfig in the root of your directory helps you define common settings like tabs/spaces.

Package Management.

Every popular language has a package manager to manage the process of installing, upgrading, deleting packages (reusable piece of software that can be downloaded) in a consistent manner.

Options:

To be used in demo: npm

Development Web Server.

Working in JavaScript you’ll find that you want to run some of your code in the browser.

Options:

Http-server:

It is simple, lightweight and requires no configuration. You can start the server with a single command and it serves the current directory.

Live-server:

Also lightweight and supports live-reloading capabilities. This means your changes are immediately visible anytime you hit save.

Express:

Also considered lightweight and is much more comprehensive and has more features than the above two. It is also highly configurable, it is not only used with static files. You can fire up complex APIs with Express.

One advantage of Express is that you can use it in production as well. This means you can have a common configuration and use it in all environments.

Alternatives to Express include Koa and Hapi.

Webpack-dev-server:

If you use Webpack as your bundler, you can use its already built-in server. Advantage to this is you avoid pulling in another dependency. It is also fast since it serves from memory and does not require generating any physical files. Supports hot-reloading.

Depending on the bundler you use (Browserify, Webpack) there are dev server options for each.

Browsersync:

One of the compelling features of Browsersync is that it automatically sets up a dedicated IP address over a network. This means anyone with the address can be able to view your app. When you hit the IP in multiple devices, all the instances of the app remain in sync. Pretty cool. This is great for cross-platform/device testing, just to ensure everything is rendering properly.

Browsersync can also integrate with Webpack, Gulp, Browserify, Express etc. You can use BrowserSync independently as a dev server, or as a platform to integrate to your existing dev server and add additional features.

All the above dev server options with the exception of Express are only used in development environment in your local machine.

To be used in demo: Express.

 

Automation.

Automation is bliss in every developer’s workflow. It ensures consistency, rapid feedback and enhances productivity.

You can simply use your custom OS command line to run commands but as things get more complex, shell scripts may have you re-inventing the wheel.

Options available:

Grunt:

Was the first JS task-runner to become popular. Grunt is configured via a gruntfile in JSON format which configures grunt to work with your plugins. The file is configuration based over code. Grunt is also file oriented. It writes files to disk after every step, this means it also reads from disk before subsequent steps. Since it has been around for a while, it has a large plugin ecosystem.

Gulp:

Gulp improves on Grunt’s plugin model in the following areas:

It focuses on in-memory streams called pipes. i.e you do not have to write to disk after every step/task, you simply pipe the output of one step into the next. This makes Gulp faster in comparison. Gulp is configured via a gulpfile which is code based over configuration. In Grunt, you configure the tool, in Gulp you write actual JavaScript code in your gulp tasks. This gives you more declarative power. Like Grunt, Gulp also has a large plugin ecosystem.

npm scripts:

npm scripts are declared in the scripts section of your package.json. With this option, you can directly leverage the power of your OS command line. You can also use anything that you can install as an npm package. This comes in handy when you want to write scripts for tasks that run differently across different platforms i.e Windows, Mac, Linux. One example is deleting files. You can also call separate Node scripts independently. It also offers convention-based hooks to run other scripts before and after your main script. By using npm scripts you are also leveraging into the world’s current largest package manager.

You can read more here on why npm scripts over Grunt/Gulp.

To be used in demo: npm scripts

 

Transpiling.

Version one (ES1) of Javascript was born in 1997 and currently we are living in yearly releases of new versions.

screen-shot-2016-12-19-at-5-44-19-am

Transpilers come in because you simply cannot write JavaScript that runs everywhere . You need to transpile it to a version compatible in the different environments (browser compatibility).

A transpiler as defined in this article:

Tools that read source code written in one programming language, and produce the equivalent code in another language. Languages you write that transpile to JavaScript are often called compile-to-JS languages, and are said to targetJavaScript.

There are over 100 languages that transpile down to JavaScript today. This makes it difficult to choose a transpiler. But these are the two popular options available:

TypeScript.

TypeScript is a superset of JavaScript. TypeScript adds additional features to JavaScript the same way ES6 adds new functionalities. Examples include: enhanced autocompletion, safer refactoring. TypeScript supports ES6 and adds additional Typescript-specific enhancements.

Bonus: TypeScript offers enhanced autocomplete and enhanced readability. Safer refactoring since you rely on a type-safe compiler. Additional non-standard features not available in JavaScript. Babel is historically known to add support for experimental features earlier.

Babel

Babel allows you to enjoy the most recent new features of JavaScript even those that are experiment-based. Babel therefore transpiles all the fresh new features down to ES5 for you to run them everywhere ES5 can be used.

Bonus: Standardized JavaScript i.e you can leverage the entire JavaScript ecosystem. This means any plugins, editors that you select are likely to be compatible with your code since it is pure JavaScript. Example: when React was released, JSX syntax clashed with TypeScript’s syntax before TypeScript offered support. TypeScript requires type definition and annotation files, Babel does not.

Both are excellent options to consider.

To be used in demo: Babel

Elm.

Elm looks nothing like JavaScript but transpiles down to JS. Has a clean syntax and offers immutable data structures. All errors are compile-time errors. The downside is the learning curve involved when shifting to Elm.

 

Bundling.

npm packages use the CommonJS format. Node can handle this, but the browser cannot understand. Bundlers convert this to a format that the browser can understand.

Bundlers aren’t just for browser use. You can bundle up your JavaScript files into a single file for use. Bundling does decrease page load time and therefore improves performance. You can also use bundlers when coding in Node.js to improve performance since Node require is slow

Options available:

Browserify.

First bundler to reach mass adoption. Takes all the npm packages that you have referenced and bundles them up in a format that can be used on the web i.e bundles code that uses the CommonJS pattern. Its design is plugin based therefore it boasts of a large ecosystem of plugins i.e to add minification, linting, transpiling etc.

Webpack.

Webpack bundles more than just JavaScript. It offers a large array of loaders that enable Webpack to handle your CSS, Images, Fonts etc. You can import these file types and bundle them accordingly.

To be used in demo: Webpack

 

Linting.

Isn’t it always a good feel to be notified immediately when we make a typo? Linting does this for us. Good linters are powerful, they can catch many errors at compile time. Linters enforce consistency. Once you have selected JavaScript coding standards as a team, a linter ensures that your team stays along those lines. Linters provide rapid feedback and mistakes are caught during development and reducing chances of potentially slipping by. Examples include: curly braces positioning, trailing commas presence/or absence, globals declaration.

Linting also prevents mistakes while programming. Examples include: Overwriting functions by declaring a function with an existing name, adding extra parenthesis, doing an assignment instead of a comparison in a conditional, leaving debugging related junk in your code i.e debugger/console.log statements.

Options:

JSLint.

Was the original linter and very opinionated. However, the public has moved on to more powerful and configurable linters.

JSHint.

It offers more configurability in comparison to JSLint.

ESLint.

Currently most powerful and configurable linter. If you are using TypeScript the alternative is TSLint.

To be used in demo: ESLint. 

Testing/Continous Integration.

JavaScript lacks built in opinions on handling testing, therefore you spend a lot of time researching and identifying a strategy before you can get started.

JavaScript Testing Styles:

Most commonly configured style of testing in JavaScript Development Environments is Unit testing.

Unit Testing:

  • Focuses on testing a single function/module in an automated fashion.
  • Often asserts that a specific function returns a certain value when passed certain parameters.
  • Mock out external dependencies like database calls/APIs/file interactions.

Integration Testing:
Focuses on testing interactions between multiple modules.

UI Testing:

Tests UI functionality by automating clicks and keystrokes and asserting that it interacts in expected ways. One popular tool in this space is Selenium.

Testing decisions to make:

  1. Testing Framework.

Mocha: Popular and highly configurable. Has a large ecosystem of support.

Jasmine: Quite similar to Mocha , but it includes a built-in assertion library.

Tape: Lean, simple with minimal configuration.

QUnit: An older option designed to test JQuery.

Jest: From Facebook and popular among React developers. Wrapper over Jasmine.

Ava: Simple to set up and runs your tests in parallel, this means it is fast. It supports ES6 by default (no transpiling eh?)

All the above options are valid. You can review each and select which will work best for you.

To be used in demo: Mocha

2. Assertion Libraries.

Some frameworks i.e Jasmine and Jest come with libraries built in, others e.g Mocha require you to get an assertion library. An assertion declares what to expect i.e

expect(5+6).toEqual(11)

Options:

Chai.js (most popular)

Should.js

Expect.js

Core difference in the above is merely syntactic, therefore any will work fine.

3. Helper Libraries.

JSDOM.

It is an implementation of the browser’s DOM and it can run in Node.js. This enables you to run browser related tests without a browser. This makes it faster.

4. Where to run tests?

Browser:
Karma and Testem are popular test runner options for running your tests on an actual browser. This, however, requires more configuration and is slower than the alternatives.

Headless browser:
Headless browser is a browser that does not have a visible UI, making it faster. PhantomJS is an option for this.

In-memory DOM:

JSDOM is an example. It simulates an actual DOM in-memory to be interacted with. It can be considered an lighter-weight alternative to PhantomJS. Faster and quick  to set up.

To be used in Demo: JSDOM

5. Where do test files belong?

The two approaches to this are:

Centralized: This means putting all your tests in a separate folder at the root of your directory (probably named test), making them independent from your source code.

Reasons: To have less noise in src folder.

Alongside: This means placing your tests files along your source file.

Reason: Easier to import. Clear visibility. Convenient to open. No recreating folder structure.

Mocha by default pushes for option one since it looks for test files at the root of your directory in a folder named test.

file.spec.js and file.test.js are also the two common methods of naming test files.

6. When should tests run?

Unit tests should run immediately you hit save for rapid feedback, to facilitate TDD (Test Driven Development) and to enhance test visibility.

This image gives a better explanation of when to run your tests (integration vs unit)

screen-shot-2016-12-20-at-6-47-16-am

That’s it for this article. In our next article, we will look at Http Calls, Project Structure, Production build and Production deploy.

 

 

 

You may also like

Leave a Reply

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