<?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" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[The Personal Blog of Corey Snyder]]></title><description><![CDATA[Web Developer. Ice Hockey Player. FPV Drone Racer. Husband. Father.]]></description><link>http://coreysnyder.me/</link><image><url>http://coreysnyder.me/favicon.png</url><title>The Personal Blog of Corey Snyder</title><link>http://coreysnyder.me/</link></image><generator>Ghost 2.21</generator><lastBuildDate>Mon, 20 Apr 2026 16:22:11 GMT</lastBuildDate><atom:link href="http://coreysnyder.me/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[React Bookmarks]]></title><description><![CDATA[<p>Just a list of cool articles I come across that I want to remember:</p><!--kg-card-begin: markdown--><ul>
<li><a href="https://blog.logrocket.com/use-hooks-and-context-not-react-and-redux/">Hooks + useReducer + useContext = Mini Redux with Hooks</a></li>
<li></li>
</ul>
<!--kg-card-end: markdown-->]]></description><link>http://coreysnyder.me/react-bookmarks/</link><guid isPermaLink="false">5fb327d25c2589304aa3e157</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Tue, 17 Nov 2020 01:32:25 GMT</pubDate><content:encoded><![CDATA[<p>Just a list of cool articles I come across that I want to remember:</p><!--kg-card-begin: markdown--><ul>
<li><a href="https://blog.logrocket.com/use-hooks-and-context-not-react-and-redux/">Hooks + useReducer + useContext = Mini Redux with Hooks</a></li>
<li></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Getting Started with FPV Updated April 2020]]></title><description><![CDATA[<p>I get asked on almost a weekly basis "How do I get started in FPV? What should I buy?". Rather than retyping it all up every time I decided to write this article and just forward people to it. I'll try and keep it updated as things change and If</p>]]></description><link>http://coreysnyder.me/how-to-get-started-with-fpv-drones/</link><guid isPermaLink="false">5e932e042d9ce11502a165ea</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Mon, 13 Apr 2020 02:02:08 GMT</pubDate><content:encoded><![CDATA[<p>I get asked on almost a weekly basis "How do I get started in FPV? What should I buy?". Rather than retyping it all up every time I decided to write this article and just forward people to it. I'll try and keep it updated as things change and If anyone asks any follow-up questions I'll be sure to update the article to answer those questions. So without further ado, let's get started.</p><p>This article is a WIP and likely contains plenty of spelling and grammatical errors, as well as many incomplete parts. Hopefully, I'll have time to continue updating it.</p><!--kg-card-begin: markdown--><p>Right from the start, there are 2 things that you need to buy, which you're going to use for all of your drones. I have around 30 drones and planes, and I use the same <strong>Goggles</strong> and <strong>Transmitter</strong> to fly all of them. So these are pretty key purchases. They can also be 2 of the most expensive things you purchase in the hobby but think of them as investments. Before we getting into suggested buying options, you need to understand a little bit about the frequencies involved.</p>
<h5 id="frequenciesinvolved">Frequencies Involved</h5>
<h3 id="beginner">Beginner</h3>
<p>Your drone is going to be using two different bands of frequencies simultaneously. One for video and one for controls.</p>
<ul>
<li>2.4Ghz for your Controls</li>
<li>5.8Ghz for your Video</li>
</ul>
<p><img src="http://coreysnyder.me/content/images/2020/04/tara.jpeg" alt="Taranis Radio"></p>
<p><strong>Controls:</strong> This uses 2.4Ghz. Your drone is connected to, typically, a 2-way communication system. your Transmitter (AKA TX or Controller), is going to be sending controls signals to your drone. When you press left, it sends a signal to your drone to go left. Your drone can also send data back to your Transmitter on this same signal, that's why I say 2-way. Your drone can tell your controller things like the drone's battery voltage, or what video frequency you're on. But that's getting too advanced for this article.</p>
<p><img src="http://coreysnyder.me/content/images/2020/04/download.jpeg" alt="FPV Goggles"></p>
<p><strong>Video:</strong> This uses 5.8Ghz. Your drone will have a Video Transmitter (AKA VTX) which will allow your drone to send the video of what it sees through its camera, wirelessly, to any receiver who's dialed to the same frequency. This means that anyone with a receiver capable of receiving your frequency can watch your video.</p>
<h2 id="advanced">Advanced</h2>
<p>These two frequencies will cover most of your bases but if you start getting into more advanced activities like Long Range Flying or HD Video you may need to check out the following:</p>
<h4 id="advancedcontrols">Advanced Controls</h4>
<ul>
<li><a href="https://www.team-blacksheep.com/products/prod:crossfire_tx">TBS Crossfire</a> which uses the following frequencies: 868MHz (EU, Russia) / 915MHz (USA, Asia, Australia)</li>
</ul>
<h4 id="advancedvideofrequencies">Advanced Video Frequencies</h4>
<p>Your goggles may have a built-in receiving module, but there are options that exist that can give you a better video signal.</p>
<p>This may come in the form of Googgle-bay mods such as:</p>
<ul>
<li><a href="https://www.getfpv.com/furiousfpv-true-d-x-receiver-module-5-8ghz.html">FuriousFPV TrueD Module</a></li>
<li><a href="https://www.banggood.com/Foxeer-Wildfire-5_8GHz-72CH-Dual-Receiver-OLED-Ground-Station-Module-Support-OSD-Firmware-Update-For-Fatshark-FPV-Goggles-p-1621877.html">Foxeer Wildfire</a></li>
<li><a href="https://hobbyking.com/en_us/rapidfire-goggle-module.html">ImmersionRC RapidFIRE</a></li>
<li><a href="https://www.getfpv.com/iftron-clearview-goggle-receiver-module.html">Iftron ClearView Goggle Receiver Module</a></li>
</ul>
<p>HD Video Technology</p>
<ul>
<li><a href="https://www.dji.com/fpv?gclid=Cj0KCQjw-Mr0BRDyARIsAKEFbefXmWDKdERlzz-ipQP7FrCHkz41iejAB9xq9rBT4ryTHe9DKL_3LTUaAquQEALw_wcB">DJI Digital FPV System</a></li>
<li><a href="https://www.getfpv.com/the-connex-prosight-hd-vision-kit.html">Connex Digital FPV System</a>. I'd personally stay away from this one unless you know what it is, and specifically want to use it for its features. For noobies, it's just going to cost you a lot of money and frustration.</li>
</ul>
<p>Next, let's talk about what you'll need to send/receive those signals.</p>
<h5 id="gogglesmonitor">Goggles / Monitor</h5>
<h3 id="beginner">Beginner</h3>
<p>If you want to see what your drone sees, you'll need to have something set up to receive that video. For most of the FPV Racing industry that's going to be a pair of goggles. You can also use a monitor or hooked up to a Video Receiver though as well. This is great for sharing your video feed with other people so they can &quot;fly along&quot;.</p>
<p>There are two main types of goggles:</p>
<ol>
<li>Box Goggles - Box goggles are going to be the cheapest entry point typically. They're bulkier, and typically have a single, lower-resolution screen, but still, give you that sense of FPV immersion. These are great starter goggles but you're likely going to find yourself eventually wanting one of the goggles below.</li>
</ol>
<p>Some great options for box goggles include:</p>
<ul>
<li><a href="https://www.getfpv.com/fat-shark-recon-v3-fpv-goggles.html">Fat Shark Recon</a></li>
<li><a href="https://www.getfpv.com/topsky-prime1s-fpv-goggles.html">Topsky Prime 1S FPV</a></li>
</ul>
<ol start="2">
<li>Form-Fitting goggles - These are usually more expensive, smaller, and have two, higher definition, screens inside; One for each eye.</li>
</ol>
<p>Some great options for form-fitting goggles include:</p>
<ul>
<li><a href="https://www.getfpv.com/fat-shark-dominator-hdo-fpv-goggles-refurbished.html">Fat Shark Dominator HDO</a></li>
<li><a href="https://www.getfpv.com/fat-shark-dominator-hd3-core-fpv-goggles-refurbished.html">Fat Shark Dominator HD3</a></li>
</ul>
<h3 id="advanced">Advanced</h3>
<p>You can get into some advanced setups for doing things like putting your video feed on a big screen with others side-by-side. This is great for getting spectators in on the action.</p>
<p>Another more advanced topic is HD Digital video. If you're interested in that check out the DJI or Connex systems listed above.</p>
<h5 id="transmittercontrollertx">Transmitter / Controller / TX</h5>
<p>This is where you have to make a decision that will follow you around for a while. When it comes to the 2.4Ghz controller frequencies, there are several different protocols, and they typically don't all work together. Spektrum, for instance, is a company. If you buy the Spektrum transmitter, you can only use it with receivers that are set up to use the Spektrum protocol.</p>
<p>The two I'm most familiar with and have used are:</p>
<ul>
<li>Spektrum</li>
<li>FrSky</li>
</ul>
<p>I would nudge new pilots toward FrSky. Spektrum is typically more expensive, moves a little slower in terms of Drone tech, and I've had issues with mine in the past. So you need to make a decision right now which you're going to use. Order your transmitter and stick with it.</p>
<p><strong>Get the best of both worlds!</strong> There are also Transmitters such as the <a href="https://www.heli-nation.com/latest-jumper-t16-pro-hall-v2-type-c-charge-and-folding-handle-opentx-radio-transmitter">Jumper T16 Pro</a> or the <a href="https://oscarliang.com/radiomaster-tx16s/">RadioMaster T16</a> which can connect to most of the protocols out there. These are both high value / low cost radios for those looking to get into the hobby though they do require a little more work out of the box than say Binding a Spektrum Radio to a BNF Quad. If you're trying to get started on the cheap, look @ for an older model that uses the protocol you're interested in.</p>
<h5 id="thepartsofthedrones">The parts of the drones</h5>
<p>Building a drone can be a lot like building a PC. There are a bunch of different parts that each serve a unique purpose. But it can be confusing to know what you need, and what parts work with what. If you're not sure what to buy, check out <a href="https://www.rotorage.com/">RotoRage</a>. It will allow you to piece together a drone and give you alerts if you try to add parts that are not compatible with one another.</p>
<p>You should do some research to make sure you're parts are compatible but in general, here are the parts you'll need.</p>
<p>At a high level here are the parts you'll need:</p>
<ul>
<li>Frame</li>
<li>Flight Controller (FC)</li>
<li>Battery</li>
<li>Motors</li>
<li>ESCs</li>
<li>Camera</li>
<li>VTX</li>
<li>Antenna</li>
<li>Propellers</li>
</ul>
<h3 id="frame">Frame</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/slimphst.jpeg" alt="slimphst"><br>
This is what all of your parts connect to. This selection will limit exactly what you can and cannot use. Frames are typically designed to carry a certain size flight-controller stack, motor sizes, camera sizes, etc. Selecting this first will help limit your potential options for the following. For help deciding on which frame to buy, read the <strong>Types of FPV Drones</strong> below.</p>
<hr>
<h3 id="flightcontrollerfc">Flight Controller (FC)</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/fc.jpeg" alt="Flight Controller"><br>
This is the brain of the operation which keeps the drone in the air and properly responding to your controls inputs.</p>
<p>The considerations for choosing a flight controller include:</p>
<ul>
<li><strong>Size:</strong> Most Flight Controllers come in 2 sizes for mounting holes, 30.5x30.5mm and 20x20mm.</li>
<li><strong>Software:</strong> Which software you want to run on it such as Betaflight, Butterflight, Raceflight, KISS.</li>
<li><strong>Features:</strong> What features you need such as # of UARTs.</li>
</ul>
<hr>
<h3 id="battery">Battery</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/battery.png" alt="battery"><br>
This going to power your drone. In the industry, we typically use Lithium Polymer(LiPo) batteries. It's especially important to verify that your parts can take the voltage of the battery you're trying to use. <strong>This is the #1 fastest way to ruin your drone.</strong> Batteries are labeled by 2 main attributes. The # of cells they include, and the capacity.</p>
<p>Examples:</p>
<ul>
<li>3S 800mah - This is a 3-Cell 800 milliamp battery</li>
<li>4S 1300mah - This is a 4-cell 1300 milliamp battery</li>
</ul>
<p><strong>So why does MAH matter?</strong><br>
So the higher the MAH of your battery, the longer you can fly. But it comes at the cost of weight. You'll need to decide what weight you're after. Here are some example sizes I use:<br>
400-800mah - Small 2-3&quot; drones<br>
1100-1550mah - 5&quot; Race Drones<br>
1300-1800mah - 5&quot; Freestyle drones<br>
1800-2500mah - 5 &amp; 6&quot; Long-Range drones.</p>
<p>Carrying a larger battery will not always get you a longer flight time b/c of weight. There is a point of diminishing returns and you'll have to find that for your drone if you stray from my general guidelines above.</p>
<p><strong>So why does voltage matter</strong><br>
You can read more about this in the motors section but essentially the higher the voltage, the faster your motors spin. But faster isn't always better, and it can damage your drone.</p>
<p>The new rage right now is using higher voltage batteries like 6S. It's generally accepted that they help with voltage sag and increase race longevity. If you're new to the hobby and want to keep costs low, I'd recommend going 4S. You may be able to buy batteries of someone whos trying to move to 6S. In my opinion, if you're jsut getting started out, you're not going to notice the difference between a 4S and 6S quad except the cost of parts.</p>
<p><strong>C-Rating:</strong><br>
You may also see a third notation on the battery like <code>75C</code>. That's the C Rating of the battery and is an indicator of the continuous discharge rate of a LiPo. It allows you to calculate the maximum constant current you can draw from the LiPo pack safely without harming the battery. For drones don't buy a battery with a C rating of under 45. And the higher the better for maintaining fast forward flight or big punchouts.</p>
<h4 id="properbatterycare">Proper Battery Care</h4>
<p>If you don't take care of your batteries they will quickly become junk. The fastest way to take a $60 battery and ruin it is to plug it into your drone, and fly for 10 minutes or until the drone comes due to there being no more juice. If you do this, you've now destroyed your battery. You may notice it's hot to the touch, swollen, and could burst into flames at any moment depending on how quickly you discharged it. If you've done this, throw your battery off to the side away from your stuff and let it rest a while.</p>
<p>If you do this there are a few outcomes for your battery:</p>
<ol>
<li>If you let it sit, it may bounce back to a normal resting voltage and allow you to recharge and reuse it. Just know that it will never have the performance it once did.</li>
<li>It may be so low in voltage that you can no longer recharge it as your charger won't recognize it as a proper battery.</li>
<li>It may burst into flames and destroy your other drone components.</li>
</ol>
<p>Another thing you should avoid doing is fully charging your batteries and then letting them sit for an extended period of time. When you're done flying you should try and fly all of your batteries down to 3.8v/cell or put them back on the charger and use the storage setting which will do the same, just a lot slower and less fun.</p>
<hr>
<h3 id="motors">Motors</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/Motor.jpg" alt="Motor"><br>
After you select your battery, you can select which motors to use. The motors are the muscles of your drone. They're what spin the props and allow you to whip that drone all over the sky.</p>
<p>Motors have a few numbers that tell you facts about the motor. A typical motor might say 2206 2300kv. That tells you that the motor is 22mm wide, 6mm tall, and spins at 2300kv. The reason the battery dictates the motor is because of that Kv spec. “Kv” refers to the constant velocity of a motor (not to be confused with “kV,” the abbreviation for kilovolt). It is measured by the number of revolutions per minute (rpm) that a motor turns when 1V (one volt) is applied with no load attached to that motor. So that means if you put a 4S battery on a motor it's going to spin at 4X that Kv. 6S battery would be 6X that Kv. Trying to spin a motor too fast, with too much load, can quickly fry it. There's kind of a balancing act between Battery, Motor, and Prop Size. You can use <a href="https://www.rotorage.com/">RotoRage.com</a> to help you pick a motor that is good for the battery you're using.</p>
<p>A few examples:<br>
DYS SE2205 PRO 2550KV - This is a 22mm tall, 5mm wide motor that spins at 2550kv. This is good for a 4S battery running 5&quot; props, but could also work for a 3S battery.<br>
BH Tornado 1407 3600kv - This is a 14mm wide, 7mm tall motor. This is going to be good for a 3&quot; or 4&quot; propeller, on 3S or 4S batteries.<br>
Hyperlite 2207 1722kv - This is a 22mm wide, 7mm tall motor. This motor is designed for 5&quot; race drones running 6S.</p>
<hr>
<h3 id="electronicspeedcontrollersescs">Electronic Speed Controllers (ESCs)</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/4in1.jpeg" alt="4in1 ESC"><br>
An ESC is the speed controller for your motor, so you'll need 1 for every motor. An industry standard has become the &quot;4in1&quot; which crams all 4 ESCs into a single stackable board. This is a good idea IMO, especially for new drone builders. It can make for really clean builds and keeps your ESCs out of the reach of your spinning propellers.</p>
<p>In my opinion, there's very little to decide about ESCs. You need to make sure you get one that is rated for the Voltage of battery you plan to use, and you want something that isn't cheap. A failed ESC sure sucks and it seems to be a common thing to go especially if you buy cheap.</p>
<hr>
<h3 id="camera">Camera</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/Camera.jpeg" alt="Camera"><br>
This is the camera that will be your eyes in the sky. Don't confuse this with the GoPro that is on the drone. It's typically a pretty low-res, low-latency camera, not too different than the back-up camera in your car. When choosing a camera you only need to consider form-factor.</p>
<p>As you get more advanced you can look at cameras that have the color profile you like, are higher definition, or offer better low-light characteristics.</p>
<hr>
<h3 id="videotransmittervtx">Video Transmitter (VTX)</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/unify-hv-1_2.jpg" alt="Video Transmitter"><br>
The job of the VTX is to take a video feed from your camera and send it wirelessly outward through your transmitting antenna. When you're picking out a VTX, make sure you get one that is 5.8Ghz, the same as the goggles you bought above. When choosing a VTX, you want to choose one with the power output to match your application. Typically the higher the mW output, the longer the range. Here's a good rule of thumb:</p>
<ul>
<li>25mW - Racing or indoor flying where you're staying close to yourself.</li>
<li>200mW - This is what we used to use for racing but it's less common.</li>
<li>500mW - Freestyle</li>
<li>Over 500mw - Long Range flying</li>
</ul>
<hr>
<h3 id="receiver">Receiver</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/receiver.jpg" alt="Radio Receiver"><br>
The receiver's job is to communicate with your Transmitter/Controller/TX. It both receives control signals, and outputs telemetry data. When choosing a Receiver you'll need to pick one that is compatible with your Transmitter/Controller.</p>
<hr>
<h3 id="antenna">Antenna</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/fpvantenna.jpg" alt="FPV Antenna"><br>
This doesn't matter so much. Two things matter to me when selecting an antenna. #1, that it is built for the right frequency video I'm outputting. So make sure you get a 5.8Ghz antenna (most are).</p>
<p>And #2, form factor. For racing, I want one very small and snug against the frame so it doesn't get damaged or knocked off. Keeping it close to the other components will degrade video reception so that comes at a cost. For Long-Range or Freestyle when I want to be able to fly far out, around obstacles and need great video connection, I'll use a longer antenna that stays out away from the frame.</p>
<hr>
<h3 id="propellers">Propellers</h3>
<p><img src="http://coreysnyder.me/content/images/2020/04/props.jpg" alt="props"><br>
The propellers go on your motors and are what spin around to create the lift for your drone. Propellers will dramatically affect your flight characteristics. They come in a variety of shapes and sizes. As such, they are very heavily personal preferences. You're going to have to fly a lot get and feel for what kind of props you like.</p>
<h5 id="typesoffpvdrones">Types of FPV Drones</h5>
<p>Ok so now that you've got your radio and goggles, you're ready to start that drone collection. FPV is a very addicting hobby and you'll find yourself with a fleet in no time.</p>
<p>When you are trying to pick out a drone it's important to consider what you're buying the drone for. Do you want to fly inside? In a small backyard? Do sweet freestyle flippy-floppies like Mr. Steele? Juicy Acro like JohnnyFPV? Fly long-range mountain surfing like Gab? Or to race like Nurk &amp; Jet? those are all going to dictate what type of parts you order. You can kind of fly all of those with a single drone but I like to specialize.</p>
<p>So before you get started, think about what you're setting out to accomplish and let that drive some of your buying decisions.</p>
<h4 id="iwanttospendverylittlemoneyandjustwanttoexperiencefpv">I want to spend very little money and just want to experience FPV.</h4>
<p>First, I'd say you should absolutely download a simulator and start practicing. Even before you fly a drone in real life. Check out the SIMULATOR section for more details.</p>
<p><strong>NOTICE:</strong> Due to some of the recent legislation, it might be a good idea that your first drone weighs less than 250G AUW (Including the battery. Basically everything that flies).</p>
<p>When you're ready for your first real drone, <a href="https://www.tinywhoop.com/collections/quads/products/tiny-whoop-nano-rtf">Something like this is perfect!</a><br>
If it's sold out, just go buy all the parts individually. It includes everything you need to experience FPV for yourself. That said, if you decide to get into it, you'll immediately want to upgrade your controller and probably goggles too. So if you want to save yourself having to waste that money maybe get the <a href="https://www.tinywhoop.com/collections/quads/products/tiny-whoop-nano-bnf">stand-alone kit</a> and then buy a nicer set of goggles &amp; controller.</p>
<p>While it is true that this will not fly 100% like a 5&quot; race drone, it's going to the be the cheapest way to get started and those skills will transition to the 5&quot; drone. Because it's so light it will break way less, and won't cause as much damage if you crash it into other things. Also, the parts are incredibly cheap so fixing it shouldn't cost you much.</p>
<h4 id="insideflying">Inside Flying</h4>
<p>100% just buy a Tiny whoop as mentioned above.</p>
<h4 id="backyardorlargeindoorflying">Backyard or Large Indoor Flying</h4>
<p>Build a 3&quot; or smaller drone with brushless motors. These little rockets are plenty fast but are much more manageable in a tight area.</p>
<h4 id="outdoorfreestyle">Outdoor Freestyle</h4>
<p>Build a 5 or 6&quot; quadcopter running 4-6S. Your primary focus for parts is going to be durability &amp; part-protection. When you free-style you're inevitably going to crash. Freestyle drones are typically bulkier and offer your parts a lot more protection.</p>
<h4 id="racingdrones">Racing Drones</h4>
<p>Build a 5&quot; quadcopter running 4-6S. Your primary focus for parts is going to be weight. Racing frames are typically not meant for holding up to 100s of crashes. They sacrifice durability for weight. The bigger the weight, the more battery you'll need to complete your laps, which results in more weight. So Keeping weight down will ensure that you can be as quick as possible and complete your laps with as small a battery as possible. It's also worth finding a frame in which you can swap out the arms easily when you break them during a race. You want to have that drone back up and running by the next heat.</p>
<h4 id="longrange">Long Range</h4>
<p>Build a 5-7&quot; Quadcopter. Your primary focus will be finding a frame that can carry an HD cam, and keeping weight down while being able to carry a large battery payload.</p>
<h4 id="cinematicslowsmoothvideo">Cinematic Slow Smooth Video</h4>
<p>Cinewhoop. Google It.</p>
<h5 id="simulators">Simulators</h5>
<p>You should be putting time in on a simulator before flying a drone in real life. It's going to save you a considerable amount of frustration and money. Your first time taking off is going to result in a crash, 100%. You may as well get those first 100 crashes out of the way on a simulator where it costs you zero time and money. You don't want to spend 10% of your time crashing and then 90% of your time on the workbench trying to band-aid it all back together.</p>
<p>You can use your Transmitter/Controller &amp; even your goggles to gain real skill with learning to maneuver a drone around.</p>
<p>The 3 simulators I use, in the order in which I like them, are:</p>
<ul>
<li><a href="https://velocidrone.com/">Velocidrone</a></li>
<li><a href="https://thedroneracingleague.com/drl-sim-3/">DRL Simulator</a></li>
<li><a href="https://store.steampowered.com/app/410340/Liftoff_FPV_Drone_Racing/">Liftoff</a></li>
</ul>
<h5 id="joinacommunity">Join a Community</h5>
<p>If you're trying to get started it's a really good idea to join Facebook Groups associated with whatever you're getting into. There are very active groups for almost anything out there. You can likely find a group for the parts you use to get help with them.</p>
<p>Here are some of the groups I'm in:</p>
<ul>
<li><a href="https://www.facebook.com/groups/BuckeyeFPVRacing/">BuckeyeFPV - A group from Columbus, Ohio</a></li>
<li><a href="https://www.facebook.com/groups/1471021132968792/">Cincinnati Quad Racers</a></li>
<li><a href="https://www.facebook.com/groups/1878850538834800/?ref=group_browse">Cinewhoopers - Small Ducted Drones for Cinemetography</a></li>
<li><a href="https://www.facebook.com/groups/138286273229152/?ref=group_browse">PyroflipRC - A company I buy parts from</a></li>
<li><a href="https://www.facebook.com/groups/betaflightgroup/">Betaflight Group</a></li>
</ul>
<p>TODO:</p>
<ul>
<li>Add in something about Chargers, power sources, and accessories.</li>
</ul>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><style>
    img{
        max-height: 250px;
    }
</style><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[FPV Gear Selloff]]></title><description><![CDATA[<p>I need to raise some funds so I'm selling off a bunch of gear I've been sitting on for a while. </p><!--kg-card-begin: markdown--><h2 id="completedrones">Complete Drones</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/1727907014051041">Spedix Rex 180 HD</a> - $55</li>
<li><a href="https://www.facebook.com/marketplace/item/963698164557506/">DJI Mavic Pro Flymore Combo</a></li>
</ul>
<h2 id="partialdrones">Partial Drones</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/218067882790129/">Flynoceros Zeus HD Buid + Extras</a></li>
<li><a href="https://www.facebook.com/marketplace/item/227393506170231/">Hyperlite EVO HD Racing Drone</a></li>
<li><a href="https://www.facebook.com/marketplace/item/864690530715116">SBA Spartan &amp; Race-flight</a></li></ul>]]></description><link>http://coreysnyder.me/fpv-gear-selloff/</link><guid isPermaLink="false">5e812b1c2d9ce11502a16583</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Sun, 29 Mar 2020 23:22:03 GMT</pubDate><content:encoded><![CDATA[<p>I need to raise some funds so I'm selling off a bunch of gear I've been sitting on for a while. </p><!--kg-card-begin: markdown--><h2 id="completedrones">Complete Drones</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/1727907014051041">Spedix Rex 180 HD</a> - $55</li>
<li><a href="https://www.facebook.com/marketplace/item/963698164557506/">DJI Mavic Pro Flymore Combo</a></li>
</ul>
<h2 id="partialdrones">Partial Drones</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/218067882790129/">Flynoceros Zeus HD Buid + Extras</a></li>
<li><a href="https://www.facebook.com/marketplace/item/227393506170231/">Hyperlite EVO HD Racing Drone</a></li>
<li><a href="https://www.facebook.com/marketplace/item/864690530715116">SBA Spartan &amp; Race-flight Drone</a></li>
</ul>
<h2 id="flightcontrollers">Flight Controllers</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/228530215222816/">New Airbot Nox 2.17</a> - $50</li>
</ul>
<h2 id="esc">ESC</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/211444160084946/">Airbot Typhoon 32 4in1</a> - $15 - 30x30</li>
</ul>
<h2 id="motors">Motors</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/213006869977132/">NEW Sunnysky R2305 2480kv</a> - $40</li>
<li><a href="https://www.facebook.com/marketplace/item/487430922498040/">TMotor F60 Pro 2500kv (Set of 4)</a> - $20</li>
</ul>
<h2 id="frames">Frames</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/589186149014886/">RC Crazed Extra Slim Phast 5&quot; (20mm Stack Only)</a> - $18</li>
<li><a href="https://www.facebook.com/marketplace/item/576032666818975">Sigan Drones x190 drone frame, PDB, and LEDs</a></li>
<li><a href="https://www.facebook.com/marketplace/item/762776047583871/">MRM Reaper &amp; Shendrones Zoom Pod, with flaco wing suit and lots of extras</a></li>
<li></li>
</ul>
<h2 id="accessories">Accessories</h2>
<ul>
<li><a href="https://www.facebook.com/marketplace/item/204567280841011/">Brand new set of stock Taranis X9D gimbals</a> - $15</li>
</ul>
<h1 id="sold">Sold</h1>
<ul>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/579443312919981/">Think Tank FPV Radio Transmitter Cover</a> - $15</s></li>
<li><s><a href="https://www.facebook.com/marketplace/item/2292291277743187/">New FPV Camera</a> - $5</s></li>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/214033083245502/">New Runcam Swift 2.8mm</a> - $20</s></li>
<li><s><a href="https://www.facebook.com/marketplace/item/509113800044079/">Eachine VTX03</a></s></li>
<li><s><a href="https://www.facebook.com/marketplace/item/1275348172674346/">RC Crazed Slim Phast 2.5&quot;</a> - $20</s></li>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/496090341060373/">Hyperlite 1106-7122kv Race Series Motors (Set of 4)</a> - $49</s></li>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/2957073697647782/">DYS 2205 2550kv with AIKON 30a ESC (set of 8)</a> - $50</s></li>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/2484711358412261/">Sunnysky 2305 2300kv Motors - heavily used</a> - $15</s></li>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/1090373284662449/">Edge Racing 2205 2480kv Motors</a> - $10</s></li>
<li>~~<strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/1082814862086837/">Edge Racing 2204 2300kv Motors</a> - $1</li>
<li><s>2x <a href="https://www.facebook.com/marketplace/item/1126800221003219/">ORI32 4-in-1 ESC 20x20</a> - $25 - 20x20</s></li>
<li><s><a href="https://www.facebook.com/marketplace/item/2577600265683019/">EMAX D-SHOT Bullet 12 A (Set of 4)</a> - $30</s></li>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/911817235918097/">AIKON SEMF 30A ESC (Set of 5)</a> - $15</s></li>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/523588145023485/">New Airbot Asgard 32 all-in-one</a> - $45</s></li>
<li><s><strong>SOLD</strong> <a href="https://www.facebook.com/marketplace/item/250394579421383/">Omnibus F4 Pro Corner Flight Controller</a> - $30</s></li>
</ul>
<!--kg-card-end: markdown--><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Mast Suite/Bathroom Remodel]]></title><description><![CDATA[<p>The last month has been quite stressful. We have been racing to get a massive master-suite remodel done before our Son was set to be born. We had a bit of a debacle with one of our contractors but we got past it and they wrapped up the project only</p>]]></description><link>http://coreysnyder.me/bathroom-remodel/</link><guid isPermaLink="false">5e17ad3adb1608051d296ca3</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Thu, 09 Jan 2020 22:56:35 GMT</pubDate><media:content url="http://coreysnyder.me/content/images/2020/01/6-4.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://coreysnyder.me/content/images/2020/01/6-4.jpg" alt="Mast Suite/Bathroom Remodel"><p>The last month has been quite stressful. We have been racing to get a massive master-suite remodel done before our Son was set to be born. We had a bit of a debacle with one of our contractors but we got past it and they wrapped up the project only 2 days before our Son joined our family! I've been on paternity leave and between taking care of Mom and Baby, I've been trying to wrap up a bunch of small things around the house.</p><p>As you might notice, we're still awaiting the delivery and install of our bedroom door, the shower door, and the bathroom mirror. I'm pumped with how it looks os far! </p><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/1-3.jpg" width="2048" height="946" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/2-4.jpg" width="1536" height="2048" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/3-3.jpg" width="2048" height="946" alt="Mast Suite/Bathroom Remodel"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/4-3.jpg" width="2048" height="1536" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/5-3.jpg" width="2048" height="946" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/6-3.jpg" width="2048" height="1536" alt="Mast Suite/Bathroom Remodel"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/7-3.jpg" width="2048" height="946" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/8-2.jpg" width="1536" height="2048" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/9-2.jpg" width="2048" height="946" alt="Mast Suite/Bathroom Remodel"></div></div></div></figure><!--kg-card-end: gallery--><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/10-4.jpg" width="1536" height="2048" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/11-2.jpg" width="1536" height="2048" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/12-2.jpg" width="1536" height="2048" alt="Mast Suite/Bathroom Remodel"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/13-2.jpg" width="2048" height="1536" alt="Mast Suite/Bathroom Remodel"></div><div class="kg-gallery-image"><img src="http://coreysnyder.me/content/images/2020/01/14-3.jpg" width="2048" height="1536" alt="Mast Suite/Bathroom Remodel"></div></div></div></figure><!--kg-card-end: gallery-->]]></content:encoded></item><item><title><![CDATA[Primsa.io and Expanding my DB Model with sub-types]]></title><description><![CDATA[<p>Right now I have <a href="https://www.rotorage.com">this pretty awesome</a> and fully featured app built on Prisma@1.34.0. As part of trying to be LEAN and get it running quickly I have purposely only focused on a single Product Type, <code>Flight Controllers</code>. The plan was never to stop there, but expand</p>]]></description><link>http://coreysnyder.me/primsa-io-and-expanding-my-db-model/</link><guid isPermaLink="false">5d8f7633db1608051d296b4e</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Mon, 04 Nov 2019 21:12:14 GMT</pubDate><content:encoded><![CDATA[<p>Right now I have <a href="https://www.rotorage.com">this pretty awesome</a> and fully featured app built on Prisma@1.34.0. As part of trying to be LEAN and get it running quickly I have purposely only focused on a single Product Type, <code>Flight Controllers</code>. The plan was never to stop there, but expand to other Types like: Motors, Receivers, Cameras, and maybe 10 other product types. I'm now at that point where it's time to expand and I am waffling on how to do this with the Prisma DataModel definitions available. </p><p>Let me start by showing you my current <code>datamodel.prisma</code>. I wanted to prune it down to reveal only what's relevant to the question but I worry in doing so, I take away context that could be important. So I apologize for it's length but here it is:</p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/e97e28de772cca2b08e38576b99617bf.js"></script><!--kg-card-end: html--><p>The Problem I ran into with just adding a new <code>type Motor{}</code> is when it comes to linking to the <code>type MerchantLinks</code>. A <code>MerchantLink</code> is essentially a way to attach a <code>FlightController</code> to a <code>Merchant(store)</code> with fields like <code>price</code>, <code>link</code>, <code>availability</code>. And as part of my DB Model I have it setup with relationships in both ways, with the purpose of being able to go to a Merchant page and see all of the products they offer. This means having a field called <code>flightController</code> on <code>type FlightControllerMerchantLink</code>. I cannot rename these to a <code>product</code> field on <code>type ProductMerchantLink</code> because <code>product</code> cannot be setup as <code>product: FlightController || Motor || Battery || Camera || ...</code>. I can only point it at a single type. </p><p>Ok, so I'm not DB Design Engineer, and it's probably one of my weaker engineering skills so this is where I turn to colleagues and the internet. In doing so, as far as I can tell I have two options to get around this. </p><h2 id="option-1-duplicate-the-flightcontrollermerchantlink-type-for-all-product-types">Option 1, Duplicate the FlightControllerMerchantLink Type for all product types</h2><p>I think I could create a bunch of the type <code>{ProductType}MerchantLink</code>, one for each product type. And then link all of those as optional fields on the merchant, like so:</p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/e90d48b4178cc9185240d74f13485c1e.js"></script><!--kg-card-end: html--><p>The thing I dislike about this approach is that it's not normalized. I'm repeating columns across many tables, such <code>price, url, inStock, postedBy, etc</code> repeated across all of the <code>{ProductType}MerchantLink</code>. Also, I'm not sure if this will have any ramifications that will block me from doing what I want to achieve in terms of site products, pages, or features. I've not taken this path yes, as I opted for option 2 instead. So I'll describe that now. </p><h2 id="option-2-replace-flight-controller-with-product-and-have-a-bunch-of-optional-fields-to-store-all-the-product-type-specific-data">Option 2, Replace Flight Controller with Product and have a bunch of optional fields to store all the product-type-specific data</h2><p>After talking with my co-worker he mentioned that he's solved this type of problem before by having a single type <code>Product</code> with a field of <code>Type</code> which describes what type it is, and then bunch of fields which point to the specific ProductType, where only one would be set at a time. Granted he did not implement something like this in Prisma, but I think it could still work. Like so:</p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/ae0ffa8a8743fd7d694072cca403f278.js"></script>
<!--kg-card-end: html--><p>With this setup, all of the linked <code>Types</code> for things common to all products, all link off of the <code>type Product</code>. These things include: Images, Product Reviews, Ratings, and Merchant Links. All of the fields common to all products can be added directly like cheapestPrice, averageReview, createdAt, etc. </p><p>I set about testing this new schema with a single type, <code>FlightController</code> and it seemed to work. So I pushed forward and expanded to 10 different product types. </p><p>Here's how my data model looks now</p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/8e53ef8ef5c66488a2afe789a8205843.js"></script><!--kg-card-end: html--><p>And here's my mutation resolvers for adding/editing products. NOTE: The code definitely needs cleaned up but I got it to a point that it works! </p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/d87ae09f2b8fea9870d67df87869abbf.js"></script><!--kg-card-end: html--><p>One of the benefits of going this route of making everything a base <code>Type Product</code> is that I can add/edit/delete any product type with a single mutation endpoint. I was also able to update my FE code for all of the pages I had setup for just flight-controllers to be retrofitted to work with the other product types. </p><!--kg-card-begin: markdown--><p>This includes:</p>
<ul>
<li>Product List Page</li>
<li>Product Details Page</li>
<li>Product Edit Page</li>
<li>Product Search Component</li>
<li>Add/Edit Images Component</li>
<li>Add/Edit Reviews Component</li>
</ul>
<!--kg-card-end: markdown--><p>I'm not sure if this approach will cause issues down the road but it seems to be working for now. </p><p>One thing that I thought for sure wouldn't work but was pleasantly surprised on, was that my product list page queries still work, with a little modification. I'm able to sort/filter at the Product and Product.SubType (Product.flightController) levels in a single Prisma query like so. A key thing to note here is that I'm doing an <code>orderBy</code> at the <code>Product</code> level but I'm doing filtering <code>where</code> clause at the <code>Product.flightController</code> level. </p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/90ba00ffb7a24d09a91a67a7853b7918.js"></script><!--kg-card-end: html--><p>Fast forward 2 weeks and this approach is still going strong. I created a new feature which allows the user to build an entire drone attaching all of the common components such as Frame, Motors, Flight Controller. The components are all of type <code>Product</code>, with product-specific sub-types. I plan to continue heading down this path and I'll report back if I run into any issues. </p>]]></content:encoded></item><item><title><![CDATA[Problems with Handling Print Styles with Javascript]]></title><description><![CDATA[<p>Recently I've been working at print-specific styling for my webpages and I'm running into interesting problems where Javascript is concerned. </p><p>TLDR; Triggering custom print state when javascript is involved is problematic.</p><p>I got assigned to take a React app and make it very print-friendly. The pages are mostly reports so</p>]]></description><link>http://coreysnyder.me/problems-with-handling-printing-with-javascript/</link><guid isPermaLink="false">5da601addb1608051d296c19</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Tue, 15 Oct 2019 17:35:55 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1434626881859-194d67b2b86f?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" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1434626881859-194d67b2b86f?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Problems with Handling Print Styles with Javascript"><p>Recently I've been working at print-specific styling for my webpages and I'm running into interesting problems where Javascript is concerned. </p><p>TLDR; Triggering custom print state when javascript is involved is problematic.</p><p>I got assigned to take a React app and make it very print-friendly. The pages are mostly reports so lots of tables and graphs. So I'm covering things like:</p><ul><li>Removing buttons like save/export, or other call-to-actions, on print</li><li>Replacing drop-downs with headers on print</li><li>Resizing text for print (things that look great on the screen are often not sized appropriately for print)</li><li>Resizing table columns or hiding/showing columns based on print to make them fit. (no side-scroll on print)</li></ul><p>Those things above are all tedious but simple. They can be accomplished with basic style changes using `@media print` queries in my LESS files or applying the proper bootstrap3 classes.</p><p>Now I'm getting into more complicated changes like:</p><ul><li>Taking dynamically scaled elements like SVG charts/graphs and making them look right on print. The types of scaling which happens via JS, not CSS.</li><li>Turning a paginated table into one which fetches more/all results. In the UI you may want only the top 10 items per page, but for print, it is helpful to have the exhaustive list or top 100.</li><li>I have header status boxes which resize the font based on its contents. So `$10` appears in a larger font than `$10,000` so that they can sit in the same size boxes on a dashboard.</li></ul><p>This latter group is not so easy. It looks like Browser Manufacturers haven't put much focus on adding events/hooks into the browsers print modal events. As far as I can tell older versions of IE &amp; Firefox have events, but they're unreliable.</p><p>In one particular example, I am using <a href="http://recharts.org/en-US/">ReCharts</a> which offers a "ResponsiveContainer" component which will resize a chart based on the size of its parent container using javascript. This is a <a href="https://github.com/recharts/recharts/issues/1114">known issue</a>. The problem is, when the print modal opens, javascript execution in that window is frozen and so it cannot run the code to handle the chart resize. So it's the exact same size it was on screen, even if, through print styles, I bump its parent container to 100% of the width of the page. The chart gets stuck at whatever size it was pre-print modal.</p><p>I've identified a few ways to handle this, none of which are great IMO:</p><ol><li>Render the chart component twice, nested in 2 different divs. One which is shown for print, the other for the screen. The one for print has a hard-coded width, the other uses the responsive container. PROS: It requires no custom JS to be executed. The user can use the browsers CMD+P, FILE-&gt;PRINT to print. CONS: This is gross b/c for every chart on the screen it is rendered twice, and only one is shown at a time. This means a decent bit of overhead, especially on pages with many charts.</li><li>Have my own "Print" button/icon on the screen which the user must click to trigger a set of custom pre/post print hooks. So the user clicks "Print", I run some PRE JS setting the page into a PRINT state, calling the window.print() method, and then using the returned promise to trigger my POST JS unsetting the PRINT state and returning the page to normal. PROS: This gives me the ability to cascade the PRE-PRINT property into my different components and let them handle setting themself up for print. The components have complete control of doing their own custom print state. CONS: The user cannot use CMD+P or FILE&gt;Print. If they do my JS won't be aware of the print being triggered. If a component needs to make an ASYNC request say to fetch more table rows, it's going to cause me to have to add a delay to the `window.print()` firing. Otherwise, it'll fire before the results are added.</li><li>GUT all JS driven responsive design. I could make it so the chart containers are all set-width columns, and let the other containers resize around them. I could remove the dynamic resizing of text based on its content. PROS: Reduces complexity around print. It doesn't require any special page state to be used. Users can print via browsers built-in mechanisms. CONS: UI/UX will not be as good. Screens and paper are not the same widths and so making it work for only 1 will result in the other not looking as good. For instance, it may be desirable to have a chart be 100% of the width of the screen and 100% of the printed pages width. Without a dynamic sizing, this isn't possible.</li></ol><p>Now when I run into a problem that doesn't have a great Stackoverflow answer, I generally start questioning why I'm a unique snowflake. It's usually b/c I've made a misguided architecture decision and I need to make some changes. In this case, I don't know how I could do things differently outside of avoiding any javascript-driven size adjustments which would mean avoiding responsive design to some extent.</p><p>If you were in my shoes what would you do? Have you faced this problem before? Let me know!</p>]]></content:encoded></item><item><title><![CDATA[Prisma and GraphQL services]]></title><description><![CDATA[<p>Recently I've been getting pretty deep into <a href="http://prisma.io">Prisma</a>. Prisma is a DB as a service replacing traditional ORMs with an auto-generated client library.  This is a WIP article which is meant to review Prisma.io versus other options and act as a brain-dump as I use it and learn more.</p>]]></description><link>http://coreysnyder.me/prisma-database-orm-tools-review/</link><guid isPermaLink="false">5d71661bdb1608051d29677a</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Databases]]></category><category><![CDATA[ORM]]></category><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Tue, 24 Sep 2019 15:24:48 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1523495556462-52cbd31f2afe?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" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1523495556462-52cbd31f2afe?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Prisma and GraphQL services"><p>Recently I've been getting pretty deep into <a href="http://prisma.io">Prisma</a>. Prisma is a DB as a service replacing traditional ORMs with an auto-generated client library.  This is a WIP article which is meant to review Prisma.io versus other options and act as a brain-dump as I use it and learn more. </p><p>The reason I chose Prisma was because it was tightly coupled with the tutorials I was going through on <a href="https://www.howtographql.com/">How to GraphQL</a>. The site is run by the Prisma team and so after finishing a handful of their tutorial tracks, I felt pretty comfortable moving forward with my Prisma &amp; GraphQL setup. </p><p>With just a few commands in the terminal, you can basically spin up a API Middleware layer tied to a deployed API and Postgres Database on the Prisma cloud. Unlike other DB as a Service platforms like Hasura, Prisma still requires you to run your own middleware API.</p><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="http://coreysnyder.me/content/images/2019/09/image.png" class="kg-image" alt="Prisma and GraphQL services"></figure><!--kg-card-end: image--><p>In my case my GraphQL server is a NodeJS server using graphql-yoga  implementation. </p><p>One of the things I really like about Prisma is that managing your DB Tables is all done through a <code>datamodel.prisma</code> file which looks like this:</p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/128a6e9f62ab234b6733f304f2f0b040.js"></script><!--kg-card-end: html--><p>If I need to add a new column, say <code>Hobbies</code> for instance. I simple add a new type and setup relationships with other types. Then I run <code>prisma deploy</code> and it will validate my schema, and then send it to the deployed prisma server where it will make the necessary Postgres changes to my DB tables. It will setup relationship tables between types, add new columns, etc. I don't ever directly manage my databases. </p><p>After making changes to the database, it generates a new client library in <code>src/generated/prisma-client</code>. This is the ORM which I use to interact with the database. I can do this through commands like </p><!--kg-card-begin: code--><pre><code>const bob = await prisma
  .users({ email: "bob@prisma.io" }</code></pre><!--kg-card-end: code--><p>I don't write any SQL for these interactions. The ORM has been able to handle all of my requests thus far for things like filtering and sorting. </p><p></p><h3 id="it-s-got-it-s-issues-though">It's got it's issues though</h3><p>I've run into some issues with Prisma that are worth talking about.</p><h4 id="support">Support</h4><p>For one their support is less than ideal. They have a slack channel and a forum, but it's pretty standard for your questions to go unanswered. You see a ton of people asking questions and very few providing answers. </p><h4 id="complex-db-schema-s-might-not-be-supported">Complex DB Schema's might not be supported</h4><p>If you have a more complex DB Schema, there's a chance Prisma can't support it. I'm currently trying to implement a new DB schema and I've been trying to get answers at whether Prisma can support what I'm trying to do. I have yet to receive a straight answer.</p><h4 id="cost">Cost</h4><p>Prisma cannot run on the Heroku free tier or on Zeit because of its image size and resource consumption. I spun up the Prisma back-end using their AWS Cloud Formation template, and with zero traffic, I was being billed $90/month. In comparison Hasura can service a few thousand complex GraphQL queries per second well within a 100MB of RAM which means you can build a side-project that scales to a thousand concurrent users at 5$ a month running both Postgres and Hasura. </p><h2 id="alternate-software">Alternate Software</h2><p>Prisma isn't the only software out there to offer what they do. Here are some alternatives:</p><!--kg-card-begin: markdown--><ul>
<li><a href="https://fauna.com/">FaunaDB</a></li>
<li><a href="http://typeorm.io/">TypeORM</a></li>
<li><a href="https://blog.hasura.io/hasura-vs-prisma-9ffc7271eda8/">Hasura</a></li>
<li><a href="https://www.graphile.org/postgraphile/?ref=stackshare">Graphile</a></li>
<li><a href="http://sequelizejs.com/">SequelizeJS</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Setting up SSL for a NodeJS GraphQL API deployed to AWS EC2]]></title><description><![CDATA[Below I'll describe how I got my NodeJS GraphQL API running on a AWS EC2 Instance setup with SSL]]></description><link>http://coreysnyder.me/setting-up-ssl-for-an-s3-static-spa/</link><guid isPermaLink="false">5d88d46bdb1608051d296a51</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Infrastructure]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Godaddy]]></category><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Mon, 23 Sep 2019 19:24:35 GMT</pubDate><content:encoded><![CDATA[<p>In <a href="http://coreysnyder.me/setting-up-https-ssl-on-my-godaddy-aws-s3-site/">my last post</a>, I set up my AWS S3 ReactJS Single-page-application with an SSL Certificate using AWS Certificate Manager and AWS CloudFront. When I left off, my App was loading correctly except it was trying to talk to my non-https-enabled API; which the browser is not OK with. Below I'll describe how I got my NodeJS GraphQL API setup with SSL.</p><h2 id="key-terms-">Key Terms:</h2><p><strong><strong>AWS - </strong></strong>Amazon Web Services</p><p><strong><strong>AWS S3 -</strong></strong> Amazon Simple Storage Service is a service offered by Amazon Web Services that provides object storage through a web service interface. This is where our static SPA is hosted.</p><p><strong>AWS API Gateway -</strong> A service for creating, publishing, maintaining, monitoring, and securing REST and WebSocket APIs. It gives us a public domain for attaching the SSL certificate.</p><p><strong><strong>AWS Certificate Manager -</strong></strong> a service that lets you easily provision, manage, and deploy public and private Secure Sockets Layer/Transport Layer Security (SSL/TLS) certificates for use with AWS services and your internal connected resources. SSL/TLS certificates are used to secure network communications</p><p><strong><strong>AWS CloudFront -</strong></strong> a content delivery network offered by Amazon Web Services. It's how we create, and attach, the SSL certificate to our S3 bucket.</p><p><strong><strong>SPA -</strong></strong> Single Page Application. In this case it will be a static Webpack-built ReactJS App.</p><h3 id="getting-my-ec2-instance-node-api-behind-a-domain">Getting my EC2 instance, Node API, behind a domain</h3><p>There are a bunch of different AWS Server/Service configurations to achieve this goal. They all come with pros and cons in terms of complexity, speed, scalability, flexibility, and cost. This project is a for-fun side project right now, so I don't want to set it up in a way that it could scale to a million users if it will cost me a fortune every month. Especially since it may very likely generate $0 indefinitely. </p><!--kg-card-begin: markdown--><p>There are two ways I considered right off the bat. <em>These are by no means the only two ways. If you know of a better, more cost-effective way, let me know in the comments.</em></p>
<ol>
<li>Use API gateway to route the API traffic to the EC2 API and the UI traffic to the S3 bucket. API Gateway will be able to use the cert I generated in the last article. This is probably the preferred way but it comes at a +$16 minimum monthly cost just to turn on the API Gateway.</li>
<li>Drop the API Gateway and the Cloudfront Distribution and run all of the traffic to Nginx to an EC2 instance where my NodeJS is running. Then have Nginx be the SSL terminator and route the /api traffic to the API running on <code>localhost:4000</code> and all other traffic to my S3 bucket for the front-end.</li>
</ol>
<!--kg-card-end: markdown--><p>In either option, the browser would hit my site at <code>mydomain.com</code> and then it would make the API calls to <code>mydomain.com/api</code>. </p><p>I ended up going with <strong>Option 2</strong>, if only temporarily until this project is generating revenue. This meant throwing away some of the work I covered in <a href="http://coreysnyder.me/setting-up-https-ssl-on-my-godaddy-aws-s3-site/">the last article</a> where I was using AWS CloudFront and AWS Certificate Manager to route traffic to my S3 bucket. Instead, the flow of loading the app will look like this.</p><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="http://coreysnyder.me/content/images/2019/09/Screen-Shot-2019-09-23-at-3.42.36-PM.png" class="kg-image"></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p>This should have been pretty straightforward as there were 2 things that needed done:</p>
<ol>
<li>Update the DNS of my website to include:</li>
</ol>
<pre><code>   A       @      IP_OF_EC2
   CNAME   www    @
</code></pre>
<ol start="2">
<li>Update Nginx to do the proper proxying</li>
</ol>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/b80ad9aad7038fc38a94f46a4c97abd3.js"></script><!--kg-card-end: html--><p>Embarrassingly, That took way longer than it should have because I kept ending up with dirty EOL characters all over and so I had to keep piping the changes through <a href="https://www.textfixer.com/tools/remove-line-breaks.php">this tool </a>every time. Which would collapse the file down with no spaces which made re-editing it a PITA. It was driving me nuts. Even when I'd edit it in Vim directly to try and remove the characters it still found them nested into my code in a way I couldn't seem to remove directly. I ended up fixing this by copying to "fixed' file back into Pycharm and installing <a href="https://plugins.jetbrains.com/plugin/4415-nginx-support">this plugin</a> and then highlighting the text and choosing "Reformat Code" which did the trick. I should have done this right off the bat instead of fighting through it, but I digress.</p><p>Once I had Nginx configured correctly, and the DNS changes had propagated to point my domain to my EC2 Public IP, the site was loading again on HTTP properly. The next step is adding SSL to the mix. </p><h3 id="get-https-setup-with-certbot">Get HTTPS Setup with Certbot</h3><p><br>Since I"m on AWS Amazon Linux 2 kernel which uses <code>YUM</code> instead of <code>APT</code>, I started <a href="https://aws.amazon.com/blogs/compute/extending-amazon-linux-2-with-epel-and-lets-encrypt/">with this tutorial</a> and <strong>followed up through step 5</strong> where they start getting into Apache Configuration.</p><p>Next jump to step 4 here: <a href="https://certbot.eff.org/lets-encrypt/centosrhel7-nginx.html">https://certbot.eff.org/lets-encrypt/centosrhel7-nginx.html</a>. At that point, you've got the certbot installed and you can proceed for a generic Nginx setup. </p><p>After wrapping that up, I was able to reload my site and it immediately got kicked over to HTTPS and all was well. I was kind of surprised to see even my WebSocket connection was using <code>WSS://</code> without any issues. </p><h2 id="-woohoo-">🎉 WOOHOO! 🎉</h2>]]></content:encoded></item><item><title><![CDATA[Deploying a static ReactJS SPA with HTTPS enabled on AWS S3 using CloudFront and Certificate Manager]]></title><description><![CDATA[This article covers setting up HTTPS/SSL for an Amazon S3 Static Single Page Application using AWS CloudFront and AWS Certificate Manager on a domain hosted by GoDaddy.com. ]]></description><link>http://coreysnyder.me/setting-up-https-ssl-on-my-godaddy-aws-s3-site/</link><guid isPermaLink="false">5d82514fdb1608051d2968e7</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Infrastructure]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Godaddy]]></category><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Mon, 23 Sep 2019 19:15:29 GMT</pubDate><content:encoded><![CDATA[<p><em>This article covers setting up HTTPS/SSL for an Amazon S3 Static Single Page Application using AWS CloudFront and AWS Certificate Manager on a domain hosted by GoDaddy.com. </em></p><h2 id="key-terms">Key Terms</h2><p><strong>AWS - </strong>Amazon Web Services</p><p><strong>AWS S3 -</strong> Amazon Simple Storage Service is a service offered by Amazon Web Services that provides object storage through a web service interface. This is where our static SPA is hosted. </p><p><strong>AWS Certificate Manager -</strong> a service that lets you easily provision, manage, and deploy public and private Secure Sockets Layer/Transport Layer Security (SSL/TLS) certificates for use with AWS services and your internal connected resources. SSL/TLS certificates are used to secure network communications </p><p><strong>AWS CloudFront -</strong> a content delivery network offered by Amazon Web Services. It's how we create, and attach, the SSL certificate to our S3 bucket.</p><p><strong>SPA -</strong> Single Page Application. In this case it will be a static Webpack-built ReactJS App. </p><!--kg-card-begin: hr--><hr><!--kg-card-end: hr--><p>This week I started on the topic of moving my project from http to https to make it more legit as I near a public "release".  Why is moving to HTTPS important?</p><h4 id="reason-1-google">Reason 1: Google</h4><p>The big driver for this need is Google, which is phasing support for HTTP connections out of Google Chrome. Today, Chrome warns users when they’re accessing a site HTTP, but doesn’t prevent it altogether. In some cases, they get a nasty warning which will likely scare away my users. </p><!--kg-card-begin: image--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="http://coreysnyder.me/content/images/2019/09/image-1.png" class="kg-image"><figcaption><em>This is a site with bad HTTPS, but it gives you a notion of how HTTP might look in the near future.</em></figcaption></figure><!--kg-card-end: image--><h4 id="reason-2-it-s-the-right-thing-to-do">Reason 2: It’s the Right Thing to Do</h4><p>HTTP connections reveal, at a minimum, full information about the routing <strong><strong>and content</strong></strong> of requests to everyone else on the local network. If your users are accessing your site in a coffee shop, no amount of server-side security will prevent you from leaking information in the stage between the user (and their router) and your site. Now I won't have any sensitive data, but it's a good practice to follow regardless.</p><h2 id="so-let-s-get-started-">So let's get started!</h2><h3 id="step-1-get-a-cert">Step 1: Get a Cert</h3><p>I initially all signs pointed toward <a href="https://letsencrypt.org/getting-started/">https://letsencrypt.org/getting-started/</a> and the tool <a href="https://certbot.eff.org/">https://certbot.eff.org/</a>. These tools looked great but as far as I could tell they aren't a good fit if you're deploying a static site running on Amazon S3 because you don't have SSH access as far as I know. Besides, AWS has its own tooling for setting up SSL certs. </p><h4 id="enter-aws-certificate-manager">Enter AWS Certificate Manager</h4><p>Amazon Web Services (AWS) has great resources for issuing and using SSL certificates, but the process of migrating existing resources to HTTPS can be complex — and it can also require many intermediate steps. It ended up being more work than I had expected, but mostly because GoDaddy DNS and UIs are awful. </p><p>To get started you log into the AWS Certificates Manager console and request a certificate. They have 2 options for confirming your domain:<br> * CNAME Records<br> * Email </p><p>The documentation suggests the CNAME path is the better of the two long term, so that's what I did. They give you some CNAME records you must add to your DNS Management for your domain. In my case this is GoDaddy (But not for long hopefully). </p><p>I entered the CNAME records, set the TTL to 30 min, and then waited.... and waited.. and waited. </p><p>After 24 hours I started to get impatient. I started googling around and found <a href="https://forums.aws.amazon.com/thread.jspa?messageID=913098">this page</a> which details an issue with the GoDaddy DNS system. The problem with GoDaddy is that they auto-append the domain name at the end of the "host" field when creating a CNAME record. Therefore, you are required to omit the apex domain from the "name" string provided to you by ACM when adding it to "host" on GoDaddy.</p><p>So if AWS gives you a record like:</p><!--kg-card-begin: markdown--><pre><code>RECORD NAME: _ho9hv39800vb302vejvnw3vnewoib3u.example.com.
RECORD VALUE: _cjhwou20vhu20uvoneouw20vuyb2ovb9.j9s73ucn9vy.acm-validations.aws.
</code></pre>
<!--kg-card-end: markdown--><p>Enter the following for GoDaddy:</p><!--kg-card-begin: markdown--><pre><code>NAME: _ho9hv39800vb302vejvnw3vnewoib3u
VALUE: _cjhwou20vhu20uvoneouw20vuyb2ovb9.j9s73ucn9vy.acm-validations.aws.
</code></pre>
<!--kg-card-end: markdown--><p>After doing so, I popped back over to AWS Cert Manager and hit refresh and after a couple of minutes, it went from pending to verified! </p><h3 id="step-2-link-with-cloudfront">Step 2: Link with CloudFront</h3><p>To connect your new cert with your S3 bucket you need to add a product to sit between your DNS &amp; your S3 bucket. This product is AWS CloudFront</p><p>Go through the AWS Console and access the CloudFront product. Click to create a CloudFront distribution and select your AWS S3 Bucket as an origin and choose the cert we just created above. </p><p>After doing this, I tried to access the site via the CloudFront distribution <strong>Domain Name</strong> and it told me <code>Access Denied</code>. </p><p>It looks like I need to specify the Default Root Object as <code>index.html</code> which is the root file inside my S3 bucket: </p><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="http://coreysnyder.me/content/images/2019/09/Screen-Shot-2019-09-18-at-3.49.45-PM.png" class="kg-image"></figure><!--kg-card-end: image--><p>When I refreshed my page, it loaded the HTML document stored in the S3 bucket, but the page was blank. I checked the JS console and saw it immediately threw errors. <code>client.js:653 Mixed Content: The page at 'https://d1krmsds175gpf.cloudfront.net/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://54.xxx.xx.49/'. This request has been blocked; this endpoint must be available over WSS.</code></p><p>I believe this is because my S3 bucket is now being served over HTTPS but the URI of my EC2 instance/api I'm trying to connect to is hardcoded to HTTP and :WS. I updated my FE to use WSS but it's telling me that my endpoint doesn't have WSS enabled still. </p><p><strong>Watch Out! </strong>I learned that CloudFront has a built-in cache, so changes I was making to the S3 bucket weren't showing up when I refreshed the CloudFront URL. I ended up finding <a href="https://aws.amazon.com/premiumsupport/knowledge-center/prevent-cloudfront-from-caching-files/">this post</a> which describes going in and setting the Min/Max TTL. I'll need to make sure I set this back later to take advantage of caching. </p><p>To at least verify that this would work on HTTP, I bumped the CloudFront Distribution viewer Protocol Policy to: HTTP and HTTPS and loaded the page on HTTP and verified it worked. </p><p>Now I need to figure out how to get my AWS EC2 instance to use an SSL Cert. A cert typically needs to be applied to a domain, not an IP, which is how I'm accessing my API. So this needs to change I think. </p><p><a href="http://coreysnyder.me/setting-up-ssl-for-an-s3-static-spa/">Up next I made some changes in order to get my NodeJS GraphQL API, running on AWS EC2, setup with an HTTPS Certificate. </a></p><h3></h3>]]></content:encoded></item><item><title><![CDATA[Gatsby, Ghost.org, and Netlify powered Website/Blog]]></title><description><![CDATA[Deploying a Blog/Site with Ghost.org, Gatsby, and Netlify. ]]></description><link>http://coreysnyder.me/gatsby-ghost-and-netlify-powered-blog-site/</link><guid isPermaLink="false">5c4b2f3e43ca1657b89bcff1</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Deployment]]></category><category><![CDATA[Infrastructure]]></category><category><![CDATA[ReactJS]]></category><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Wed, 18 Sep 2019 15:25:00 GMT</pubDate><content:encoded><![CDATA[<p>I have been hearing about this JS Library/Starter project called Gatsby for a while so I decided to finally take a swing at it since I had a new site I wanted to launch and I figured it would be a good opportunity to do so. This blog runs on <a href="http://ghost.org">Ghost.org</a> which allows me to get a really great content editor for my dynamic content/posts. I saw that Ghost.org had a Gatsby integration which essentially lets you do launch a standard Gatsby site, but connect to your blog content using GraphQL. The way it works is that you end up with 2 separate sites:</p><ul><li>Your standard ghost.org site which really doesn't need a domain. I spun up a standard DigitalOcean Ghost.org droplet and I access that blog site through the IP address. This won't be a customer facing site but rather a content authoring tool.</li><li>Your Gatsby Site which pulls in content from the blog, but is the full Gastby platform. I plan to deploy this one via Netlify and point a domain at it. It'll be the customer facing site.</li></ul><p>UPDATE: 10/2019 - This setup ended up being pretty easy and I was able to do exactly as described above. I meant to document this process but unfortunately forgot about it, and it's been over 8 months since I got the work done. Feel free to ask me question though and I'll help out where I can! </p><p>Here's the deployed project: <a href="https://www.moonlitaerial.com/">https://www.moonlitaerial.com/</a></p>]]></content:encoded></item><item><title><![CDATA[React-Apollo Store update not triggering UI update]]></title><description><![CDATA[<p><strong>[SOLVED] Scroll to the bottom!</strong></p><p>I am consistently having the issue where in some cases when I update the Apollo Cache/Store the UI is auto-magically updated and in other cases the UI doesn't seem to be affected by the change. It depends on what type of change I'm making</p>]]></description><link>http://coreysnyder.me/react-apollo-cache-update-issue/</link><guid isPermaLink="false">5d7fa281db1608051d296870</guid><category><![CDATA[Web-App]]></category><category><![CDATA[ReactJS]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Mon, 16 Sep 2019 15:18:24 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1563856475798-54b0529545bc?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" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1563856475798-54b0529545bc?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="React-Apollo Store update not triggering UI update"><p><strong>[SOLVED] Scroll to the bottom!</strong></p><p>I am consistently having the issue where in some cases when I update the Apollo Cache/Store the UI is auto-magically updated and in other cases the UI doesn't seem to be affected by the change. It depends on what type of change I'm making to the data. </p><p>If I make API calls to do a <code>DELETE</code> mutation, and on success I update the apollo store by plucking the item from the array and calling <code>store.writeQuery</code>, the UI auto-magically gets updated and it's great!</p><p>On the other hand whenever I do an <code>ADD</code> mutation, and on success I update the apollo store by pushing the newly created item into the array and calling <code>store.writeQuery</code>, the UI is unaffected. </p><h3 id="let-me-show-you-the-code">Let me show you the code</h3><p>Here is my code for deleting an review:</p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/d4d64ee906b8acb594cf45d5fbbd4295.js"></script><!--kg-card-end: html--><p>And here's my code for adding a review:</p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/c6b436924364cc7da323443d4a21dcc3.js"></script><!--kg-card-end: html--><p></p><p>As you can see the code is identical outside of how I modify the collection of reviews. In one case I delete an item, in the other I push a new one. Yet their impact on the page is very different. I'm following the examples from the <a href="https://www.apollographql.com/docs/angular/features/cache-updates/#update">update documentation</a>.</p><p>One piece of feedback I got was that the writeQuery has issues if the data your adding/editing doesn't match what's already in the store. So I logged an existing item versus the new item being added and here are the results. </p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/414ca01f6eed3d8a51cd0243716f4aed.js"></script><!--kg-card-end: html--><p>As you can see they're identical. So I'm not sure what's up!?</p><p>I <code>console.log('newReview', newReview)</code> and here's what I get:</p><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="http://coreysnyder.me/content/images/2019/09/Screen-Shot-2019-09-16-at-5.26.55-PM.png" class="kg-image" alt="React-Apollo Store update not triggering UI update"></figure><!--kg-card-end: image--><p>If I <code>console.log</code> the <code>localStoreData</code> after updating it I see the following. You can see that the new review was added to the collection. And that's what I'm passing to the <code>writeQuery</code>, so what gives?</p><!--kg-card-begin: image--><figure class="kg-card kg-image-card"><img src="http://coreysnyder.me/content/images/2019/09/Screen-Shot-2019-09-16-at-5.29.52-PM.png" class="kg-image" alt="React-Apollo Store update not triggering UI update"></figure><!--kg-card-end: image--><p>This is infuriating! Is it a bug? Am I doing something wrong? I'm having trouble getting answers.</p><h3 id="my-workarounds">My Workarounds</h3><p>Initially I was getting around this by triggering a page refresh, which is gross and I don't want to go that route. </p><p>I did find another trick which was to add a <code>refetchQueries</code> property to my mutation call. This tells Apollo that the data has changed on the server and it needs to re-call the API to fetch the updated data. This isn't the worst thing every but it does seem silly to hit the server when I have all of the info on the client to update the store. </p><!--kg-card-begin: html--><script src="https://gist.github.com/coreysnyder/92bdde35252289944dc3be147d64112f.js"></script><!--kg-card-end: html--><p>If you know what I'm doing wrong please drop me a line in the comments below or on twitter <a href="https://twitter.com/coreysnyder">@coreysnyder</a>. This is driving me nuts! </p><h1 id="solved-">SOLVED! </h1><p>Thanks to the help of Lawrence Baker, <a href="https://spectrum.chat/apollo/react-apollo/">from Spectrum Chat</a>, who pointed me in the right direction; This is case closed! He pointed out that there was a nuance between my delete code and my add/edit code in that with the delete I was creating an entirely new object versus modifying the existing one. When you modify the existing object in memory, when Apollo does an equality check between the new/old state, it sees the two objects as the same object, and therefor does not trigger an update. </p><p>I tested this by first doing: <code>localStoreData.getProductReviews = [...localStoreData.getProductReviews, newReview]</code></p><p>This didn't work because I was still modifying the base <code>localStoreData</code> object, even though I was creating an entirely new <code>getProductReviews</code> array. </p><p>So I with a level further with:<code>localStoreData = { getProductReviews: [...localStoreData.getProductReviews, newReview] }</code></p><p>In this case I am creating an entirely new <code>localStoreData</code> object and therefor Apollo sees it as a new state and triggers the updates to my UI. </p><p>I'm so glad to have solved this because it was driving me nuts! I am going to circle back and retrofit my old code using this new revelation. </p>]]></content:encoded></item><item><title><![CDATA[Learning about Lerna]]></title><description><![CDATA[<p>Today I spent some time learning about and evaluating the tool <a href="http://coreysnyder.me/learning-about-lerna/lerna.js.org">Lerna</a>. Here's what I picked up.</p><h3 id="what-is-lerna">What is Lerna?</h3><p>From the docs: "A tool for managing JavaScript projects with multiple packages." When I first read this it didn't make complete sense so I had to dig in further. </p><p>Lerna</p>]]></description><link>http://coreysnyder.me/learning-about-lerna/</link><guid isPermaLink="false">5d727101db1608051d2967a3</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Fri, 06 Sep 2019 15:18:38 GMT</pubDate><content:encoded><![CDATA[<p>Today I spent some time learning about and evaluating the tool <a href="http://coreysnyder.me/learning-about-lerna/lerna.js.org">Lerna</a>. Here's what I picked up.</p><h3 id="what-is-lerna">What is Lerna?</h3><p>From the docs: "A tool for managing JavaScript projects with multiple packages." When I first read this it didn't make complete sense so I had to dig in further. </p><p>Lerna is an NPM installable tool that you install on top of your existing project. When you <code>init</code> it, it adds some extra directories/files and structure to your app which enables some handy tools which you can run against your projects to add some quality-of-life features.</p><h3 id="what-kind-of-qol-features">What kind of QoL features?</h3><!--kg-card-begin: markdown--><ul>
<li>It can do some fancier <code>npm-link</code> functionality for allowing you to reference other packages in your mono-repo via symlinks. This is helpful since in a monorepo you cannot npm install from github links <code>npm i http://github</code>.</li>
<li>It can help you run scripts across all of your packages. For instance <code>learna run test</code> will kick off the <code>npm run test</code> in all of your packages. This can be used for other scripts like for building your code.</li>
<li>It can help you with creating new versions of your packages for releasing code with some intelligent features like only updating versions when necessary.</li>
<li>It will maintain a Changelog keeping track of everything that is in a release.</li>
<li>It will give you a diff tool which enables you to see the changes in all commits across all packages since the last release.</li>
</ul>
<!--kg-card-end: markdown--><h3 id="who-should-use-lerna">Who should use Lerna?</h3><p>If you run a <a href="https://www.google.com/search?q=monorepo+github&amp;rlz=1C5CHFA_enUS853US853&amp;oq=monorepo+&amp;aqs=chrome.0.69i59j69i57j0j69i60l2j69i61.2175j0j0&amp;sourceid=chrome&amp;ie=UTF-8">Monorepo</a> it might be worth using Lerna. If you don't use a monorepo I doubt it's worth adding. In my current role I don't believe it's a good fit for what we do, as we have the opposite of a Monorepo. Our frontend stack is a MicroServices architecture. </p><p>If I've missed anything please drop me a message in the comments below. Thanks!</p>]]></content:encoded></item><item><title><![CDATA[NPM Audit === A lot of tedious work]]></title><description><![CDATA[<p>On a project recently I decided to run <code>npm audit</code> and then fix 100% of the issues it revealed. The purpose of this is to make sure that I'm not running code in production with known security vulnerabilities. This idea was sparked by a <a href="https://blog.npmjs.org/post/185397814280/plot-to-steal-cryptocurrency-foiled-by-the-npm">recent security breach</a> where an NPM</p>]]></description><link>http://coreysnyder.me/the-importance-of-npm-audit-and-how-to-use-it/</link><guid isPermaLink="false">5d49bb9cdb1608051d2964aa</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Tue, 27 Aug 2019 16:35:21 GMT</pubDate><content:encoded><![CDATA[<p>On a project recently I decided to run <code>npm audit</code> and then fix 100% of the issues it revealed. The purpose of this is to make sure that I'm not running code in production with known security vulnerabilities. This idea was sparked by a <a href="https://blog.npmjs.org/post/185397814280/plot-to-steal-cryptocurrency-foiled-by-the-npm">recent security breach</a> where an NPM module was updated to attempt to steal $13 Million in cryptocurrency. It was kind of a pain but I think it was a worthwhile exercise and I learned a lot about NPM and Docker having gone through it. </p><p>Here's what I got on the initial run of <code>npm audit</code>:<br>`found 239 vulnerabilities (1 moderate, 238 high) in 42756 scanned packages`</p><!--kg-card-begin: code--><pre><code>
....................
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ @private/ui-scaffolding                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ @private/ui-scaffolding &gt; karma-webpack &gt; lodash                │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1065                            │
└───────────────┴──────────────────────────────────────────────────────────────┘


┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ @private/ui-scaffolding                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ @private/ui-scaffolding &gt; react2angular &gt; ngcomponent &gt; lodash  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1065                            │
└───────────────┴──────────────────────────────────────────────────────────────┘


┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ @private/ui-scaffolding                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ @private/ui-scaffolding &gt; webpack-dev-server &gt;                  │
│               │ http-proxy-middleware &gt; lodash                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1065                            │
└───────────────┴──────────────────────────────────────────────────────────────┘


found 239 vulnerabilities (1 moderate, 238 high) in 42756 scanned packages</code></pre><!--kg-card-end: code--><p>Ideally, you could use <code>npm audit --fix</code> to have it auto-fix the issues. Unfortunately, there's a good chance this isn't going to work for you as I don't believe it will update past any MAJOR versions. </p><p>The reason this ended up being a lot of work was that it usually wasn't the immediate dependency that had the vulnerability. It was more likely a dependency 2-6 levels deep that was the problem. </p><p>Here's an example dependency tree describing that problem.</p><p><code>Your Project Uses&gt; Third-Party-Lib-A@1.0.0 Uses&gt; Third-Party-Lib-B@1.0.0 Uses&gt; Third-Party-Lib-C@1.0.0 Uses&gt; Third-Party-Lib-D@1.0.0</code></p><p>Let's say <code>Project D</code> had a security vulnerability that got patched out in version <code>2.0.5</code> but  <code>Third-Party-Lib-C@1.0.0</code> was pinning it to version 1.0.0. Well,  <code>Third-Party-Lib-C</code> is going to have to update itself to use version <code>Third-Party-Lib-D@2.0.5</code>. But maybe it's on version 4 now. This means that for <code>Third-Party-Lib-B</code> to get rid of it's security vulnerabilities it's going to require a potential refactor to pull in <code>Third-Party-Lib-C@4.0.1</code>. Now just continue that pattern up the chain until you get to your code. So you might have been on <code>Third-Party-Lib-A@1.0.0</code> but now to get rid of the security vulnerability, you'll have to upgrade to whatever version  <code>Third-Party-Lib-A</code> ended up at to patch out its downstream issues. This may come with a ton of breaking changes as which will require refactoring of your own code's implementation.</p><p>How long will it take for all of these 3rd party libraries to get their dependencies updated? LibA can't do anything until B fixes its dependencies, B is blocked by C, and C by D. This seems like a real cluster-f and if I'm not understanding it right, please let me know in the comments. </p><p>It gets scarier. What if any one of those dependencies along the way is no longer maintained by anyone? You have to find an alternate library to use that is maintained, or fork a library just to make these security updates, and then convince the upstream dependencies to use your library instead. And now you're its maintainer. 😳</p><p>If the project is maintained it may mean that I have to open PRs with those open source projects and fix the issues, which I truly don't have the cycles to do. </p><p>Luckily for me, In most cases, I was able to simply upgrade the immediate dependencies, IE <code>Third-Party-Lib-A</code>, to the latest libraries and that resolved most of the downstream issues. I also ended up removing a lot of unused dependencies and replaced dependencies that were depreciated. Security vulnerabilities aside, this was a good exercise to keep our codebase lean. </p><p>This would have gone more smoothly except that I manage a micro-services-frontend architecture which meant that I had 30'ish frontends with dependencies to fix. <em>Though most of these libraries share a lot of the same dependencies.</em> Also, we run these frontends in Docker containers and I had a misconception on what layers are cached. So even after fixing some of the dependency issues, and re-running <code>npm-audit</code>, I was getting a lot of false negatives as my changes weren't picked up. </p><p>It was a good bit of work but we now have all of our front-end repos vulnerability free! In order to enforce this going forward, we've done two different things: </p><ol><li>We added some lines to our build tools which block PRs from being merged. Essentially on each push to the branch, it runs some checks like lint, unit-tests, and now <code>npm-audit</code> . If it detects any issues it will fail the build and notify the developer that action must be taken. </li><li>We pin all of our 3rd-party dependencies. This is to prevent random build failures on a Developer's PR when he/she didn't even modify dependencies. Also it gives us the security that we'll never update a dependency to the latest version before the community and NPM team have a chance to catch any potential issues with it. Also, there's no sense in updating working code in production just for the sake of updating. We may as well only update the library when there's a feature or bugfix that was made that we require. </li></ol><p> </p>]]></content:encoded></item><item><title><![CDATA[NPM Package-lock  and semver caret versions.]]></title><description><![CDATA[<p><strong>Maintaining dependencies of our front-end apps has been a struggle. </strong>The problems we’re facing are unique to Aver’s situation in that we maintain a micro-services-front-end. You can read more about that <a href="http://coreysnyder.me/how-i-setup-micro-frontends-for-a-large-web-application/">here</a>. TLDR; Our web product is made up of 25+ different micro-frontends. We are have tried all</p>]]></description><link>http://coreysnyder.me/npm-package-lock-and-semver-caret-versions/</link><guid isPermaLink="false">5d641d00db1608051d2964bb</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Tue, 27 Aug 2019 15:25:47 GMT</pubDate><media:content url="http://coreysnyder.me/content/images/2019/08/761956-636752040959851328-16x9.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://coreysnyder.me/content/images/2019/08/761956-636752040959851328-16x9.jpg" alt="NPM Package-lock  and semver caret versions."><p><strong>Maintaining dependencies of our front-end apps has been a struggle. </strong>The problems we’re facing are unique to Aver’s situation in that we maintain a micro-services-front-end. You can read more about that <a href="http://coreysnyder.me/how-i-setup-micro-frontends-for-a-large-web-application/">here</a>. TLDR; Our web product is made up of 25+ different micro-frontends. We are have tried all of the industry-standard tools like package-lock of NPM, yarn, shrinkwrap, etc appropriately, but they still have their shortcomings in a micro-services world and we’re feeling the pain.</p><h3 id="our-current-setup">Our Current Setup</h3><p>In our current setup we pin all 3rd party library versions (<code>react: 16.8.6</code>), and we use semver caret versions for our own dependencies (<code>@aver/ui-scaffolding: ^2.3.3</code>). The idea behind this: </p><ol><li>We are <strong><em>not</em></strong> ok with our 3rd party libraries getting updated whenever their developers release new code. We want to vet that new code and make sure it's bug free and tested before we pull it into our apps. Most of the time, the risk of making changes is not worth the reward of whatever they add. We only upgrade if there's a feature/bugfix we need, or if there's a known security vulnerability. <em>Note: We make a point that our <code>npm audit</code> has zero Major, Minor, Trivial issues 100% of the time.</em></li><li>Alternatively, because we use a <a href="http://coreysnyder.me/how-i-setup-micro-frontends-for-a-large-web-application/">micro-services-front-end</a> consisting of 25+ <code>*-web</code> front-end repos, pinning the versions of 1st party libraries would mean each change would require 25+ package.json changes, branches, PR reviews, and deploys. As our # of front-ends grows, so does the pain of rolling out updates. We want frequent changes to our own libraries, which we code-review and vet all changes on, to be able to be rolled out to the many front-end apps easily without code reviews or a bunch of process and blockers. </li></ol><p><em>We originally switched to trying to use ^versions for our first-party libraries not necessarily because it was better, but because it was less of a burden on developers.</em></p><h3 id="the-latest-issue">The Latest Issue</h3><p>So my thought was that if we do things this way and we check in our package-lock file, that at deploy time, it'll run <code>npm ci</code> which will install the dependencies from the dependency tree that exists in the <code>package-lock</code> file which will pick up our 1st party library updates and not those of 3rd party dependencies. </p><p><strong>SPOILER: This is not the case. </strong></p><p>Our current issue is that even when we attempt to use semver ^versioning of our internal libraries, they are not being updated when re-deploying our front-end apps. </p><h2 id="what-i-ve-learned-">What I've learned:</h2><h3 id="package-json-package-lock-json">Package.json &gt; Package-lock.json</h3><p>As of NPM@5.0.1 - <code>package.json</code> will overrule the package-lock if <code>package.json</code> has been updated. What does this mean? If you make changes to your <code>package.json</code> file and run <code>npm i</code> it will result in changes being made to your lock file. So if you are running <code>npm i</code> as part of your deploy process, it's going to negate your lock file. Instead you should use <code>npm ci</code> which installs dependencies based on the lock file alone. </p><h3 id="you-cannot-reliably-use-caret-versions-with-package-lock-json">You cannot reliably use caret versions with package-lock.json </h3><p>If you have caret versions of your assets in your <code>package.json</code> such as <code>ui-scaffolding: ^1.0.1</code>, there is no guarantee that it will be updated to the latest non-major version when deployed. Essentially whatever version is placed into the lock file at the time that you last ran <code>npm i</code> locally is what is going to be used when your run <code>npm ci</code> or <code>npm i</code> in your deploy process. So say it the latest version <code>1.1.0</code> at the time you run <code>npm i</code>. That's what's going to get put in the lock file and that is what is going to get installed at deploy time. Even if version <code>1.2.0</code> is released and you redeploy your app, it's going to still use <code>1.1.0</code> instead because that's what's "locked" in the lock file. </p><p>Furthermore, if version <code>ui-scaffolding@1.2</code> gets released, and you re-run <code>npm i</code> locally to update it, version <code>1.2.0</code> will not get pulled in! This is because npm will look to see what's installed and it'll be 1.1.0 and that satisfies what is in the lock file <code>^1.0.1</code>. So it'll make no changes to the lock file. </p><p>Conversely, If you didn't commit the lock file OR your <code>node_modules</code> directory, and did a deployment, when <code>npm i</code> was executed it would go grab the latest version because there's nothing already in place which satisfied the <code>package.json</code> file and so it'll go grab the latest version which does. </p><p><strong>If you want to change the lock file so it FOR SURE pulls in <code>1.2.0</code> you have a few options. </strong></p><p><strong>Option 1:</strong> <code>npm i --save ui-scaffolding@^1.2.0</code> Update your package.json to require the later version of ui-scaffolding. When it runs it'll detect that you don't have a version installed which satisfies the package.json file and so it's going to fetch the latest file which does satisfy it, and update the package-lock to describe the version it used. </p><p><strong>Option 2: </strong><code>(rm -rf node_modules || rm package-lock.json) &amp;&amp; npm i</code>. If the node modules  or the package-lock file isn't present, it's going to detect that you don't have a version installed which satisfies the package.json file and so it's going to fetch the latest file which does satisfy it, and update the package-lock to describe the version it used. The lock file is updated because: </p><blockquote>package-lock.json is automatically generated for any operations where npm modifies either the node_modules tree, or package.json.</blockquote><h3 id="so-how-can-we-have-our-cake-and-eat-it-too">So how can we have our cake and eat it too?</h3><p>That's what I've got to figure out. How can we lock down our dependency tree for all 3rd party libraries while still being able to roll out changes to our 1st party libraries painless? </p><h3 id="my-first-thought-but-not-the-right-answer-">My first thought (But not the right answer):</h3><p>I could possibly use <code>npm-update</code> as part of a <code>pre-install</code> script like: <code>"preinstall": "npm update"</code>. What this is going to do is, before it runs <code>npm ci</code>, it will run <code>npm update</code> which will update all versions which are not pinned to an exact version number.  </p><p>When I first tried this I got an error in my deployment <code>npm WARN lifecycle MyApp@1.0.0~preinstall: cannot run in wd MyApp@1.0.0 npm update (wd=/code)</code>. I think this is telling me that the user in the docker container that is trying to execute <code>npm update</code>doesn't have the proper permissions to safely perform this action so  have to add this to my <code>package.json</code> to allow it: <code>"config": {"unsafe-perm":true}</code></p><h3 id="on-second-thought">On second thought</h3><p>I no longer believe our current idea will reliably work without some the unsafe-perm hackiness. I just don't believe that is the best option for us going forward. Instead, I propose that we write a simple dev tool that we can use to roll-out the library changes to the web repos and subsequently the environments. Something that is more straightforward and intentional with how we deploy 1st-party library code.</p><p><strong>Initial thoughts:</strong></p><ul><li>It might be nice if it were to live as a code-build tool so that developers don’t have to run/install it on their machines</li><li>It would be great if it didn’t create a branch/PR but rather merge directly to master. The code being merged has already been PR Reviewed and tested at this point. No point in creating 30 PRs to bug a developer to OK a 1-line change that they aren’t really doing any verification on.</li><li>We would want to be able to select which front-end Apps receive which version of which 1st party library. <code>[List of *-web Repos to be affected] [1st-party-library] [version]</code></li></ul><p>I'm going to be forming a team including representation from devops to try and see if this is a viable option. </p>]]></content:encoded></item><item><title><![CDATA[Why do I get a different dependency tree for a library when installing it?]]></title><description><![CDATA[<p>At my place of work we have some private NPM packages that we maintain. Packages like <code>ui-scaffolding</code>. I'm running into a weird issue where when I use <code>ui-scaffolding</code> in two different front-end repos and run <code>npm i &amp;&amp; npm audit</code> I get wildly different results between the two. And</p>]]></description><link>http://coreysnyder.me/how-to-handle-npm-audit-security-issues-in-downstream-npm-dependencies/</link><guid isPermaLink="false">5d43274adb1608051d296414</guid><dc:creator><![CDATA[Corey Snyder]]></dc:creator><pubDate>Thu, 01 Aug 2019 18:15:37 GMT</pubDate><content:encoded><![CDATA[<p>At my place of work we have some private NPM packages that we maintain. Packages like <code>ui-scaffolding</code>. I'm running into a weird issue where when I use <code>ui-scaffolding</code> in two different front-end repos and run <code>npm i &amp;&amp; npm audit</code> I get wildly different results between the two. And to make matters worse, I don't have a clean way to fix the problem.</p><p>In <code>ProjectA</code> I get <code>found 0 vulnerabilities</code>. </p><p>In <code>ProjectB</code>  I get the following:</p><!--kg-card-begin: code--><pre><code>
....................
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ @private/ui-scaffolding                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ @private/ui-scaffolding &gt; karma-webpack &gt; lodash                │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1065                            │
└───────────────┴──────────────────────────────────────────────────────────────┘


┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ @private/ui-scaffolding                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ @private/ui-scaffolding &gt; react2angular &gt; ngcomponent &gt; lodash  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1065                            │
└───────────────┴──────────────────────────────────────────────────────────────┘


┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ @private/ui-scaffolding                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ @private/ui-scaffolding &gt; webpack-dev-server &gt;                  │
│               │ http-proxy-middleware &gt; lodash                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1065                            │
└───────────────┴──────────────────────────────────────────────────────────────┘


found 239 vulnerabilities (1 moderate, 238 high) in 42756 scanned packages</code></pre><!--kg-card-end: code--><p>All of the 239 vulnerabilities are found as dependencies of <code>ui-scaffolding</code> and all of the vulnerabilities are related to <code>lodash</code> not being updated to version <code>4.17.12</code> or later. So why do I get all these in 1 repo and not they other when they use the same library? </p><h3 id="wait-i-figured-out-why">Wait I figured out why</h3><p>Ok.. after all this, I realized that the problem of 1 project works, one doesn't that really all I needed to do was delete the <code>package-lock.json</code> file in the failing web repo and rerun <code>npm i</code> would actually result in <code>found 0 vulnerabilities</code>. <s>How does this work.. No idea. Previously changing node modules in the package.json file and running npm i always generated a new lock file. So I'm clueless as to why this wasn't working as expected. I hope to revisit this Monday when I'm back in the office and try and get to the bottom of what was going on, and I'll update this page accordingly. Because right now it'll just confuse people.</s></p><p>Update a few weeks later: Ok I know what was going on. </p><ul><li>If you have node modules installed that satisfy the lock file, then it's not going to go grab the latest ui-scaffolding version. </li><li>If you run <code>npm i</code> and it detects changes to the package.json file, it'll generate a new lock file to the latest satisfying version. </li></ul><p>I also need to look into <a href="https://www.google.com/url?q=https://www.npmjs.com/package/npm-audit-ci-wrapper&amp;sa=D&amp;source=hangouts&amp;ust=1564774152002000&amp;usg=AFQjCNGz3cUpJI0cUJWiR7Y9maAy6zKQrQ" rel="nofollow noreferrer noopener">https://www.npmjs.com/package/npm-audit-ci-wrapper</a></p>]]></content:encoded></item></channel></rss>