A modern Javascript project setup
As a Web developer, you know that things are evolving fast. Especially JavaScript development dramatically changed in the past few years. A bunch of new tools and best practices are available today to create and maintain code.
In this article I will show my personal way to setup and maintain a generic JavaScript project. In detail, I will talk about GitHub, NodeJs, Webpack, Babel and the new ES6/ES2015 JavaScript syntax.
GitHub
Are you a Git-Hubber?
GitHub is an amazing way to maintain and share your code among colleagues but, also, among yourself when you’re coding from different locations.
If you don’t know Git/GitHub, this article covers only the essentials aspects with no detailed description on how and why Git/GitHub works. I’m not a Git advanced user, but I find it really simple.
So, why GitHub?
- To have an online repository for your source code.
- To share the same source code between different locations and/or collaborators. You have immediate access to your code everywhere.
- To keep track of your bugs. Among other things, GitHub features an issues tracking section.
- To keep track of every single change for every file. Git is primarily a version control software.
NodeJS
Server-side JavaScript? WHAT?!
Simply put, with NodeJS you may execute Javascript code on your machine — without a browser. You can run JavaScript code through the command-line in a shell environment.
So, why NodeJS?
We’ll not directly run JavaScript code using NodeJS, but we’ll take advantage of the environment to be able to launch other tools. In detail:
- We’ll use the NodeJS package manager, named NPM. With it, we’ll be able to download useful javaScript libraries using the command line.
- We’ll also use NPM to manage the entire project. Keep reading for details.
BabelJS
JavaScript evolved
I will not run into a discussion about what and why the other name of JavaScript is ECMAScript.
You should just be aware that JavaScript has a new syntax and new interesting features. This new language is called ES6, or ES2015. For details, query the excellent StackOverflow site.
The interesting parts are:
- a new way to define classes, much more C++/Java/PHP like.
- the possibility to subdivide JavaScript code (functions, classes) into external modules and import them.
- an alternative, less verbose, syntax to define functions.
Bad news: at present time, browsers do not (or partially) understand the new language. This is where Babel comes to help. “Babel transforms your JavaScript”. From the new ES6 Syntax to the plain old “standard” JavaScript, ready to be executed by actual browsers.
Why Babel?
Of course it is not mandatory to use ES6 Syntax today. But it would be a good idea to do so because:
- imports are really useful and simplify code organization.
- obvious advantages derived by the new syntax specs. The code will be clearer and easier to follow.
- if you want to create applications with ReactJS, there’s plenty of example projects and tutorials out there, coded in ES6. Being unaware of the new syntax will make you unable to understand the code.
- it will be the main language on the web for the next years. You will be ready when the revolution comes!
Webpack
Bundling?!
Even a small/medium sized project may have a number of .js source files. They are normally included in your web page, and you have to keep track of the dependencies manually:
<script src="jquery.js"></script>
<script src="awesome_lib_that_uses_jquery.js></script>
<script src="awesome_lib_that_uses_awesome_lib_that_uses_jquery.js>
...
Why not have a way to bundle them in a single .js file? Doing so, we would have the following advantages:
- An unique http request issued by the browser, as we’ll load a single file containing all the code.
- No more worries about what to include first.
- The possibility to minify the code as part of the bundling process.
Webpack does the trick. It is an advanced module bundler: it takes many JavaScript files from a directory and bundles them into one single JavaScript file.
Practice!
If you agree to use such tools and you’re not afraid of new adventures, we can go on the practical.
Preparing you PC
- Install NodeJS. See the NodeJS website for details.
- Install Git on your machine. I’m using windows, so I installed the Git for Windows that comes with a nice Git Bash in which I can issue Linux commands.
Setup the project
- Create a GitHub account and add a new empty repo.
- CD into your projects root and clone the online repo. You will have to setup an SSH key, maintaining the private key on your machine and the public key added to your GitHub account.
git clone git@github.com:<your_github_account>/<your_repo>
This will create a new folder in your projects root. CD into that folder.
3. Initialize the project using NPM.
npm init -y
The -y option stands for not asking a confirm everytime. As a result of this action, a package.json file is created. It contains the project configuration. It is useful for two main reasons:
- it keeps track of the libraries used by the project.
- it allows to define a command to be launched every time we need to build the project and create the bundle.
4. Install Webpack
npm install --save-dev webpack
That’s it! A “node_modules” folder will be created. It will contain a number of subdirectories that will be automatically added by npm when you install new packages. The save-dev option is for adding webpack in the package.json file.
You will notice that package.json has been automatically updated by npm and now contains “webpack” in the “devDependencies” section.
5. Configure Webpack
The webpack configuration is done in the webpack.config.js file:
module.exports = {
entry: './src/index.js',
output: {
path: './build',
filename: 'bundle.js'
}
};
Note: if you experience troubles with the previous configuration about the “path” value, please see this comment https://medium.com/@kaleemkhan/date-18th-july-2017-6d70bdc4d1c8
This should be quite clear. It tells where to find the project entry-point, and where to place the output.
6. Install Babel
We’ll not launch Babel directly. Since we’re using webpack for bundling, we’ll use Babel with it to automatically translate (transpile) the source files before bundling.
How to use Babel with Webpack? The official site is quite clearer:
npm install --save-dev babel-loader babel-core
Then add a loader in the webpack config:
module.exports = {
entry: './src/index.js',
output: {
path: './build',
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}]
}
};
With this, every .js file encountered by Webpack will be processed by Babel first. Babel needs to be configured. We want it to translate ES6 to current JavaScript.
7. Tell Babel what to do
Babel features are packed in separate libraries named presets. To translate ES6 we need to install the following:
npm install --save-dev babel-preset-es2015
The Babel configuration is saved in the .babelrc file. Create it with the following content:
{
"presets": ["es2015"]
}
Note: if you are on Windows, you won’t be able to create a file whose name begins with a full stop. You can create the file using the Git Bash, sending the “touch .babelrc” command.
8. Install jQuery
No more need to download the jQuery code and manually place in your project folder. Just give
npm install --save jquery
and the jQuery library is available for import.
import $ from 'jquery'
jQuery was saved in the “dependencies” section, because it’s a library used by the runtime code. The other libraries installed so far, instead, need to be used to build the project. Again, query StackOverflow for details.
When you need a library, you should check the corresponding npm page (for jQuery: https://www.npmjs.com/package/jquery). It contains useful information about installation and usage in the Node environment.
9. Write some code
I wrote a little class that displays a simple currency converter. It’s a basic example on how to define and use a class in ES6.
Converter.js
import $ from 'jquery';export default class {
constructor(rootElement, eur_usd_coeff) {
this.rootElement = rootElement;
this.eur_usd_coeff = eur_usd_coeff;
this.EUR = 0;
this.USD = 0;
}
render() {
// detach event listeners
$('button').off('click');
// define html
let html = `
<table>
<tr>
<td>EUR</td>
<td> </td>
<td>USD</td>
</tr>
<tr>
<td><input id="EUR" value="${this.EUR}"/></td>
<td>
<button id="convertEURtoUSD">>>></button><br>
<button id="convertUSDtoEUR"><<<</button>
</td>
<td><input id="USD" value="${this.USD}" /></td>
</tr>
</table>
`;
rootElement.innerHTML = html;
// attach event listeners
$('#convertEURtoUSD').on('click', function() {
this.convertEURtoUSD()
});
$('#convertUSDtoEUR').on('click', () => {
this.convertUSDtoEUR()
});
}
convertEURtoUSD() {
this.EUR = $('#EUR').val();
this.USD = this.EUR * this.eur_usd_coeff;
this.render();
}
convertUSDtoEUR() {
this.USD = $('#USD').val();
this.EUR = this.USD / this.eur_usd_coeff;
this.render();
}
};
index.js
import Converter from './Converter';const rootElement = document.getElementById('rootElement');
var conv = new Converter(rootElement, 1.11745);
conv.render();
It’s worth dwelling on a few points:
- a file may export a number of functions or classes. You can define an element to be “export default”, so it will be automatically assigned to the new variable when importing without specifying a name. For details, refer to the Mozilla Developer Network pages (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/export).
- The “html” variable is set by using the ES6 template literals syntax. This is an handy way to write multiline html templates, including variables inside thus avoiding boring string chains. For reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
- When attaching the listeners, I used the new ES6 syntax to define an anonymous function. The following are equivalent:
$('#convertEURtoUSD').on('click', () => {
this.convertEURtoUSD()
});// is exactly the same as$('#convertEURtoUSD').on('click', function() {
this.convertEURtoUSD()
}.bind(this));
This way to define functions is called “arrow functions” syntax. Arrow functions have an additional advantage: they automatically binds the current main object. This topic would deserve an entire article to be well explained, but I think a little practice is better. Try to “console.log(this)” inside the arrow function and see what “this” is with/without the .bind.
For details, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
10. Build
We’re close to the objective. We’re just one step far from the bundle.js. Configure the package.json “build” script to run webpack:
...
"scripts": {
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
...
To buil the project now you can simply run:
npm run build
That’s it. You will find the bundle.js in the “/build” folder.
11. Run in the browser
In the “/build” folder create a simple html page:
<!doctype html>
<html>
<head>
</head>
<body>
<div id="rootElement"></div>
<script src="bundle.js"></script>
</body>
</html>
As you can see, it provides the root element for the application and loads the bundle.js file.
I launch the file on my machine pointing at localhost, since I have a Wamp server running.
12. Git push
It’s time to push our code in the online repository!
Note that the “node_modules” directory contains a huge number of elements downloaded automatically by the npm utility. They should not be saved in the source code repository, since all dependencies are tracked in package.json and could be downloaded when needed by typing:
npm install
bundle.js should not be part of the repository too, as it’s the result of the “webpacking” process and it’s not source code at all — see it as the compiled code.
To exclude such elements, add them in the .gitignore file:
node_modules
bundle.js
We are ready. To save the code in the online repository, I follow the steps:
git status
to see the new or modified files.
git add .
to include them in the next commit.
git commit -m "first commit"
to commit them.
At this point, the changes are saved in your local Git repository. To push them online, type
git push
Visit your online GitHub repo and see the code you just pushed. Cool.
13. Clone your repo to work from another machine
When you’re working on a different machine, you may want to download the source code from the online repo. The first time you need to clone the repo:
git clone git@github.com:<your_github_account>/<your_repo>
Since the ”/node_modules” directory was not uploaded in the repo, we need to install the required packages (dependencies). This is where the package.json come in help: instead of installing every package, just give
npm install
and wait for the magic.
Since the “bundle.js” file was not uploaded in the repo, we need to build the project to produce it. It’s quite straightforward:
npm run build
and, again, remember to thank the “package.json” file.
14. commit new changes
You may want to work and modify the code. Just act like before. A quick recap:
git status
git add .
git commit -m "second commit"
git push
When working in team, you should give a “git pull” command right before the “git push”. This is to download the latest version of the code that may be changed. This could lead to manually merge the code, but this is another topic. See the GitHub pages for details: https://help.github.com/articles/resolving-a-merge-conflict-from-the-command-line/.
The code is updated online. Cool.
15. Download the latest code version
You may want to download the updated code from the first machine: since the local repo exists yet, you won’t clone it again. Just cd into the project folder and give
git pull
to update the files.
Conclusion
See my github repo containing the project here. You may clone it and use as a starting point for your next project.
The code in the repo has a little bug. Are you able to find and correct it?
Please notice me about any error or any part you may find obscure. I tried to be as clear as possible.
References
GitHub
https://github.com/
The complete code used in this article
https://github.com/paooolino/modern-javascript-setup
How to create a SSH key and save it to your GitHub account
https://help.github.com/articles/generating-an-ssh-key/
Babel
https://babeljs.io/
How to setup Babel for various tools
https://babeljs.io/docs/setup/
Webpack
https://webpack.github.io/
NodeJS
https://nodejs.org/en/
jQuery npm repository page
https://www.npmjs.com/package/jquery
ES6 features
http://es6-features.org/
Follow-up
See the next article: A simple React project setup for rapid application prototyping
Edit
September 9, 2016
Due to some feedback from the excellent subreddit r/javascript, I updated the code in the “render” function to use the ES6 template literals.
July 28, 2017
Added a note about the Webpack config path value thans to @kaleemkhan