<?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: Chris Jackson</title>
    <description>The latest articles on DEV Community by Chris Jackson (@chrsjxn).</description>
    <link>https://dev.to/chrsjxn</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%2F511352%2F3f2f97c4-cfc7-4db5-bf13-a3a8775aaa0b.png</url>
      <title>DEV Community: Chris Jackson</title>
      <link>https://dev.to/chrsjxn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chrsjxn"/>
    <language>en</language>
    <item>
      <title>Building a blog with Svelte: Dynamic imports For Svelte components</title>
      <dc:creator>Chris Jackson</dc:creator>
      <pubDate>Wed, 17 Feb 2021 20:01:37 +0000</pubDate>
      <link>https://dev.to/chrsjxn/building-a-blog-with-svelte-dynamic-imports-for-svelte-components-5hlp</link>
      <guid>https://dev.to/chrsjxn/building-a-blog-with-svelte-dynamic-imports-for-svelte-components-5hlp</guid>
      <description>&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports"&gt;Dynamic imports&lt;/a&gt; are a really powerful JavaScript feature. Loading modules only when needed can significantly speed up the initial load of a single page application.&lt;/p&gt;

&lt;p&gt;There is a cost, of course. Loading pages that aren't included in your initial bundle will be slower. But if you pick less popular pages to dynamically import—like account settings—most of your users will never have to pay that cost!&lt;/p&gt;

&lt;p&gt;So how do we take advantage of dynamic imports with Svelte?&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter &lt;code&gt;&amp;lt;svelte:component&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Svelte provides a special element for rendering components dynamically, &lt;code&gt;&amp;lt;svelte:component&amp;gt;&lt;/code&gt;! The example from the &lt;a href="https://svelte.dev/tutorial/svelte-component"&gt;official tutorial&lt;/a&gt; renders different components based on a user interaction, but the fundamentals are exactly what we need!&lt;/p&gt;

&lt;p&gt;So let's set up a quick example with a static import first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  import About from './Routes/About.svelte'
&amp;lt;/script&amp;gt;

&amp;lt;svelte:component this={About}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Making it dynamic
&lt;/h2&gt;

&lt;p&gt;This example isn't very useful yet. Of course, we could always render our about page using the component directly: &lt;code&gt;&amp;lt;About /&amp;gt;&lt;/code&gt;. So let's make it dynamic!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  import { onMount } from 'svelte'
  import Error404 from './Routes/Error404.svelte'

  let dynamicPage = null

  onMount(async () =&amp;gt; {
      try {
          dynamicPage = (await import('./Routes/About.svelte')).default
      } catch (e) {
          // Handle errors if the dynamic route doesn't load:
          dynamicPage = Error404
      }
  })
&amp;lt;/script&amp;gt;

&amp;lt;svelte:component this={dynamicPage}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down the changes into smaller pieces, to understand what each change is doing with this dynamic route.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initial component setup
&lt;/h3&gt;

&lt;p&gt;We're using &lt;a href="https://svelte.dev/tutorial/onmount"&gt;&lt;code&gt;onMount&lt;/code&gt;&lt;/a&gt; to trigger the dynamic import when this component is first rendered. My blog uses &lt;a href="https://github.com/visionmedia/page.js"&gt;page.js&lt;/a&gt; as a router, so these dynamic imports are triggered by page transitions, but the logic is the same.&lt;/p&gt;

&lt;p&gt;I've also imported an error component that is available in the main bundle, just in case there's an issue with the dynamic import: &lt;code&gt;import Error404 from './Routes/Error404.svelte'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;let dynamicPage = null&lt;/code&gt; is a little unusual, but &lt;code&gt;&amp;lt;svelte:component&amp;gt;&lt;/code&gt; won't render if the value of &lt;code&gt;this&lt;/code&gt; is &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy"&gt;&lt;code&gt;falsy&lt;/code&gt;&lt;/a&gt;. We'll update that value once we've loaded the page contents, but initially this will stop our component from rendering any output.&lt;/p&gt;

&lt;p&gt;You can replace &lt;code&gt;null&lt;/code&gt; with other values, if you'd prefer. &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, or many other values will behave the same as &lt;code&gt;null&lt;/code&gt;. Or you could import a loading component to indicate that this content is waiting on a network request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamically importing &lt;code&gt;About.svelte&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;await import('./Routes/About.svelte')&lt;/code&gt; is the expression that dynamically imports the About page, but we have two challenges. &lt;/p&gt;

&lt;p&gt;First, &lt;code&gt;await&lt;/code&gt; will throw an exception if the promise rejects, so we need a &lt;code&gt;try/catch&lt;/code&gt; to handle that error. In this case, we're setting &lt;code&gt;dynamicPage&lt;/code&gt; to indicate that an error has happened: &lt;code&gt;dynamicPage = Error404&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Second, &lt;code&gt;import('./Routes/About.svelte')&lt;/code&gt; resolves to a module object, and &lt;code&gt;&amp;lt;svelte:component&amp;gt;&lt;/code&gt; needs a component constructor. Looking at our static import, &lt;code&gt;import About from './Routes/About.svelte'&lt;/code&gt;, we can see that our component is exported as the default export from its module, once it's been bundled. Our dynamic import can access the default export directly on the resolved module: &lt;code&gt;(await import('./Routes/About.svelte')).default&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing bundles
&lt;/h2&gt;

&lt;p&gt;One challenge that's less obvious with dynamic imports is how your bundler handles components that are imported from these dynamic chunks. With my rollup config, moving to dynamic imported Svelte components created significantly more dynamic chunks than I expected!&lt;/p&gt;

&lt;p&gt;That might make sense for your use case, but I wanted my shared components to be included in the &lt;code&gt;main&lt;/code&gt; bundle, rather than dynamically imported. I previously split my &lt;code&gt;node_modules&lt;/code&gt; into a separate bundle, with Rollup's &lt;a href="https://www.chrsjxn.io/svelte/code-splitting"&gt;&lt;code&gt;manualChunks&lt;/code&gt; option&lt;/a&gt;, so let's update that config.&lt;/p&gt;

&lt;p&gt;My shared components live in &lt;code&gt;src/Components/&lt;/code&gt;, so we can use that directory to assign modules to chunks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// rollup.config.js:&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
    &lt;span class="nl"&gt;manualChunks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;)&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vendor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/Components/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;Our example dynamic &lt;code&gt;About&lt;/code&gt; page is potentially good enough for your app. It has basic error handling, and we discussed how you'd integrate a loading indicator. But I want to show you an example that's a little bit more complex.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;App.svelte&lt;/code&gt; sets up a router with some static pages and some dynamically rendered posts. The paths for the dynamic posts are stored in a config object, along with some metadata and a loader function that does the dynamic import.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// posts.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/svelte/dynamic-imports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;loader&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;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../Routes/DynamicImportsForSvelteComponents.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- App.svelte --&amp;gt;
&amp;lt;script&amp;gt;
  import About from './Routes/About.svelte'
  import Error404 from './Routes/404.svelte'
  import Home from './Routes/Home.svelte'
  import router from 'page'
  import { posts } from './Modules/posts'

  // Default to showing About:
  let page = About
  let nextPost = null

  // Scroll to top when navigating from the bottom of a post:
  router('*', (_, next) =&amp;gt; {
    window.scrollTo({
      top: 0,
      left: 0,
    })

    next()
  })

  // Set up a dynamic route for each post in the config object:
  posts.forEach((post, i) =&amp;gt; {
    router(post.path, async () =&amp;gt; {
      // Posts take a `nextPost` prop to link to more content:
      nextPost = posts[i + 1]
      try {
        page = (await post.loader()).default
      } catch (err) {
        page = Error404
      }
    })
  })

  // Set up static routes:
  router('/', () =&amp;gt; (page = Home))
  router('/about', () =&amp;gt; (page = About))
  router('*', () =&amp;gt; (page = Error404))

  router.start()
&amp;lt;/script&amp;gt;

&amp;lt;svelte:component this={page} {nextPost} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the dynamic imports in action by visiting a post on &lt;a href="https://www.chrsjxn.io/"&gt;my blog&lt;/a&gt;. If you open up dev tools, you should see the core bundles loaded on the home page, and a small additional bundle loaded when clicking into any post. They're all around 3kB, because they include the markdown content as well as the Svelte component that renders the post, and they should cache very well as long as the content doesn't change.&lt;/p&gt;

&lt;p&gt;Hopefully this was useful for you! If you have questions or comments, you can always find me &lt;a href="https://twitter.com/c_jackson_js"&gt;on twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting Value from End to End Tests</title>
      <dc:creator>Chris Jackson</dc:creator>
      <pubDate>Wed, 03 Feb 2021 16:22:23 +0000</pubDate>
      <link>https://dev.to/chrsjxn/getting-value-from-end-to-end-tests-4g</link>
      <guid>https://dev.to/chrsjxn/getting-value-from-end-to-end-tests-4g</guid>
      <description>&lt;p&gt;My big project for the second half of 2020 was to "fix" some of our end to end tests—to make them useful. In some ways, the project was a huge success!&lt;/p&gt;

&lt;p&gt;We unblocked automation through our login flow, fixing some persistent flakiness from an ongoing refactor of our session management. And we built the tests into a docker image, so we could easily execute them in any of our deploy pipelines. We now run them automatically before deploying several critical services, and it only takes a single PR to integrate them with other deploys.&lt;/p&gt;

&lt;p&gt;Despite that success, I still see a lot of challenges with these tests. And I have some advice, if you're thinking about writing your own end to end tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Isolate your test data
&lt;/h2&gt;

&lt;p&gt;Every interesting test relies on test data. You need a predictable storefront to test adding and removing items from a shopping cart. You need a test account with payment details to test checkouts. You may be able to mock some of the data you need, or you may be able to write less specific tests for some features, but the data that backs your tests is critical.&lt;/p&gt;

&lt;p&gt;My ideal approach would be a set of tools that set up test data before the tests are run, and tear down the data after the tests complete. But I would settle for data that's only used by the end to end testing suite.&lt;/p&gt;

&lt;p&gt;Changing one setting on a shared test account could easily lead to hours debugging end to end test failures. If the tests block deploys, that could be a very costly delay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test as early as possible
&lt;/h2&gt;

&lt;p&gt;We chose to test release candidates for a few of our critical services. Those deploys trigger the tests about once a day, meaning we have up to 24 hours of changes to check if the tests fail.&lt;/p&gt;

&lt;p&gt;Running the tests as soon as possible after a change makes it a lot easier to find the change that introduced any problems. Engineers are also more likely to be available and paying attention after making a change. Especially now, when so many teammates are remote, engineers might not be available if the tests run infrequently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invest in monitoring and error tracking
&lt;/h2&gt;

&lt;p&gt;Errors in end to end tests are very similar to errors in production. The tests generally only have access to the UI, like a user would, and problems could occur in any part of your stack.&lt;/p&gt;

&lt;p&gt;If your end to end test fails with a request that times out, your UI might not give you enough information to find out what caused that error. But this is just like errors that happen to real users.&lt;/p&gt;

&lt;p&gt;There are a ton of different tools and strategies for monitoring and detecting errors in production, from simple error log collection to distributed tracing solutions. And those tools will help you debug errors in your end to end tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invest in the rest of your tests
&lt;/h2&gt;

&lt;p&gt;This feels like a combination of my previous two suggestions, but I think it's worth calling out separately. (It's also the suggestion most likely to come up during a job interview!)&lt;/p&gt;

&lt;p&gt;Many of the failures I've seen with end to end tests could have been caught much sooner with stronger unit or integration testing. Especially as testing tools, like &lt;a href="https://testing-library.com/"&gt;Testing Library&lt;/a&gt; and &lt;a href="https://mswjs.io/"&gt;MSW&lt;/a&gt; get more sophisticated. &lt;/p&gt;

&lt;p&gt;These tests give you more consistent results, and diligent developers might even catch problems before committing them. Debugging test failures is also significantly easier when you're only testing a small piece of your full application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full stack tests need full stack owners
&lt;/h2&gt;

&lt;p&gt;I originally stated this one to my manager as "product tests need product owners," but I think that's not actually strong enough. It's easy to think of end to end tests as "UI tests," because that's how they interact with your application.&lt;/p&gt;

&lt;p&gt;Every team involved in the stability of your product should care about the results of your end to end tests. After all, every one of those teams could introduce a change that breaks the tests!&lt;/p&gt;

&lt;p&gt;If the only team investigating failures is your UI team, it could take them a long time to find issues at another layer of the stack. Hopefully you've invested in error monitoring, so it's easy to find the team that should investigate!&lt;/p&gt;

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

&lt;p&gt;I'm moving on to other projects for 2021, but the team is working on a couple of these. Maybe I'll be able to convince them to try all five.&lt;/p&gt;

&lt;p&gt;What do you think? Have developer-driven end to end tests been beneficial for you? Or are they still too slow—or too flaky—to feel useful?&lt;/p&gt;

&lt;p&gt;If you've got suggestions I've missed, or you just want to chat about testing, you can find me &lt;a href="https://twitter.com/c_jackson_js"&gt;on twitter&lt;/a&gt;! 🙌&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Building a blog with Svelte: Fetching images via CDN</title>
      <dc:creator>Chris Jackson</dc:creator>
      <pubDate>Wed, 16 Dec 2020 17:30:05 +0000</pubDate>
      <link>https://dev.to/chrsjxn/building-a-blog-with-svelte-fetching-images-via-cdn-3ddj</link>
      <guid>https://dev.to/chrsjxn/building-a-blog-with-svelte-fetching-images-via-cdn-3ddj</guid>
      <description>&lt;p&gt;Continuing along with the blog series, we're in a pretty good place right now. The main bundle is less than 10 kB of javascript over the network, and the vendor bundle is about 50 kB. Add in a few small CSS files, thanks to tailwind and some custom styles, and my blog pages are currently seeing 100s across the board on Lighthouse!&lt;/p&gt;

&lt;p&gt;Except if I'm on a post with an image.&lt;/p&gt;

&lt;p&gt;Netlify caching is great, but a single image file could outweigh the entire application. And using a CDN gives us some other advantages specific to hosting images, so let's set one up!&lt;/p&gt;

&lt;h2&gt;
  
  
  Signing up for Cloudinary
&lt;/h2&gt;

&lt;p&gt;I picked &lt;a href="https://cloudinary.com/"&gt;Cloudinary&lt;/a&gt;, because I have some familiarity with their &lt;a href="https://cloudinary.com/documentation/fetch_remote_images#remote_image_fetch_url"&gt;remote image fetch&lt;/a&gt; feature from work, and their free tier is way more than I need for the amount of traffic that my blog is currently seeing.&lt;/p&gt;

&lt;p&gt;Once signed up for Cloudinary, all I had to do in their admin UI was configure my security settings to restrict remote image fetching to images on my domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redirecting to Cloudinary on Netlify
&lt;/h2&gt;

&lt;p&gt;Netlify supports &lt;a href="https://docs.netlify.com/routing/redirects/rewrites-proxies/#proxy-to-another-service"&gt;proxy redirects&lt;/a&gt; to other services, as long as we configure our redirect with a 200 status. To enable those redirects, we just need to add a &lt;a href="https://docs.netlify.com/configure-builds/file-based-configuration/#redirects"&gt;redirect config&lt;/a&gt; to our &lt;code&gt;netlify.toml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Paths like `/cloudinary/imageFile.jpg` go to cloudinary
# Don't forget to swap in your username and domain:
[[redirects]]
  from = "/cloudinary/*"
  to = """\
    https://res.cloudinary.com/\
    &amp;lt;Cloudinary Account Name&amp;gt;/\
    image/fetch/\
    q_auto,f_auto/\
    https://&amp;lt;Your Blog Domain&amp;gt;/images/:splat\
  """
  status = 200

# All other URLs serve /index.html for the Svelte app:
[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this in place, I'll update all the image URLs in my posts to refer to &lt;code&gt;/cloudinary/&amp;lt;imageName&amp;gt;.&amp;lt;ext&amp;gt;&lt;/code&gt;, and Netlify will proxy them via Cloudinary!&lt;/p&gt;

&lt;h2&gt;
  
  
  Local development support
&lt;/h2&gt;

&lt;p&gt;But there's a small problem, still. Locally, my images aren't in a &lt;code&gt;/cloudinary&lt;/code&gt; directory, so local development can't render them. They're currently located in &lt;code&gt;/public/images&lt;/code&gt;, and I think that's a sensible location for them. So we're going to update our Rollup config to generate different image paths for local assets and built assets.&lt;/p&gt;

&lt;p&gt;We've already used a few Rollup plugins to add features to this blog, and we're going to add one more now.&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-dev&lt;/span&gt; @rollup/plugin-replace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/rollup/plugins/tree/master/packages/replace"&gt;&lt;code&gt;@rollup/plugin-replace&lt;/code&gt;&lt;/a&gt; will replace strings with other content during a build. And the &lt;code&gt;rollup.config.js&lt;/code&gt; that comes with a new Svelte project already knows whether it's building for &lt;code&gt;production&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We're going to use the plugin to replace &lt;code&gt;__imgPath__&lt;/code&gt; with the right path for each environment. That will be &lt;code&gt;/images&lt;/code&gt; in local development, and &lt;code&gt;/cloudinary&lt;/code&gt; on production:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import @rollup/plugin-import with the other imports:&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;replace&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;@rollup/plugin-replace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="c1"&gt;// Add @rollup/plugin-replace to the plugins config&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/main.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;__imgPath__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;production&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cloudinary&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;images&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does mean we need to make one more change to the Svelte components. Anywhere we updated to load images from &lt;code&gt;/cloudinary/&amp;lt;fileName&amp;gt;.&amp;lt;ext&amp;gt;&lt;/code&gt; now needs to use &lt;code&gt;__imgPath__/&amp;lt;fileName&amp;gt;.&amp;lt;ext&amp;gt;&lt;/code&gt;. Once that change is in place, local development serves local images and the Netlify deploy will serve assets from Cloudinary!&lt;/p&gt;

&lt;p&gt;One caveat: My code actually uses a slightly different replacement snippet, but this config will process &lt;code&gt;__imgPath__&lt;/code&gt; in markdown, so the real one would get replaced by the same plugin in my actual build! 🤣&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudinary transformations
&lt;/h2&gt;

&lt;p&gt;The Netlify redirect we set up applies a very basic set of transformations: &lt;code&gt;q_auto,f_auto&lt;/code&gt;. Those flags let Cloudinary decide what quality image to serve (&lt;code&gt;q_auto&lt;/code&gt;), and which format to serve (&lt;code&gt;f_auto&lt;/code&gt;). Automatic format selection even serves &lt;code&gt;webp&lt;/code&gt; images to browsers that support them!&lt;/p&gt;

&lt;p&gt;Taken together, both of these settings help reduce the size of images without significantly affecting how they look at common image sizes for the web.&lt;/p&gt;

&lt;p&gt;There are a ton of other transformations you can apply via URL, including cropping to fit an aspect ratio, automatically rotating, and more. These are all documented in &lt;a href="https://cloudinary.com/documentation/transformation_reference"&gt;Cloudinary's documentation&lt;/a&gt;, and can be applied simply by updating the Cloudinary URL in the Netlify config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;My image assets are still generally larger than my blog's code, but the file size via Cloudinary is significantly smaller. And they're served with cache headers that avoid any network round trips to verify the cache, like other Netlify assets.&lt;/p&gt;

&lt;p&gt;I may follow up by setting up a second image path for HD images, like photos that should stay high quality. And all I'll need to do is follow the same steps as above, adding a new redirect rule and a new Rollup replacement rule for local dev support!&lt;/p&gt;

&lt;p&gt;And even if you're not using Netlify to host your blog, you can use &lt;code&gt;@rollup/plugin-replace&lt;/code&gt; to swap out your local URL for a Cloudinary URL in production. You'll need to include the full Cloudinary fetch URL in your plugin config, and you'll need to be sure to serve the base image assets on your production domain.&lt;/p&gt;

&lt;p&gt;Of course, how could I end this post without including at least one image? So here's a screenshot of the &lt;a href="https://www.chrsjxn.io/components/polaroid"&gt;polaroid component I've been hacking on&lt;/a&gt;, rendered in dark mode, with images fetched from Cloudinary:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l4PN-IxN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8ms6psqxyfmfjnt1i81r.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l4PN-IxN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8ms6psqxyfmfjnt1i81r.PNG" alt="PolaroidComponentDemo"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>Do's and don't's of writing code review feedback</title>
      <dc:creator>Chris Jackson</dc:creator>
      <pubDate>Wed, 09 Dec 2020 16:55:57 +0000</pubDate>
      <link>https://dev.to/chrsjxn/do-s-and-don-t-s-of-writing-code-review-feedback-2lcm</link>
      <guid>https://dev.to/chrsjxn/do-s-and-don-t-s-of-writing-code-review-feedback-2lcm</guid>
      <description>&lt;p&gt;Code review is a core piece of many engineering workflows. Good code review practices have a big impact on code quality. They can identify bugs or testing gaps before code is shipped to users, or identify overly complex logic before it becomes tech debt. And they're one of many tools available to teach engineers about your team's technology, standards, and practices!&lt;/p&gt;

&lt;p&gt;But if done carelessly, code review can also contribute to a toxic team culture. If feedback isn't given intentionally, it can add a lot of stress and anxiety to a process that's supposed to be helpful.&lt;/p&gt;

&lt;p&gt;Here are some of my tips for writing PR feedback, based on my experiences and some of the mistakes I've made. Not every review or every comment should use all of them, but using them will help keep your feedback constructive and collaborative! &lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Include positive and negative feedback!

&lt;ul&gt;
&lt;li&gt;⛔ Don't go overboard with positive feedback&lt;/li&gt;
&lt;li&gt;⛔ Don't leave insincere positive comments&lt;/li&gt;
&lt;li&gt;✅ Do leave emoji comments for quick praise&lt;/li&gt;
&lt;li&gt;✅ Do highlight things you learned as a reviewer&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Keep your feedback respectful

&lt;ul&gt;
&lt;li&gt;⛔ Don't use dismissive language&lt;/li&gt;
&lt;li&gt;⛔ Don't leave comments without content&lt;/li&gt;
&lt;li&gt;⛔ Don't repeat the same comment&lt;/li&gt;
&lt;li&gt;✅ Do respect different levels of expertise&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Be personal

&lt;ul&gt;
&lt;li&gt;✅ Do offer feedback from your perspective&lt;/li&gt;
&lt;li&gt;✅ Do ask questions&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Be explicit

&lt;ul&gt;
&lt;li&gt;✅ Be explicit about &lt;em&gt;why&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;✅ Be explicit about &lt;em&gt;importance&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Take conversations offline&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Include positive and negative feedback!
&lt;/h2&gt;

&lt;p&gt;PR feedback tends to focus on areas for improvement. Like functions that could have better names, missed best practices, or places that need better test coverage.&lt;/p&gt;

&lt;p&gt;Adding comments about good code reinforces those practices, and helps cut down on feedback anxiety in the PR process.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⛔ Don't go overboard with positive feedback
&lt;/h3&gt;

&lt;p&gt;Too much positive feedback can feel forced or overwhelm your other comments.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⛔ Don't leave insincere positive comments
&lt;/h3&gt;

&lt;p&gt;People will be able to tell if your comments are forced or insincere. This could make them assume all your positive feedback is insincere, or make them defensive about future areas for improvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Do leave emoji comments for quick praise
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👍 Do:&lt;br&gt;
🔥&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
🎉&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
🙌&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Emoji responses are an easy way to call out positive contributions without putting much thought into the wording.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Do highlight things you learned as a reviewer
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👍 Do:&lt;br&gt;
I've never used this function before. Thanks for sharing!&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
I didn't know our library supported this function! Can you share a link to the docs?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Code reviews are a great learning tool, and not only for the code author. If you learned something new from your review, celebrate it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep your feedback respectful
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⛔ Don't use dismissive language
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👎 Don't:&lt;br&gt;
Why didn't you just implement your function this way? It would be so much simpler!&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
Let's rewrite your function this way. I think that implementation would be easier for readers to understand!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Comments that belittle or diminish people turn code review into an antagonistic process. Staying more collaborative makes it easier for people to accept your feedback, and makes them more likely to ask you for feedback in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⛔ Don't leave comments without content
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👎 Don't:&lt;br&gt;
?&lt;/p&gt;

&lt;p&gt;// 👎 Don't:&lt;br&gt;
Fix me&lt;/p&gt;

&lt;p&gt;// 👎 Don't:&lt;br&gt;
WTF?&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
Looks like this &lt;code&gt;debugger&lt;/code&gt; was left in by accident. Let's be sure to remove it before merging the PR!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These comments might be enough to raise attention to obvious issues, like a &lt;code&gt;debugger&lt;/code&gt; left in an open PR. But they can contribute to a dismissive tone and put code authors on the defensive.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⛔ Don't repeat the same comment
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👎 Don't:&lt;br&gt;
Don't use &lt;code&gt;any&lt;/code&gt;&lt;br&gt;
Don't use &lt;code&gt;any&lt;/code&gt;&lt;br&gt;
...&lt;br&gt;
Don't use &lt;code&gt;any&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
Typescript &lt;code&gt;any&lt;/code&gt; is potentially dangerous, because it erases type information and could lead to subtle bugs elsewhere in the application.&lt;/p&gt;

&lt;p&gt;I see a few instances of &lt;code&gt;any&lt;/code&gt; in this PR. Can you update them to use stricter typing?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Repeating the same comment multiple times makes it difficult to include relevant details in each comment, and you run the risk of overwhelming your other feedback. &lt;/p&gt;

&lt;p&gt;One or two repetitions is okay, as long as the comments have useful content.&lt;/p&gt;

&lt;p&gt;If you are repeating feedback too many times, you should summarize your suggestion in one comment with full details. You can refer to specific examples in that comment, or add comments that link instances back to the full feedback, if needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Do respect different levels of expertise
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👎 Don't:&lt;br&gt;
Let's reimplement this function to use this pattern.&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
Let's reimplement this function to use this pattern. Check out this other example from our codebase, or these docs, and let me know if you have any questions!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Code review is one of the tools we have to teach engineers about new projects, new libraries, or new technologies. When working with someone who's learning, links to resources or examples are useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be personal
&lt;/h2&gt;

&lt;p&gt;Feedback is generally subjective, based on your experiences as an engineer and a reviewer. Acknowledging that makes it more clear that your feedback is based on your perspective, and not an objective requirement.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Do offer feedback from your perspective
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👎 Don't:&lt;br&gt;
This pattern is hard to understand. Could we refactor to use named functions?&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
I found this pattern hard to understand. If we refactored to use named functions, it'd be easier for me to read and understand what we're doing here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Giving feedback from your perspective leaves it open to the possibility that you're missing information. Maybe there's a shared pattern in the code base that you're just not used to yet.&lt;/p&gt;

&lt;p&gt;Giving feedback from your perspective also leaves it open to discussion and differing opinions. The whole team doesn't need to agree about code patterns or naming schemes, so absolutes aren't helpful when giving this feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Do ask questions
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👍 Do:&lt;br&gt;
This boolean logic is tough for me to understand. Can you explain the different conditions to me?&lt;/p&gt;

&lt;p&gt;Maybe we can use that to break the full condition down into some helper functions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Asking questions can lead to a clearer explanation of what some complex logic is doing. That explanation can suggest ways to simplify or refactor that aren't as obvious without being familiar with the details.&lt;/p&gt;

&lt;p&gt;Asking questions can also help you learn, if you're reviewing code for an app or library you aren't familiar with!&lt;/p&gt;

&lt;h2&gt;
  
  
  Be explicit
&lt;/h2&gt;

&lt;p&gt;When offering feedback, it helps to be explicit. It makes your expectations clearer to other participants, and can make your feedback more actionable.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Be explicit about &lt;em&gt;why&lt;/em&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👎 Don't:&lt;br&gt;
Don't use &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
Typescript &lt;code&gt;any&lt;/code&gt; is potentially dangerous, because it erases type information and could lead to subtle bugs elsewhere in the application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Explaining why makes it clear where your feedback is coming from, especially for best practices or dangerous patterns.&lt;/p&gt;

&lt;p&gt;Explaining why can also act as a teaching tool for your collaborators, because it gives them information about the reason your feedback is important.&lt;/p&gt;

&lt;p&gt;If you've got docs, this is a great reason to link them!&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Be explicit about &lt;em&gt;importance&lt;/em&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;// 👍 Do:&lt;br&gt;
I'm requesting changes on this PR. Please remove these secret keys from the source code and rotate them to avoid leaks before this is deployed to production.&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
As a follow up: Let's refactor this component and add more test coverage to (hopefully) prevent future regressions&lt;/p&gt;

&lt;p&gt;// 👍 Do:&lt;br&gt;
Nit: This function name may be clearer as &lt;code&gt;shouldShowModal&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some feedback is critical to address before a PR is merged, like security concerns or bugs in critical flows. If your feedback calls out an issue like that, your review should Request Changes to ensure they're addressed.&lt;/p&gt;

&lt;p&gt;Other feedback is much less urgent. If your feedback can wait until after a PR is merged, especially for an urgent change, call that out by asking for a follow up. You can also ask the author to file a ticket to track that follow up, if you want them to take some concrete action before merging their change.&lt;/p&gt;

&lt;p&gt;Marking nits is also a good practice, to be explicit about that feedback being less important than more critical feedback. If you're making a lot of significant comments, it may even be worth omitting the nits to emphasize the more important changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take conversations offline
&lt;/h2&gt;

&lt;p&gt;If you've got a lot of feedback, or there's a communication gap between reviewer and author, it can be very helpful to take conversations out of GitHub.&lt;/p&gt;

&lt;p&gt;Try pairing with the code author if they need help implementing your feedback, or schedule a quick call to discuss different options for addressing feedback. This can be especially helpful if a PR has gone through more than one round of feedback and some of your concerns aren't being addressed, or if there is a strong disagreement about the best way to address some feedback.&lt;/p&gt;

&lt;p&gt;After discussing out of band, leave a summary in a comment on the PR. It will help remind everyone of the discussion, especially if there is more work to do before the PR is merged.&lt;/p&gt;

</description>
      <category>codereview</category>
    </item>
    <item>
      <title>Building a blog with Svelte: Code splitting</title>
      <dc:creator>Chris Jackson</dc:creator>
      <pubDate>Wed, 02 Dec 2020 16:46:10 +0000</pubDate>
      <link>https://dev.to/chrsjxn/building-a-blog-with-svelte-code-splitting-1mdi</link>
      <guid>https://dev.to/chrsjxn/building-a-blog-with-svelte-code-splitting-1mdi</guid>
      <description>&lt;p&gt;Last week, I shared the steps I took to add Markdown support to my blog, written in Svelte. And I'm happy with how portable the Markdown content is, and how smooth the authoring experience is with &lt;code&gt;livereload&lt;/code&gt; in my development environment.&lt;/p&gt;

&lt;p&gt;But I do have one more concern that I want to address before I feel good about this solution.&lt;/p&gt;

&lt;p&gt;Right now, adding content increases the size of my app bundle. The more I write, the slower my site will be!&lt;/p&gt;

&lt;p&gt;So let's fix that with code splitting. We can keep our authoring working with static files in a git repository, and get significantly better cache performance for our assets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a vendor bundle
&lt;/h2&gt;

&lt;p&gt;For the first step, we'll split out our &lt;code&gt;npm&lt;/code&gt; modules into a separate vendor bundle. Rollup will fingerprint that file, so our users will be able to cache it as long as we don't change any of our dependencies!&lt;/p&gt;

&lt;p&gt;We're going to use the &lt;a href="https://rollupjs.org/guide/en/#outputmanualchunks"&gt;&lt;code&gt;manualChunks&lt;/code&gt;&lt;/a&gt; option in our rollup config to split our files with a custom function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/main.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Code Splitting requires specific module types, so we'll use EcmaScript modules:&lt;/span&gt;
    &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Our output needs to be a directory, instead of a single file:&lt;/span&gt;
    &lt;span class="na"&gt;dir&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/build/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;manualChunks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Every module whose name includes `node_modules` should be in vendor:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vendor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// Every other module will be in the chunk based on its entry point!&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;But now we have a problem. The HTML template included in the Svelte template doesn't support ES module files by default, and now rollup is generating files with a different name!&lt;/p&gt;

&lt;p&gt;So let's fix our HTML now. We need to tell the browser that this script is an EcmaScript module with &lt;code&gt;type="module"&lt;/code&gt;, and we need to use the updated name, &lt;code&gt;/build/main.js&lt;/code&gt;.&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="c"&gt;&amp;lt;!-- Before: &amp;lt;script defer src='/build/bundle.js'&amp;gt;&amp;lt;/script&amp;gt; --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;'/build/main.js'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With those changes, we should be able to run our site in development without any issues. Loading the page will now load two javascript files, &lt;code&gt;/build/main.js&lt;/code&gt; and a second file &lt;code&gt;/build/vendor-[hash].js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing Markdown from the main bundle
&lt;/h2&gt;

&lt;p&gt;Our vendor bundle should be a big performance benefit, but we still have the problem where adding Markdown content will continue to increase our app size over time.&lt;/p&gt;

&lt;p&gt;We can fix that by using the &lt;code&gt;import()&lt;/code&gt; function to load that content as needed, and rollup will split those chunks for us automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding dynamic imports
&lt;/h3&gt;

&lt;p&gt;We'll start by adding &lt;a href="https://rollupjs.org/guide/en/#dynamic-import"&gt;dynamic imports&lt;/a&gt; for the Markdown content to the post components:&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="nt"&gt;&amp;lt;script&amp;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;Layout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Markdown&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;../Components&lt;/span&gt;&lt;span class="dl"&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;onMount&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;svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

  &lt;span class="c1"&gt;// When we mount this component, load the markdown chunk:&lt;/span&gt;
  &lt;span class="nx"&gt;onMount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../Markdown/AddingMarkdownToSvelte.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;Layout&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Markdown&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;markdown&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Layout&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of those lines is a little odd, though: &lt;code&gt;(await import('../Markdown/AddingMarkdownToSvelte.md')).default&lt;/code&gt;. As a side effect of loading this markdown content as an application chunk, it's been packaged as a module! &lt;/p&gt;

&lt;p&gt;This does add a small bit of overhead into the file contents, but it's not much. And it does mean that we need to access the &lt;code&gt;default&lt;/code&gt; export when we import the module.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the &lt;code&gt;Markdown&lt;/code&gt; component
&lt;/h3&gt;

&lt;p&gt;The last change we need to make is to update the &lt;code&gt;Markdown&lt;/code&gt; component to rerender when its content loads. My initial component assumed the Markdown was fixed as soon as the component was rendered, so we could just render once.&lt;/p&gt;

&lt;p&gt;But now, we need to be able to update the Markdown content when the chunk loads, and we'll use &lt;code&gt;beforeUpdate&lt;/code&gt; from Svelte to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;beforeUpdate&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;svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

  &lt;span class="nx"&gt;beforeUpdate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdown&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;The component will still render the content like before: &lt;code&gt;{@html rendered}&lt;/code&gt;, but now replacing the markdown will rerender the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-browser compatibility
&lt;/h2&gt;

&lt;p&gt;One concern to be aware of if you want to add this to your site, is that scripts with &lt;code&gt;type="module"&lt;/code&gt; are not supported in Internet Explorer or some older phone browsers. &lt;a href="https://caniuse.com/es6-module"&gt;&lt;code&gt;caniuse&lt;/code&gt;&lt;/a&gt; has the full details.&lt;/p&gt;

&lt;p&gt;If you're following along, this shouldn't be a huge concern. By default, the Svelte build is also not supported in Internet Explorer, so if this compatibility is critical for you, you've got more work to do!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;With all of that in place, my blog now loads only the content it needs and is set to have good cache performance for the larger &lt;code&gt;vendor&lt;/code&gt; chunk.&lt;/p&gt;

&lt;p&gt;My authoring workflow is still simple, mostly writing Markdown into a file with a little bit of Svelte to wire up the page.&lt;/p&gt;

&lt;p&gt;And if I want to migrate to a CMS or build an api to serve my content, the components are ready to load that content asynchronously with only a small change! (Moving to loading posts from another source would even let me avoid creating a new route component for each post!)&lt;/p&gt;

&lt;p&gt;These changes will be up shortly &lt;a href="https://github.com/chrsjxn/svelte-plus-markdown"&gt;on github&lt;/a&gt;, and if you want to chat, you can find me &lt;a href="https://twitter.com/c_jackson_js"&gt;on twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a blog with Svelte: Adding Markdown</title>
      <dc:creator>Chris Jackson</dc:creator>
      <pubDate>Wed, 25 Nov 2020 21:07:10 +0000</pubDate>
      <link>https://dev.to/chrsjxn/building-a-blog-with-svelte-adding-markdown-17k1</link>
      <guid>https://dev.to/chrsjxn/building-a-blog-with-svelte-adding-markdown-17k1</guid>
      <description>&lt;p&gt;I started building a personal blog with Svelte a few weeks ago, cross posting to &lt;a href="https://dev.to/chrsjxn"&gt;dev.to&lt;/a&gt; for more reach and community.&lt;/p&gt;

&lt;p&gt;And it &lt;strong&gt;&lt;em&gt;sucks&lt;/em&gt;&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;I've been manually building content with Svelte components, to get the look and feel I want on my site. And then I have to translate those posts into Markdown for posting elsewhere.&lt;/p&gt;

&lt;p&gt;So I'm going to build Markdown support for my Svelte site, starting with &lt;em&gt;this post&lt;/em&gt;. I'll tell you how to add support to your Svelte site, and I'll compare the output on both platforms when I'm done!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding &lt;code&gt;markdown-it&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The first thing we want to do is add a library for Markdown parsing. I'm going to use &lt;a href="https://github.com/markdown-it/markdown-it" rel="noopener noreferrer"&gt;&lt;code&gt;markdown-it&lt;/code&gt;&lt;/a&gt;. It's seeing active development and the README has examples of rendering markdown in code, which I will need!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Installing dependencies
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;markdown-it&lt;/code&gt; is an easy install via npm, but it does assume that you have a full node environment to fall back on. So I needed to install a few extra dependencies.&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; markdown-it punycode
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @rollup/plugin-json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Updating &lt;code&gt;rollup.config.js&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;With dependencies installed, we can import the library into our Svelte app and try rendering basic Markdown. But &lt;code&gt;rollup&lt;/code&gt; is going to complain because it can't import JSON, and it needs to be configured to support adding &lt;code&gt;punycode&lt;/code&gt; into the browser bundle.&lt;/p&gt;

&lt;p&gt;So let's fix that now.&lt;/p&gt;

&lt;p&gt;To support JSON, we just need to add the rollup plugin (&lt;code&gt;@rollup/plugin-json&lt;/code&gt;) with its default settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In imports:&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;json&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;@rollup/plugin-json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// In rollup config:&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;//...&lt;/span&gt;
        &lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="c1"&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;And we also need to tell &lt;code&gt;rollup&lt;/code&gt; to include the &lt;code&gt;punycode&lt;/code&gt; version we just installed into our browser bundle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In plugins:&lt;/span&gt;
&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dedupe&lt;/span&gt;&lt;span class="p"&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;svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="c1"&gt;// Include our installed package, instead of the built in version&lt;/span&gt;
    &lt;span class="na"&gt;preferBuiltins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;h3&gt;
  
  
  Step 3: Rendering some sample Markdown
&lt;/h3&gt;

&lt;p&gt;With those config updates, we should now be able to render Markdown inside of our Svelte app. So let's build a Markdown component to render that content.&lt;/p&gt;

&lt;p&gt;We'll take in our Markdown string as a prop (&lt;code&gt;markdown&lt;/code&gt;) for now. That lets us test with a static string, and we can update the app to read Markdown from files or a CMS in the future.&lt;/p&gt;

&lt;p&gt;And we need to use Svelte's &lt;code&gt;@html&lt;/code&gt; feature to add our generated HTML to the page. &lt;/p&gt;

&lt;p&gt;⚠️ Warning: Using &lt;code&gt;@html&lt;/code&gt; with user submitted content could expose your users to an XSS vulnerability. &lt;code&gt;markdown-it&lt;/code&gt; has documentation about its &lt;a href="https://github.com/markdown-it/markdown-it/blob/master/docs/security.md" rel="noopener noreferrer"&gt;security features and recommendations&lt;/a&gt;, which you should read and understand if you need to support user submitted content. ⚠️&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- src/Markdown.svelte --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MarkdownIt&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;markdown-it&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

  &lt;span class="c1"&gt;// Initialize `markdown-it`&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MarkdownIt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// Render to an html string&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Render with the `@html` directive --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;@html&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we'll need to add our &lt;code&gt;Markdown&lt;/code&gt; component to test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Markdown&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;./Markdown.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;Markdown&lt;/span&gt; &lt;span class="na"&gt;markdown=&lt;/span&gt;&lt;span class="s"&gt;"# Hello from Markdown!"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reading Markdown from a file
&lt;/h2&gt;

&lt;p&gt;Now that we can render Markdown, we're going to set up our build to read Markdown from files. Authoring is much easier in separate files, and I can use my project's git repo for some basic versioning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Importing &lt;code&gt;*.md&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Our &lt;code&gt;Markdown&lt;/code&gt; components renders content from a string, so we need to be able to read our Markdown content in that format. &lt;code&gt;rollup&lt;/code&gt; will fail right now if we try to import an &lt;code&gt;.md&lt;/code&gt; file, but we can fix that with another plugin: &lt;code&gt;rollup-plugin-string&lt;/code&gt;.&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-dev&lt;/span&gt; rollup-plugin-string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when we add it to &lt;code&gt;rollup.config.js&lt;/code&gt;, we need to configure it to read &lt;code&gt;.md&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In imports:&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;string&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;rollup-plugin-string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// In rollup config:&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;//...&lt;/span&gt;
        &lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&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;**/*.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="c1"&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;h3&gt;
  
  
  Step 5: Updating our test to render from a file
&lt;/h3&gt;

&lt;p&gt;First, let's create a new Markdown file to test, &lt;code&gt;src/example.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Hello from Markdown!&lt;/span&gt;

We can render &lt;span class="ge"&gt;*text*&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now import that markdown into your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Markdown&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;./Markdown.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;exampleMarkdown&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;./example.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;Markdown&lt;/span&gt; &lt;span class="na"&gt;markdown=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;exampleMarkdown&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Supporting syntax highlighting
&lt;/h2&gt;

&lt;p&gt;Basic Markdown is great, but one of the killer features for blogging as an engineer is syntax highlighting. &lt;code&gt;markdown-it&lt;/code&gt; supports highlighting via a library, so let's add that now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Install &lt;code&gt;highlight.js&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;highlight.js&lt;/code&gt; will allow us to add syntax highlighting to a wide variety of languages (including Markdown 🤣), and is bundled with a wide variety of themes we can use. And &lt;code&gt;markdown-it&lt;/code&gt; uses it in their example, so let's start there.&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; highlight.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don't need to update our &lt;code&gt;rollup&lt;/code&gt; config for this step, but we will need to configure highlighting in our &lt;code&gt;Markdown&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- src/Markdown.svelte --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MarkdownIt&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;markdown-it&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="c1"&gt;// NEW: Import `highlight.js`&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;hljs&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;highlight.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

  &lt;span class="c1"&gt;// Initialize `markdown-it`&lt;/span&gt;
  &lt;span class="c1"&gt;// NEW: Configure highlight via constructor params!&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MarkdownIt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;highlight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;hljs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;hljs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;highlight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// eslint-disable-next-line no-console&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to highlight string&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="c1"&gt;// use external default escaping&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// Render to an html string&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Render with the `@html` directive --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;@html&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7: Import &lt;code&gt;highlight.js&lt;/code&gt; themes
&lt;/h3&gt;

&lt;p&gt;Adding a code block to the example markdown will render a code block, but we're not currently getting any styling for our highlighting. We can import styles directly from &lt;a href="https://github.com/highlightjs/highlight.js/tree/master/src/styles" rel="noopener noreferrer"&gt;&lt;code&gt;highlight.js&lt;/code&gt; styles&lt;/a&gt;, but we'll need to update our &lt;code&gt;rollup&lt;/code&gt; config again for this to work.&lt;/p&gt;

&lt;p&gt;We're going to add &lt;code&gt;rollup-plugin-styles&lt;/code&gt; to handle our CSS imports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev rollup-plugin-styles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can use its default configuration in &lt;code&gt;rollup.config.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In imports:&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&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;rollup-plugin-styles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// In rollup config:&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;//...&lt;/span&gt;
        &lt;span class="nf"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="c1"&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;Once we've done that, we can import a stylesheet from &lt;code&gt;highlight.js&lt;/code&gt; into our &lt;code&gt;Markdown&lt;/code&gt; component to render those styles into our site. I'm going to use &lt;code&gt;a11y-light&lt;/code&gt; for this example, but there are lots of options you can pick, depending on your site's color scheme.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- src/Markdown.svelte --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MarkdownIt&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;markdown-it&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;highlight.js/styles/a11y-light.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up and writing the post!
&lt;/h2&gt;

&lt;p&gt;With all of these pieces in place, I can now write this blog post in Markdown! There is still some work to do, especially styling the rendered HTML to match the rest of my site. But I can create my content in Markdown and let these libraries worry about the HTML!&lt;/p&gt;

&lt;p&gt;For a quick demo, here's a comparison of the markdown for this post rendered in my local development environment and in a draft post on &lt;code&gt;dev.to&lt;/code&gt;:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj6qh025jzeik7j51jkbj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj6qh025jzeik7j51jkbj.PNG" alt="Comparison of this post rendered in Svelte and on dev.to"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to see the final version of the rollup config, I have a completed copy of the tutorial posted &lt;a href="https://github.com/chrsjxn/svelte-plus-markdown" rel="noopener noreferrer"&gt;on github&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;And if you have suggestions for improvements, I'm happy to chat &lt;a href="https://twitter.com/c_jackson_js" rel="noopener noreferrer"&gt;on twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a simple theme store with Svelte</title>
      <dc:creator>Chris Jackson</dc:creator>
      <pubDate>Wed, 18 Nov 2020 15:56:28 +0000</pubDate>
      <link>https://dev.to/chrsjxn/building-a-simple-theme-store-with-svelte-9bo</link>
      <guid>https://dev.to/chrsjxn/building-a-simple-theme-store-with-svelte-9bo</guid>
      <description>&lt;p&gt;Dark mode has been gaining in popularity over the past few years, and now all of the major operating systems support a global dark theme. And a lot of major sites offer a dark mode toggle. But with modern browsers we can do better! We can use the user's OS preference to show them the color theme they prefer when they first land on our sites!&lt;/p&gt;

&lt;p&gt;This tutorial is going to teach you how to detect a user's OS theme in CSS and JavaScript, as well as how to build a Svelte store to respond to theme changes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Detecting dark mode in CSS
&lt;/h1&gt;

&lt;p&gt;The secret to detecting a user's OS theme is the media query &lt;code&gt;prefers-color-scheme&lt;/code&gt;. The two major options are light and dark, and we can easily use them to define CSS variables to apply these themes for an entire site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;midnightblue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;snow&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;h1&gt;
  
  
  Detecting dark mode in JavaScript
&lt;/h1&gt;

&lt;p&gt;We can use the same media query to detect a user's OS theme in JavaScript, as well!&lt;/p&gt;

&lt;p&gt;JavaScript supports executing any media query with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia"&gt;&lt;code&gt;window.matchMedia&lt;/code&gt;&lt;/a&gt;. The call returns a &lt;code&gt;MediaQueryList&lt;/code&gt; object that supports two features we'll need when we build the Svelte store.&lt;/p&gt;

&lt;p&gt;The two properties we care about are &lt;code&gt;matches&lt;/code&gt;, for checking the result of the media query, and &lt;code&gt;addListener&lt;/code&gt; for detecting changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;darkModeQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(prefers-color-scheme: dark)&lt;/span&gt;&lt;span class="dl"&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;darkModeEnabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;darkModeQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;

&lt;span class="nx"&gt;darkModeQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Theme changed to:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&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;light&lt;/span&gt;&lt;span class="dl"&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;h1&gt;
  
  
  Building our Svelte store
&lt;/h1&gt;

&lt;p&gt;The CSS approach is very useful for a static site, but as we add components or import libraries that need to know about our theme, it becomes more important to have a single source of truth for that data in our app.&lt;/p&gt;

&lt;p&gt;So let's build a theme store for a Svelte app!&lt;/p&gt;

&lt;p&gt;We start by defining our writable store based on the user's OS theme when the store is first loaded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;writable&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;svelte/store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Set up our MediaQueryList&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prefersDarkMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(prefers-color-scheme: dark)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Initial theme config from current state&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;writable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prefersDarkMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&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;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a great start, and it's probably enough for many apps, because users don't change their OS themes too often. But it's only a little bit more work to add an event listener to detect changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Update the store if OS preference changes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateThemeOnChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&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;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;prefersDarkMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateThemeOnChange&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Export a function to clean up the listener if needed&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cleanUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prefersDarkMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateThemeOnChange&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting all of this together, we have a simple theme store that responds to OS theme changes quickly! If you want to see a demo, you can check it out &lt;a href="https://svelte.dev/repl/15a88f72670845b4a173bc558fd537f9?version=3.29.7"&gt;on the Svelte REPL&lt;/a&gt;!&lt;/p&gt;

&lt;h1&gt;
  
  
  Caveats
&lt;/h1&gt;

&lt;p&gt;There are a few small gotchas with this approach that might result in your users seeing the wrong theme.&lt;/p&gt;

&lt;p&gt;A few browsers, including IE, do not support the media query we're using. However, nearly all browsers support &lt;code&gt;matchMedia&lt;/code&gt;, so they should fall back to whichever theme you picked as the default. For full details, see &lt;a href="https://caniuse.com/prefers-color-scheme"&gt;Can I use prefers-color-scheme?&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you enable some privacy settings, like &lt;code&gt;privacy.resistFingerprinting&lt;/code&gt; in Firefox, this media query will default to the light theme. For more details here, see &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme"&gt;prefers-color-scheme on MDN&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Next steps!
&lt;/h1&gt;

&lt;p&gt;This simple store is only a few lines of code, thanks to the power of the prefers-color-scheme media query. So I want to leave you with some suggestions for work you could do to learn a little more!&lt;/p&gt;

&lt;p&gt;The Svelte store I'm using here is relatively simple. We set an initial value when we create it with &lt;code&gt;writable&lt;/code&gt;, and we can update the value with &lt;code&gt;set&lt;/code&gt;. Can you write a React hook for this state, or implement the store in another state library?&lt;/p&gt;

&lt;p&gt;It's great to respond to user preferences, but what if the user wants to use your app with a different theme? Can you update the store to change themes when the user pushes a button? Can you update the store so that our app theme is independent from the OS theme, after they've pushed that button?&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>svelte</category>
      <category>javascript</category>
      <category>css</category>
    </item>
    <item>
      <title>Three tips to be a better code reviewer today</title>
      <dc:creator>Chris Jackson</dc:creator>
      <pubDate>Fri, 13 Nov 2020 16:35:49 +0000</pubDate>
      <link>https://dev.to/chrsjxn/three-tips-to-be-a-better-code-reviewer-today-4g2j</link>
      <guid>https://dev.to/chrsjxn/three-tips-to-be-a-better-code-reviewer-today-4g2j</guid>
      <description>&lt;p&gt;As a professional software developer, code review is a big part of the job! It's often a requirement for shipping your work, and understanding code well enough to give feedback takes time.&lt;/p&gt;

&lt;p&gt;So engineering teams often turn to automation to help reduce the cost of code reviews. Test coverage and static analysis tools help avoid bugs and vulnerabilities. Linters and formatters keep devs from spending time and energy on code style.&lt;/p&gt;

&lt;p&gt;And these tools are great! But they miss the human aspect of professional development. With that in mind, here are three tips to help you be a better code reviewer for your team, no matter how experienced you are or what technology you use!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Do the tests document the code well enough?
&lt;/h2&gt;

&lt;p&gt;Comments get out of date quickly. Design docs get lost. When you revisit a project, sometimes the only documentation you have is the tests.&lt;/p&gt;

&lt;p&gt;If you have great tests, that might not be too bad. If you have no tests, it could be a disaster!&lt;/p&gt;

&lt;p&gt;As a starting point for feedback about the tests, ask yourself these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can I call this function, use this library, or render this component using the tests as examples?&lt;/li&gt;
&lt;li&gt;Do the tests tell me what inputs are valid?&lt;/li&gt;
&lt;li&gt;Do the tests tell me what inputs will throw an error or have invalid results?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. What parts of the code were the hardest to understand?
&lt;/h2&gt;

&lt;p&gt;After a feature has shipped, it needs to be maintained. Eventually, someone will read this code who has never seen it before, and they'll need to understand it well enough to change it.&lt;/p&gt;

&lt;p&gt;That person reading the code for the first time might even be you! Lots of engineers have done a &lt;code&gt;git blame&lt;/code&gt; and realized they were the original author of the code they were just complaining about.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dTZ_NpoM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.redd.it/5z3kspwmpkbz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dTZ_NpoM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.redd.it/5z3kspwmpkbz.jpg" alt="git blame as spiderman looking at spiderman"&gt;&lt;/a&gt;&lt;br&gt;
(from &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/6p9syt/the_problem_with_git_blame/"&gt;/r/ProgrammerHumor&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Thankfully, code review is a similar experience. As a reviewer, you're probably reading the code for the first time, and you don't have all the context of the code author. If any of the code was difficult to understand when you read it, offer some feedback to improve it!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Could the names be clearer, or more descriptive?&lt;/li&gt;
&lt;li&gt;Could complex logic be broken down into utility functions?&lt;/li&gt;
&lt;li&gt;Could the documentation be improved with a comment? Or a more targetted test case?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Explain why
&lt;/h2&gt;

&lt;p&gt;This last one is a little different from the first two, because it's about how you give your feedback, not about what feedback you give. And it's much simpler.&lt;/p&gt;

&lt;p&gt;When you give feedback during a code review, explain why!&lt;/p&gt;

&lt;p&gt;If you're an expert, code review is a tool to teach other engineers. Making suggestions and explaining why is how you do that.&lt;/p&gt;

&lt;p&gt;And if you're not teaching, explaining why helps to build empathy and open discussions about other options.&lt;/p&gt;

&lt;p&gt;You don't have to write a novel, but even a little explanation helps. For example, &lt;code&gt;This boolean logic was tough for me to follow. Can you split it into a few utility functions?&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Being great at code reviews is a skill that takes a lot of practice, and there are a ton of topics that can't be covered in a quick list like this. Some of them are technical, like language specific best practices, and some of them are interpersonal, like offering effective feedback.&lt;/p&gt;

&lt;p&gt;But hopefully these tips will help you and your team get more value out of your code reviews!&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
