<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Starr Horne</title>
    <description>The latest articles on DEV Community by Starr Horne (@starrhorne).</description>
    <link>https://dev.to/starrhorne</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F207504%2Fa0ed9d9a-6d51-4a68-819c-cf2af27eab60.jpg</url>
      <title>DEV Community: Starr Horne</title>
      <link>https://dev.to/starrhorne</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/starrhorne"/>
    <language>en</language>
    <item>
      <title>Understanding Elixir's Strange Module Names</title>
      <dc:creator>Starr Horne</dc:creator>
      <pubDate>Wed, 24 Jul 2019 22:49:15 +0000</pubDate>
      <link>https://dev.to/honeybadger/understanding-elixir-s-strange-module-names-2d45</link>
      <guid>https://dev.to/honeybadger/understanding-elixir-s-strange-module-names-2d45</guid>
      <description>&lt;p&gt;Last week was amazing. It was our first ever Honeybadger Hack Week. We got to take a momentary break from thinking about exceptions and uptime to focus all our energies on something completely new. We decided as a team to build a small app in Elixir and Phoenix. &lt;/p&gt;

&lt;p&gt;As I was getting comfortable with Elixir, one weird thing began to stand out to me. When you open up the console (iex) and type in a module name, there's never an error. Even when the module doesn't exist.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex&amp;gt; SomeModule
# =&amp;gt; SomeModule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is unlike Ruby, where you'll always get an error:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;irb&amp;gt; SomeClass
NameError: uninitialized constant SomeClass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It turns out, Elixir handles module names in an unexpected way. It's a little strange, but once you understand the underlying mechanism, it becomes very easy to reason about modules. &lt;/p&gt;

&lt;p&gt;So pull up a seat. Gather round the fire and let me tell you a story.  &lt;/p&gt;

&lt;h2&gt;
  
  
  How other languages handle modules
&lt;/h2&gt;

&lt;p&gt;In static languages like Rust, modules only really exist at compile-time. They're used to perform correctness checks, but then they're discarded and aren't present in the compiled object file except perhaps as debug metadata. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mod sound {
    fn guitar() {
    }
}

sound::guitar();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In Ruby, modules and classes are special kinds of objects. Module "names" are just variables. They have special &lt;code&gt;CamelCase&lt;/code&gt; names, and some special lookup rules, but they're basically just variables.  You can even reassign them. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module MyModule
  def self.hello()
    puts "world"
  end
end

YourModule = MyModule
MyModule = nil
YourModule.hello
# =&amp;gt; "world"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Elixir's surprising approach
&lt;/h2&gt;

&lt;p&gt;At first glance, Elixir looks like Ruby. We can define modules, assign them to variables then call functions as if we were referencing the original. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule MyModule do
  def hello() do
    IO.puts("world")
  end
end

x = MyModule
x.hello()
# =&amp;gt; "world"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But there &lt;em&gt;is&lt;/em&gt; a difference. &lt;/p&gt;

&lt;p&gt;If you're &lt;em&gt;really&lt;/em&gt; paying attention you may have noticed that in the ruby example, we have &lt;code&gt;YourModule = MyModule&lt;/code&gt;, while in elixir, we have &lt;code&gt;x = MyModule&lt;/code&gt;. That's because elixir gives an error if I try the former:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YourModule = MyModule
# ** (MatchError) no match of right hand side value: MyModule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I can assign a module name to  a variable, but the module name itself doesn't seem to be a variable like it is in Ruby. Instead, module names are "atoms."&lt;/p&gt;

&lt;h2&gt;
  
  
  Atoms
&lt;/h2&gt;

&lt;p&gt;Atoms are used to name things when you don't want the overhead of using a string. They're very similar to Ruby's "symbols":&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:foo
:bar
:"this atom has spaces and.special.chars"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Common uses for atoms  are as keys in maps (hashes in Ruby, objects in JavaScript) and to specify keyword arguments in functions:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_map = %{foo: 1}
my_func(foo: 1) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;They're also used to name modules. For example, if I want to call Erlang's &lt;code&gt;format&lt;/code&gt; function from elixir, I would write something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:io.format(arg1, arg2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Like all Erlang modules, we reference the &lt;code&gt;io&lt;/code&gt; module via an atom, &lt;code&gt;:io&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aliases
&lt;/h2&gt;

&lt;p&gt;At this point I imagine you're thinking, "Wait a second! Elixir module names look like &lt;code&gt;MyModule&lt;/code&gt; not &lt;code&gt;:my_module&lt;/code&gt;! Those aren't the same!"&lt;/p&gt;

&lt;p&gt;That's because Elixir is playing tricks on us. Behind the scenes, it converts any code referring to &lt;code&gt;MyModule&lt;/code&gt; to refer to the atom, &lt;code&gt;:"Elixir.MyModule"&lt;/code&gt; . You can see this in action if you open up iex:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MyModule == :"Elixir.MyModule"
# true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The substitution of module name like &lt;code&gt;MyModule&lt;/code&gt; with an atom is called "aliasing." It happens automatically for any keyword that looks like a module name: &lt;code&gt;AnythingThatLooksLikeThis&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The reason that we reference Erlang modules directly with atom (&lt;code&gt;:io&lt;/code&gt;, etc) is because there's no aliasing involved. Though, if you wanted to you could manually create an alias:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias :io, as: IO

IO
# =&amp;gt; :io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Practical Implications
&lt;/h2&gt;

&lt;p&gt;Now that we know that "module names" in Elixir are just atoms + aliasing, it's easy to reason about modules. &lt;/p&gt;

&lt;p&gt;First, we see why we got an error when we tried to assign &lt;code&gt;YourModule = MyModule&lt;/code&gt;. When expanded, that code becomes:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:"Elixir.YourModule" = :"Elixir.MyModule"
# error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Assigning one atom to another makes no sense. You might as well try to say &lt;code&gt;1 = 2&lt;/code&gt; or &lt;code&gt;"foo" = "bar"&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Furthermore, we see that anything that can be done with an atom can also be done with a module name:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Call functions using the atom directly&lt;br&gt;
:"Elixir.MyModule".hello()
&lt;h1&gt;
  
  
  Construct module names from strings, dynamically
&lt;/h1&gt;

&lt;p&gt;String.to_atom("Elixir.MyModule").hello()&lt;/p&gt;
&lt;h1&gt;
  
  
  Pass a module into an anonymous function
&lt;/h1&gt;

&lt;p&gt;(fn x -&amp;gt; x.hello() end).(MyModule)&lt;/p&gt;
&lt;h1&gt;
  
  
  Make a genserver name equal the current module name
&lt;/h1&gt;

&lt;p&gt;GenServer.start_link(Stack, [:hello], name: &lt;strong&gt;MODULE&lt;/strong&gt;)&lt;/p&gt;
&lt;h1&gt;
  
  
  Execute the same function in a list of modules
&lt;/h1&gt;

&lt;p&gt;for mod &amp;lt;- [MyModule, OtherModule], do: mod.hello()&lt;/p&gt;
&lt;h1&gt;
  
  
  Reference a module before it's defined. Just don't run this function if it isn't :)
&lt;/h1&gt;

&lt;p&gt;def do_something(), do: SomeOtherModule.something()&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;When I first discovered the use of atoms for elixir modules, I wasn't thrilled. It seemed ugly and weird. But I've come around. &lt;/p&gt;

&lt;p&gt;Atoms are perfect for naming things, including modules. They're fast. They're never garbage-collected. They're unique. And best of all, they're easy to reason about. Like a lot of Erlang, they make a lot of sense once you get over the intitial strangeness.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>php</category>
    </item>
    <item>
      <title>How We Migrated To Turbolinks Without Breaking Javascript</title>
      <dc:creator>Starr Horne</dc:creator>
      <pubDate>Tue, 23 Jul 2019 17:46:33 +0000</pubDate>
      <link>https://dev.to/honeybadger/how-we-migrated-to-turbolinks-without-breaking-javascript-4cag</link>
      <guid>https://dev.to/honeybadger/how-we-migrated-to-turbolinks-without-breaking-javascript-4cag</guid>
      <description>&lt;p&gt;It's 2019, so we decided it was time to take a more modern approach to the &lt;a href="https://www.honeybadger.io/"&gt;Honeybadger&lt;/a&gt; front end. We implemented Turbolinks! This is only the first step on an ambitious roadmap. In 2025 we plan to migrate to Angular 1, and we'll finish out the decade on React unless we run into any roadblocks!&lt;/p&gt;

&lt;p&gt;But let's get real. Honeybadger isn't a single page app, and it probably won't ever be. SPAs just don't make sense for our technical requirements. Take a look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our app is mostly about displaying pages of static information.&lt;/li&gt;
&lt;li&gt;We crunch a lot of data to generate a single error report page.&lt;/li&gt;
&lt;li&gt;We have a very small team of four developers, and so we want to keep our codebase as small and simple as possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Days of PJAX
&lt;/h2&gt;

&lt;p&gt;There's an approach we've been using for years that lets us have our cake and eat it too. It's called PJAX, and its big idea is that you can get SPA-like speed without all the Javascript. When a user clicks a link, the PJAX library intercepts it, fetches the page and updates the DOM with the new HTML.&lt;/p&gt;

&lt;p&gt;It's not perfect, but it works better than you'd think -- especially for an app like ours. The only problem is that our PJAX library is no longer maintained and was preventing us from updating jQuery (ugh). So it had to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving to Turbolinks
&lt;/h2&gt;

&lt;p&gt;Now if you think about it, PJAX sounds a lot like Turbolinks. They both use JS to fetch server-rendered HTML and put it into the DOM. They both do caching and manage the forward and back buttons. It's almost as if the Rails team took a technique developed elsewhere and just rebranded it.&lt;/p&gt;

&lt;p&gt;Well, I'm glad they did, because Turbolinks is a much better piece of software than &lt;code&gt;jquery-pjax&lt;/code&gt; ever was. It's actively maintained and doesn't require jQuery at all! So we're one step closer to our dream of ditching &lt;code&gt;$&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'm going to tell you about our migration from PJAX to Turbolinks. The good news is that Turbolinks works surprisingly well out-of-the-box. The only tricky thing about it is making it work with your JavaScript. By the end of this article I hope you'll have a good idea of how to do that. &lt;/p&gt;

&lt;h2&gt;
  
  
  Turbolinks is a Single-Page Application
&lt;/h2&gt;

&lt;p&gt;Turbolinks doesn't just give you some of the benefits of a single-page app. Turbolinks &lt;strong&gt;is&lt;/strong&gt; a single page app. Think about it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When someone visits your site, you serve them some HTML and Javascript.&lt;/li&gt;
&lt;li&gt;The JavaScript takes over and manages all subsequent changes to the DOM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If that's not a single-page app, I don't know what is.&lt;/p&gt;

&lt;p&gt;Now let me ask you, do you write JS for a single page application differently from a "traditional" web application? I sure hope you do! In a "traditional" application, you can get away with being sloppy because every time the user navigates to a new page, their browser destroys the DOM and the JavaScript context. SPAs, though, require a more thoughtful approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Approach to JS that works
&lt;/h2&gt;

&lt;p&gt;If you've been around for a while you probably remember writing code that looked something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$(document).ready(function() {
  $("#mytable").tableSorter();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It uses jQuery to initialize a table-sorting plugin whenever the document finishes loading. Let me ask you: where's the code that unloads the table-sorter plugin when the page unloads?&lt;/p&gt;

&lt;p&gt;There isn't any. There didn't need to be back in the day because the browser handled the cleanup. However, in a single-page application like Turbolinks, the browser &lt;em&gt;doesn't&lt;/em&gt; handle it. You, the developer, have to manage initialization &lt;strong&gt;and&lt;/strong&gt; cleanup of your JavaScript behaviors.&lt;/p&gt;

&lt;p&gt;When people try to port traditional web apps to Turbolinks, they often run into problems because their JS never cleans up after itself.&lt;/p&gt;

&lt;p&gt;All Turbolinks-friendly JavaScript needs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize itself when a page is displayed&lt;/li&gt;
&lt;li&gt;Clean up after itself before Turbolinks navigates to a new page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For new projects, I would recommend using Webpack, along with perhaps a lightweight framework like &lt;a href="https://github.com/stimulusjs/stimulus"&gt;Stimulus&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capturing Events
&lt;/h2&gt;

&lt;p&gt;Turbolinks provides its own events that you can capture to set up and tear down your JavaScript. Let's start with the tear-down:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.addEventListener('turbolinks:before-render', () =&amp;gt; {
  Components.unloadAll(); 
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;turbolinks:before-render&lt;/code&gt; event fires before each pageview &lt;em&gt;except&lt;/em&gt; the very first one. That's perfect because on the first pageview there's nothing to tear down.&lt;/p&gt;

&lt;p&gt;The events for initialization are a little more complicated. We want our event handler to runs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On the initial page load&lt;/li&gt;
&lt;li&gt;On any subsequent visit to a new page&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's how we capture those events:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Called once after the initial page has loaded
document.addEventListener(
  'turbolinks:load',
  () =&amp;gt; Components.loadAll(),
  {
    once: true,
  },
);

// Called after every non-initial page load
document.addEventListener('turbolinks:render', () =&amp;gt;
  Components.loadAll(),
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;No, you're not crazy. This code seems a little too complicated for what it does. You'd think there would be an event that fires after &lt;em&gt;any&lt;/em&gt; page is loaded regardless of the mechanism that loaded it. However, as far as I can tell, there's not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loving and hating the cache
&lt;/h2&gt;

&lt;p&gt;One reason Turbolinks sites seem faster than traditional web apps is because of its cache. However, the cache can be a source of great frustration. Many of the edge cases we're going to discuss involve the cache in some way.&lt;/p&gt;

&lt;p&gt;For now, all you need to know is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Turbolinks caches pages immediately before navigating away from them.&lt;/li&gt;
&lt;li&gt;When the user clicks the "Back" button, Turbolinks fetches the previous page from the cache and displays it.&lt;/li&gt;
&lt;li&gt;When the user clicks a link to a page they've already visited, the cached version displays immediately. The page is also loaded from the server and displayed a short time later.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Clear the Cache Often
&lt;/h2&gt;

&lt;p&gt;Whenever your front-end persists anything, you should probably clear the cache. A straightforward way to cover a lot of these cases is to clear the cache whenever the front-end makes a POST request.&lt;/p&gt;

&lt;p&gt;In our case, 90% of these requests originate from Rails' UJS library. So we added the following event handler:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$(document).on('ajax:before', '[data-remote]', () =&amp;gt; {
  Turbolinks.clearCache();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Don't Expect a Clean DOM
&lt;/h2&gt;

&lt;p&gt;Turbolinks caches pages right before you navigate away from them. That's probably &lt;em&gt;after&lt;/em&gt; your JavaScript has manipulated the DOM.&lt;/p&gt;

&lt;p&gt;Imagine that you have a dropdown menu in its "open" state. If the user navigates away from the page and then comes back, the menu is still "open," but the JavaScript that opened it might be gone.&lt;/p&gt;

&lt;p&gt;This means that you have to either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write your JS so that it's unfazed by encountering the DOM elements it manipulates in an unclean state.&lt;/li&gt;
&lt;li&gt;When your component is "unloaded" make sure to return the DOM to an appropriate state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These requirements are easy to meet in &lt;em&gt;your&lt;/em&gt; JavaScript. However, they can be harder to meet with third-party libraries. For example, Bootstrap's modals break if Turbolinks caches them in their "open" state.&lt;/p&gt;

&lt;p&gt;We can work around the modal problem, by manually tidying the DOM before the page is cached. Below, we remove any open bootstrap modals from the DOM.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.addEventListener('turbolinks:before-cache', () =&amp;gt; {
  // Manually tear down bootstrap modals before caching. If turbolinks
  // caches the modal then tries to restore it, it breaks bootstrap's JS.
  // We can't just use bootstrap's `modal('close')` method because it is async.
  // Turbolinks will cache the page before it finishes running.
  if (document.body.classList.contains('modal-open')) {
    $('.modal')
      .hide()
      .removeAttr('aria-modal')
      .attr('aria-hidden', 'true');
    $('.modal-backdrop').remove();
    $('body').removeClass('modal-open');
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Remove all Javascript from the body
&lt;/h2&gt;

&lt;p&gt;Turbolinks runs any javascript it encounters in the body of your HTML. This behavior may sound useful, but it's an invitation to disaster.&lt;/p&gt;

&lt;p&gt;In "traditional" web apps, scripts placed in the body run precisely once. However, in Turbolinks, it could be run any number of times. It runs every time your user views that page.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do you have a third-party chat widget that injects a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag into the page? Be prepared to get 10, 50, 100 script tags injected.&lt;/li&gt;
&lt;li&gt;Do you set up an event handler? Be prepared to get 100 of them and have them stay active when you leave the page.&lt;/li&gt;
&lt;li&gt;Do you track page views with Google Analytics? Be prepared to have &lt;strong&gt;two&lt;/strong&gt; page views registered each time the user visits a cached paged. Why? Turbolinks first displays a cached version, then immediately displays a server-rendered version of the page. So for one "pageview," your page's inline JS runs twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem isn't just inline JavaScript. It's &lt;strong&gt;any&lt;/strong&gt; JavaScript placed in the document's body, even when loaded as an external file.&lt;/p&gt;

&lt;p&gt;So do yourself a favor and keep all JavaScript in the document's head, where it belongs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use JS Modules to Load Third-Party Widgets
&lt;/h2&gt;

&lt;p&gt;If you can't use inline JS to load your third-party widgets, how can you do so? Many, such as our own &lt;code&gt;honeybadger-js&lt;/code&gt; library provide npm packages that can be used to import them to webpack or another build tool. You can then import them and configure them in JS.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Here's how you can set up honeybadger-js inside webpack.
// Because the webpack output is included in the document head, this 
// will only be run once. 

import Honeybadger from 'honeybadger-js';

const config = $.parseJSON($("meta[name=i-honeybadger-js]").attr('content'));

Honeybadger.configure({
  api_key: this.config.key,
  host: this.config.host,
  environment: this.config.environment,
  revision: this.config.revision,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There are lots of ways you could pass data like API keys from the server. We encode them as JSON and put them in a meta tag that is present on every page.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%meta{name: "i-honeybadger-js", content: honeybadger_configuration_as_json}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sadly, some third-party services don't provide npm packages. Instead, they make you add a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag to your HTML. For those, we wrote a JS wrapper that injects the script into the dom and configures it.&lt;/p&gt;

&lt;p&gt;Here's an example of how we wrap the heroku widget for users who purchase our service as a Heroku add-on.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Heroku extends Components.Base {&lt;br&gt;
  // For every page load, see if heroku's JS is loaded. If not, load it.&lt;br&gt;
  // If so, reinitialize it to work with the reloaded page. &lt;br&gt;
  initialize() {&lt;br&gt;
    this.config = $.parseJSON(this.$el.attr('content'));&lt;br&gt;
    if (this.herokuIsLoaded()) {&lt;br&gt;
      this.initHeroku();&lt;br&gt;
    } else {&lt;br&gt;
      this.loadHeroku();&lt;br&gt;
    }&lt;br&gt;
  }

&lt;p&gt;herokuIsLoaded() {&lt;br&gt;
    return !!window.Boomerang;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;initHeroku() {&lt;br&gt;
    window.Boomerang.init({ app: this.config.app, addon: 'honeybadger' });&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;loadHeroku() {&lt;br&gt;
    const script = document.createElement('script');&lt;br&gt;
    script.type = 'text/javascript';&lt;br&gt;
    script.async = true;&lt;br&gt;
    script.onload = () =&amp;gt; this.initHeroku();&lt;br&gt;
    script.src =&lt;br&gt;
      '&amp;lt;&lt;a href="https://s3.amazonaws.com/assets.heroku.com/boomerang/boomerang.js&amp;gt;"&gt;https://s3.amazonaws.com/assets.heroku.com/boomerang/boomerang.js&amp;amp;gt;&lt;/a&gt;';&lt;br&gt;
    document.getElementsByTagName('head')[0].appendChild(script);&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Components.collection.register({&lt;br&gt;
  selector: 'meta[name=i-heroku]',&lt;br&gt;
  klass: Heroku,&lt;br&gt;
});&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Handle Asset Updates Gracefully&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Since Turbolinks is a single page application, active users may still be using an old copy of your JS and CSS after you deploy. If they request a page that depends on the new assets, you're in trouble.&lt;/p&gt;

&lt;p&gt;Fortunately, you can tell Turbolinks to watch for changes in asset file names, and do a hard reload whenever they change. This approach works well in Rails because your application CSS and JS typically have a content hash appended to their filenames.&lt;/p&gt;

&lt;p&gt;To enable this feature, we need to set the &lt;code&gt;data-turbolinks-track&lt;/code&gt; attribute on the appropriate &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags. With rails/webpacker, it looks like this:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;= stylesheet_pack_tag "application", "data-turbolinks-track": "reload"&lt;br&gt;
= javascript_pack_tag 'application', "data-turbolinks-track": "reload"&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Give to Turbolinks what belongs to Turbolinks&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Finally, realize that using Turbolinks involves giving up control of some things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can't manipulate the window location &lt;em&gt;in any way&lt;/em&gt; using JS without breaking Turbolinks. We had been saving the currently-selected tab state in the URL hash but had to get rid of it.&lt;/li&gt;
&lt;li&gt;Using jquery to fake clicks on links doesn't work. Instead, you should manually invoke &lt;code&gt;Turbolinks.visit&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I'm a fan of Turbolinks. We've discussed many edge cases here, but for the most part, it works very well out of the box.&lt;/p&gt;

&lt;p&gt;PJAX touched nearly every part of our front-end. Replacing something that central was never going to be painless. However, I have to say the migration went much more smoothly than I ever expected.&lt;/p&gt;

&lt;p&gt;We've been running it in production for several weeks now and have only had two minor bug reports. For the most part, it seems like nobody noticed the switch, which is my ideal outcome.&lt;/p&gt;

</description>
      <category>turbolinks</category>
      <category>pjax</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
