<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.2">Jekyll</generator><link href="http://shellscape.org/feed.xml" rel="self" type="application/atom+xml" /><link href="http://shellscape.org/" rel="alternate" type="text/html" /><updated>2023-01-16T02:11:47+00:00</updated><id>http://shellscape.org/feed.xml</id><title type="html">Shellscape Software</title><subtitle>Perceptions, Projects, and Software from the grey matter of Andrew Powell</subtitle><entry><title type="html">Plugin to a Fresh Webpack Development Server</title><link href="http://shellscape.org/2018/11/27/webpack-plugin-serve" rel="alternate" type="text/html" title="Plugin to a Fresh Webpack Development Server" /><published>2018-11-27T00:00:00+00:00</published><updated>2018-11-27T00:00:00+00:00</updated><id>http://shellscape.org/2018/11/27/webpack-plugin-serve</id><content type="html" xml:base="http://shellscape.org/2018/11/27/webpack-plugin-serve">&lt;p&gt;The developer experience is something that should be continuously improved upon. It is after all, just as important to the daily lives of developers as the user experience is to end-users of our efforts. For bundlers, a great development server and the experience that goes along with one is crucial.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;Nearly a year ago, I sat down to try and remedy the development server experience for &lt;a href=&quot;https://www.npmjs.com/package/webpack&quot;&gt;Webpack&lt;/a&gt; by authoring webpack-serve. The &lt;em&gt;&lt;a href=&quot;https://www.npmjs.com/package/webpack-serve&quot;&gt;webpack-serve&lt;/a&gt;&lt;/em&gt; project was meant to be a complete replacement for &lt;em&gt;webpack-dev-server&lt;/em&gt;; a project that suffers from oodles of quirks and edge cases, development stagnation, extreme legacy support requirements, and an aging architecture increasingly difficult to maintain. Unfortunately, what started as an effort to simplify with &lt;em&gt;webpack-serve&lt;/em&gt; was revealed to have its own shortcomings. It was too large a departure from what devs had come to expect, many concepts behind it were too abstract, and it just tried to be too fancy. Following a handoff to the Webpack organization, it was sadly, immediately deprecated. &lt;em&gt;(For users of webpack-serve, the project is now being maintained on &lt;a href=&quot;https://github.com/shellscape/webpack-serve&quot;&gt;this fork&lt;/a&gt;.)&lt;/em&gt; For all of its faults, &lt;em&gt;webpack-serve&lt;/em&gt; was still a step above &lt;em&gt;webpack-dev-server&lt;/em&gt;, and was a step in the right direction.&lt;/p&gt;

&lt;p&gt;From all that has emerged &lt;a href=&quot;https://github.com/shellscape/webpack-plugin-serve&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-plugin-serve&lt;/code&gt;&lt;/a&gt; - A Development Server fully-contained in a Webpack plugin.&lt;/p&gt;

&lt;h2 id=&quot;code-cadre-confab&quot;&gt;Code Cadre Confab&lt;/h2&gt;

&lt;p&gt;Unbeknownst to me there was a solid chunk of users who enjoyed what webpack-serve was trying to accomplish. In late September I was approached by a few talented Brazilian developers who were super bummed about Webpack’s decision to shutter webpack-serve. Their idea was to, at the least, fork and maintain webpack-serve. For their taste, webpack-serve was a better choice than webpack-dev-server, despite its own set of quirks. And so we talked about how a fork might look. The idea quickly emerged that this could be a platform to launch a standard experience for many bundlers, not just restricted to Webpack, and it could be accomplished within a plugin.&lt;/p&gt;

&lt;p&gt;Targeting Webpack was the most logical starting point. We had a lot of accumulated knowledge about how a server should and shouldn’t interact with Webpack compilers and bundles, and of maintaining webpack-dev-server and authoring webpack-serve. Between that and the real-world, day-to-day user perspective that Matheus and Sibelius were able to provide, we were able to create something really great. Much of this plugin is just “plumbing,” but it’s how that plumbing is arranged that makes this project a stand-out in the space.&lt;/p&gt;

&lt;p&gt;Our contributing team on this effort consists of:&lt;br /&gt;
  &lt;a href=&quot;https://twitter.com/bebraw&quot;&gt;@bebraw&lt;/a&gt;&lt;br /&gt;
  &lt;a href=&quot;https://twitter.com/sseraphini&quot;&gt;@sseraphini&lt;/a&gt;&lt;br /&gt;
  &lt;a href=&quot;https://twitter.com/matheus1lva&quot;&gt;@matheus1lva&lt;/a&gt;&lt;br /&gt;
  &lt;a href=&quot;https://twitter.com/shellscape&quot;&gt;@shellscape&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(And let me just say how great working with those folks it is! Please give them a follow.)&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;scintillatingly-savory&quot;&gt;Scintillatingly Savory&lt;/h2&gt;

&lt;p&gt;If you’re new to Webpack, it would be a great move to read up on &lt;a href=&quot;https://webpack.js.org/concepts/plugins/&quot;&gt;how to use Plugins&lt;/a&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-plugin-serve&lt;/code&gt; is a Webpack Plugin, a self-contained development server triggered by a Webpack build, and part of the Webpack process. Users must add an instance of the plugin to their Webpack configuration. A configuration might look something like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;WebpackPluginServe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Serve&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;webpack-plugin-serve&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
		&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;app.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;webpack-plugin-serve/client&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// ← important: this is required, where the magic happens in the browser&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Serve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// ← important: webpack and the server will continue to run in watch mode&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When a Webpack build is initiated, the plugin sets itself up. That includes a &lt;a href=&quot;https://koajs.com&quot;&gt;Koa&lt;/a&gt; application, built-in and user-defined middleware is setup, and a few other static goodies that need to be ready to go down the line. Once a build starts, a web server is spun up and attached to the Koa application, a &lt;a href=&quot;https://github.com/websockets/ws&quot;&gt;WebSocket server&lt;/a&gt; instance is attached to the web server, and the plugin begins listening to the compiler instance for notification of a refreshed build. If Hot Module Replacement is enabled, it’ll communicate changes via WebSocket to the client/browser and you’ll see changes based on the options passed to the plugin.&lt;/p&gt;

&lt;p&gt;There are a myriad of different &lt;a href=&quot;https://github.com/shellscape/webpack-plugin-serve/blob/master/README.md#options&quot;&gt;options&lt;/a&gt; available to configure and use the server. We’ve also &lt;a href=&quot;https://github.com/shellscape/webpack-plugin-serve/tree/master/recipes&quot;&gt;prepared a few recipes&lt;/a&gt; that users can reference to get started, and we’re keen to add more.&lt;/p&gt;

&lt;h2 id=&quot;decidedly-different&quot;&gt;Decidedly Different&lt;/h2&gt;

&lt;p&gt;First and foremost, it’s a plugin. Before starting development to we searched quite a bit to try and find a pre-existing, similar solution. We believe this is a novel approach for Webpack. As a plugin it doesn’t have the learning curve of a separate Command Line Interface and there are no subsets of flags to learn or understand to use it. Plugins are one of the first things that new Webpack users learn about - a perfect entry-point for a bolt-on development server. And by leveraging the compiler directly the server can offload responsibilities, like file watching, to the compiler and can avoid reinventing the wheel, thus reducing complexity.&lt;/p&gt;

&lt;p&gt;Just as with webpack-serve, we chose to use WebSockets for server-client communication (the magic that enables Hot Module Replacement instructions in the client/browser). Unlike webpack-serve, we were able to leverage a new “serverless” WebSocket server implementation. We learned from webpack-serve that while the intention behind a secondary WebSocket server was good, it increased complexity and issues with very little benefit.&lt;/p&gt;

&lt;p&gt;We also took the approach of building in support for the most popular feature sets of the other two development server options. Only this time around, there’s no getting fancy with it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;User-defined and user-ordered middleware is available, though vastly simplified as compared to webpack-serve&lt;/li&gt;
  &lt;li&gt;Useful overlays for errors and warnings, and progress are included out of the box, and were developed using a somewhat-standardized approach, and have a sexy, uniform look and feel for a consistent experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;div align=&quot;center&quot;&gt;
	&lt;img height=&quot;244&quot; src=&quot;https://raw.githubusercontent.com/shellscape/webpack-plugin-serve/HEAD/assets/status-overlay.png&quot; alt=&quot;status overlay&quot; style=&quot;height: 244px !important&quot; /&gt;
&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Features like HTML History API Fallback, Proxying, and Compression have support baked in, though we differ in that options are passed straight through to the underlying dependencies. That makes use and documentation much easier for the end user, as there’s no intermediate layer to have to understand.&lt;/li&gt;
  &lt;li&gt;Built-in Troubleshooting for common errors:&lt;/li&gt;
&lt;/ul&gt;

&lt;div align=&quot;center&quot;&gt;
	&lt;img height=&quot;300&quot; src=&quot;https://raw.githubusercontent.com/shellscape/webpack-plugin-serve/HEAD/assets/404.png&quot; alt=&quot;status overlay&quot; style=&quot;height: 300px !important&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;I’d also argue that this approach is far cleaner than the others that preceded it. We’ve given a lot of consideration to how the feature set might be expanded and have put an architecture in place that should allow for new features to be supported without adding the kind of complexity that cripples maintainability. We learned quite a bit from the shortcomings of both webpack-dev-server and webpack-serve, and really made an effort to improve upon them.&lt;/p&gt;

&lt;p&gt;Lastly, and what is sure to be a slightly controversial choice, we chose to support only the &lt;a href=&quot;https://github.com/nodejs/Release&quot;&gt;Active LTS versions&lt;/a&gt; of Node, which is presently v8 and v10, and the &lt;em&gt;Current&lt;/em&gt; version (Node v11 as of this post date). We’ve covered why in our &lt;a href=&quot;https://github.com/shellscape/webpack-plugin-serve/blob/master/.github/FAQ.md&quot;&gt;FAQ&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;forthright-finale&quot;&gt;Forthright Finale&lt;/h2&gt;

&lt;p&gt;Moving forward we’re open to adding more features, or developing the modules to provide pass-through features, as use-cases arise. The Node server space is so rich in functionality that we should be able to easily expand &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-plugin-serve&lt;/code&gt;or, most importantly, provide excellent direction for how users can apply needed functionality, easily. Aside from that, the stack is pretty solid. I’m sure the Webpack user-base will surprise us with scenarios we haven’t considered.&lt;/p&gt;

&lt;p&gt;We’re just a few developers hoping to provide a better experience for everyone, and would really appreciate folks spreading the word about it. Please don’t hesitate to open an issue or hit us up on Twitter. And if you’d like to help us improve the project, please consider &lt;a href=&quot;https://github.com/shellscape/webpack-plugin-serve&quot;&gt;contributing&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Ice Skating Waiter image, via &lt;a href=&quot;http://historydaily.org/ice-skating-cocktail-waiters&quot;&gt;http://historydaily.org/ice-skating-cocktail-waiters&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</content><author><name></name></author><category term="webpack" /><category term="development" /><category term="server" /><category term="open source" /><category term="npm" /><category term="module" /><summary type="html">The developer experience is something that should be continuously improved upon. It is after all, just as important to the daily lives of developers as the user experience is to end-users of our efforts. For bundlers, a great development server and the experience that goes along with one is crucial.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/plugin-fresh-dev.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/plugin-fresh-dev.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How Webpack and JSF Stole Code, Returned It, and Assigned Bad Copyright</title><link href="http://shellscape.org/2018/11/03/webpack-jsf-cla" rel="alternate" type="text/html" title="How Webpack and JSF Stole Code, Returned It, and Assigned Bad Copyright" /><published>2018-11-03T00:00:00+00:00</published><updated>2018-11-03T00:00:00+00:00</updated><id>http://shellscape.org/2018/11/03/webpack-jsf-cla</id><content type="html" xml:base="http://shellscape.org/2018/11/03/webpack-jsf-cla">&lt;p&gt;Or, &lt;em&gt;Why You Should be Dubious About Contributor License Agreements&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In a corner of the webpack ecosystem lives a small, mostly unnoticed module: &lt;a href=&quot;https://github.com/webpack-contrib/webpack-log&quot;&gt;webpack-log&lt;/a&gt;. webpack is a JavaScript Foundation project and contributions to webpack are subject to the JSF Contributor License Agreement (CLA). In August 2018, a webpack-contrib admin copied code from one of my modules into that project wholesale, verbatim, and without retaining the license. This is a short cautionary story of my efforts trying to get that corrected.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;em&gt;It is likely that this post will be attacked by those passionate about webpack and by those in the organization who dislike me personally. There are many good people whose livelihoods depend upon webpack, the organization, and the donations it receives. If you or your company are donating to the project, &lt;strong&gt;please&lt;/strong&gt; continue to do so. However, if you feel the information in this post demands improvement of the organization, please ask them to do better.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I do not like the spotlight in tech, and I do not seek it. However, I do feel that the information in this post needs to be shared. This post will not name names and will not call out individuals for action, or a lack thereof. Rather, already public information will speak for those involved.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (Nov 3rd 2018 23:12 UTC): Since posting and sharing this article, the webpack project has &lt;a href=&quot;https://github.com/webpack-contrib/webpack-log/pull/14&quot;&gt;taken steps to remedy the situation&lt;/a&gt;. It’s regrettable that it took this article to gain action, but it is appreciated. I don’t have knowledge as to whether or not JSF had a part in the remedy. This article should still serve as a cautionary tale on licensing, copyright, and Contributor License Agreements.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;backstory&quot;&gt;Backstory&lt;/h2&gt;

&lt;p&gt;I want to quickly share some backstory that I have not shared publicly prior, so that the issue, situation, and links contained in this post have some context for the reader.&lt;/p&gt;

&lt;p&gt;In mid June of 2017 I was contacted by webpack leadership to assist on an &lt;a href=&quot;https://github.com/webpack/webpack-dev-server/pull/942&quot;&gt;emergency fix&lt;/a&gt; for a somewhat serious &lt;a href=&quot;https://medium.com/@mikenorth/webpack-preact-cli-vulnerability-961572624c54&quot;&gt;SSL security flaw in webpack-dev-server&lt;/a&gt;, because I had made some prior contributions to that project. Shortly thereafter I was invited to be a maintainer and, following that a webpack-contrib admin and webpack core team member. I was also introduced to the contributor payment program at the time and actively participated. As a new husband with our first child on the way, that program was massively helpful in starting our new family and I benefited from it.&lt;/p&gt;

&lt;p&gt;I created a bunch of new modules for the webpack community in webpack-contrib, and made a concerted effort to challenge the status quo in the project and in the User Experience. One of those modules happened to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-log&lt;/code&gt;. To quote a favorite movie, &lt;em&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8kcgosLwPDE&amp;amp;t=10s&quot;&gt;“I fight for the users”&lt;/a&gt;&lt;/em&gt;. But I was naive. I pushed too hard, too fast and vastly underestimated the deep nepotism and significant hero-worship that exists in the webpack organization. The culmination of which occurred at the same time the organization started to run out of funding, forcing in a change in how donations were allocated and distributed that I vehemently disagreed with. As a core team member, it was my responsibility to make my dissent known. A later, ill-fated effort I undertook to replace the default CLI for webpack resulted in poor communication within the core team, poor decisions by leadership, and was ultimately the straw that convinced me to walk away from the team.&lt;/p&gt;

&lt;p&gt;Communication from my end was not perfect. I can be brash, passionate, and have a deep sense of pride and ownership in code that I write. I acknowledge my flaws. Despite 18 months of dedication and work, several new projects for the benefit of users, and huge gains for the webpack user experience, I was subsequently accused of violating a non-existent Code of Conduct, cheating users and the project, labeled a thief, a poor developer, and &lt;a href=&quot;https://github.com/webpack-contrib/webpack-log/issues/11#issuecomment-423636767&quot;&gt;toxic&lt;/a&gt; by most of the organization’s members. Those members who disagreed did not speak publicly in my defense.&lt;/p&gt;

&lt;p&gt;I was shunned, an outcast - &lt;strong&gt;open dissent is not welcome in webpack.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;enter-webpack-log&quot;&gt;Enter webpack-log&lt;/h2&gt;

&lt;p&gt;I got involved in webpack because it was starting to be used by the company I was working for at the time. I was aghast as just &lt;em&gt;how bad&lt;/em&gt; the user experience for webpack was. In December 2017 I put together webpack-log to try and give some consistency to the log output webpack and ecosystem tools were generating, and to make my eyes bleed a little less while using it.&lt;/p&gt;

&lt;p&gt;Just prior, I had created &lt;a href=&quot;https://github.com/shellscape/loglevelnext&quot;&gt;loglevelnext&lt;/a&gt;, which was at the time a fork of the still much-loved and wildly-popular &lt;a href=&quot;https://github.com/pimterry/loglevel&quot;&gt;loglevel&lt;/a&gt;. I forked because at the time I had proposed changes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loglevel&lt;/code&gt; that the maintainer couldn’t agree with. (I love open source for that!). loglevelnext was a project created for work and used primarily by colleagues internally on development environments. I leveraged loglevelnext in webpack-log as a dependency. The feature set was apt and it suited the goals I had for webpack-log both in the console and in the browser.&lt;/p&gt;

&lt;p&gt;And so, webpack-log went on to be used in the new webpack-contrib projects I created, webpack modules I maintained, and in several third-party modules, and it sat quietly in the corner.&lt;/p&gt;

&lt;h2 id=&quot;curiously-copied-code&quot;&gt;Curiously Copied Code&lt;/h2&gt;

&lt;p&gt;Now, I’m not a whore for download counts, but I do check in on them from time to time out of curiosity and for various other reasons. In September, a month after the copy commit to webpack-log, I noticed a steep drop in loglevelnext downloads, and that webpack-log was no longer a dependent of the module. Naturally; I investigated.&lt;/p&gt;

&lt;p&gt;Following my falling-out with the webpack organization, nearly all of the projects I contributed were marked &lt;em&gt;[DEPCRECATED]&lt;/em&gt;, users were notified they were now unmaintained, and code I had contributed was summarily &lt;a href=&quot;https://github.com/webpack-contrib/schema-utils/pull/25&quot;&gt;erased from git history&lt;/a&gt; altogether. In that same month, loglevelnext was &lt;a href=&quot;https://github.com/webpack-contrib/webpack-log/commit/b5c2017e45b013a1b4c9e09694fc120afc3a307a&quot;&gt;copied wholesale into webpack-log&lt;/a&gt;, and removed as a dependency. Weird, but OK.&lt;/p&gt;

&lt;p&gt;But not OK. My license for loglevelnext wasn’t retained. My code was effectively stolen. A curious event given the previously mentioned deprecation and git history rewrites.&lt;/p&gt;

&lt;p&gt;I immediately thought about filing a DCMA. I would have been well within my right to do so, but that would ultimately hurt the users. Instead, I cringed and decided to open an issue.&lt;/p&gt;

&lt;h2 id=&quot;the-issue&quot;&gt;The Issue&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/webpack-contrib/webpack-log/issues/11&quot;&gt;Github issue&lt;/a&gt; started out plainly enough. Surprising, the organization’s own members weren’t even on the same page as to how the license should be attributed, or whether a standard MIT license could be used with the JavaScript Foundation’s Contributor License Agreement. The maintainer behind the copy commit &lt;em&gt;tried&lt;/em&gt; to make it right by &lt;a href=&quot;https://github.com/webpack-contrib/webpack-log/pull/12&quot;&gt;adding my name&lt;/a&gt; to the project’s LICENSE file, but bungled the attempt. By adding my name to that license file in the way done, they had granted me (and another individual) copyright over the &lt;em&gt;entire project&lt;/em&gt;. One might think that’s no big deal, and in the grand scheme of things it’s probably not - but it isn’t correct licensing. What should have been done instead, would have been to include the LICENSE file from loglevelnext in the directory of the copied code. That would have limited my copyright to only my code. Alternatively, they could have pasted the copyright as a header in the file in question.&lt;/p&gt;

&lt;p&gt;The crux of the situation now is that by copying loglevelnext into the webpack-log project, effectively hard-forking and adopting the project under JSF-owned webpack-contrib, the user asserted that they could &lt;strong&gt;circumvent the JSF adoption process&lt;/strong&gt; by copying MIT-licensed code into a project and submitting the code under a CLA.&lt;/p&gt;

&lt;p&gt;To &lt;a href=&quot;https://github.com/webpack-contrib/webpack-log/issues/11#issuecomment-423500502&quot;&gt;quote&lt;/a&gt; a &lt;a href=&quot;https://github.com/webpack-contrib/webpack-log/issues/11#issuecomment-423573438&quot;&gt;JSF board member&lt;/a&gt; in the issue:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The JS Foundation has &lt;a href=&quot;https://github.com/JSFoundation/TAC/blob/master/Project-Lifecycle.md#applying-to-join&quot;&gt;a process&lt;/a&gt; for adopting projects. Copying the code into a JSF-supported organization while removing the old license (or inserting the JSF license) is definitely not the process. To ensure that we have the legal rights to the software, we need the author(s) to transfer ownership.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;What seems to have happened here is that a large amount of someone else’s code was copied from an outside project to this one without attribution, and without the license specified in their code. So now it de-facto appears to have the JSF license (since it’s in this repo) but is not code licensed to the JSF. You can’t avoid having the JSF adopt someone else’s project by copying the whole project source code into yours.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that’s where the MIT license and the JSF CLA get really, really murky. After that the issue gets testy.&lt;/p&gt;

&lt;p&gt;I admit; I was snarky in my final reply before the issue was closed. I should have done better there. I have real trouble abiding false statements about myself, and having someone so completely naive about the situation misrepresenting my intentions. Unfortunately, after that exchange, naming-calling by an organization member ensued and the issue was closed and locked (notably without rebuke). The result of that issue was a ban from webpack and webpack-contrib organization repositories.&lt;/p&gt;

&lt;p&gt;The copyright issue however persists, and the webpack/webpack-contrib organization’s members have not addressed it further.&lt;/p&gt;

&lt;h2 id=&quot;legal-eagles&quot;&gt;Legal Eagles&lt;/h2&gt;

&lt;p&gt;After being summarily banned by both webpack and webpack-contrib organizations, I took my grievances to the next logical recourse: JavaScript Foundation’s legal department. Since webpack is a JSF project, I thought their legal department should surely be able to remedy this, given that one of their members are in support of a resolution.&lt;/p&gt;

&lt;p&gt;Everyone I conversed with in JSF’s legal department was extremely polite and communication was excellent. That’s pretty much where the positive experience ended. After a month of inaction, I contacted them to let them know of my intention to write this article. Purely as a courtesy and stated as much. A few days later, a new representative for their outside counsel contacted me and stated that some responsibilities had changed hands. They asked for more time and I enthusiastically granted it; I had thought an additional week would be plenty. But after nearly  two weeks passed with no visible action, nor resolution, nor statement of position from JSF, I have to consider the interaction with JSF a failure. Unfortunately, &lt;a href=&quot;https://twitter.com/scott_gonzalez/status/1048220377934155778&quot;&gt;concerns shared&lt;/a&gt; about inaction from JSF legal seem to prove true.&lt;/p&gt;

&lt;p&gt;Given that JSF ultimately holds authority over code contributed under the CLA, this should be a cause for some concern about copyright and the enforcement of the CLA and how it, and your contributions under it, will be handled by JSF and projects belonging to it, moving forward.&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In Closing&lt;/h2&gt;

&lt;p&gt;Be dubious about signing a Contributor License Agreement. Be especially dubious about signing one in which the organization members don’t fully understand their own CLA, and about which the organization who owns the CLA won’t act upon it.&lt;/p&gt;

&lt;p&gt;I’ve since moved most of my personal projects to the copy-left &lt;a href=&quot;https://www.mozilla.org/en-US/MPL/2.0/&quot;&gt;Mozilla Public License&lt;/a&gt;, which should (hopefully) help to prevent this kind of scenario in the future within any project underneath the JavaScript Foundation.&lt;/p&gt;

&lt;p&gt;And finally, if any of my own code or repositories are in violation of copyright or have failed to cite or include license correctly, please &lt;a href=&quot;https://github.com/shellscape/meta/issues/new&quot;&gt;let me know&lt;/a&gt; and it shall be remedied quickly.&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Printing Press Image By African American Photographs Assembled for 1900 Paris Exposition [Public domain], via &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Printing_with_printing_presses_at_Claflin_University,_Orangeburg,_S.C._LCCN93506648.jpg&quot;&gt;Wikimedia Commons&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</content><author><name></name></author><category term="webpack" /><category term="node.js" /><category term="open source" /><category term="npm" /><category term="module" /><category term="extend" /><summary type="html">Or, Why You Should be Dubious About Contributor License Agreements. In a corner of the webpack ecosystem lives a small, mostly unnoticed module: webpack-log. webpack is a JavaScript Foundation project and contributions to webpack are subject to the JSF Contributor License Agreement (CLA). In August 2018, a webpack-contrib admin copied code from one of my modules into that project wholesale, verbatim, and without retaining the license. This is a short cautionary story of my efforts trying to get that corrected.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/webpack-jsf-cla.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/webpack-jsf-cla.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Webpack, Now With Extended Flavor!</title><link href="http://shellscape.org/2018/07/02/webpack-now-with-extended-flavor" rel="alternate" type="text/html" title="Webpack, Now With Extended Flavor!" /><published>2018-07-02T00:00:00+00:00</published><updated>2018-07-02T00:00:00+00:00</updated><id>http://shellscape.org/2018/07/02/webpack-now-with-extended-flavor</id><content type="html" xml:base="http://shellscape.org/2018/07/02/webpack-now-with-extended-flavor">&lt;p&gt;&lt;em&gt;Warning: GIFs and pop-culture references incoming&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’m just crazy psych’d to announce a new feature available to users of
&lt;a href=&quot;https://www.npmjs.com/package/webpack-command&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-command&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://www.npmjs.com/package/webpack-serve&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt;&lt;/a&gt;. Like,
&lt;a href=&quot;https://twitter.com/ken_wheeler/status/1013206931207524357&quot;&gt;Ken Wheeler in a crisp new pair of America short-shorts&lt;/a&gt;
excited.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;img src=&quot;http://www.bioexamples.com/wp-content/uploads/2018/04/van-wilder-quotes-je3t81qpbjqbywdduxt1zm9nj2q_.gif&quot; alt=&quot;zooom&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A webpack configuration file can now extend the properties and collections from
other sharable or common configurations, and can be done right in the config
&lt;em&gt;without&lt;/em&gt; installing any additional plugins, modules, or utilities.&lt;/p&gt;

&lt;p&gt;The premise here is the same as you’ll find in
&lt;a href=&quot;https://eslint.org/docs/user-guide/configuring#extending-configuration-files&quot;&gt;ESLint&lt;/a&gt;
and we make no bones about stating that this feature was modeled after ESLint and
how that project manages extending configs. The concept of a sharable config
directly supported in this manner by a tool goes at least as far back as
&lt;a href=&quot;https://eslint.org/blog/2015/05/eslint-0.21.0-released&quot;&gt;ESLint 0.21.0&lt;/a&gt; in May
of 2015. That’s a while back, and there are certainly early examples. It’s about
time that landed for webpack users.&lt;/p&gt;

&lt;h2 id=&quot;the-chimi-effing-changas&quot;&gt;The Chimi-Effing-Changas&lt;/h2&gt;

&lt;p&gt;So here’s how this works - Take a super bare-bones base config:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;development&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;kinds&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;webpack&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And a config that we want to inherit (or extend from) our base config:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;batman&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BatmanWebpackPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And you ✨magically✨ end up with:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;batman&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;development&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BatmanWebpackPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;webpack&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;OMG that’s so incredible and underwhelming!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.reactiongifs.com/r/but-why.gif&quot; alt=&quot;but why&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s say that you work for a company that maintains a Software As A Service
application that’s customized per-client and requires slightly different builds,
which are deployed to their own instance. (“Sales Engineers” encounter this
often). You might find yourself in the less-than-ideal situation of a base
webpack configuration that ends up being copied and pasted, and then tweaked
just a tad in each copy, for each client. Now you’ve got the same build logic
spread all over digital-hell and back. Messy.&lt;/p&gt;

&lt;p&gt;Introduce a sharable config, complexity is instantly reduced, and the client
configs now only appear to contain only what needs to be customized.&lt;/p&gt;

&lt;h2 id=&quot;alternatives-and-existing-solutions&quot;&gt;Alternatives and Existing Solutions&lt;/h2&gt;

&lt;p&gt;As mentioned before, the concept at its core is not new. A number of NPM modules
exist which perform similar functions. The most popular of which is
&lt;a href=&quot;https://www.npmjs.com/package/webpack-merge&quot;&gt;webpack-merge&lt;/a&gt;. Many others are
obscure and haven’t yet found the same kind of user base that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-merge&lt;/code&gt;
has developed. If you’d rather go with a module and some code around your config,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-merge&lt;/code&gt; is a great option and we wanted to make sure that project got a
shout out.&lt;/p&gt;

&lt;p&gt;We didn’t use an existing module to implement this, however. The reasons were
many, but the big ones were:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@webpack-contrib/config-loader&lt;/code&gt; already handled the task of resolving configs
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Functions&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promises&lt;/code&gt;, etc)&lt;/li&gt;
  &lt;li&gt;We found the reduce-right approach functionally superior and performant&lt;/li&gt;
  &lt;li&gt;Filtering approaches from other modules were more mature, but not as flexible,
and so we desired a different architecture to build on&lt;/li&gt;
  &lt;li&gt;Introducing config property examination for determining &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extents&lt;/code&gt; (base,
sharable configs) would have disrupted existing modules significantly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lobster-and-cracked-crab-for-everyone&quot;&gt;Lobster and Cracked Crab for Everyone&lt;/h2&gt;

&lt;p&gt;Shared or base configs can also extend other configs, and those can extend yet
other configs, and so on, and so on. Recursive extending config happy fun time!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.giphy.com/media/5xtDarqlsEW6F7F14Fq/giphy.webp&quot; alt=&quot;billy valentine&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So along with infinitely recursive extendable configs, this feature also has the
ability to filter different portions of an extended config by different rules.
And of course you can control which filter rules to use. To use filters you’ll
have to specify your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'extends'&lt;/code&gt; slightly different:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;some&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You get the idea. Use an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'extends'&lt;/code&gt; instead of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; or
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;, and specify which filters to affect and what their filtering rule
should be. Boom. Done.&lt;/p&gt;

&lt;p&gt;The existing filters can perform a rudimentary de-dupe on
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module.rules&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugins&lt;/code&gt;. The default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rules&lt;/code&gt; filter compares &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module.rule&lt;/code&gt;
tests and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugins&lt;/code&gt; filter has the ability to filter on plugin &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constructor&lt;/code&gt;
name. You can read more about filtering
&lt;a href=&quot;https://github.com/webpack-contrib/config-loader/blob/master/docs/EXTENDS.md#filtering-properties-and-collections&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Presently there are only two filters &lt;em&gt;but we really want to add more based on
what you all need&lt;/em&gt;. We can’t emphasize that enough.&lt;/p&gt;

&lt;h2 id=&quot;have-fun-storming-the-castle&quot;&gt;Have Fun Storming the Castle&lt;/h2&gt;

&lt;p&gt;There’s no limit to what sharable configurations can look like, or how deeply
nested they can be. All-in-all this gives webpack users a lot more flexibility
and freedom when authoring many configs. So that’s fun.&lt;/p&gt;

&lt;p&gt;There’s also room for improvement, and the use-cases we had to work with to start
were limited, and we know that. That said, if this feature can be improved to
help you work with webpack a little bit easier or you have filter suggestions,
&lt;a href=&quot;https://github.com/webpack-contrib/config-loader/issues/new/choose&quot;&gt;please let us know&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.giphy.com/media/OzTUhZE7LXTig/giphy.webp&quot; alt=&quot;ok I'm done&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;</content><author><name></name></author><category term="webpack" /><category term="node.js" /><category term="open source" /><category term="npm" /><category term="module" /><category term="extend" /><summary type="html">Warning: GIFs and pop-culture references incoming I’m just crazy psych’d to announce a new feature available to users of webpack-command and webpack-serve. Like, Ken Wheeler in a crisp new pair of America short-shorts excited.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/flava-flav.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/flava-flav.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">webpack-serve Up a Side of Whoop-Ass</title><link href="http://shellscape.org/2018/02/12/webpack-serve-up-whoopass" rel="alternate" type="text/html" title="webpack-serve Up a Side of Whoop-Ass" /><published>2018-02-12T00:00:00+00:00</published><updated>2018-02-12T00:00:00+00:00</updated><id>http://shellscape.org/2018/02/12/webpack-serve-up-whoopass</id><content type="html" xml:base="http://shellscape.org/2018/02/12/webpack-serve-up-whoopass">&lt;p&gt;All aboard the S.S. Shipit. Come, break my things. I present 
&lt;a href=&quot;https://github.com/webpack-contrib/webpack-serve&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt;&lt;/a&gt;: 
A lean, modern, and flexible &lt;em&gt;webpack-dev-server&lt;/em&gt; alternative. And it’s 
gonna serve up a big ‘ol side of whoop-ass on your development experience for 
&lt;a href=&quot;https://webpack.js.org&quot;&gt;webpack&lt;/a&gt;.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;strong&gt;webpack-serve&lt;/strong&gt; is everything that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-dev-server@next&lt;/code&gt; was supposed to be,
in my mind anyhow. But &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-dev-server&lt;/code&gt; (&lt;em&gt;WDS&lt;/em&gt;) had one thing holding it up
that was always seen as a negative: over the years so many features were packed
into it, that it became a bit of a pill to maintain. Coupled with the inability
to embrace modern features, due in part to users with extreme legacy needs,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-dev-server&lt;/code&gt; is essentially stuck where it is.&lt;/p&gt;

&lt;p&gt;A new approach flips the script in a number of ways…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Don’t care about the backstory and just want the goods? Skip to
&lt;a href=&quot;#the-new-hotness&quot;&gt;The New Hotness&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;koa&quot;&gt;Koa&lt;/h3&gt;

&lt;p&gt;Gone is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;express&lt;/code&gt; and the unneeded complexity and heft of the module &lt;em&gt;in this
context&lt;/em&gt;. It was convenient, but lighter-weight alternatives weren’t available
when &lt;em&gt;WDS&lt;/em&gt; was conceived. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt; makes use of &lt;a href=&quot;http://koajs.com/&quot;&gt;Koa&lt;/a&gt;
and all of it’s bare-bones, greased lightning speed glory.&lt;/p&gt;

&lt;p&gt;To make things easy while working with Koa, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt; uses
&lt;a href=&quot;https://github.com/webpack-contrib/webpack-hot-client&quot;&gt;koa-webpack&lt;/a&gt; under the
hood, which handles wiring up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-dev-middleware&lt;/code&gt; and a new horse in the
race; &lt;a href=&quot;#webpack-hot-client&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-hot-client&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;api-first-design&quot;&gt;API-First Design&lt;/h3&gt;

&lt;p&gt;One of the long-standing gripes about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WDS&lt;/code&gt; was the fact that the API and the
CLI have never (maybe at one time?) been aligned. There are features that only
work on the CLI, options only supported by the CLI, and vise-versa. Not so with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt;. The CLI acts as a CLI should - as a gateway to the API.
Naturally there are some limitations as to what can be passed as an option via
the CLI, but there is alignment out of the gate none the less.&lt;/p&gt;

&lt;h3 id=&quot;webpack-hot-client&quot;&gt;webpack-hot-client&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/webpack-contrib/webpack-hot-client&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-hot-client&lt;/code&gt;&lt;/a&gt;
was explicitly written for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt; with the intention of ditching the
old &lt;em&gt;Hot Module Replacement&lt;/em&gt; client scripts contained within &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack&lt;/code&gt; proper to
make use of modern features in modern browsers. Namely &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebSocket&lt;/code&gt;. That does
mean that there are some user &lt;a href=&quot;#those-damn-gotchas&quot;&gt;limitations&lt;/a&gt;, but more on that later.&lt;/p&gt;

&lt;p&gt;Using this module also means we get some automatic sugar. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hot-client&lt;/code&gt; injects
the necessary client scripts &lt;em&gt;and&lt;/em&gt; webpack plugins required to enable &lt;em&gt;HMR&lt;/em&gt;. One
less thing the user has to handle.&lt;/p&gt;

&lt;h3 id=&quot;add-ons&quot;&gt;Add Ons&lt;/h3&gt;

&lt;p&gt;I mentioned earlier on that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WDS&lt;/code&gt; was a kitchen sink approach.
Add-ons seeks to balance the force as the opposite. It’s lean by nature and will
only ever contain the most common, most sought after features in a development
server. &lt;em&gt;But how you say?&lt;/em&gt; Teams of monkeys and hamsters painstakingly ran the
numbers. Educated guesses were made. In the future this may be backed up by
analytics and real numbers.&lt;/p&gt;

&lt;p&gt;And so, add-ons. The idea of an add-on for this server allows the user complete
control over the middleware, and the order of that middleware, should they so need.
Things like &lt;em&gt;compression, bonjour broadcasting, history api fallback, and request
proxying&lt;/em&gt; have no business as a core feature. Instead, the user can easily add
features to their server. Have a look at
&lt;a href=&quot;https://github.com/webpack-contrib/webpack-serve/tree/master/docs/addons&quot;&gt;some example add-ons&lt;/a&gt;
which duplicate many of the features found in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WDS&lt;/code&gt; that are omitted from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-new-hotness&quot;&gt;The New Hotness&lt;/h2&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt; is easier than taking down that first huge Tolberone you
bought when you were a kid because hey a big-ass prism of chocolatey goodness
was too good to pass up and you can’t like just eat half of it right?&lt;/p&gt;

&lt;h4 id=&quot;we-better-install-it-first&quot;&gt;We Better Install It First&lt;/h4&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;webpack-serve@next &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’re still in pre-release beta, this-could-go-sideways mode, so you’ll need
that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@next&lt;/code&gt; part.&lt;/p&gt;

&lt;p&gt;You can also install it globally, though it’s not recommended, and will use a
local install if one exists.&lt;/p&gt;

&lt;h4 id=&quot;cli&quot;&gt;CLI&lt;/h4&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;webpack-serve &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; configs/webpack.config.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;api&quot;&gt;API&lt;/h4&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;use strict&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;serve&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;webpack-serve&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./configs/webpack.config.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;serve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;those-damn-gotchas&quot;&gt;Those Damn Gotchas&lt;/h2&gt;

&lt;p&gt;The tagline for this project, &lt;em&gt;A lean, modern, and flexible webpack
development server&lt;/em&gt;, is revealing. We’ve covered &lt;em&gt;lean&lt;/em&gt; and &lt;em&gt;flexible&lt;/em&gt; but
there’s that &lt;em&gt;modern&lt;/em&gt; bit. The scripts injected into the client webpack bundle(s)
loaded by the server rely on browser-native &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebSocket&lt;/code&gt;. That means the minimum
browser requirements are tied to that feature support. This is a hard requirement,
and naturally will limit the user-base - those with the need to support the afore
mentioned legacy browsers won’t be able to leverage &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack-serve&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;go-on-get-you-some&quot;&gt;Go On, Get You Some&lt;/h2&gt;

&lt;p&gt;So that’s the gist, the long and the short of what this module is and why it
exists. Install it. Tinker. Break it. Open an
&lt;a href=&quot;https://github.com/webpack-contrib/webpack-serve/issues&quot;&gt;Issue&lt;/a&gt;, or even better,
a Pull Request. Make it go bananas.&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;</content><author><name></name></author><category term="webpack" /><category term="node.js" /><category term="open source" /><category term="npm" /><category term="module" /><category term="beta" /><summary type="html">All aboard the S.S. Shipit. Come, break my things. I present webpack-serve: A lean, modern, and flexible webpack-dev-server alternative. And it’s gonna serve up a big ‘ol side of whoop-ass on your development experience for webpack.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/webpack-serve.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/webpack-serve.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Signal to Bug Ratio</title><link href="http://shellscape.org/2017/04/24/signal-to-bug-ratio" rel="alternate" type="text/html" title="Signal to Bug Ratio" /><published>2017-04-24T00:00:00+00:00</published><updated>2017-04-24T00:00:00+00:00</updated><id>http://shellscape.org/2017/04/24/signal-to-bug-ratio</id><content type="html" xml:base="http://shellscape.org/2017/04/24/signal-to-bug-ratio">&lt;p&gt;&lt;em&gt;Preface: I work with Signal through my regular job, I’m not promoting the product
 or service in any way.&lt;/em&gt; &lt;a href=&quot;https://www.signal.co/&quot;&gt;Signal&lt;/a&gt; is a platform for
  implementing and managing tags and data for marketing, tracking, and affiliates.
  Debugging Signal events can be very problematic, exacerbated by a lack of tools,
  guidance on best practices, and engineering support.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;oodles-of-noise&quot;&gt;Oodles of Noise&lt;/h2&gt;

&lt;p&gt;Signal events are the de facto method for a client (a web page) to interact with
a signal implementation. Typically you bind an event to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window&lt;/code&gt; and use some
JavaScript to trigger an event on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window&lt;/code&gt; in the client. Sounds easy, yeah? If
you happen to work within an environment in which an engineering team doesn’t
manage and test data being sent along with these events, debugging that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eventData&lt;/code&gt;
can be far more difficult than it should be. There’s a simple solution to debugging
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eventData&lt;/code&gt; that introduces responsible patterns and ease of use, which go beyond
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;knowledge-gap&quot;&gt;Knowledge Gap&lt;/h2&gt;

&lt;p&gt;I’d like to say right-off-the-bat that my intentions in this section are not to
belittle anyone at Signal, but rather raise the flag about related gaps in knowledge
within Signal’s support team.&lt;/p&gt;

&lt;p&gt;If you approach Signal about a tag implementation, an error with a tag, or pretty
much any in-product code need, you’ll wind up talking with an “Implementation Consultant.”
For most basic questions and implementation needs, these folks do a good job helping
out. However, &lt;strong&gt;they are not &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_engineer&quot;&gt;engineers&lt;/a&gt;.&lt;/strong&gt; Rarely do we receive code from them, or
review code they’ve added to our Signal implementation, that would pass review
in any corner of our &lt;a href=&quot;http://tech.gilt.com&quot;&gt;engineering department&lt;/a&gt;. Again, this is not to knock their
skill level - they aren’t advertised as engineers. But it’s important to understand
the distinction, and important to consult engineers for architectural needs and
best-practice guidance.&lt;/p&gt;

&lt;h2 id=&quot;the-consolelog-conundrum&quot;&gt;The Console.log Conundrum&lt;/h2&gt;

&lt;p&gt;At one point in time, our Signal implementation went from being an engineering-first,
engineering-owned product, to a Marketing and Analytics owned product. Those
teams did a fine job using Signal to drive the associated sites forward with very
little JavaScript experience. However, their guidance was coming from non-engineers
as well, and at no fault of their own, &lt;a href=&quot;https://sourcemaking.com/antipatterns&quot;&gt;many anti-patterns were implemented&lt;/a&gt;.
One of the more egregious was the overuse of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our Signal managing teams were advised to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt; wherever they wanted
to view the value/content of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eventData&lt;/code&gt; for each event that came through Signal.
That resulted in &lt;strong&gt;&lt;em&gt;well over 50 instances&lt;/em&gt;&lt;/strong&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt; sprinkled throughout
just one of five Dashboards. That’s a hell of a lot of console noise for a single
page. Imagine engineers for the site trying to figure out where all the noise was
originating, having no knowledge of the Signal implementation nor what it was doing.
&lt;a href=&quot;https://www.youtube.com/watch?v=s8MDNFaGfT4&quot;&gt;Bananas&lt;/a&gt;!&lt;/p&gt;

&lt;h2 id=&quot;simple-engineering-save&quot;&gt;Simple Engineering Save&lt;/h2&gt;

&lt;p&gt;Since our implementation is not (yet!) engineering-owned, we can’t run tests and
such on the data in a pre-production environment. Some would argue that Signal has
some pre-production ability, but even “Previewing” tags and events still runs live
in production. So we needed a method for our Marketing and Analytics teams to be
able to debug in a familiar way (which is unfortunately &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt;) but in a
&lt;em&gt;controlled&lt;/em&gt; manner that doesn’t affect the world.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/shellscape/fdcd98aa743b683eb4539336b06200c9.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The idea is dead simple. Sprinkle &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bananas.signal.debug(...)&lt;/code&gt; all over, anywhere,
go bananas! It won’t output to the console until explicitly enabled. That can be
done in two ways; by adding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?debug=true&lt;/code&gt; to the URI and refreshing, or by calling
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bananas.signal.enable()&lt;/code&gt; in the console before executing an action on the page
that will trigger a Signal event.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/in-post/signal-debug-output.png&quot; alt=&quot;debug output&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Only the debugging user will ever see the output.
Zero console pollution.&lt;/p&gt;

&lt;h2 id=&quot;mind-bottling&quot;&gt;Mind Bottling&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;You know when things are so crazy it gets your thoughts all trapped, like in a bottle - &lt;a href=&quot;https://www.youtube.com/watch?v=rSfebOXSBOE&quot;&gt;Blades of Glory&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Signal consultants suggested a few variants on the same theme but over all their
solutions were either too similar, or too confusing for the non-engineer custodians
of our Signal implementation. It’s surprising that something similar and as simple
as this isn’t already part of Signal’s client library and available for folks
who are using the product without engineering support.&lt;/p&gt;

&lt;p&gt;Please feel free to use the script above in your implementation. Or, if you have
a better solution, please comment!&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;</content><author><name></name></author><category term="bright-tag" /><category term="events" /><category term="javascript" /><category term="marketing" /><category term="open source" /><category term="signal" /><category term="tagging" /><category term="tracking" /><summary type="html">Preface: I work with Signal through my regular job, I’m not promoting the product or service in any way. Signal is a platform for implementing and managing tags and data for marketing, tracking, and affiliates. Debugging Signal events can be very problematic, exacerbated by a lack of tools, guidance on best practices, and engineering support.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/signal-to-bug-ratio.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/signal-to-bug-ratio.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Strike a Harmony with Node.js and Harmonica</title><link href="http://shellscape.org/2017/04/05/strike-harmony-nodejs-harmonica" rel="alternate" type="text/html" title="Strike a Harmony with Node.js and Harmonica" /><published>2017-04-05T00:00:00+00:00</published><updated>2017-04-05T00:00:00+00:00</updated><id>http://shellscape.org/2017/04/05/strike-harmony-nodejs-harmonica</id><content type="html" xml:base="http://shellscape.org/2017/04/05/strike-harmony-nodejs-harmonica">&lt;p&gt;With every new version of Node.js, the platform quietly provides
 access to experimental features that ship with v8 which may not be quite ready
 for production use. That doesn’t mean we can’t use those features today, though.
 And there’s a nearly effortless way to access them.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;For those that may be new to Node.js or those who haven’t yet delved into the
inner workings of Node.js - the platform runs atop Google’s JavaScript engine,
&lt;a href=&quot;https://developers.google.com/v8/&quot;&gt;V8&lt;/a&gt; by default. V8 is constantly improving
and typically ships with features which may not be stable or ready for production
environments, that require command-line flags to enable. Those flags are the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt;
flags.&lt;/p&gt;

&lt;p&gt;Prior to Node.js v7.6, the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;asyc/await&lt;/a&gt;
feature - the feature I’d been most looking forward to - was locked behind
the&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--harmony-async-await&lt;/code&gt; flag. There’s a good likelihood that &lt;a href=&quot;https://www.chromestatus.com/feature/5365692190687232&quot;&gt;ES6 Modules&lt;/a&gt;
will arrive in much the same way.&lt;/p&gt;

&lt;h2 id=&quot;harmony-flags&quot;&gt;Harmony Flags&lt;/h2&gt;

&lt;p&gt;Determining what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt; flags are supported by a version of Node.js is easy:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;node &lt;span class=&quot;nt&quot;&gt;--v8-options&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;in progress&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For example, I’m currently on Node.js version 7.8. Running that command, the list
of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt; flags shows as follows:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;→ node &lt;span class=&quot;nt&quot;&gt;--v8-options&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;in progress&quot;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_array_prototype_values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony Array.prototype.values&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_function_sent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony function.sent&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_sharedarraybuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony sharedarraybuffer&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_simd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony simd&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_do_expressions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony do-expressions&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_restrictive_generators&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony restrictions on generator declarations&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_regexp_named_captures&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony regexp named captures&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_regexp_property&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony unicode regexp property classes&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_for_in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony for-in syntax&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_trailing_commas&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony trailing commas in function parameter lists&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--harmony_class_fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;harmony public fields in class literals&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;progress&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To enable a harmony flag, Node.js typically has to be run from the command-line
with the flag and the target entry script as such:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;node index.js &lt;span class=&quot;nt&quot;&gt;--harmony_array_prototype_values&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or to enable all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt; flags:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;node index.js &lt;span class=&quot;nt&quot;&gt;--harmony&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And that can just get tedious for tooling, cross-team development, etc.&lt;/p&gt;

&lt;h2 id=&quot;an-easy-instrument&quot;&gt;An Easy Instrument&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/harmonica&quot;&gt;Harmonica&lt;/a&gt; is an NPM Module that allows
developers to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--harmony&lt;/code&gt; flags programmatically, which means
an end to the need for specifying command-line options for experimental &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt;
features. If you’ve ever wanted to use experimental features within
&lt;a href=&quot;http://gulpjs.com/&quot;&gt;Gulp&lt;/a&gt; tasks, or have a need to run an app through wrappers
like &lt;a href=&quot;https://www.npmjs.com/package/forever&quot;&gt;forever&lt;/a&gt;, this module takes the
command-line headache out of the equation.&lt;/p&gt;

&lt;p&gt;Setting up Harmonica is painless. Within your entry file (index.js, app.js, etc)
place a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmonica&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;harmonica&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s the equivalent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node --harmony&lt;/code&gt;. Should you need only specific flags,
pass an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; of strings representing the flags you want to enable, without
the leading hyphens, as the first parameter.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;harmonica&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)([&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;harmony_function_sent&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;harmony_do_expressions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And from there, let the module handle initializing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt; flags you wish
to use, with no need to specify them within the terminal or command prompt.&lt;/p&gt;

&lt;h2 id=&quot;not-all-roses-and-rainbows&quot;&gt;Not All Roses and Rainbows&lt;/h2&gt;

&lt;p&gt;It’s really important to note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt; features are not production ready.
And as folks have &lt;a href=&quot;https://github.com/koajs/koa-hbs/pull/65&quot;&gt;pointed out&lt;/a&gt;, some
of the experimental / unstable features that are hidden behind &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt; flags
can come with issues that affect security, performance, etc. It’s never advisable
to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;harmony&lt;/code&gt; features in a production environment unless thoroughly vetted.&lt;/p&gt;

&lt;p&gt;Now get to dabbling with the latest that Node.js has to offer!&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;</content><author><name></name></author><category term="flags" /><category term="harmony" /><category term="node.js" /><category term="open source" /><category term="npm" /><category term="module" /><category term="v8" /><category term="experimental" /><summary type="html">With every new version of Node.js, the platform quietly provides access to experimental features that ship with v8 which may not be quite ready for production use. That doesn’t mean we can’t use those features today, though. And there’s a nearly effortless way to access them.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/harmonica-nodejs-v8.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/harmonica-nodejs-v8.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Floaties for Gulp Users</title><link href="http://shellscape.org/2017/01/08/floaties-for-gulp-users" rel="alternate" type="text/html" title="Floaties for Gulp Users" /><published>2017-01-08T00:00:00+00:00</published><updated>2017-01-08T00:00:00+00:00</updated><id>http://shellscape.org/2017/01/08/floaties-for-gulp-users</id><content type="html" xml:base="http://shellscape.org/2017/01/08/floaties-for-gulp-users">&lt;p&gt;In large or distributed teams, sharing knowledge about tooling can be a
 challenge. When a toolchain or pipeline gets to be big and contains a lot of
 code, that challenge grows with the size of the codebase. Providing a solution
 is as easy as describing your tasks.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;gulp-assist&quot;&gt;gulp-assist&lt;/h2&gt;

&lt;p&gt;I recently put together &lt;a href=&quot;https://www.npmjs.com/package/gulp-assist&quot;&gt;gulp-assist&lt;/a&gt;
as a tool to address that issue. An extension of sorts for
&lt;a href=&quot;https://www.gulpjs.com&quot;&gt;Gulp&lt;/a&gt;, gulp-assist displays meaningful information on
a tooling setup in a stylish format. How meaningful is completely up to the
developer providing it.&lt;/p&gt;

&lt;p&gt;What about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--tasks&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--tasks-simple&lt;/code&gt; flags that Gulp already has? Those
are great if one wants a basic idea of the structure of the tooling, but gives us
nothing if we want to know about the individual tasks.&lt;/p&gt;

&lt;h2 id=&quot;floaties-and-lifejackets&quot;&gt;Floaties and Lifejackets&lt;/h2&gt;

&lt;p&gt;That all sounds lovely, but what’s this thing look like?
&lt;a href=&quot;https://www.youtube.com/watch?v=K0nGwZfPLB0&quot;&gt;GIMME’DA CASSHHH!&lt;/a&gt;. As run in the terminal:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/shellscape/gulp-assist/blob/master/gulp-assist.png?raw=true&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And for each individual task including flags, and their descriptions:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/shellscape/gulp-assist/blob/master/gulp-assist-task.png?raw=true&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Is purty no?&lt;/p&gt;

&lt;h2 id=&quot;to-inflate-pull-down-on-the-tab&quot;&gt;To Inflate, Pull Down On The Tab&lt;/h2&gt;

&lt;p&gt;This thing really is &lt;a href=&quot;https://www.youtube.com/watch?v=HWrjBBXjjhM&amp;amp;t=1m3s&quot;&gt;easy to use&lt;/a&gt;,
and the few extra keystrokes it costs will undoubtedly save time down the road.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// initialize the module&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-assist&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)();&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;lint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;lint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Analyzes code for errors and convention violations.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Specifies a directory / module to inspect, within the `src` directory.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Define your tasks as per usual, then register the task with gulp-assist. It’s
&lt;strong&gt;important to note&lt;/strong&gt; that gulp-assist needs the task defined with Gulp before it
can be registered with gulp-assist. That’s an intentional design decision, but
I’m always &lt;a href=&quot;https://github.com/shellscape/gulp-assist/issues&quot;&gt;open to suggestions&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h2&gt;

&lt;p&gt;The great thing about Gulp is that there’s a slew of alternatives for any one
thing you might want to get done. With that, you might enjoy
&lt;a href=&quot;https://www.npmjs.com/package/gulp-help&quot;&gt;gulp-help&lt;/a&gt; more so than my extension.
It hooks the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp.task&lt;/code&gt; method to allow for additional parameters that
describe a task.&lt;/p&gt;

&lt;p&gt;I didn’t care for this approach as I prefer separation of
concerns and dislike modifying established API. I also prefer the output of
gulp-assist (but I’m obviously biased).&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;</content><author><name></name></author><category term="assist" /><category term="gulp" /><category term="help" /><category term="npm" /><category term="plugin" /><summary type="html">In large or distributed teams, sharing knowledge about tooling can be a challenge. When a toolchain or pipeline gets to be big and contains a lot of code, that challenge grows with the size of the codebase. Providing a solution is as easy as describing your tasks.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/floaties-for-gulp-users.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/floaties-for-gulp-users.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Pants Optional: Working Remotely</title><link href="http://shellscape.org/2016/11/28/pants-optional-working-remotely" rel="alternate" type="text/html" title="Pants Optional: Working Remotely" /><published>2016-11-28T00:00:00+00:00</published><updated>2016-11-28T00:00:00+00:00</updated><id>http://shellscape.org/2016/11/28/pants-optional-working-remotely</id><content type="html" xml:base="http://shellscape.org/2016/11/28/pants-optional-working-remotely">&lt;p&gt;I’ve been working remotely for nearly 7 years now, and I couldn’t imagine ever
 going into an office on a daily basis again. It’s a magical setup that affords
 incredible freedom, and far more responsibility. I love working remotely, and
 I’m going to share with you my strategy for working in my own, pants-optional
 office.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;blockquote&gt;
  &lt;p&gt;I could never work from home, I’d never get anything done.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s the response I typically get from anyone I’ve ever told about my setup.
I’ve come to acquire several key lessons and skills that make working remotely a
joy, so much so that I doubt I’ll ever again take employment where reporting to
an office is a requirement, if I can at all help it.&lt;/p&gt;

&lt;h2 id=&quot;never-say-never&quot;&gt;Never Say Never&lt;/h2&gt;

&lt;p&gt;The “I could never do it” response from folks isn’t surprising. The last thing
most of us want to do at home is think about work. In fact,
&lt;a href=&quot;https://hbr.org/2016/07/dont-take-work-stress-home-with-you&quot;&gt;many smart types will tell you&lt;/a&gt;
that it’s an unhealthy thing to do. And for those who work the typical &lt;em&gt;9 to 5&lt;/em&gt;
routine, I’d probably agree. But I live the software developer life, and I’ve
come to find a method that makes it very easy to be successful remotely.&lt;/p&gt;

&lt;h2 id=&quot;when-work-isnt-work&quot;&gt;When Work Isn’t Work&lt;/h2&gt;

&lt;p&gt;If work is work, you shouldn’t be doing it from home. I’m lucky enough to do something
that I’m fairly decent at, and that which I really enjoy. That’s really key.
Enjoying the work lets you turn on and off at will without contaminating your
home with “the office”. You’ll be able to let ideas flow throughout the day
and night. The official hours of your physical office will become more
guidelines, whereby you need to stay available, but that which you’re not
constrained by.&lt;/p&gt;

&lt;h2 id=&quot;pants-are-actually-optional&quot;&gt;Pants Are Actually Optional&lt;/h2&gt;

&lt;p&gt;Just don’t forget them if you’re planning on taking video conference meetings.
You don’t want to be that person that has to get up to shut the window and
inadvertently shows off those new adventurous undies.&lt;/p&gt;

&lt;p&gt;But in all seriousness, get comfortable. Choose a workspace that works best for
you. Remember that you’re not in an office! I personally choose to work from my
dining table with lots of light and fresh Florida air. Some of my peers prefer
a cordoned off basement office. Your workspace should be what keeps you the most
comfortable throughout the day.&lt;/p&gt;

&lt;p&gt;Part of a great workspace is surrounding yourself with things you love. My
kitchen is about 20 feet from my laptop - my inner fat kid loves that. That also
means that I have water and &lt;a href=&quot;https://www.youtube.com/watch?v=A14qyN0rVGA&quot;&gt;other beverages&lt;/a&gt;
readily accessible. I’ve also got a solid TV on the wall and typically have
Netflix going all day long. For me, some kind of white noise and the occasional
mental break in close proximity keeps me sane throughout the day.&lt;/p&gt;

&lt;h2 id=&quot;creature-feature&quot;&gt;Creature Feature&lt;/h2&gt;

&lt;p&gt;Get a pet! They’re an incredible stress reliever and amazing outlet for problem
solving. Don’t be afraid to be that crazy person who talks to their animals.
&lt;a href=&quot;https://scontent-atl3-1.cdninstagram.com/t51.2885-15/e35/14723445_1810525985861202_6702972046583791616_n.jpg&quot;&gt;Leelu&lt;/a&gt;
frequently helps me out in a mental bind.&lt;/p&gt;

&lt;h2 id=&quot;communicate-silly&quot;&gt;Communicate, Silly&lt;/h2&gt;

&lt;p&gt;Communication. Communication. Communication. You must go out of your way to
communicate with your peers, your supervisors, even the person working at the
reception desk in the office. There are reasons, of course:&lt;/p&gt;

&lt;h3 id=&quot;communication-builds-trust&quot;&gt;Communication Builds Trust&lt;/h3&gt;

&lt;p&gt;Trust in you from your peers is key, and while it would be grand if we were all
judged by our merits, many people can’t trust until there’s a base of
communication that’s usual and comfortable.&lt;/p&gt;

&lt;h3 id=&quot;communication-builds-rapport&quot;&gt;Communication Builds Rapport&lt;/h3&gt;

&lt;p&gt;Until you’re in the office and have the chance at in-person face time with
everyone you work with, you’re the faceless (or single faced avatar) internet
person who apparently gets paid by the same company bi-weekly. You may be fortunate
and work for a company that has access to video conferencing, but even then
you’re still a floating head in a window. Great communication builds a
familiarity with your peers that will ultimately aid in collaboration.&lt;/p&gt;

&lt;h3 id=&quot;frequent-communication-creates-value&quot;&gt;Frequent Communication Creates Value&lt;/h3&gt;

&lt;p&gt;Frequent communication is paramount. Vanishing for extended stretches of time
has a negative effect. Remember that you’re not in the office and people can’t
see what you’re up to. For all they know you’re out at the pool floating on a
giant inflatable swan. When you reach out throughout the day, you’re reminding
people that you’re there. When you share what you’re working on frequently,
you’re reminding people of the work you’re doing.&lt;/p&gt;

&lt;h2 id=&quot;hellooooooo&quot;&gt;Hellooooooo&lt;/h2&gt;

&lt;p&gt;Working remotely can sometimes &lt;a href=&quot;https://www.youtube.com/watch?v=eCdRFMp8Xwo&quot;&gt;feel like a scene&lt;/a&gt;
out of &lt;em&gt;28 Days Later&lt;/em&gt;. The feeling of isolation is something every remote worker
needs to combat on a daily basis. Sometimes it’s a slow day in the office, and
others it’s that the physical office is too busy. It’s easy in that frequent
situation to get discouraged, frustrated, or just plain bummed out. That’s a good
opportunity to step away and right your ship.&lt;/p&gt;

&lt;p&gt;Since us remotes are also neglected socializing throughout the day, make up for
that deficit when work is done for the day. I’m a social guy and staying in or
isolated for too long gets me stir-crazy. I make a concerted effort to socialize
after-hours. Befriend some bartenders or others that work outside the 9-to-5
cycle. If you’ve a family, visit with some neighbors or take the kiddies out for
something fun around other people.&lt;/p&gt;

&lt;h2 id=&quot;halt-and-catch-fire&quot;&gt;Halt, and Catch Fire&lt;/h2&gt;

&lt;p&gt;Take breaks. Take lunches. Take naps. Decline meetings. Run errands. Play with
the dog. Go for a walk. Go for a run. Get a hobby and indulge it. Watch an
episode of &lt;em&gt;The Walking Dead&lt;/em&gt;. Have an adult beverage if you feel the urge. I
personally never like to work for more than two hours straight. Halting keeps me
fresh and keeps me sane.&lt;/p&gt;

&lt;p&gt;Stopping and taking a breath is one of my keys to the gig. Those incredible
freedoms I mentioned earlier come into play here. Of course this depends on the
company you work for and the folks above or around you in the hierarchy, but
take advantage of the ability to do throughout the day what those in an office
aren’t able to. Just bear in mind that your responsibility to the work doesn’t
end. If you’re going to play a little hookey, remember to make time later to
cover your deliverables.&lt;/p&gt;

&lt;h2 id=&quot;expand-your-organizational-skills&quot;&gt;Expand Your Organizational Skills&lt;/h2&gt;

&lt;p&gt;When no one’s available to chat, you don’t always have the luxury of stopping
work and waiting. You’ll have to develop solid organizational skills that will
allow you to revisit things that need discussing, or to resume tasks that you’re
blocked on down the line. A great degree of self-management is necessary
regardless of the kind of management structure you’re working in. A cautious
level of independence will go a long way. You won’t always have the time or the
opportunity to discuss choices, problems, or solutions with your peers. Which
brings us to…&lt;/p&gt;

&lt;h2 id=&quot;peer-dependencies&quot;&gt;Peer Dependencies&lt;/h2&gt;

&lt;p&gt;(That’s an NPM pun, for the nerds reading this)&lt;/p&gt;

&lt;p&gt;Your peers are going to mean success or failure in a remote gig. When
interviewing, make sure you’re asking questions as well. You’ll want to interview
the folks doing the interviewing to make sure they know how to work with remote
developers. Some companies are freshly wading into hiring remotes, others are
seasoned, and yet others have no idea what they’re getting into. Management
should be on board with and see value in remote employees. It also helps to jump
into a gig with peers that have experience working with remotes. Talk to the
folks that will be managing you and your projects to get a feel for how they
expect to work with you. Never be afraid to share your ideas early on.&lt;/p&gt;

&lt;h2 id=&quot;time-for-a-whisky&quot;&gt;Time For a Whisky&lt;/h2&gt;

&lt;p&gt;I hope that the lessons I’ve learned can give others in or considering remote
work something to think about and help out if needed.&lt;/p&gt;

&lt;p&gt;If you’ve been thinking about remote work, there are a plethora of resources
that can help:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/RemoteTeams&quot;&gt;@RemoteTeams&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://cultivatenow.com/&quot;&gt;CultivateNow&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/lukasz-madon/awesome-remote-job&quot;&gt;Awesome Remote Jobs&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/jessicard/remote-jobs&quot;&gt;Remote-friendly companies&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://weworkremotely.com/&quot;&gt;WeWorkRemotely&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://remoteok.io/&quot;&gt;Remote OK&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://jobspresso.co/&quot;&gt;Jobspresso&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.workingnomads.co/jobs&quot;&gt;Working Nomads&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And those are just a few. Good luck!&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;</content><author><name></name></author><category term="career" /><category term="life" /><category term="remote work" /><category term="time management" /><category term="work life balance" /><summary type="html">I’ve been working remotely for nearly 7 years now, and I couldn’t imagine ever going into an office on a daily basis again. It’s a magical setup that affords incredible freedom, and far more responsibility. I love working remotely, and I’m going to share with you my strategy for working in my own, pants-optional office.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/pants-optional-working-remotely.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/pants-optional-working-remotely.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Rebuilding a Personal Brand</title><link href="http://shellscape.org/2016/11/18/rebuilding-a-personal-brand" rel="alternate" type="text/html" title="Rebuilding a Personal Brand" /><published>2016-11-18T00:00:00+00:00</published><updated>2016-11-18T00:00:00+00:00</updated><id>http://shellscape.org/2016/11/18/rebuilding-a-personal-brand</id><content type="html" xml:base="http://shellscape.org/2016/11/18/rebuilding-a-personal-brand">&lt;p&gt;Complacency. It’s the worst. Grab a coffee, we’re about to board the &lt;a href=&quot;https://i.chzbgr.com/full/1324739328/hC8866755/&quot;&gt;failboat&lt;/a&gt;. We all know that company brands are of paramount importance. But personal brands are often overlooked. They speak to your abilities, they’re a realtime, interactive, functional resume. And your brand speaks volumes about who you are. What happens when a personal brand falls by the wayside? I learned the hard way.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;blockquote&gt;
  &lt;p&gt;It’s never crowded along the extra mile. - Wayne Dyer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My personal brand peaked in 2012. I was working with/on the &lt;a href=&quot;https://jqueryui.com/&quot;&gt;jQuery UI&lt;/a&gt; project, I was attending events (thanks much in part to my employers at the time), I was doing some occasional speaking, and my online presence was never more prolific. And then it all went to shit.&lt;/p&gt;

&lt;h2 id=&quot;ground-up&quot;&gt;Ground Up&lt;/h2&gt;

&lt;p&gt;I started getting a modicum of notoriety in the Freeware space in the early 2000s with some Windows apps I had written, and it’s what landed me my first job out of college. I built shellscape.org around that, and used it as a landing for all of my projects. As I added more projects, I added a small blog to the site.&lt;/p&gt;

&lt;p&gt;It was really &lt;em&gt;“the jQuery Company”&lt;/em&gt; that helped build my brand the most. I was one of &lt;em&gt;those people&lt;/em&gt; who thought that Twitter was a passing fad and that the concept was silly. But the company asked assertively that I sign up and be active promoting the company’s work, and my own. They pushed me to speak at small gatherings and they got me going to conferences and talking to heavy hitters in the front end development space.&lt;/p&gt;

&lt;p&gt;I had solid Twitter followers. I had enough traffic to my site to pull in $200 a month in AdWords.&lt;/p&gt;

&lt;h2 id=&quot;ive-made-a-terrible-mistake&quot;&gt;I’ve Made a Terrible Mistake&lt;/h2&gt;

&lt;p&gt;At the crux of it, I became complacent. I moved on from the afore mentioned conference-enabling-employer to a really interesting startup, riding on the success of my previous position and my personal brand out in the open. It was a big pay raise and I was doing exactly the work I wanted to do. I was pumped.&lt;/p&gt;

&lt;p&gt;It was during the 9 month stint with the startup that I began to let my brand slip. I wasn’t writing blog posts, I wasn’t really contributing to any notable open source projects, I stopped working with jQuery UI. I stopped participating on Twitter in my field. I was happy with my job and my pay, and bought a tear-down investment home that sucked up every minute of my spare time. I was adulting, but I was neglecting the thing that got my career to where it was.&lt;/p&gt;

&lt;p&gt;Unfortunately the startup folded on a random Wednesday. I was not prepared for it. Fortunately, and &lt;em&gt;&lt;strong&gt;due in large part&lt;/strong&gt;&lt;/em&gt; to my visibility to peers in tech, I was quickly scooped up by a Twitter follower I had never spoken to prior. After a few weeks of interviews, and several competing offers, I started working at Gilt.&lt;/p&gt;

&lt;p&gt;I was again awarded an increase in benefits and I was doing insanely cool work. I mean the stuff that makes you want to skip sleep for a week, that makes eating seem like an inconvenience. And there again, I slipped into deeper complacency with regard to my brand.&lt;/p&gt;

&lt;h2 id=&quot;the-sky-is-falling&quot;&gt;The Sky is Falling&lt;/h2&gt;

&lt;p&gt;Gilt was always a tumultuous business; it’s well-documented on a myriad of business websites and blogs. In late 2015 the company underwent significant layoffs. &lt;em&gt;&lt;strong&gt;PANIC MODE&lt;/strong&gt;&lt;/em&gt;. Then in early 2016 Gilt was purchased by a larger corporation. Without going into detail - lots of people were &lt;em&gt;very&lt;/em&gt; unhappy.&lt;/p&gt;

&lt;p&gt;After sticking it out for the first quarter, I decided it was prudent to start looking at what was out there. I was really excited; there were great companies hiring at competitive salaries and even though the field for remote work was narrow (I’ve been working remotely since 2009) it looked like I was in good shape. Fast-forward two months and I was still looking. I’d been passed up by numerous companies. Some passed straight up, and for some I didn’t shine bright enough over other local candidates to warrant a hire. Let alone that I’d fallen into a maintenance culture with day-to-day work, which left me at a slight disadvantage as I wasn’t up and up with the latest tech. But I’d always been able to convince folks that I could pick up easily what I didn’t know (and I could/still can).&lt;/p&gt;

&lt;p&gt;There was a deficit somewhere, and I had to identify it.&lt;/p&gt;

&lt;h2 id=&quot;mirror-mirror&quot;&gt;Mirror Mirror&lt;/h2&gt;

&lt;p&gt;After a significant amount of reflection and speaking with peers, I zeroed in on three conditions that were affecting my hiring process:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I was way behind on the latest tech.&lt;/li&gt;
  &lt;li&gt;I had become awful at interviewing.&lt;/li&gt;
  &lt;li&gt;My personal brand was non-existent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now see, I hadn’t had to give a work example or perform a test project for evaluation - ever. Not a single time in my entire career before recently. Sure, I’ve done some live coding but that’s never been a big deal. All of a sudden companies are asking me to build projects for interviews. Only a few took the time to look through my Github account and the work there. I had lost my brand, I had lost the wow factor. Another odd anomaly was that I hadn’t received a single referral. Movement throughout my entire career had been through referrals.&lt;/p&gt;

&lt;p&gt;I wasn’t an attractive candidate. Nothing was making me stand out from the crowd. I didn’t seem like an authority on what companies wanted, because I’d become an authority only on proprietary tech within my current position. I lost the edge.&lt;/p&gt;

&lt;p&gt;And as such, I was cold-calling folks for interviews who had never heard of me, and who’s recruiting gatekeepers weren’t fluent in the work that I had been doing. Hell, some of them didn’t even know what a “remote employee” was.&lt;/p&gt;

&lt;h2 id=&quot;the-lessons-they-have-me&quot;&gt;The Lessons, They Have Me&lt;/h2&gt;

&lt;p&gt;I quit looking for new opportunities. I decided instead to use the time I usually reserved for movies or heading to the bar to instead create a foundation for rebuilding what I had lost. And so I spent a few weeks recreating this website. I realigned to treat it as a weekly priority. I talked to a ton of successful bloggers in a range of niches and got solid advice. I spoke with some creative types on how to create a unique feel for the site.&lt;/p&gt;

&lt;p&gt;I started publishing again. I started open sourcing and creating projects around segments of the work I was doing daily, and most importantly: whatever I was tinkering with on the side. I started posting to Twitter, LinkedIn, Medium, and Facebook. I got my ass into gear.&lt;/p&gt;

&lt;h2 id=&quot;important-things-are-important&quot;&gt;Important Things are Important&lt;/h2&gt;

&lt;p&gt;A personal brand in tech is so damned important. It’s a window into who you are and what you’re doing. It’s a launchpad for anyone who wants to get to know you, before you know, actually speaking to you first. It’s only been a few months and I’m already amazed how my work is making the rounds. It’s a small audience, but it’s an audience and I’m only going to continue to work to increase that.&lt;/p&gt;

&lt;p&gt;Don’t &lt;a href=&quot;https://www.youtube.com/watch?v=wl2uDi6Zju8&quot;&gt;be me with cable tv&lt;/a&gt;, don’t be this me. &lt;em&gt;&lt;strong&gt;If you don’t have an established brand, create one.&lt;/strong&gt;&lt;/em&gt; If you have one, maintain it!&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;</content><author><name></name></author><category term="career" /><category term="blog" /><category term="site" /><summary type="html">Complacency. It’s the worst. Grab a coffee, we’re about to board the failboat. We all know that company brands are of paramount importance. But personal brands are often overlooked. They speak to your abilities, they’re a realtime, interactive, functional resume. And your brand speaks volumes about who you are. What happens when a personal brand falls by the wayside? I learned the hard way.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/rebuilding-personal-brand.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/rebuilding-personal-brand.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Increasing Build IQ with Travis CI</title><link href="http://shellscape.org/2016/11/16/increasing-build-iq-travis-ci" rel="alternate" type="text/html" title="Increasing Build IQ with Travis CI" /><published>2016-11-16T00:00:00+00:00</published><updated>2016-11-16T00:00:00+00:00</updated><id>http://shellscape.org/2016/11/16/increasing-build-iq-travis-ci</id><content type="html" xml:base="http://shellscape.org/2016/11/16/increasing-build-iq-travis-ci">&lt;p&gt;Continuous Integration is a must these days. And for social, open source
projects it’s crucial. Our tool of choice for automated testing is
&lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt;. Like most tools, Travis does what it does
well. Unfortunately it’s not very “smart”. Heaven help you if you have a large
or modular project with a multitude of tests - you’ll be waiting an eternity
between builds.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;And that’s exactly what we ran into. We have a repository that contains &lt;em&gt;30 NPM
modules&lt;/em&gt;, each with their own specs (tests). These modules are part of an aging
assets pipeline that I
&lt;a href=&quot;http://shellscape.org/2016/11/09/linting-npm-version-conflicts&quot;&gt;briefly mentioned&lt;/a&gt;
last week. As such each module is subject to a litany of tasks each time a change
is made. Travis CI is hooked into the repo and for each Pull Request would run
specs for every module, assuring that there are no errors in the code changes
contained in the PR. When you’re only working on one or two modules the run-time
for the tasks is relatively low; typically 1 - 2 minutes. That of course depends
on things such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; time, as each module requires an install for testing.
&lt;em&gt;Multiply that by 30&lt;/em&gt; and you start to see where the problem arises.&lt;/p&gt;

&lt;h2 id=&quot;waiting-sucks&quot;&gt;Waiting Sucks&lt;/h2&gt;

&lt;p&gt;Without targeted build testing we’re left waiting or task-shifting until the
build completes successfully. Our need was clear: figure out what files were
affected, map and filter the results, and run only the specs for the modules
changed in any particular Pull Request or push. That’s where
&lt;a href=&quot;https://www.npmjs.com/package/travis-target&quot;&gt;travis-target&lt;/a&gt; comes into play.&lt;/p&gt;

&lt;p&gt;Here’s a snippet of our repo structure, for reference:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ui-tracking
|--src
   |--common
      |--event_registry
      |--tracking_metadata
   |--tracking
      |--cart
      |--etc..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;target-acquired&quot;&gt;Target Acquired&lt;/h2&gt;

&lt;p&gt;In order to target modules, we need to know what their normalized names are; the
names that we publish them to NPM under. Because of some legacy stuff baked into
our pipeline, we store modules at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group/name&lt;/code&gt; but publish them as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group.name&lt;/code&gt;.
So let’s fire up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;travis-target&lt;/code&gt; (bear in mind we’re using ES6 syntax that Node v7 supports).&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;travis-target&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^src&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\/&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;targets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s pretend that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;common.event_registry&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tracking.cart&lt;/code&gt; modules were
both modified in one Pull Request (a common pattern for us) - our results
would could look like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;README.md&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/common/event_registry/js/event_registry.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/common/event_registry/js/registry.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/common/event_registry/package.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/tracking/cart/js/cart.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/tracking/cart/package.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But that’s just silly, so let’s give &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;travis-target&lt;/code&gt; some options to work with:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;travis-target&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^src&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\/&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;targets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;parts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By passing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pattern&lt;/code&gt; in options, we’re telling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;travis-target&lt;/code&gt; to filter on (or
return only those results which match) the regular expression pattern. That gives
us an initial result set of directories starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/common/event_registry/js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/tracking/cart/js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll notice that the initial example of results contained some duplicate
directories; travis-target cleans that up for you.&lt;/p&gt;

&lt;p&gt;Next, we specify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; function on options. That’ll let us transform the each
element in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; of results so that it’s ready to use. Our results would
now look like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;common.event_registry&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;tracking.cart&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;great-justice&quot;&gt;Great Justice&lt;/h2&gt;

&lt;p&gt;Using this last result set, we now know which modules were affected in the PR,
and we know which modules to run specs for. Our next steps are firing off a
sequence of shell commands using
&lt;a href=&quot;https://www.npmjs.com/package/@exponent/spawn-async&quot;&gt;@exponent/spawn-async&lt;/a&gt;,
which plays nicely with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; patterns now supported in Node v7.1 with
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--harmony-async-await&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;Since we implemented this pattern, build times for our PRs are in the 1-2 minute
range; a vast improvement and one sure to bring developer happiness in some small
degree.&lt;/p&gt;

&lt;h3 id=&quot;cheers&quot;&gt;Cheers!&lt;/h3&gt;</content><author><name></name></author><category term="continuous integration" /><category term="node.js" /><category term="open source" /><category term="travis ci" /><summary type="html">Continuous Integration is a must these days. And for social, open source projects it’s crucial. Our tool of choice for automated testing is Travis CI. Like most tools, Travis does what it does well. Unfortunately it’s not very “smart”. Heaven help you if you have a large or modular project with a multitude of tests - you’ll be waiting an eternity between builds.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://shellscape.org/assets/images/posts/increasing-build-iq-travis-ci.jpg" /><media:content medium="image" url="http://shellscape.org/assets/images/posts/increasing-build-iq-travis-ci.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>