Use Webpack with D3 Dashboard Pages
Introduction
Although I found it a little bit tedious to set up margin conventions, scales, axis while studying the demos, I didn’t put chart reusability on the top of my todo list until I finished the Air Quality demo. Rewriting some basic or common settings can be time consuming given that you have to spend a huge amount of time to clean and process data per se.
Apart from reuse components or settings of charts on the same page, it is more efficient if these functions can be used across pages, say you have a relatively large multipage or single page dashboard app, each page has its own purpose of presenting data, but they certainly have something in common, be it the layout or styles of path or line.
That’s why I want to work on reusing d3 components within and across pages.
Within the Page - Reusable D3 Chart
Mike wrote an article addressing reusable charts a while ago, this post is a really good start to learn to add reusability to your chart despite existing different opinion. To understand this methodology better, there are some examples dedicated to this topics.
Another quite new tool is d3kit that I mentioned earlier. I haven’t tried it yet since I am still trying to figure which level of customization is best for me. But give it a try if you want since the maintainers said that it is already been used in production.
Get Started with Webpack
With regards to efficiency across pages, or packaging files, there are many outstanding tools including grunt, gulp, browserify, components etc. They all have its own pros and cons which I won’t address here. The reasons I prefer webpack including splitting files, packing other static resources like css and images, etc.
The general goal is to write javascript for each chart on one dashboard page, , reuse common modules, and packaging publicly used vendors/modules across pages in one app.
This webpack-howto post can provide you with a quick view about what webpack can do and how to do them.
Scenarios & Examples
Setting Up Webpack
The official tutorial is fairly straightforward and simple, but let’s get more practical here(assuming you have all necessary packages correctly installed):
Project Structure:
By and large, the build
folder is the ultimate page while app
folder is where we write modules and utilize these modules. The most important file is the webpage.config.js
in which we config webpack.
Another thing worth noting is that in the demo repo, there is no style file in build folder, which is different than outcomes of other packaging tools I used before, we’ll look at it in a minute.
The minimal codes for webpack.config.js are:
That is to say webpack will take the main.js
in app
folder and the dependencies, and generate a bundle.js
in build folder.
Meanwhile, let’s create a page1.html
in build:
Then write sth in the margin.js
module and main.js
:
and use this component in main.js
:
Open your browser and check that message in console.
Webpack Dev Server
The approach of open html files directly with browser is obviously out of date. We can use webpack-dev-server
instead.
So what we need for local development? 1) recompile files once updated 2) show source map files 3) live reload:
webpack-dev-server --devtool eval --progress --colors --content-base build --port 3030
What this line of command does is to:
1) add source url so errors will point to the right file(--devtool eval
, --d
is also okay but slower);
2) show compiling progress and add some colors to output message (--progress --colors
)
3) specify the directory to serve, the build folder in this case (--content-base build
)
4) override default port 8080 to 3030
To save time, you can add the above command line to package.json:
One thing I need to point out is that if you use webpack-dev-server, it won’t generate the bundle.js file in build folder because modified bundle is served from memory.
More Than Just JavaScript
As mentioned here, other static resources also need to be handled, such as stylesheets, images, template html etc. For example, we need to apply the style.less to page1.html, all we need to do is add this in main.js
:
require('../style/style.less')
and config loaders in config file:
And don’t forget to install style-loader
,css-loader
,less-loader
before compiling. What happened is that for every .less
file, it will be processed by less-loader
,css-loader
,style-loader
(apply the styles in the css file).
Add External Libraries
Suppose we need d3.js to render data presentation and jQuery for DOM manipulation or other things, let’s integrate them into our app by download them first: bower install d3 jquery --save
And update config file:
Furthermore, we can add a function in config to make it easier to add external libraries:
Restart the webpack, and require the external libraries in your js files:
Make Modules Available Everywhere
Since we’re going to use d3.js almost everywhere, it would be cumbersome to require d3 in every file. Fortunately, webpack allows us to make it available in every file as a customized variable by using the ProvidePlugin
plugin:
Then we can just simply use d3
as usual in components files.
Extract Common Chunks
Another scenario is to extract commonly used javascript chunk into a seperate file, for instance, we need all external libraries compressed in a vendors.js
so we can use it in other pages, this can be achieved by the CommonsChunkPlugin
in webpack:
Run webpack, it will generate another file vendors.js
in build folder which contains the d3 and jquery libraries.
Multiple Entry Points
Let’s say we want to use different bundles for page1.html
and page2.html
. Assuming page2.html contains maps, thus needs extra libraries such as topojson.js
Furthermore, you can also use CommonsChunkPlugin
to extract common chunks from different sets of js files.
Will update advance usage of webpack later.