<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Technical Leader]]></title><description><![CDATA[The Technical Leader]]></description><link>https://blog.dniccumdesign.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>The Technical Leader</title><link>https://blog.dniccumdesign.com</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 13 May 2026 22:53:59 GMT</lastBuildDate><atom:link href="https://blog.dniccumdesign.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Troubleshooting NodeJS installation/run issues]]></title><description><![CDATA[When a requested update or bugfix comes across my desk, there is nothing more daunting when a fresh clone/fork of repository completes and then the installation process ensues. If you are like me, you]]></description><link>https://blog.dniccumdesign.com/troubleshooting-nodejs-installation-run-issues</link><guid isPermaLink="true">https://blog.dniccumdesign.com/troubleshooting-nodejs-installation-run-issues</guid><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Wed, 13 May 2026 18:56:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/20fd6490-5f77-4eb0-8606-e7e5d0f17a46.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When a requested update or bugfix comes across my desk, there is nothing more daunting when a fresh clone/fork of repository completes and then the installation process ensues. If you are like me, you almost don't even want to look at your screen in fear of that system alert or red text to appear within your console, meaning only one thing: there are installation errors.</p>
<p>But let's assume for a second that your installation goes without a hitch. NPM gives you a grand success message and everything was installed without a hiccup. You then proceed to type <code>gulp watch</code> or whatever your task manager of choice and then the whole process crashes followed by you slamming your fist on your desk in frustration.</p>
<p>The two examples that were listed above are more common than we would like to admit. It can be just as simple as a syntax error or as bad as a deprecated package that simply doesn't exist anymore. As I'm sure that most developers are aware of, one of the largest and problematic issues of working with legacy projects is how to manage project dependencies.</p>
<p><em>While this fiasco persists within all facets of development, for the sake of this post, we will focus on the front-end side (whew).</em></p>
<h2>Diagnosing the problem</h2>
<p>While I don't consider myself a genius when it comes sifting threw the <em>needle in a haystack</em> that is an error log, for most developers a <code>npm install</code> error log can deciphered with ease. I can say that most NodeJS packages now-a-days do a pretty good job of explaining what the problem is in layman terms. It could be just as simple as saying that a package doesn't exist or something is <em>undefined,</em> and this can remedied by performing an additional installation command.</p>
<p>Where diagnosing becomes difficult is when multiple dependencies of a NodeJS module and in turn their dependencies start throwing errors. As I'm sure most of us can agree, this is what we as developers begin to lose sleep over.</p>
<h2>A couple different solutions</h2>
<p>In my experience, the two scenarios that I briefly outlined above can be solved about 80-90% of the time with a couple different or a combination of tactics.</p>
<h3>NodeJS version</h3>
<p>If the project that you are trying to work on is more than 2-3 years old, it is very possible the version of NodeJS that is installed on your machine is too recent for the dependencies that are listed within the <code>package.json</code> that accompanies your project.</p>
<h3>NodeJS modules</h3>
<p>A common mistake that we all make when we are building our <code>package.json</code> file and utilizing the <code>npm install</code> command is that we just tell NPM to retrieve the most stable and recent version of a package and added as a dependency. In doing so, our dependency list could look like this:</p>
<pre><code class="language-json">"dependencies": {
    "bower": "^1.7.2",
    "connect-redis": "1.4.5",
    "ejs": "~0.8.4",
    "grunt": "0.4.2"
}
</code></pre>
<p>The issue with this JSON object is the <strong>~</strong> and <strong>^</strong> punctuation (<a href="https://docs.npmjs.com/files/package.json">source</a>) before the version numbers. What these mean, respectively, is the version is approximately this number or it needs to be compatible with the listed version. While for one package it is not detrimental, spreading this level of variability throughout the entire project can be disastrous.</p>
<h2>So what's next?</h2>
<p>Yeah so what's next? Well here are a couple routes you can take to trouble shoot these issues that can creep up during an installation/run.</p>
<h2>Using n to change your version of NodeJS</h2>
<p>NodeJS gives a tool called <a href="https://github.com/creationix/nvm">NVM</a> (Node Version Manager) to control our versions of NodeJS that are active on our machines. I have found that this module can be clunky at best and the command line syntax is just <em>weird</em>.</p>
<p>I recommend using <a href="https://github.com/tj/n">n</a>. n is a simpler version of NVM and allows you to easily transition between versions of NodeJS on your machine.</p>
<h3>How to install/use n</h3>
<p><strong>1.</strong> Before we install anything, we need to make sure that your user has read/write access to the <code>/usr/local/bin/</code> directory on your machine so we can modify the "node" directory that will live there. To do this, enter the following command followed by your user password:</p>
<pre><code class="language-shell">\( sudo chown -R \)(whoami) /usr/local
</code></pre>
<p><strong>2.</strong> After that is complete, now we need to install n globally on your machine like so:</p>
<pre><code class="language-shell">$ npm install -g n
</code></pre>
<p><strong>Note:</strong> If you computer asks you to perform this action as an Administrator, simply prefix this command with <code>sudo</code>.</p>
<p><strong>3.</strong> Now that n is installed, we can see all of the actions that are available to us by simply entering the following command:</p>
<pre><code class="language-shell">$ n
</code></pre>
<p>which should look like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/994dcda7-f9e6-47e6-9f0e-4c3798fc85c8.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Note:</strong> Once versions of NodeJS are installed, to be able to return to this screen use the <code>n --help</code> command.</p>
<p><strong>4.</strong> Before we start getting crazy with installing all sorts of NodeJS on your machine, lets give ourselves a good baseline to work from by install the current version of NodeJS on our machine. First enter:</p>
<pre><code class="language-shell">$ node -v
</code></pre>
<p>The result that is outputted should look like this: <code>v5.3.0</code>. Note the version number (not including the v) and then enter this command:</p>
<pre><code class="language-shell">$ n [your current version]
</code></pre>
<p>This will install your current version of NodeJS within n. Next enter this command to install the most recent stable version of NodeJS:</p>
<pre><code class="language-shell">$ n latest
</code></pre>
<p>Once finished, enter the <code>n</code> command again and you should see something like this (note your version numbers could be different):</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/a87590bb-c338-44a6-a82f-e45379bbac3f.png" alt="" style="display:block;margin:0 auto" />

<p>Now you can use your arrow keys to navigate the versions installed and then hit Enter to select your version, or just use Ctrl + C to exit. Go ahead and select the newest version that you have, and then hit Enter. Give your machine a second to process the change and then it will exit the screen. Afterwards test your version with:</p>
<pre><code class="language-shell">$ node -v
</code></pre>
<p><strong>Note: Make sure you have killed all of your NodeJS servers/process!</strong></p>
<p>Assuming you did everything correctly you should see your version change. But that's not all! You can go back as easily as you can go forward. If you enter:</p>
<pre><code class="language-shell">$ node ls
</code></pre>
<p>This will output all of the versions of NodeJS that are available to install. You can simply copy the version number that you want and then repeat the process to be able to install legacy versions of NodeJS. It's that easy! Once you have found a version that you think will work (it may take some trial and error), purge the <code>node_modules</code> directory and the retrying the install and run commands.</p>
<h2>Fix your module versions</h2>
<p>As I touched on earlier, another way we can troubleshoot these errors is not allow NPM to install versions of our dependencies that are not explicitly what we ask for. The punctuation marks (^, ~) that are prepended to our version numbers can cause modules to be full feature versions ahead of what we want; causing major compatibility issues.</p>
<p>To fix this, simply remove any prepended ^ or ~ marks within your <code>package.json</code> file, purge the <code>node_modules</code> directory and the retrying the install and run commands.</p>
<h2>Disclaimer</h2>
<p>Again, restating what I said earlier, I have found these two methods of debugging to solve about 80-90% of my compatibility issues. However keep in mind that other things can go wrong, things that are not covered here. But hopefully this will get you pointed in the right direction.</p>
]]></content:encoded></item><item><title><![CDATA[Setting yourself above: speaking at a conference]]></title><description><![CDATA[Whenever I tell a colleague that I am speaking at a conference, the common response is usually along the lines of, "you get up in front of people and talk? I could never do that." The fact that I am h]]></description><link>https://blog.dniccumdesign.com/setting-yourself-above-speaking-at-a-conference</link><guid isPermaLink="true">https://blog.dniccumdesign.com/setting-yourself-above-speaking-at-a-conference</guid><category><![CDATA[Editorial]]></category><category><![CDATA[speaking ]]></category><category><![CDATA[conference]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Wed, 13 May 2026 18:38:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/db033c1f-3c95-4d0d-aa69-d609509b1148.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever I tell a colleague that I am speaking at a conference, the common response is usually along the lines of, "you get up in front of people and talk? I could never do that." The fact that I am here in the flesh writing to you now proves that this daunting task is easier than many think. What's more is the fact that it's not just about doing something intimidating or challenging, it's all about sharing that little bit of knowledge that you have with someone to make them better.</p>
<p>It has been said that when you attend a conference (technical or creative) the speakers at that conference represent the top 5% of minds in your respective fields. Essentially the cream of the crop. While the attendees can very easily benefit from this type of talent and knowledge, speaking at a conference can benefit you just as much. Surrounding yourself with this type of knowledge is in infectious; which can only improve you as a person, personally and professionally, and as a subject matter expert.</p>
<p>So you may be saying to yourself, "Ok so I can get smarter and/or more knowledgable. Big deal. Is that all?" Well no of course not. Keep reading.</p>
<h2>Investing in your skill</h2>
<p>I can speak from experience that there is nothing more embarrassing than getting up in front of a group of people and you start receiving questions that you don't know the answers to; especially when you are live-coding. It's awkward for you and the people attending your talk. So how do you avoid this?</p>
<p>It's simple: do your homework.</p>
<p>While you may be pretty comfortable with your subject matter, there is always an opportunity for you to add just a few extra facts to help draw in your audience even more. More often than not, these facts, pointers, or how-to's are items that you probably don't already know. A common requirement for conferences is for you to stage your code on GitHub or any other equivalent with any associated documentation. A bi-product of this requirement is clean code and detailed how-to's; all extremely effective tools who may not be experts. It's these little nuggets that help validate you even more as a speaker.</p>
<h3>What it did for me</h3>
<p>For example, in preparation for a session that I was going to give on the <a href="http://ionicframework.com/">Ionic Mobile Framework</a>, I had to familiarize myself with multiple deployment platforms. I am an Apple/Mac guy: I have multiple iPads, several iPhones, and a couple Apple computers at home. However to think that everyone else works on the exact same devices I do would be naive and frankly, stupid. So I invested in a cheap PC as well as an Android phone so I could broaden my scope of documentation; allowing me to understand the ins and outs of Android Studio and the Java SDK (software developer kit). Boy am I glad I did. I found more than a couple "gotchas" that could have easily derailed my talk.</p>
<p>All of these items require time. This is time that you spend becoming even more familiar with the documentation and processes and thus committing even more information to memory. In the end you solidify yourself within the minds of your attendees as a subject matter expert.</p>
<h2>Building yourself up</h2>
<p>If you want to speak publicly, you don't necessarily have to immediately jump into the conference environment. Speaking in front of complete strangers with zero context on who you are or where you come from can be frightening. I get it. Fortunately I can vouch for the fact that there are several other opportunities for you to speak before taking the conference plunge.</p>
<h3>Client meetings</h3>
<p>One opportunity that commonly gets overlooked is client meetings. While you may not be speaking in a traditional workshop session type setting, you are in fact speaking to people who are not familiar with your content; requiring your to explain in detail how you came to a certain conclusion. What's more is you may receive questions on your conclusions forcing you to think quickly on your feet thus placing even more emphasis on your preparation.</p>
<h3>Focus groups</h3>
<p>Another type of meeting that is common in the agency setting is a focus group. This can be a meeting that was called between like-minded people to decide on a process for the larger masses, or this could be an open forum during a lunch and learn. Each setting has a different type of audience make up all with unique skillets and knowledge, but each requires you to be prepared and explain your content in detail to ensure no one is left behind.</p>
<h3>Screencasts</h3>
<p>While not necessarily formal, putting yourself on a YouTube video screencast is another great starting place for you to begin speaking. You don't have the pressure of a live audience, allowing for additional focus on your diction and flow of the presentation. As an added benefit, if your videos get popular you begin to make a little ad revenue as well!</p>
<h2>Promotion - self and company</h2>
<p>Being in the industry that we are in, it could be safe to say that we take the concept of marketing for granted. We consistently market a product or idea to others while not necessarily putting a lot of effort in marketing ourselves or our employer's brand. It's this notion of brand recognition, of either ourselves or our company, that attracts like-minded talent and brand recognition.</p>
<p>People and thus word of mouth are the best way for a message to spread. I'm sure that all of you social media people can agree. This is how viral threads get started, word of mouth, or a social presence; which is in fact an extension of our voice. The more advocates and content that is in the public eye with your brand being connected to only fuels the message.</p>
<p>In my opinion, a common misconception of brand recognition comes associated with award winning work. Design periodicals and other marketing resources continuously push the draw of awards to their readers. Don't get me wrong, awards are great: they create great magazine material and are awe-inspiring when you enter the front doors of the office, seeing all of those trophies on the walls. However these awards can be all but useless if the message of your brand is lost.</p>
<p>Stereotypically when you speak at a conference, you introduce yourself and the company that you work for. At this moment you are instantly bringing your employer's brand to the fore-front of your attendee's minds. Just like a creative TV advertisement, that recognition will be associated with the content that you are about to present; not only making you appear better but your employer as well.</p>
<h2>So you want to speak? Great you have help.</h2>
<p>While you prepare for your session, one thing to keep in mind while you prepare is to remember that you do not have to go through this process alone.</p>
<p>Your company leadership has a number of professionals that have attended conferences of various sizes that have an enormous wealth of information. While the subject matter may be different, that doesn't matter. Having a fresh perspective on your content can only help you during the preparation and feedback stages.</p>
<p>Refer to the section above about the various settings that you can utilize to help you get your feet wet in speaking publicly. I understand that this is not an easy task for everyone. I can place myself in that category at one point in time. However just like everything else, practice makes perfect. Keep reviewing your notes and always be open to feedback; good and bad.</p>
<p>At the end of the day, the people who attend your talks want you to succeed. No one attends your sessions looking for you to fail. Determination and hard work yields quality for your talk and for you as a presenter.</p>
]]></content:encoded></item><item><title><![CDATA[Passing uploaded files between Laravel Livewire components]]></title><description><![CDATA[I recently discovered a need to be able pass temporary (without being saved to your filesystem) uploaded files using Laravel Livewire for an API that I am building for my 9-5 job. Essentially (thinkin]]></description><link>https://blog.dniccumdesign.com/passing-uploaded-files-between-laravel-livewire-components</link><guid isPermaLink="true">https://blog.dniccumdesign.com/passing-uploaded-files-between-laravel-livewire-components</guid><category><![CDATA[Laravel]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Livewire]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Fri, 06 Nov 2020 16:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/34414f18-8332-4cde-b11b-fda45ae1d8e6.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently discovered a need to be able pass temporary (without being saved to your filesystem) uploaded files using Laravel Livewire for an API that I am building for my 9-5 job. Essentially (thinking with my VueJS cap) I wanted to build a uniform file-upload input that I could use multiple times within my application.</p>
<p>Again, using my VueJS-centered brain, I just assumed that I would be able to simply emit up the <code>TemporaryUploadedFile</code> class that Livewire generates with a file-upload. Naturally I was incorrect. <strong>My problem:</strong> when you attempt to pass this class to a parent/child component all you get is:</p>
<p>Obviously you cannot do anything with this. So after some discovery, I was able to come up with a scalable solution.</p>
<h2>The result</h2>
<p>For the sake of being thorough, I am going to show you all of my code, so you can replicate the entire component for yourself. It is worth noting that I also used Alpine.JS and Tailwind for this component.</p>
<p>In the next few steps, this is what we are going to build:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/aa8fbcfe-1b2a-4b96-94e4-e8b163f6182d.png" alt="Step 1" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/a0134fc9-a2c0-439f-a404-5eedd330335f.png" alt="Step 2" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/cc92266d-d821-4487-a1f1-2225a09a2657.png" alt="Step 3" style="display:block;margin:0 auto" />

<p>Yours <em>MIGHT</em> look a little different as I have modified my <code>tailwind.config.js</code> file a bit.</p>
<h2>How I did it</h2>
<p>Assuming you have at least skimmed the documentation for <a href="https://laravel-livewire.com/docs/2.x/file-uploads">Laravel Livewire on file uploads</a>, you can see that once a file is uploaded, Livewire stores the file in a temporary directory within your filesystem; whether it is remote or locally depends on your infrastructure. The response of this action is an object with a bunch of other meta data named <code>Livewire\TemporaryUploadedFile</code>. From there you can extract any information that you need and save/move the file around where you need it. Again, you can <a href="https://laravel-livewire.com/docs/2.x/file-uploads#storing-files">refer to the documentation</a> for further details.</p>
<p>Like I said above, if you simply try to use the <code>emit()</code> action to pass the result to other components, all that is passed is the disk path. I even tried JSON encoding the object, but that didn't work either. After dissecting the <code>Livewire\TemporaryUploadedFile</code> class, I discovered there is an exposed method <code>getRealPath()</code> that returns the temporary location of the file. Furthermore, I found that the path of the file is the parameter required to construct a new instance of the <code>TemporaryUploadedFile</code> class. Passing strings with Laravel Livewire is easy, so that was my ticket: emitting the full <em>real</em> path of the temporary file, and then simply re-constructing the <code>TemporaryUploadedFile</code> class in the parent/listening component.</p>
<p>Once finished, then you can either move/save the emitted file like so:</p>
<pre><code class="language-php">class FileUpload extends Component
{
    use WithFileUploads;

    public $file;
    
    ...
    
    public function fileComplete()
    {
        $this-file-&gt;storePubliclyAs(
            'documents',
            'sample',
            config('filesystems.default'),
        );
    }
}
</code></pre>
<h2>Full code</h2>
<h3>Child Component Template</h3>
<pre><code class="language-html">&lt;div
    x-data="{ isUploading: false, progress: 0, name: null }"
    x-on:livewire-upload-start="isUploading = true"
    x-on:livewire-upload-finish="isUploading = false; $wire.fileComplete()"
    x-on:livewire-upload-error="isUploading = false"
    x-on:livewire-upload-progress="progress = $event.detail.progress"
&gt;

    &lt;div class="overflow-hidden relative w-64 mt-4 mb-4"&gt;
        &lt;label class="font-sans py-2 px-4 border border-transparent text-sm font-semibold tracking-wider rounded-md transition duration-150 ease-in-out uppercase border-gray-300 text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue inline-flex cursor-pointer" x-show="!name"&gt;
            &lt;svg fill="#FFF" height="18" viewBox="0 0 24 24" width="18" xmlns="http://www.w3.org/2000/svg"&gt;
                &lt;path d="M0 0h24v24H0z" fill="none"/&gt;
                &lt;path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/&gt;
            &lt;/svg&gt;
            &lt;span class="ml-2"&gt;Select File&lt;/span&gt;
            &lt;input class="hidden" type="file" wire:model="file" x-on:change="name = $event.target.files[0].name"&gt;
        &lt;/label&gt;
        &lt;div class="text-gray-500" x-show="name"&gt;
            &lt;span x-show="isUploading"&gt;Uploading... Please wait.&lt;/span&gt;
            &lt;div class="flex items-center" x-show="!isUploading"&gt;
                &lt;div class="flex-1 truncate mr-2"&gt;
                    &lt;span x-text="name"&gt;&lt;/span&gt;
                &lt;/div&gt;
                &lt;button type="button" class="inline-flex items-center justify-center h-7 w-7 rounded-full bg-red-600 hover:bg-red-800 text-white shadow-lg hover:shadow-xl transition duration-150 ease-in-out focus:bg-red-700 outline-none focus:outline-none" x-on:click="progress = 0; name = null; \(wire.file = null; \)wire.fileReset()"&gt;
                    &lt;svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"&gt;
                    &lt;path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" /&gt;
                &lt;/svg&gt;
                &lt;/button&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- Progress Bar --&gt;
    &lt;div class="relative pt-1" x-show="isUploading"&gt;
        &lt;div class="overflow-hidden h-2 mb-4 text-xs flex rounded bg-green-200"&gt;
            &lt;div :style="`width: ${progress}%`" class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-500"&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h3>Child component</h3>
<pre><code class="language-php">&lt;?php

namespace App\Http\Livewire;

use Livewire\Component;
use Livewire\WithFileUploads;

class FileUpload extends Component
{
    use WithFileUploads;

    public $file;

    public function render()
    {
        return view('livewire.file-upload');
    }

    public function updatedFile()
    {
        $this-&gt;validate([
            'file' =&gt; 'file|max:8192', // 8MB Max
        ]);

        \(this-&gt;emitUp('fileUploaded', \)this-&gt;file);
    }

    public function fileComplete()
    {
        \(this-&gt;emitUp('fileUpload', \)this-&gt;file-&gt;getRealPath());
    }

    public function fileReset()
    {
        $this-&gt;emitUp('fileReset');
    }
}
</code></pre>
<h3>Parent Component</h3>
<pre><code class="language-php">&lt;?php

namespace App\Http\Livewire;

use Livewire\Component;
use Livewire\TemporaryUploadedFile;

class ParentComponent extends Component
{
    protected $listeners = [
        'fileUpload',
        'fileReset',
    ];
    
    public $file;
    
    public function fileUpload($payload)
    {
        \(this-&gt;file = new TemporaryUploadedFile(\)payload, config('filesystems.default'));
        
        /* When you are ready to store the file */
        /*
        $this-&gt;file-&gt;storePubliclyAs(
            'documents',
            'sample',
            config('filesystems.default'),
        );
        */
    }

    public function fileReset()
    {
        $this-&gt;file = null;
    }
}
</code></pre>
<p>Hopefully you can find this useful. I was banging my head against the wall for a couple hours with this, and naturally the solution was easier than anticipated.</p>
<img src="https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExc3RvazZwMXV3Z2N2ajlsODBlMHV4YjVjMW5xZGF4M2RhdHd0NmllYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xT5LMzIK1AdZJ4cYW4/giphy.gif" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[Adding documentation to your Laravel Nova installations]]></title><description><![CDATA[Documentation (especially good documentation) for an application can make a good application and experience for a client, a great application. Once we as developers complete an application that we hav]]></description><link>https://blog.dniccumdesign.com/adding-documentation-to-your-laravel-nova-installations</link><guid isPermaLink="true">https://blog.dniccumdesign.com/adding-documentation-to-your-laravel-nova-installations</guid><category><![CDATA[Laravel]]></category><category><![CDATA[Nova]]></category><category><![CDATA[documentation]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Wed, 13 Feb 2019 16:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/6185fce7-4921-454b-9502-5c215f79e744.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Documentation (especially good documentation) for an application can make a good application and experience for a client, a <em>great</em> application. Once we as developers complete an application that we have worked and potentially even lost sleep over, will live on well after we stop working on it. Despite our best efforts, clients and customers tend to forget things that we show them on how to manage their application. That's where documentation comes in.</p>
<img src="https://images.unsplash.com/photo-1509239129736-8c395375220d?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="" style="display:block;margin:0 auto" />

<p>I'll come right out and say it: I hate writting documentation; regardless for what it is for. My normal avenue's of implementation documention are via Word document, or even a repository wiki. Recently I even used this <a href="https://larecipe.binarytorch.com.my/docs/1.3/overview">awesome documentation package called LaRecipe</a>, that I thorougly enjoyed using. However these solutions didn't solve my pain point of the documentation isn't all in the same place. It required a client to open up another application or web browser and comb through a few different pages. It was these issues that was the inspiration behind a new Nova tool that I built to solve.</p>
<h2>Building yet another tool</h2>
<p>So like I said, to solve my own pain, I built a <a href="https://github.com/dniccum/nova-documentation">new Laravel Nova tool called Nova Documentation</a> (creative name right?).</p>
<p>What this tool essentially does is convert Markdown files and then passes them to the Vue component within the tool. Ultimately it is that simple, however there are a few other things that I added that I think will be useful:</p>
<ul>
<li><p>Syntax highlighting to code blocks (thanks to <a href="https://highlightjs.org/">highlight.js</a>)</p>
</li>
<li><p>Dynamic navigation/table of contents</p>
</li>
<li><p>Document nesting with url rewriting</p>
</li>
<li><p>Flexible configuration settings</p>
</li>
</ul>
<h2>Installation</h2>
<p>To start, lets install the Nova tool with:</p>
<pre><code class="language-shell">composer require dniccum/nova-documentation
</code></pre>
<p>Next, we need to publish the tool's configuration file and a couple markdown files with examples to get you started:</p>
<pre><code class="language-shell">php artisan vendor:publish --provider="Dniccum\NovaDocumentation\ToolServiceProvider"
</code></pre>
<p>By default, the sample markdown files that the tool uses to render it's content will be added to <code>resources/documentation</code> path. If you would like to move this directory, be sure to update this setting within the <code>config/novadocumentation.php</code> configuration file:</p>
<pre><code class="language-php">/*
|--------------------------------------------------------------------------
| Home Page
|--------------------------------------------------------------------------
|
| The markdown document that will be used as the home page and/or entry
| point. This will be located within the documentation directory that resides
| within your application's resources directory.
|
*/

'home' =&gt; 'documentation/home.md',
</code></pre>
<p>And finally, just like every other Nova tool, we need to register the tool within the NovaServiceProvider:</p>
<pre><code class="language-php">use Dniccum\NovaDocumentation\NovaDocumentation;

...

/**
 * Get the tools that should be listed in the Nova sidebar.
 *
 * @return array
 */
public function tools()
{
    return [
        // other tools
        new NovaDocumentation,
    ];
}
</code></pre>
<p>Assuming that you have done everything correctly, you should see a "Documentation" link in your Nova sidebar with this as a homepage:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/10e8732c-25dc-48ae-86f7-48ab14ab4d75.png" alt="Documentation tool home page" style="display:block;margin:0 auto" />

<h2>Using the tool</h2>
<p>Assuming that you are using the default installation configuration, the directory where all of the markdown file will be stored in the <code>resources/documentation</code> directory. Again, if you use the default settings, the <a href="http://home.md"><code>home.md</code></a> file that will be found there will represent the home page:</p>
<pre><code class="language-markdown"># Welcome to your documentation

Within this area, you can:

* Define features
* Add how-to's
* Link to tutorial videos/images

To see any other Markdown syntax and examples, please see [the sample](sample.md).
</code></pre>
<h3>Generating your content</h3>
<p>A few things you should note:</p>
<ul>
<li><p>Any and all markdown is allowed in these markdown files.</p>
</li>
<li><p>You should be able to add any other HTML that you want to render within the page; excluding any Javascript as I am using Vue.js template compiler to build the page and any Javascript-based content probably won't render correctly.</p>
</li>
<li><p>I did add the necessary CSS to clean up some of the appearance of standard HTML tags like ordered/un-ordered lists, headers, block quotes, etc from the base stylesheet that Taylor Otwell constructed for the Nova dashboard. If you happen to find something that isn't quite styled correctly, drop me a line on the <a href="https://github.com/dniccum/nova-documentation/issues">issues page on Github</a>.</p>
</li>
<li><p>Feel free to organize your markdown files as you wish; whether everything is in the base directory or if you would like to add files within directories. The tool will detect them and build their url's accordingly.</p>
</li>
</ul>
<h3>Setting your titles</h3>
<p>It is important to note that the H1 tags within each of these files will be dynamically pulled to build the sidebar navigation. With that said, make sure your titles are descriptive yet short in length to prevent the sidebar from becoming cluttered.</p>
<h2>Other features?</h2>
<p>As you continue to work with this tool, let me know if there are any other features that you would like to add. Thank you for your interest!</p>
]]></content:encoded></item><item><title><![CDATA[Customizing your Laravel Broadcasting payloads]]></title><description><![CDATA[One piece of the Laravel documentation that is somewhat glanced over in my opinion is the ability to customize the payload that is sent out to your Laravel Echo listeners upon new events or broadcast ]]></description><link>https://blog.dniccumdesign.com/customizing-your-laravel-broadcasting-payloads</link><guid isPermaLink="true">https://blog.dniccumdesign.com/customizing-your-laravel-broadcasting-payloads</guid><category><![CDATA[Laravel]]></category><category><![CDATA[pusher]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Wed, 30 Jan 2019 16:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/7e15dc56-1047-4697-b978-1b233f296e5e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One piece of the Laravel documentation that is somewhat <em>glanced</em> over in my opinion is the ability to customize the payload that is sent out to your Laravel Echo listeners upon new events or <code>broadcast</code> methods. This can be extremely important when results from the models passed to these events are large and/or bloated; for example: when you are storing chunks of HTML in your database.</p>
<p>By default, the Broadcasting functionality within Laravel serializes any and all classes/models that you pass to the events. What does this mean? Well lets say for example that you have a model that has 15 columns for each result, however during your select method you only query 3 columns; like so:</p>
<pre><code class="language-php">$user = \App\Models\User::where('id', 6)
	-&gt;select(['id', 'name', 'email'])
	-&gt;first();

event(new \App\Events\UserLoggedOut($user));
</code></pre>
<p>If you pass this model to the event all 15 columns will be queried; regardless of what you select, or the number of <code>unset</code> methods you use. If you are using a service like that of <a href="https://pusher.com/">Pusher</a>, you could run into character limits that will ultimately lead to errors and failed messages.</p>
<p>In order to prevent our broadcasts from erroring, we need to customize the payload that is sent to Pusher or any other platform. We can do that by playing a <code>broadcastWith</code> method within our event class. Let's to back to the example above, where we only want to broadcast the id, name, and email address. Our broadcastWith method would look like this:</p>
<pre><code class="language-php">/**
 * Specifically broadcasts the necessary array keys
 *
 * @return array
 */
public function broadcastWith()
{
    return [
        'user' =&gt; [
            'id' =&gt; $this-&gt;user-&gt;id,
            'name' =&gt; $this-&gt;user-&gt;name,
            'email' =&gt; $this-&gt;user-&gt;email,
        ]
    ];
}
</code></pre>
<p>By implementing this method, your broadcasts will be significantly simplified and thus carry a light payload. But that's not all! Because this is a method, and not a variable, you can perform additional logic within this method to conditionally add content to the payload. Refer to another example below:</p>
<pre><code class="language-php">/**
 * Specifically broadcasts the necessary array keys
 *
 * @return array
 */
public function broadcastWith()
{
    $payload = [
        'configuration' =&gt; [
            'id' =&gt; $this-&gt;configuration-&gt;id,
            'name' =&gt; $this-&gt;configuration-&gt;name,
            'user' =&gt; [
                'first_name' =&gt; $this-&gt;configuration-&gt;user-&gt;first_name,
                'last_name' =&gt; $this-&gt;configuration-&gt;user-&gt;last_name,
            ],
        ]
    ];

    if (!empty($this-&gt;configuration-&gt;jurisdictions)) {
        \(jurisdiction = \)this-&gt;configuration-&gt;jurisdictions-&gt;first();

        $payload['jurisdiction'] = [
            'id' =&gt; $jurisdiction-&gt;id
        ];
    }

    if (!empty($this-&gt;configuration-&gt;comments)) {
        \(payload['comments'] = \)this-&gt;configuration-&gt;comments;
    }

    return $payload;
}
</code></pre>
<p>What I have done is that I have assigned the initial associative array to a variable and performed some basic if-statements to conditionally add content to the payload.</p>
<p>While this isn't necessarily rocket science, using this method of customizing your broadcasts can simplify your application and save you a bunch of time wrestling with the Pusher/websockets APIs.</p>
]]></content:encoded></item><item><title><![CDATA[The end is nigh for Bower?]]></title><description><![CDATA[Over the last four or five years, I have come to have a deep adoration for the front end package manager Bower. Going to the official jQuery or Angular repositories to download dependencies was a thin]]></description><link>https://blog.dniccumdesign.com/the-end-is-nigh-for-bower</link><guid isPermaLink="true">https://blog.dniccumdesign.com/the-end-is-nigh-for-bower</guid><category><![CDATA[Editorial]]></category><category><![CDATA[bower]]></category><category><![CDATA[yoeman]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Thu, 22 Sep 2016 15:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/65f030b8-8556-4c61-860f-da64ea16169b.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the last four or five years, I have come to have a deep adoration for the front end package manager <a href="https://bower.io/">Bower</a>. Going to the official jQuery or Angular repositories to download dependencies was a thing of the past. The even deeper integrations with scaffolding tools like Yeoman even made the attraction even more irresistible. The fact I could build a basic project with a couple shell commands just blew my mind the first few times.</p>
<p>Now that Angular 2 has <strong>finally</strong> been released and is no longer in the purgatory of beta or release candidate, I am starting to see a trend with the support of public projects and the technologies that supports them. This trend is that <strong>these new projects are not supported by Bower.</strong></p>
<p>While I would like to note that these trends are somewhat specific to brand new projects like that of Angular 2 and <a href="http://ionicframework.com/docs/v2/getting-started/installation/">Ionic 2</a>. Projects like Angular 1 and Ionic 1 that are currently being maintained, though not improved, are still supported with Bower compatible packages; I digress...</p>
<p>But why would I be thinking about this? Is there something that Bower did wrong to seal it's demise? I have a few ideas.</p>
<h2>It's a NodeJS package</h2>
<p>So what if it is a NodeJS package? We use helpers like Grunt and Gulp all of the time to process code and to make our lives easier as developers. Why would Bower be any different? Here's my theory: because it is a required dependency to install further dependencies with its own set of shell commands; <em>automation</em> in other words.</p>
<p>When working with CMS applications like <a href="http://www.adobe.com/marketing-cloud/enterprise-content-management.html">Adobe Experience Manager</a> or even platforms like <a href="https://laravel.com/">Laravel</a> (PHP-based), these tools ship with scaffolding tools or provide a tool for you to create your own. The majority of these assets require you to use Node Package Manager (npm) to install and run their associated dependencies. It has become so common that it is second-nature for us as developers to clone a repository and then run <code>$ npm install</code>. Configuring AEM to run this command isn't very hard either. The issues that I can identify lies in the fact that:</p>
<ul>
<li><p>Bower downloads is packages differently than NodeJS does</p>
</li>
<li><p>It has a different set of configurations and requires additional files to apply these configurations</p>
</li>
<li><p>It is discouraged to store your Bower-related files or <em>bower_components</em> in the same place as your node modules. Bad things start to happen when you do</p>
</li>
</ul>
<p>Each of these points could become troublesome if you are trying to develop in an existing ecosystem that was never designed to support Bower.</p>
<p>Additionally, in most instances you have to have Bower installed globally on your machine. If not, for instance it is a dependency of your NodeJS application, then you are limited to calling the Bower command like so:</p>
<pre><code class="language-shell">/usr/local/bin/bower install
</code></pre>
<p>Now you are liable to manage two different sets errors and feedback. And as I pointed out earlier, if this Bower project has been automated, debugging these errors can be troublesome.</p>
<h2>The lack of updates</h2>
<p>If you look at the <a href="https://github.com/bower/bower/releases">Bower repository release page</a>, you can see that the platform hasn't been touched (at the time of this article being written) since April. A platform that was as widely used as this, and when you throw in the recent macOS update of Sierra, the lack of updates should come as a bit of an alarm to you.</p>
<h2>No new project adaptation</h2>
<p>As I said above, if you are familiar with Angular 2, Ionic 2, or even <a href="http://foundation.zurb.com/">Zurb's Foundation</a>, currently <strong>none</strong> of these projects have developed Bower components. It is also worth touching on that these three projects also have a corresponding command line interface (CLI) to be able to initializes or compile its assets. As you would expect, these CLI's using NodeJS to install their dependencies. With not relying on Bower to install their dependencies applications such as these can scaffold a project without having to call additional shell commands; resulting in both supplementary speed and stability within the applications.</p>
<h2>Just a few thoughts</h2>
<p>As I draw this <em>techy</em> rant to a close, keep in mind that I am basing my conclusions purely off of observations and some basic research. I proudly disclose that I have not spoken to the Bower guys about the longevity of their project, or do I have any usage metrics to show a decline. Again, just a few thoughts that I tied together into a hypothesis. For all I know, Bower could be alive and well.</p>
<p>But nevertheless, we as developers have to take note of this evidence and begin to make decisions when we are scaffolding a new project or making enhancements to existing projects.</p>
]]></content:encoded></item></channel></rss>