Captain Codeman Captain Codeman

Polymer App Configuration and URL Generation

Don't overcomplicate configuration settings

Contents

Introduction

One thing that seems to come up a lot in the Polymer Slack is how and where to store configuration settings for an app, how to access them and related to that, how to generate URLs within the app.

There are a few different ways to do this and no one approach is going to be the best fit for all (depending on specific needs) but I’ll describe the approach that I generally use which has been working well for me.

The first thing is the configuration. Don’t over-think it - if you’ve come from other platforms (looking at you Angular 2/4!) then you might believe that you need all kind of complicated dependency injection to pass a configuration object around.

You really don’t.

It’s the web platform - there is already a global scope object called window and we can add our own objects to it. Lots of highly used and well known web systems such as Google Maps have been doing this for many years. Using a global singleton is not the development crime some might have you believe as long as you are using it properly. We just have to pick a namespace that should be unique and presumably, within our app, we can easily manage this.

So, if we want to add some config, we can add something like this to index.html containing whatever app settings might be needed within our app:

<script>
  window.MySuperApp = {
    api_endpoint: 'https://api.example.com',
    google_maps_key: 'abc',
    stripe_public_key: 'xyz'
  }
</script>

How you put this JSON into index.html is up to you - there are lots of Gulp plugins that can handle it if you need to automate it as part of a build / deploy process. You could also chose to load it dynamically from an external file but I prefer not to do this because it adds some latency to the app startup time and you have to cope with delaying your app running until the config is available.

If it needs to be dynamic, you can also render it on the server so to the client it’s still ‘static’ (i.e. defined in the page when it loads).

So how do you then use it?

Suppose you previously had something hard coded within one of your elements, maybe something like:

<iron-ajax url="https://api.example.com/items/1" ...></iron-ajax>

Now you could create a property to represent the configurable part instead:

<iron-ajax url="[[apiEndpoint]]/items/1" ...></iron-ajax>

and populate the property within the element from the config object:

properties: {
  apiEndpoint: {
    type: String,
    value: MySuperApp.api_endpoint
  }
}

Note that it doesn’t need to be computed because as we said earlier, at runtime it’s static - it can be whatever it’s set to when the app first starts and the elements load.

So that works to allow us to change our app configuration in one place or avoid having configured values hidden and buried in deep elements. In this example, we could easily point the app to use a different server for API requests, maybe a testing instance or local development (why it’s good to have the proper config added as part of a build / deploy script - we don’t want live users being pointed to localhost!).

But adding properties can become repetitive, especially as we accumulate more configurable settings. So instead of putting them on each element, we can instead put them on a behavior (or a mixin if using Polymer 2.0) and that way they are available to any element that needs them within the app.

The related issue is routing. It seems to be a perennial issue in any JavaScript web framework chat room - people wondering why, when they refresh the page on their new Single Page App, it breaks. Of course you need to make sure the server returns index.html to every request. Some people like to use hash based routing as a quick solution and it does work but isn’t a great solution nowadays IMO.

But you may want to be able to change how URLs are created within your app. Whether that is to switch between hash based routing and path routing or to just be able to change the URL structure of your app as it develops. Do you really want to go hunting through lots of elements to find the place URLs are built? It can also get untidy and inconsistent having the same URLs built up in different places in different ways.

We can turn back to our app configuration behavior / mixin and add some methods to it to generate URLs in a central place.

So now, instead of templates containing:

<a href="#/topic/[[topic.id]]/[[topic.slug]]?page=[[page]]">Link</a>

We could use something simpler such as:

<a href="[[topicURL(topic.id, topic.slug, page)]]">Link</a>

or maybe:

<a href="[[topicURL(topic, page)]]">Link</a>

Generation of URLs throughout the application is now in one place and changing them should be easy and straightforward.