There are some choices if you need a web application bundler. One of them is ParcelJS, which is relatively new. Described as blazing fast, zero configuration web application bundler, Parcel can be an alternative if you want to build application quickly.
If you use Webpack, you need to create configuration first before running the build process. It gives you flexibility to define loaders, plugins, etc. However, if you don't like to setup configuration, using Parcel is more appropriate because it uses zero configuration. In addition, the build process is usually much faster.
Features
Below are some features of ParcelJS:
- Super-fast bundle times: Parcel uses multiple worker processes and supports multi-core compilation. With the helpf of filesystem cache, the rebuild process is really fast
- Bundle all your assets: It has built-in support for JS, CSS, HTML, file assets, and more .
- Automatic transforms: Using Babel, PostCSS, and PostHTML, the code will be automaticaly transformed, including minified.
- Zero config code splitting: With dynamic
import()
syntax, output bundles are splited, so that it will only load what's need on initial load. - Hot module replacement: While you're developing and making changes to the code, it automatically performs rebuild and updates the modules on the browser.
- Error logging: When an error occurs, it will print the highlighted code that causes the error - that's really useful to find a mistake.
Dependencies
Below are the dependencies required for this project. Add them to package.json
and run npm install
.
"dependencies": {
"express": "~4.16.3"
},
"devDependencies": {
"babel-preset-env": "~7.0.0-beta.3",
"babel-preset-react": "~6.24.1",
"node-sass": "~4.9.3",
"parcel-bundler": "~1.9.7",
"react": "~16.4.2",
"react-dom": "~16.4.2"
},
Developing Application
Parcel requires an entry point where it starts to build, usually an HTML or a JS file. In this tutorial, we're going to use an HTML file as the entry point.
src/index.html
<!DOCTYPE html>
<html>
<head>
<title>React starter app 4</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css">
</head>
<body>
<header>
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="https://www.woolha.com">
Woolha.com
</a>
</div>
</nav>
</header>
<div id="app"></div>
<script src="./index.js"></script>
</body>
</html>
The HTML file above loads a JavaScript file <script src="./index.js"></script>
. Parcel knows it and it will build the JavaScript file as well. Here's the JavaSript file.
src/index.js
import React from "react";
import ReactDOM from "react-dom";
import './scss/app.scss';
import MainComponent from './components/Main'
const App = document.getElementById("app");
ReactDOM.render(, App);
Just like other application bundler, it will go through each dependencies and include them in the output. The JavaScript file renders a ReactJS component MainComponent
and also imports a scss
file for CSS styling.
src/scss/app.scss
body {
background-color: #efefef;
text-align: center;
height: 100vh;
.navbar {
background: #009696;
color: #ffffff;
height: 30px;
a {
color: #ffffff;
}
}
#app {
margin-top: 50px;
font-size: 20px;
input {
-webkit-appearance: none;
height: 30px;
background-color:#FFF;
color:#666;
font-weight:bold;
border: solid #666 1px;
font-size: 14px;
padding: 10px;
margin: 20px;
}
}
}
In this tutorial, we're going to create a very simple React application which renders a text input field and prints the value on the input field (entered by user) as a text.
src/components/Main.jsx
import React, { Component } from 'react';
import ParcelLogo from '../img/parcel-logo.png';
class MainComponent extends Component {
constructor() {
super();
this.state = {
text: '',
};
this.submit = this.submit.bind(this);
if (module.hot) {
module.hot.dispose(function () {
// Module is about to be replaced
console.log('Replacing ...');
});
module.hot.accept(function () {
// Module or one of dependencies was just updated
console.log('Successfully updated');
this.setState({ text: '' })
});
}
}
submit(e) {
this.setState({ text: e.target.value });
}
render() {
return (
<div>
<img src={ParcelLogo} />
<div className="form-group">
<input
className="form-control"
height="100px"
id="name"
name="name"
onChange={this.submit}
value={this.state.text}
/>
</div>
<h1>Hello6 {this.state.text}</h1>
</div>
);
}
}
export default MainComponent;
As examplifed above, it's possible to import not only code, but also static files such as images.
import ParcelLogo from '../img/parcel-logo.png';
The file must be exist of course, otherwise the build will be failed.
As mentioned above, one of the ParcelJS features is hot module replaement and it's enabled by default. So, if you change the code, you can also add what should your app do when module is about to be replaced, and when module or one of dependencies was just updated. Inside the constructor, add the following:
src/components/Main.jsx
if (module.hot) {
module.hot.dispose(function () {
// Module is about to be replaced
console.log('Replacing ...');
});
module.hot.accept(function () {
// Module or one of dependencies was just updated
console.log('Successfully updated');
this.setState({ text: '' });
});
}
The code above will make the text state set to empty string every time the module updated. Hot swapping only works if safe write is disabled. Some IDEs enable safe write by default.
Now, let's use Parcel to bundle our application. As we use src/index.html
as the entry point, run parcel build src/index.html
. Wait a couple of seconds and it will start a server at port 1234. Open http://localhost:1234
on a web browser, you should be able to see the application running. Using view source or inspect element feature, you'll see that the CSS file is automatically injected to the HTML.
If you want to make sure hot replacement is working, just modify the code and Parcel would build it automatically and also refresh the application running on the browser.
To make it easy the next time you need to run it, add the following to your package.json
.
package.json
"scripts": {
"build-run": "parcel src/index.html"
}
Now you can use npm run build-run
to run Parcel to build your code and running a server for debugging.
Build Only
Running Parcel with the above command is useful for debugging while developing application. However, if you only need to only build the code without running it on a port, you have to use a slightly different command by adding build
before the entry point.
Let's assume we render the HTML file from back-end using any template engine, which is the most likely case in production. But, to make it simple, in this tutorial, we only serve a static HTML file from the back-end using ExpressJS' sendFile
.
app.js
const express = require('express');
const fs = require('fs');
const http = require('http');
const path = require('path');
const app = express();
app.get('/', (req, res) => {
res.writeHead(200, {"Content-Type": "text/html"});
fs.createReadStream(path.resolve(__dirname, 'src/index.html'))
.pipe(res);
});
// Parcel generates file on dist directory
app.use('/', express.static(path.join(__dirname, 'dist')));
http.createServer(app).listen(3333, function(){
console.log("Server started at port 3333");
});
However, because we serve a static HTML file, the CSS file will not be included automatically. Therefore, we need to slightly modify the HTML file to include the CSS file generated by the bundler. The name of the CSS file is the same as the entry point file name, of course with different extension. Add this line to the <head>
section of src/index.html
.
<link rel="stylesheet" href="/index.css"></head>
Then, modify the scripts
section of package.json
.
package.json
"scripts": {
"build": "parcel build src/index.js",
"build-run": "parcel src/index.html"
}
Now we have two commands available. To build application, run npm run build
. Wait until the build finish and you'll see some files generated on dist directory. Then, start the Express server by running node app.js
By default, the output will be on dist
directory. For custom output directory, you can add --out-dir custom_dir_name flag
.
That's all about how to use ParcelJS bundler to build React application. You can download the code on Github.