Building CampaignHawk: File Structure and Packages (Part 2)
We went over the project scope and the wireframing process in the first part. So now that we have the basic idea of what the app should look like, we need to actually put that into code.
My preferred method is to start by building out the user interface (UI), then connect all the internals. For a project like this where the UI is a big part of the project, I’ll probably spend the majority of my time making the interface clean and user friendly.
And depending on how well-defined the project is, it might also make sense to write some end-to-end tests using Cucumber in advance. I know a lot of people like test driven development (TDD), but I’ve always found it more of a hinderance. It’s nothing personal.
Step 1: Directories and Files
First create the Meteor project:
$ meteor create campaign-hawk
$ cd campaign-hawk
Then set up the basic file structure. Meteor is not very opinionated on file structure, which gives us a lot of flexibility. I’m going to use the following file structure to get started:
├── client
│ ├── components
│ │ ├── App.jsx
│ │ ├── AppLoading.jsx
│ │ ├── AppNotFound.jsx
│ │ ├── Map.jsx
│ │ ├── Login.jsx
│ │ └── Settings.jsx
│ ├── router.jsx
│ ├── index.html
│ └── styles
│ └── styles.scss
├── lib
│ └── collections.js
└── server
│ └── server.jsx
└── scss.json
These can be added manually or with the following command:
$ mkdir client client/components client/styles
$ mkdir lib
$ mkdir server$ touch client/components/App.jsx
$ touch client/components/AppLoading.jsx
$ touch client/components/AppNotFound.jsx
$ touch client/components/Map.jsx
$ touch client/components/Login.jsx
$ touch client/components/Settings.jsx
$ touch client/router.jsx
$ touch client/index.html
$ touch client/styles/styles.scss
$ touch lib/collections.js
$ touch server/server.jsx
$ touch scss.json
Then trash the template files:
$ trash campaign-hawk.*
If you don’t have trash, I recommend getting it. You can add it with $ brew install trash. If you don’t have Homebrew, you should get it already.
Step 2: Packages
I’m starting this just before Meteor 1.2 comes out, which is not ideal. That said, the release candidate was just released publicly, and I have faith that it’s stable so I’m going to start by upgrading to 1.2. If you’re reading this in the future and 1.2 has already been released, please let me know so I can change this part of the process.
$ meteor update --release METEOR@1.2-rc.7
A few other packages we’re going to need:
meteor add fourseven:scss
meteor add react
meteor add reactrouter:react-router
I’m also going to add the following to the scss.json file to enable auto-prefixing so we don’t have to deal with those annoying vendor prefixes:
{
"enableAutoprefixer": true,
"autoprefixerOptions": {
"browsers": ["> 5%"],
"cascade": false
}
}
That should work for now as far as packages go.
Step 3: Basic Template
Time to put together a few React components and get them to render properly. Within App.jsx:
App = React.createClass({
render() {
return (
<div>
{this.props.children}
</div>
)
}
})
…Map.jsx:
Map = React.createClass({
render() {
return (
<h1>This is where the map goes</h1>
)
}
})
…Login.jsx:
Login = React.createClass({
render() {
return (
<h1>This is where the login goes</h1>
)
}
})
Now that the components are set up, it’s time to set up the router within the router.jsx file:
const {
Router,
Route,
Redirect
} = ReactRouter;const history = ReactRouter
.history
.useQueries(ReactRouter.history.createHistory)()Meteor.startup(function() {
let AppRoutes = (
<Router history={history}>
<Route component={App}>
<Router component={Map} path="/" />
<Router component={Login} path="login" />
</Route>
</Router>
)
React.render(AppRoutes, document.body)
})
This gives access to the browser history and sets up a route to login. Access to login is not actually needed at this point, but it’s easier to set up the router now rather than later. At this point in the process, the app looks like the image below:
Next Steps
I need to decide on what mapping API I want to use. There’s always Google Maps, but there are some better options out there. I’ve used Mapbox in the past and I’ve had a good experience with them. There’s also CartoDB which seems to put more focus on data, and since this is a very data-intensive map application, they might be a good bet.
I’ll make a decision on mapping APIs later on in the process.
I also need to decide on a database. I’ve become a big fan of Neo4j and graph databases in general. That said, I don’t think the data I’m working with will be particularly relational, so sticking with Mongo might be easier.
I’m going to stick with Mongo for the time being, and if my queries start to get too complex and relational for Mongo, then I’ll switch over to Neo4j and the any-db package for Meteor.
Sam Corcos is the lead developer and co-founder of Sightline Maps, the most intuitive platform for 3D printing topographical maps, as well as LearnPhoenix.io, an advanced tutorial site for building scaleable production apps with Phoenix and React.
Additional
- Building CampaignHawk: An open-source election canvassing app with Meteor and React (Part 1)
- File Structure and Packages (Part 2)
- Styling the Sidenav (Part 3)
- Styling Tooltips (Part 4)
- Connecting Tooltips with React (Part 5)
- Making Modals (Part 6)
- Populating Modals (Part 7)
- Connecting Modals with React (Part 8)
- Mapbox and Data (Part 9)
- Thinking about Data (Part 10)
- Mapbox and GeoJSON (Part 11)
- Mapbox.js and Meteor Data (Part 12)
- Popouts and Radio Buttons (Part 13)
- Radio Button Styling (Part 14)
- Triggering Functions with Radio Buttons (Part 15)
- Spacial Analysis Overview (Part 16)
- Clustering with Leaflet Markercluster (Part 17)
- Making a Precinct Data Layer (Part 18)
- Scaling Colors and Values with D3 (Part 19)
- Styling the Precinct Data Layer (Part 20)
- Toggling Data Layers (Part 21)
- Voter Filter Data Layer (Part 22)