<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zak Miller</title>
    <description>The latest articles on DEV Community by Zak Miller (@zakmiller).</description>
    <link>https://dev.to/zakmiller</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F169328%2Fa95678a8-46bb-46e0-8553-9a71a24236ea.jpeg</url>
      <title>DEV Community: Zak Miller</title>
      <link>https://dev.to/zakmiller</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zakmiller"/>
    <language>en</language>
    <item>
      <title>The Micropreneur Toolkit</title>
      <dc:creator>Zak Miller</dc:creator>
      <pubDate>Thu, 14 Nov 2019 03:59:22 +0000</pubDate>
      <link>https://dev.to/zakmiller/the-micropreneur-toolkit-3f8d</link>
      <guid>https://dev.to/zakmiller/the-micropreneur-toolkit-3f8d</guid>
      <description>&lt;p&gt;If you’re building a software product during your nights and weekends, then you don’t have any time or money to waste. That doesn’t stop most people from writing code they don’t have to write, spending time configuring things they don’t have to configure, and paying bills they don’t have to pay.&lt;/p&gt;

&lt;p&gt;Here are some tools I’ve found that will save you thousands of dollars and hours as you build a software product in your spare time:&lt;/p&gt;

&lt;h2&gt;
  
  
  A static site generator (e.g. Hugo, Jekyll, Gatsby)
&lt;/h2&gt;

&lt;p&gt;What it is: A tool that transforms a config file and markdown files (that you write) into a complete website.&lt;/p&gt;

&lt;p&gt;What it replaces: Wordpress, Squarespace, or a bespoke website written from scratch.&lt;/p&gt;

&lt;p&gt;Why it’s better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cheap (plenty of free themes and great ones for less than $100).&lt;/li&gt;
&lt;li&gt;Quick to configure (you’re just editing a config file and writing markdown).&lt;/li&gt;
&lt;li&gt;Totally customizable (you can always edit the HTML and CSS if you want to).&lt;/li&gt;
&lt;li&gt;Hostable for free on Netlify (because there’s no PHP backend like Wordpress).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Netlify
&lt;/h2&gt;

&lt;p&gt;What it is: A hosting platform with excellent tooling.&lt;/p&gt;

&lt;p&gt;What it replaces: AWS EC2, Digital Ocean, a server in your garage.&lt;/p&gt;

&lt;p&gt;Why it’s better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No server to manage.&lt;/li&gt;
&lt;li&gt;Completely free for teams of one.&lt;/li&gt;
&lt;li&gt;Amazing integrations with GitHub (every time you open a PR it creates a unique URL previewing the changes).&lt;/li&gt;
&lt;li&gt;Handles migrations and rollbacks for you (just click a button).&lt;/li&gt;
&lt;li&gt;Automatically requests and renews SSL certs for you (once you configure it).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Firebase
&lt;/h2&gt;

&lt;p&gt;What it is: A service built on top of Google Cloud that solves common problems for you. It was originally intended to support mobile apps but works just as well for SaaS.&lt;/p&gt;

&lt;p&gt;What it replaces: A standard backend web API.&lt;/p&gt;

&lt;p&gt;Why it’s better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handles common use-cases like account creation, email validation, and password resets (you just make an API call from the front-end and Firebase handles the rest).&lt;/li&gt;
&lt;li&gt;Database support (SQL and NoSQL) that you can effectively and securely query from front-end code.&lt;/li&gt;
&lt;li&gt;Extremely cheap (especially for MVPs). You’re charged based on usage - not a flat fee per month like if you were running a server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Looka.com
&lt;/h2&gt;

&lt;p&gt;What it is: A website that lets you design your own logo by browsing through thousands of variations on logos, colors, and fonts.&lt;/p&gt;

&lt;p&gt;What it replaces: Making something yourself or hiring a designer for thousands of dollars.&lt;/p&gt;

&lt;p&gt;Why it’s better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Probably higher quality than something you could do yourself.&lt;/li&gt;
&lt;li&gt;Fast (you’ll be done in 30 minutes).&lt;/li&gt;
&lt;li&gt;Cheap (you can get both SVGs and PNGs for $65).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Unsplash.com
&lt;/h2&gt;

&lt;p&gt;What it is: A place to find high-quality images.&lt;/p&gt;

&lt;p&gt;What it replaces: Subscribing to some image repository, limiting yourself to images in the public domain, or desperately searching for “free images” and hoping they don’t have an attribution clause.&lt;/p&gt;

&lt;p&gt;Why it’s better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hundreds of thousands of images.&lt;/li&gt;
&lt;li&gt;Free.&lt;/li&gt;
&lt;li&gt;No attribution necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are some of the tools I’ve found especially useful in my micropreneurial journey. Hope you found it useful! Anything I’m missing?&lt;/p&gt;

</description>
      <category>startup</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>5 Mistakes to Avoid When Building Your First Product</title>
      <dc:creator>Zak Miller</dc:creator>
      <pubDate>Tue, 12 Nov 2019 08:30:32 +0000</pubDate>
      <link>https://dev.to/zakmiller/5-mistakes-to-avoid-when-building-your-first-product-4k0h</link>
      <guid>https://dev.to/zakmiller/5-mistakes-to-avoid-when-building-your-first-product-4k0h</guid>
      <description>&lt;h2&gt;
  
  
  Mistake #1 - Solving a problem that no one has (or that no one is willing to pay for)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.paulgraham.com/startupideas.html"&gt;Paul Graham wrote&lt;/a&gt; about how trying to come up with a startup idea is a pretty bad way to come up with a good idea. You generate a bunch of plausible-sounding ideas (that superficially resemble products you’re familiar with) that are doomed to fail. To paraphrase Mark Twain, the difference between a plausible-sounding idea and a good idea is the difference between the lightning bug and the lightning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake #2 - Writing off an idea because someone else has already done it
&lt;/h2&gt;

&lt;p&gt;Facebook wasn’t the first social network, Google wasn’t the first search engine, and the iPhone wasn’t the first smartphone. More importantly, many markets are not monopolies and can easily support multiple products. The fact that someone built something similar to what you’re thinking about is a good thing. They proved it’s an economically viable idea, and you can learn from their successes and failures. The alternative (building something no one has made into a successful business before) is much riskier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake #3 - Not having a marketing plan
&lt;/h2&gt;

&lt;p&gt;If you build it, they won’t come. Go ahead, spend the next six months building something and put it out on the internet. No one will know it’s there unless you do something about it. For a product idea to be a good idea there has to be an economically viable way to gain new customers. Maybe that’s inbound traffic through blog posts (content marketing), maybe that’s Google Ads, or maybe that’s outbound cold calls. Regardless, without a viable channel, you don’t have a product idea - you have a fun project. Check out &lt;a href="https://www.amazon.com/Traction-Startup-Achieve-Explosive-Customer/dp/1591848369"&gt;Traction&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake #4 - Not setting your sights low enough
&lt;/h2&gt;

&lt;p&gt;With large markets comes lots of money. Thus, lots of competition, a large (required) marketing budget, and a relatively small number of viable business ideas (it’s hard to make something that everyone wants). It’s much easier to build something that’s perfect for a few thousand people. Better yet, once you have a target niche in mind it’s much easier to find ideas that will delight your customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake #5 - Not being remarkable
&lt;/h2&gt;

&lt;p&gt;People are busy and won’t care about your little app. Cut through the noise and give them an experience they’ll remark about. &lt;a href="https://seths.blog/2007/01/how_to_be_remar/"&gt;Seth Godin has written&lt;/a&gt; about this.&lt;/p&gt;

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

&lt;p&gt;A good way to find out if your product has legs is to build an MVP as quickly as possible and try to sell it (this is the premise of &lt;a href="http://theleanstartup.com/"&gt;The Lean Startup&lt;/a&gt;, which you should read). The longer you put that off, the more likely you are to be wasting your time. Even better, know that people will pay for it before you start to build it (get them to fund the development!).&lt;/p&gt;

</description>
      <category>startup</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Serve Vue with Nest</title>
      <dc:creator>Zak Miller</dc:creator>
      <pubDate>Tue, 12 Nov 2019 02:58:30 +0000</pubDate>
      <link>https://dev.to/zakmiller/how-to-serve-vue-with-nest-1e11</link>
      <guid>https://dev.to/zakmiller/how-to-serve-vue-with-nest-1e11</guid>
      <description>&lt;p&gt;Want to serve a VueJS app from a NestJS backend? Here's how you do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new Nest app
&lt;/h2&gt;

&lt;p&gt;Install the Nest CLI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @nestjs/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the NestJS app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nest new nest-with-vue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;nest-with-vue
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verify it's all working properly
&lt;/h2&gt;

&lt;p&gt;First, run it (this will watch the folder so we won't have to restart the server as we make changes):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run start:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, hit it (in a separate terminal window):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl localhost:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get &lt;code&gt;Hello World!&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set it up to serve static content
&lt;/h2&gt;

&lt;p&gt;Install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @nestjs/serve-static
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use the package
&lt;/h3&gt;

&lt;p&gt;src/app.module.ts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppController&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ServeStaticModule&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/serve-static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// New&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;join&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// New&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;ServeStaticModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="c1"&gt;// New&lt;/span&gt;
      &lt;span class="na"&gt;rootPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client/dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// New&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="c1"&gt;// New&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppController&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;src/main.ts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setGlobalPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// New&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're moving all the existing endpoints to under &lt;code&gt;/api&lt;/code&gt;, and then serving the static content in the &lt;code&gt;./client/dist&lt;/code&gt; folder (which doesn't exist yet) when someone hits the root (in this case &lt;code&gt;localhost:3000&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Also note that the name &lt;code&gt;client&lt;/code&gt; here could be anything. It's just the folder where we're going to put the Vue app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify that the controller endpoint moved
&lt;/h2&gt;

&lt;p&gt;Now, if we hit the previous endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl localhost:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get &lt;code&gt;{"statusCode":500,"message":"Internal server error"}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But if you hit the new &lt;code&gt;/api&lt;/code&gt; endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl localhost:3000/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get &lt;code&gt;Hello World!&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;Now we just have to create the Vue app in that &lt;code&gt;./client/dist&lt;/code&gt; folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the VueJS app
&lt;/h2&gt;

&lt;p&gt;Install the Vue CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @vue/cli
&lt;span class="c"&gt;# OR&lt;/span&gt;
yarn global add @vue/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vue create client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;client
npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will put all the static files in &lt;code&gt;./client/dist&lt;/code&gt;, right where the Nest app will be looking for them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify that Nest is serving the compiled Vue app
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl localhost:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get something that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; ... &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;We're sorry but client doesn't work properly without JavaScript enabled. Please enable it to continue.&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; ... &lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is the HTML being served by the Vue app.&lt;/p&gt;

&lt;p&gt;Open it up in your browser and you'll see it's working!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fiqn0F96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fiqn0F96.png" alt="Vue screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing words
&lt;/h2&gt;

&lt;p&gt;That's it. You can find the complete code &lt;a href="https://github.com/ZakMiller/NestWithVue" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Access Firestore using Ionic</title>
      <dc:creator>Zak Miller</dc:creator>
      <pubDate>Sun, 10 Nov 2019 16:27:09 +0000</pubDate>
      <link>https://dev.to/zakmiller/how-to-access-firestore-using-ionic-pa2</link>
      <guid>https://dev.to/zakmiller/how-to-access-firestore-using-ionic-pa2</guid>
      <description>&lt;p&gt;When I created an app using Firebase and Ionic, I started my authentication&lt;br&gt;
 journey by trying a few different packages: &lt;a href="https://www.npmjs.com/package/firebase"&gt;firebase.js&lt;/a&gt;, &lt;a href="https://github.com/firebase/firebaseui-web"&gt;firebaseui&lt;/a&gt;, &lt;a href="https://github.com/angular/angularfire2"&gt;angularfire2&lt;/a&gt;, &lt;a href="https://github.com/ionicthemes/ionic-firebase-authentication"&gt;ionic-firebase-authentication&lt;/a&gt;, and &lt;a href="https://github.com/AnthonyNahas/ngx-auth-firebaseui"&gt;ngx-auth-firebaseui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I found one that worked with Ionic, and used that for a while, only to&lt;br&gt;
 discover when I moved to testing on my mobile device that the auth didn't&lt;br&gt;
 work on the mobile device because it was using an in-app browser, and&lt;br&gt;
 Google had cracked down on using those inside of apps to authenticate.&lt;/p&gt;

&lt;p&gt;I then found the &lt;a href="https://ionicframework.com/docs/native/firebase-authentication/"&gt;official Firebase Authentication plugin for Ionic&lt;/a&gt;&lt;br&gt;
 and was pretty excited. After a bit, I realized that although it allows you to sign in, &lt;em&gt;you can't actually access the Firestore database&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you use another package, like the firebase.js package, to retrieve and&lt;br&gt;
 store data and you've locked down the Firestore database &lt;a href="https://firebase.google.com/docs/firestore/security/get-started"&gt;as you should&lt;/a&gt;&lt;br&gt;
 you'll quickly find that as far as the firebase.js package is concerned,&lt;br&gt;
 you aren't actually authenticated.&lt;/p&gt;

&lt;p&gt;I'm not thrilled with my current implementation, but to allow facebook&lt;br&gt;
 logins it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;loginWithFacebook&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public_profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FacebookAuthProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;signInAndRetrieveDataWithCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowUserIn&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'm using the &lt;a href="https://beta.ionicframework.com/docs/native/facebook"&gt;native Facebook Auth package&lt;/a&gt; to prompt the user for permission to Facebook (this seems to be what can't be done via a browser on Android), and then using firebase.js to take care of the rest.&lt;/p&gt;

</description>
      <category>typescript</category>
    </item>
    <item>
      <title>Hugo - How to Filter Posts With a Tag</title>
      <dc:creator>Zak Miller</dc:creator>
      <pubDate>Sun, 10 Nov 2019 16:22:36 +0000</pubDate>
      <link>https://dev.to/zakmiller/hugo-how-to-filter-posts-with-a-tag-58cb</link>
      <guid>https://dev.to/zakmiller/hugo-how-to-filter-posts-with-a-tag-58cb</guid>
      <description>&lt;p&gt;While recently working on a website, I wanted to display a subset of my posts based on a particular tag. I hadn't had any prior experience with the go templating engine, so this took me a bit longer to figure out than I'd care to admit, so I thought I'd share it with all of you.&lt;/p&gt;

&lt;p&gt;This example applies anytime you want to filter any list of pages with a taxonomy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Paginator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt; &lt;span class="s"&gt;".Params.tags"&lt;/span&gt; &lt;span class="s"&gt;"intersect"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="s"&gt;"popular"&lt;/span&gt;&lt;span class="p"&gt;)}}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dateFormat&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="s"&gt;"January 2, 2006"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{{ .URL }}"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first line is really all that matters. We're &lt;code&gt;range&lt;/code&gt;-ing over the pages, grabbing the tags from each of those pages and seeing if they intersect with a new slice that only contains &lt;code&gt;popular&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;contains&lt;/code&gt; operator is what I would expect to use here, but as far as I can tell there isn't one, so you have to use this &lt;code&gt;intersect&lt;/code&gt; workaround.&lt;/p&gt;

&lt;p&gt;I hope that was helpful! If you have any questions please let me know.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Google Cloud Functions and the File System</title>
      <dc:creator>Zak Miller</dc:creator>
      <pubDate>Sun, 10 Nov 2019 16:20:48 +0000</pubDate>
      <link>https://dev.to/zakmiller/google-cloud-functions-and-the-file-system-3pf4</link>
      <guid>https://dev.to/zakmiller/google-cloud-functions-and-the-file-system-3pf4</guid>
      <description>&lt;p&gt;If you want to write a cloud function, and you need to write temporary data to the file system, how do you do it?&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;/tmp&lt;/code&gt;. Under the hood, it's actually &lt;a href="https://cloud.google.com/functions/docs/concepts/exec#file_system"&gt;just storing it in memory&lt;/a&gt; but if you must simulate reading and writing to the file system it'll work.&lt;/p&gt;

&lt;p&gt;I was cloning a repo programmatically and parsing JSON files from that repo, so it made sense for my situation.&lt;/p&gt;

&lt;p&gt;To write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Hello World"&lt;/span&gt;
    &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"/tmp/file"&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"writing file %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error encountered writing file %v, %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file wrote successfully&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"tmp/file"&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"reading file %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error encountered reading file %v, %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file %v read, content: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can find a complete sample &lt;a href="https://github.com/ZakMiller/cloudstorage/blob/master/cloudstorage.go"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you care about preserving the files you're writing, then don't use this solution. Instead, use something &lt;a href="https://cloud.google.com/storage/"&gt;like this&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>The Technology Behind Carnivore Coach</title>
      <dc:creator>Zak Miller</dc:creator>
      <pubDate>Sun, 10 Nov 2019 16:18:24 +0000</pubDate>
      <link>https://dev.to/zakmiller/the-technology-behind-carnivore-coach-32b8</link>
      <guid>https://dev.to/zakmiller/the-technology-behind-carnivore-coach-32b8</guid>
      <description>&lt;p&gt;Carnivore Coach is an Android app that I designed to help people track their progress on the carnivore (zero-carb) diet. I wrote about &lt;a href="https://www.zakmiller.com/posts/carnivore-coach-business/"&gt;the business decisions behind Carnivore Coach&lt;/a&gt;, but today I'm going to talk about the tech stack and the reasoning behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile Framework and Language
&lt;/h2&gt;

&lt;p&gt;When it comes to mobile development you have a few options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Native (Java/Kotlin or Objective-C/Swift)&lt;/li&gt;
&lt;li&gt;Web Technologies + Cordova&lt;/li&gt;
&lt;li&gt;Xamarin (C#)&lt;/li&gt;
&lt;li&gt;Flutter (Dart)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are some genuine tradeoffs here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native is fast but specific to either Android or iOS&lt;/li&gt;
&lt;li&gt;Flutter is not quite as fast and is sort of arcane technology, but it lets you deploy on both platforms.&lt;/li&gt;
&lt;li&gt;Xamarin lets you write in C# (a language I'm very familiar with) and deploy on both platforms, but the functionality is limited and slower than Flutter.&lt;/li&gt;
&lt;li&gt;Web technologies are slowest of all, but the Ionic/Cordova ecosystem has a lot of great components, and it also lets you deploy to iOS or Android.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I chose web technologies for a simple reason: I wanted to get better at Angular and Typescript. I didn't know whether Carnivore Coach would make me any money, but I could guarantee that I would learn some technologies useful to me.&lt;/p&gt;

&lt;p&gt;I used v4 of the &lt;a href="https://ionicframework.com/docs/api"&gt;Ionic Framework&lt;/a&gt; which I would highly recommend if you want to write an Angular app for mobile. I have heard good things about &lt;a href="https://facebook.github.io/react-native/"&gt;React Native&lt;/a&gt; but I wanted to learn more about Angular so it was off the table immediately.&lt;/p&gt;

&lt;p&gt;Ionic really shines in a couple of areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It provides web components that mimic the look and feel of native controls, so you don't have to worry about styling HTML elements in a native-esque way.&lt;/li&gt;
&lt;li&gt;It has libraries that abstract away native functionality (e.g. storing data locally, interacting with Facebook auth, etc) and will work with the same code on both Android and iOS, so you can just write the code once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ionic also integrates with Cordova to the degree that you don't ever really have to worry about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend
&lt;/h2&gt;

&lt;p&gt;When it came to the backend, I chose &lt;a href="https://firebase.google.com/"&gt;Firebase&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I just needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Account management and auth&lt;/li&gt;
&lt;li&gt;A place to store some data (e.g. resources to learn more about the diet, food statistics).&lt;/li&gt;
&lt;li&gt;The users' data so that they could go back and review it (e.g. what they ate, their weight, etc).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was mostly painless to set up using Firebase, and I plan on using Firebase in the future wherever I can. You can read about how I ran into a little bit of pain with &lt;a href="https://www.zakmiller.com/posts/why-ionics-firebase-authentication-package-sucks/"&gt;Ionic Firebase Auth&lt;/a&gt;, but the fact that &lt;em&gt;I didn't have to write any backend code at all&lt;/em&gt; really sold me. It's funny, because I've always been a backend developer, but I guess I'm more excited about quickly building things than backend design because I was happy to outsource all that work to Firebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Website
&lt;/h2&gt;

&lt;p&gt;I knew that I wanted to have a website to help market Carnivore Coach. As usual, my goal was to have something that looked professional and had the functionality I wanted, without spending any more time or money than necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting
&lt;/h3&gt;

&lt;p&gt;I heard about Netlify on &lt;a href="https://www.youtube.com/channel/UC29ju8bIPH5as8OGnQzwJyA"&gt;Traversy Media's Youtube Channel&lt;/a&gt; and it seemed like a great option. Basically, Netlify hosts websites created with a static site generator. It's free for a single user and makes it very easy to set up HTTPS and auto-deploys when you push to GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technology
&lt;/h3&gt;

&lt;p&gt;I hadn't had any prior exposure to static site generators, but it looked like the two options were &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; and &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;. I assumed both would be fine, but went with Hugo because it was newer and I was more interested in Golang than Node.js.&lt;/p&gt;

&lt;p&gt;It took me a couple of weeks to become really comfortable with Hugo, but I probably could have reduced that time if I had spent less time trying to figure things out and more time &lt;a href="https://gohugo.io/documentation/"&gt;reading the docs&lt;/a&gt;. I wrote about how to &lt;a href="https://www.zakmiller.com/posts/filter-post-with-tag-hugo/"&gt;filter posts with a tag using Hugo&lt;/a&gt;, one of the more interesting problems I ran into.&lt;/p&gt;

&lt;h2&gt;
  
  
  At the End of the Day
&lt;/h2&gt;

&lt;p&gt;I'm happy with the technologies I chose. I was able to get all of this done in my free time over about a month. That's not bad for not being very familiar with Angular, and having basically zero experience with mobile development, and no experience with Hugo.&lt;/p&gt;

&lt;p&gt;If I was going to develop another mobile app, then I'd be tempted to go fully native. When the app starts up it has this annoying blue Ionic graphic, and it does seem a little slower than I'd like. That's really my only complaint.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>android</category>
    </item>
    <item>
      <title>What Makes Ghost.org So Successful?</title>
      <dc:creator>Zak Miller</dc:creator>
      <pubDate>Thu, 17 May 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/zakmiller/what-makes-ghost-org-so-successful-48jg</link>
      <guid>https://dev.to/zakmiller/what-makes-ghost-org-so-successful-48jg</guid>
      <description>&lt;p&gt;Ghost.org, the markdown blogging non-profit, released a &lt;a href="https://blog.ghost.org/5/"&gt;blog post&lt;/a&gt; covering its five-year journey to $82,000 in monthly recurring revenue and a customer list that includes Apple, Mozilla, and Cloudflare.&lt;/p&gt;

&lt;p&gt;The post itself is great, especially if you’re interested in open-source software, but the most insightful bit wasn’t in the post itself. John O’Nolan (of Ghost) did a sort of AMA on &lt;a href="https://www.indiehackers.com/forum/5-years-3m-no-investors-everything-we-learned-building-the-1-cms-on-github-ama-0ac99b72d7"&gt;Indie Hackers&lt;/a&gt;, after writing the article.&lt;/p&gt;

&lt;p&gt;The Ghost Foundation is a non-profit that works on the open-source technology Ghost. They make their money through a paid solution called Ghost(Pro), where &lt;strong&gt;they host and manage blogs written in Ghost&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A commenter noted that he saw complaints all over the internet about Ghost(Pro)’s high price, and asked why the price was higher than people would expect (~20 dollars rather than ~10).&lt;/p&gt;

&lt;p&gt;John responded with a detailed answer that I recommend you read in full. The gist is that they price their product very deliberately. &lt;strong&gt;Their goal is to have ~4000 customers, and they just charge the amount of money necessary to keep the number of customers constant&lt;/strong&gt;. If demand increased sharply, they would increase their prices until they got about 4000 customers again. If demand fell, and the number of customers fell below 4000, they would decrease their prices.&lt;/p&gt;

&lt;p&gt;That blew me away. Yes, of course, if you increase your prices you will get fewer customers, and if you decrease your prices you will get more customers (depending on elastic vs inelastic demand, and all that).&lt;/p&gt;

&lt;p&gt;I never considered that a business model would center around keeping the number of customers constant. You suddenly look at customer acquisition and pricing differently.&lt;/p&gt;

&lt;p&gt;His method wouldn’t make much sense for an app that scales well, but when your business model is hosting websites it makes sense to be extremely conscious of how many websites you’re hosting.&lt;/p&gt;

&lt;p&gt;I’m tempted to say that it’s unusual that a non-profit would come up with such an interesting approach to pricing, but maybe it’s not strange. Maybe when you’re a little distanced from the profits you’re also more likely to innovate. Regardless, John’s thoughtfulness will serve the Ghost Foundation well in the future, and I look forward to his next blog post.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://www.zakmiller.com/posts/ghost-org/"&gt;&lt;em&gt;https://www.zakmiller.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on May 17, 2018.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>startup</category>
      <category>businessmodels</category>
      <category>indiehackers</category>
      <category>ghostblog</category>
    </item>
  </channel>
</rss>
