Let’s Try To Build My Locator in NativeScript-Vue!

Building a locator with Mapbox without JS framework had worked out pretty well in my last post. This time, I decided to try it with a JS framework. I have been working with React for a while, so I decided to use a new framework this time -Vue, to be precise.

Since I wanted the app to be used while a bicyclist may be on the road, I wanted the app to work well with mobile. React have React Native. How about Vue? Lo and behold, NativeScript! They even have a tutorial: Include Feature-Rich Maps in a NativeScript-Vue App with Mapbox.

Things I noticed on my first run of the tutorial:

  • NativeScript installation required pod setup, which took forever but didn’t displayed progress bar or related message. I thought the installation got stuck and was quite confused. In the end,  command pod setup –verbose showed me that it was indeed setting up and not getting stuck.
  • The command vue init nativescript-vue/vue-cli-template set a MIT open-source license by default. Nice feature – I usually don’t really think about license when I am building a side project, so this was a good reminder.
  • The vue/devtools package was behind in its electron dependency update, so I got a npm audit alert. When I checked their Github issues, it seemed they were aware of it but haven’t gotten around to fixing it yet.
  • Like pod setup,the npm install also took a while. I downed an entire cup of coffee, and it was still loading! I don’t work with mobile app development framework a lot. Was that normal?
  • Although the tutorial was made only this July, there seemed to be quite a bit of changes for the vue template. For one thing, I saw a hook directory – wasn’t hook only out this or last month? Some changes related to the tutorial content:
    • Directory “src” is now “app“.
    • HelloWorld.vue is now App.vue
    • npm run watch:ios is not working…
    • … the vue template “vue-cli-template” went through some major changes. The one used in the tutorial is now legacy. I should had changed the command for initiating the template to “vue init nativescript-vue/vue-cli-template#legacy <directory-name>” instead. In the new template, instead of npm run watch:ios, the command tns run ios  –bundle should be use instead.

Sadly, after tns run ios –bundle, it tried to run the iPhone emulator in my Macbook, and I was reminded of the main reason why I don’t do much mobile development. My emulator has always been ridiculously slow and would even freeze my Macbook sometimes.

There was tns build ios –bundle, which build and run the code in NativeScript’s iPhone app, but that one also took forever. In fact, it’s still bundling right now as I am writing this post – and I would have to build it every time I want to see changes in this case.

I really just want to learn Vue, but I had spent over a day trying to set up and troubleshoot NativeScript issues. The tns run, tns build, and the various package download and setup took a lot of time. NativeScript isn’t my goal – Vue and Mapbox is. So for my next step, I will take a step back and re-focus on building a web app with Vue.

My First Mapbox Project: Building a Locator

A while I ago, I went to a Map meetup, where I was introduced to Mapbox – I have always been kind of curious about GIS mapping since I interned at SF Bicycle Coalition, where they had another intern worked with GIS maps.

Recently, I finally got back to the codebase that I started during that meetup. The tutorial I did was a map of parks. I wanted to do a locator, and eventually replace the geojson file with park location data with bike shop data – turns out mapping APIs typically uses json-like file call geojson.

Well, not just bike shop – SFBike members get discounts at specific bike shop and even general stores like groceries and book store. I want to do a map of SFBike-related business. That means I would be writing a scraper for the SFBike member page, and then processing Yelp’s API for store hours so the map will display only opened stores.

Lo and behold, Mapbox have a locator tutorial! And while I do that, let put it on Github so I can keep track of my progress!

However, as I code, I came across 2 major problem: how to get a dataset that I already uploaded on Mapbox (most tutorials seems to use local files?) and how to protect my API key in a simple HTML/CSS/JS site without JS framework?

Here’s what I learned and did to troubleshoot:

Retrieving GeoJson Dataset

I tried reading the tutorials first, but it seems to mostly using local files that is already there or add Sources before extracting the sources – that’s whether convoluted…

At one point, I tried queryRenderedFeatures(), but nope, not working. I think the features gets rendered later, so even though I know there is features created from the mapbox tileset, I can’t grab them.

By the way, the flow of mapbox is

  1. Often time, the data are in geoJSON format. GeoJSON can contain FeatureCollection object, which is an object that contain a geometry object and additional properties called features.
  2. In Mapbox, a Dataset is needed, and it is often uploaded GeoJSON.
  3. Dataset creates what’s called a Tileset.
  4. The Tileset can be styled with Style, which is documents that defines the visual appearance of a map.

But first – back to getting the data.

I started searching in the documentation, when I started wondering why there is so many curl when the tutorial never mentions it – only to realize there is a selector for different programming languages on top, JavaScript included.

I resisted the urge to hit the table. The answer was right there!

Here’s what I did to get the uploaded code from Mapbox Studio:

map.on('load', function() {
// Retrieve the geoson dataset uploaded in Mapbox Studio
const mapboxClient = mapboxSdk({ accessToken: mapboxgl.accessToken });
datasetId: 'some datasetId'
response => { builLocatioList(response.body) },
error => console.log(error)

API Key in Working .env File, No JS Framework Needed

Since I wanted to keep it to JavaScript, I thought I would use a .env to store the key – but don’t I usually use framework with that? I don’t want a framework for now, so let’s search for ways to use .env without framework!

… Damn, all the express and node solutions online looks ways too complicated for such simple needs (I just need an .env file working!). There seems to be a simple one. But once I try to use process.env.APIKEY, it says that process is not defined.

Maybe I need to require the dotenv package? I mean, I did it in server.js, but maybe they need it in index.js?

Now it is saying require is not defined.

*Flips table, or at least thinks about it*

After some search, I learned that require is for the server side of the app, not the client side. After reading about multiple options, including an hour tweaking with RequireJS, I decided to go with webpack. Basically, I just need add a simple plugin code in my webpack config file:

node: { fs: 'empty' },
plugins: [
new Dotenv()

The fs: ’empty’ was added because the error code keep saying Can’t resolve fs.

So here are my final file directory structure:

The steps to create a simple framework-less node app is as follow:

    1. In your project directory root, enter command: touch .env .gitignore README.MD
    2. Inside .gitignore, make sure to include .env and dist. If not, when you push it up to Github, everyone will know your API key! Also add node_modules and any files or directories that you don’t want to upload to Github.
    3. Create a directory named public (some people like app). Inside, create files you needed. You will want index.html and index.js at least.
    4. Now do an npm init -y, which will create a package.json file with default content. You can always change the content later.
    5. Do an npm install express express path. Then npm install -D dotenv-webpack webpack webpack-cli.
    6. Now, time to create your own webpack.config.js file. The output variable will determine what the bundled file output to. In this case, it would be dist/bundle.js.
    7. Since the output bundle file will be at dist/bundle.js, make sure the index.html will use that file instead of index.js. Replace what would normally be <script src=index.js> to <script src = [new bundle file path]>.
    8. Now in index.js, I can use require(‘dotenv’).config();!
    9. Make sure your .env contains your API keys!
    10. When the code is set up, run npm run build to create the bundle file. Everthing looks good? No error? Then go and do a npm run start.
    11. Everything’s setup. You should see your working page in the index.html page.