Build an E-Commerce Site with Wyam, a .NET Static Content Generator

The JAMstack (JavaScript, APIs & Markup) is on the rise, people!

Dedicated APIs, serverless backends, and site generators are getting more popular by the minute. Here at Snipcart, we're witnessing the growing traction for this new frontend stack firsthand: an increasing number of developers use our HTML/JS cart platform to craft snappy and secure client-side e-commerce sites. And most of these are built for paying clients, not just geeky side-projects!

Needless to say, it's thrilling to be a part of this paradigm shift. You can count on us to keep spreading the JAM right here on the blog, with in-depth e-commerce tutorials and open source repos.

We've previously explored popular Ruby apps like Jekyll & Middleman, or Golang's Hugo. But since I'm now a .NET proponent, I'm happy to reveal the object of my first tutorial this year: Wyam, a .NET static generator.

Today, I'm going to show you how you can integrate our shopping cart platform into a Wyam site in 5 simple steps. As usual, a live demo and full GitHub repo will be available at the end of the tutorial.

But first, a quick definition.

Is Wyam just a .NET static site generator?

Well, not exactly. Here's how Dave Glick, Wyam's creator, put it:

Wyam provides a static generation toolkit that can be used to produce custom static sites limited only by your imagination. You define your specific generation process by combining flexible pre-built modules as well as custom code if needed, or by starting with one of the default recipes that configures your generation for common scenarios (such as a blog). This makes Wyam extremely flexible, suitable for anything from blogs and documentation to store fronts and e-commerce sites.

Wyam also allows you to embed its static generation engine within your apps.

To get a better understanding of how much flexibility it provides, dive into the docs!

PS: If you've read this far and are still asking yourself "Wait, what is a static site generator?", give this DWB intro on the subject a read.


Pre-requisites

To go smoothly through this tutorial, you'll need to:

1. Creating the scaffolding

Let's start by putting together the scaffolding for our demo e-commerce site.

Note: Wyam might seem a little confusing at first. But as soon as you start reading the documentation, you easily understand how the build process works. I strongly suggest reading the Concepts section; it'll help you understand how things get bundled together.

For this tutorial, we'll use the blog recipe & Phantom theme to get us up and running as quickly as possible.

First, let's create a new Wyam project with the following bash command: wyam new -r Blog

Once it's done, you will have a barebones input folder containing an 'About' page and a single 'Post' page, both in Markdown format.

Wyam projects use a config.wyam file to customize build processes through modules/pipelines. So let's go ahead and add a config.wyam file at the root of our project.

Let's keep it simple for the moment and simply use this for our config file:

Settings.Host = "localhost";
GlobalMetadata["Title"] = "Snipcart powered Wyam static site";
GlobalMetadata["Snipcart_API_Key"] = "{YOUR_SNIPCART_API_KEY}";

Here, we use the GlobalMetadata object to store data that will be available site-wide.

Let's take a first look at our website by building it with the following command: wyam -r Blog -t Phantom -p

The -p part is used to serve the output folder using Wyam's preview server!

Result at this point:

2. Customizing the config

Now, time to tweak the architecture a bit.

While digging around, I found this neat example repo showing how to use the Razor templating engine with Markdown files.

The code from this example config file fits our needs, so we'll use some and append the following lines to our config file:

#n -p Wyam.Yaml
#n -p Wyam.Razor
#n -p Wyam.Markdown

Pipelines.Add("Products",
    ReadFiles("products/*.md"),  // Read all markdown files in the "products" directory
    FrontMatter(Yaml()),  // Load any frontmatter and parse it as YAML markup
    Markdown(),  // Render the markdown content
    Meta("Product", @doc.Content),  // Move the markdown content to metadata
    Meta("Snipcart_API_Key", GlobalMetadata["Snipcart_API_Key"]), //Add snipcart api key to the metadata of product pages
    Merge(
        ReadFiles("products/products.cshtml")  // Load the Razor product page template
    ),
    Razor(),  // Compile and render the page template
    Meta("ProductFile", string.Format(@"products\{0}.html", ((string)@doc["Title"]).ToLower().Replace(' ', '-'))),  // Use the product title as the filename and save it in metadata so we can use it in links later
    WriteFiles((string)@doc["ProductFile"])  // Write the product file 
);

Pipelines.Add("Home",
    ReadFiles("{!_,}*.cshtml"),
    Razor(),
    WriteFiles(".html")
);

As you can see, we use the same logic as the example repo, but adapted to our specific use case.

3. Declaring custom files

Now that we have established the necessary logic to output our files, we need to create them.

First, we'll rename the posts folder to "products".

Then, we'll create the following files in our input folder:_ViewStart.cshmtl, _Layout.cshtml and home.cshtml. The viewstart file is where we declare the logic processed before views rendering. The layout file is, of course, the layout template. And the home.cshtml is the index that will be served by default.

Here's the content for all of them:

//_ViewStart.cshtml
@{
    Layout = "_Layout.cshtml";
}


//_Layout.cshml
@RenderBody()

//Home.cshtml
<h1>Welcome to our store!</h1>
<hr/>
<h2>Products</h2>
@foreach(var doc in Documents["Products"])
{
    <ul>
        <li><a href="@doc["ProductFile"]">@doc["Title"]</a></li>
    </ul>
}

From there, the only other template we need is the product page template.

We'll go into our products folder and create a products.cshtml file.

Here's its content:

<h1>@Metadata["Title"]</h1>
<hr />
@Html.Raw(Metadata["Product"])

We also need to update the first-post.md to first-product.md for it to make sense. We'll update the content later on.

Since we started from the blog recipe, let's just use the build command with: wyam build -p

(Use the -p argument to start Wyam's preview server to see the site locally)

And here we are! We now have ourselves a spanking new, custom-made Wyam site.

What you should see from here:

4. Building product templates

Now let's add actual data for our product pages.

What we need to do here is add Snipcart's required scripts. For this demo, we'll only show buy buttons on a product's individual page. So we'll include these scripts only in the product template.

And while we're at it, let's add a little more content to our product template:

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
    <script src="https://cdn.snipcart.com/scripts/2.0/snipcart.js" data-api-key="@Metadata["Snipcart_API_Key"]"     id="snipcart"></script>
    <link href="https://cdn.snipcart.com/themes/2.0/base/snipcart.min.css" rel="stylesheet" type="text/css" />

    <h2>@Metadata["Name"]</h2>
    
    <div class="product-details">
      <img src="@Metadata["Image"]" width="150px" class="thumbnail"/>
      <div class="product-description">
        <p>
          @Html.Raw(Metadata["Product"])
        </p>
    
        <button class="snipcart-add-item"
          data-item-name="@Metadata["Name"]"
          data-item-id="@Metadata["Sku"]"
          data-item-image="@Metadata["Image"]"
          data-item-url="@Metadata["Url"]"
          data-item-price="@Metadata["Price"]">
          Buy it for @Metadata["Price"] $
        </button>
      </div>
    </div>

You can see we've added some CSS classes to our template. To use them, we'll have to create a CSS folder nested inside our input folder.

We added a main.css file in there. Now that we've added the desired CSS classes to the file, we'll need to create a new pipeline so it gets added to the output folder.

This one is fairly simple—you can just append this to your config.wyam:

Pipelines.Add("Resources",
    CopyFiles("**/*{!.cshtml,!.md,!.yaml,}")
);

Then we just add it to our _Layout.cshtml file:

<link rel="stylesheet" type="text/css" href="/css/main.css">

<div class="body">
    @RenderBody()
</div>

5. Adding more products to our Wyam store

With the current state of our set up, we have the necessary templates to render products, but those products have yet to be declared.

Let's hop back into our first-product.md file, and update its content as follows:

Url: /
Name: Tent
Description: Water and wind resistant. Perfect nightly shelter from the wilderness.
Image: https://snipcart.com/media/10102/tent.png
Price: 200.00
Sku: 1
Title: Tent
---
Water and wind resistant. Perfect nightly shelter from the wilderness!

Now we have the needed data to fit our product template needs.

As long as we add products with the .md extension to the products folder, the products pipeline will take these new files into account and bundle them accordingly.

Result: A Snipcart-powered Wyam e-commerce site

After a little bit of styling and template updates, here's the full GitHub repo.

You can also check out our live e-commerce static website example, deployed and hosted on Netlify. :)

A sneak-peek at our grandiose demo's final result:

Closing words

Overall, I had a blast developing with Wyam. The CLI is neat, and the preview server offers a watch method so you don't have to trigger the compile manually. And I really enjoyed the pipeline workflow within the configuration file. Getting to understand how pipelines work was probably the biggest challenge, but the documentation was straight to the point, and their GitHub repo had a good examples folder, which helped heaps.

Like many other JAMstack tutorials, this Wyam integration went super fast. It took me around 2 hours to get this functional demo up and running.

I wish I had more time to further experiment with the pipelines: they're quite powerful, and I couldn't get as creative with them as I'd have wanted. There's also a ton of modules out there that I could have played with. If you're interested, you should check out this page to see what's available. I think anyone who loves .NET and wants to get into the JAMstack & static generation will thoroughly enjoy themselves working with Wyam. It's definitely great for small websites, but it also can be a perfect fit for bigger projects once you get familiar with it.

I hope this post encourages you to create something cool with Wyam and to look more seriously into the JAMstack. If end up building such a project, be it with Snipcart or not, let us know. We'd love to have a look and potentially feature or share it somewhere!

We publish technical and editorial posts like this one on a regular basis, so feel free to subscribe to our newsletter to stay in the loop!


Questions regarding this Wyam & Snipcart integration? Any other site generators or frameworks you'd like us to explore on the blog? Let us know in the comments. And If you liked this post, we'd sure love a share on Twitter.

About the author

Maxime Laboissonniere
Developer

Max was the first dev hire for Snipcart back in 2016. Since then, he has stood out by his curiosity towards new technologies. He’s the one that introduced the team to Vue.js, for instance. In his 4 years experience as a developer, he’s mastered JavaScript and its ecosystem, as well as C#. These days, he likes to explore Elixir, Clojure, ELM, RxJS, and data science--when he doesn’t have his nose in a book.

Follow him on Twitter.

Quick Processwire E-Commerce Tutorial: Lean Store on PHP CMS

Read next from Maxime
View more

36 000+ geeks are getting our monthly newsletter: join them!