Skip to content

Latest commit

 

History

History
311 lines (191 loc) · 18.6 KB

File metadata and controls

311 lines (191 loc) · 18.6 KB

Creating a Website with Stacy

This is a tutorial/walkthrough that explains step-by-step how to create and publish a simple website using Stacy.

Let's create a website that will tell people what humanity knows about various animals we love to have as our pets. The website will have a single page with a title followed by a number of modules that will follow the same template, one for each pet kind. Each module will have a title, a picture and some description text. Something like the following:

Site Screenshot

Step 1: Content Model

For this step, first create a space in your Contentful account. This space will hold all the dynamic content for your website.

Now, we need to define our content model. We are going to need two content types defined: one for the top page as a whole, and one for the article modules. Let's start with the article module. To do that, go to your space's Content model and add a new content type:

Create Article Content Type

Note the content type's Api Indentifier "article", which we will need later when we create a template for it.

Now, let's add fields to the article content type. We will need three: one for the article title, one for the pet picture and one for the description.

To add title field, click Add field button, select Text field type, enter the field name "Title" and click Create and configure button. In the Settings tab of the following dialog check the This field represents the Entry title checkbox:

Article Title Field Settings

Also note the Field ID "title", which we will use to refer to the field's value in the module template.

In the Validations tab make the field required by checking Required field checkbox:

Article Title Field Validations

And save the field.

Now, let's add the picture field. Click Add field button again, pick Media this time, enter name "Picture" and proceed to Create and configure. In the Validations make the field required and also make sure that only images are accepted:

Article Picture Field Validations

Save the field.

Finally, let's add the description field. Click Add field again, select Text, type in "Description" into the Name field and pick Long text, full-text search option this time:

Article Description Create Field

Click Create and configure button, make the field required in the Validations tab, and make sure that in the Appearance tab the field uses Markdown option. This will allow the authors to use rich text for the field, including different size fonts, bold, italic, multiple paragraphs, etc.

Note: Another option is to use a Rich Text field for the description.

Now, once we have all the three fields in place, save the content type:

Article Content Type

Go back to the Content model and click Add content type to create our second content type—the one for the page as a whole. Enter "Page" for the content type name and hit Create.

We are going to need two fields for this content type: the page caption and the list of article modules to include.

Let's start with the caption. Click Add field button, pick Text, type in "Caption" into the field name input, and hit Create and configure. In the field's Settings tab check the This field represents the Entry title checkbox. In the Validations tab check the Required field checkbox. And save the field.

Now, let's add the articles. Click Add field button again and pick Reference for the field type this time around. The Reference type allows the field to refer other entities, which in our case will be our Article entities. Type in "Articles" into the field name input and select Many references option (the authors should be able to include multiple articles on the page, not just one):

Page Articles Create Field

Proceed to Create and configure. In the Validations tab specify that only entries of type Article can be used for the field:

Page Articles Field Validations

And save the field.

Before we save the content type, there is one more special field that needs to be added— the slug field. Every content type that corresponds to a page as a whole (as opposed to an includable module) must have a field named "slug". The field will be used to define at what URL the page will be available in the target website. For example, if we create an entry of content type Page and we provide the slug as "my-best-page", the page will be available in our website under URL "/my-best-page.html".

Let's create the field. Click Add field one more time, select Text field type and enter "Slug" for the field name (make sure the Field ID is "slug"—this is the ID Stacy will expect it to be). Proceed to Create and configure. In the Validations make the field required, unique (every page entry has to have its own unique slug to correspond to a unique page URL in the target website) and also check the Match a specific pattern checkbox. Enter pattern ^\w[\w-]*(/\w[\w-]*)*$ (it is a regular expression):

Page Slug Field Validations

In the Appearance tab pick Slug:

Page Slug Field Appearance

And save the field and the content type.

Our content model is complete.

Step 2: Add Initial Content

Now, that our content model is ready, let's add some initial content. We are going to have one page and two articles: one for dogs and one for cats.

Let's start with the articles. Go to the Content section of your Contentful space and add an Article entry. You will see the user interface that your content authors will be using to maintain your website. Enter the title "Dogs", then use Create new asset and link to upload a picture of your favorite puppy (use Publish button to save the picture once uploaded and click arrow back in the top left corner of the dialog to return to the atricle form). Make sure that it says "PUBLISHED" at the top of the picture. In the description field type in a few nice words about dogs and hit Publish to save the article entry.

Go back to the Content and add another Article entry for the cats.

Now we can add an entry for our main page. Click Add entry and pick Page content type this time. In the caption field type in "What We Know About Pets". Then for the articles select Link existing entries option and select both article entries we just created for dogs and cats.

In the slug field overwrite the default value Contentful has put there for you and enter "index". This will make the page to be generated at "/index.html" in our website.

Publish the entry and we are done with the content!

Step 3: Create Website Project

Once we have our content model and some initial content in place, we can create our website project where we will have templates for our pages and modules.

Some prerequisites:

  • Make sure you have Node.js version 10.16.3 or newer installed along with NPM (Node.js comes with it).

  • For publishing your website in Amazon Cloud you will need AWS CLI installed and configured to access your AWS account.

  • Know Handlebars, which is the language used in Stacy for the templates.

  • Get your space ID and your Content Delivery API access token from Contentful. To do that, in your Contentful account go to Space settingsAPI keys. Then either add a new API key or use an existing one (Contentful automatically created "Example Key 1" for you when you create the new space). Find values in fields Space ID and Content Delivery API - access token below it.

First, install Stacy package globally:

npm install -g stacy

Next, change to the directory where you will want your website project development environment to live and generate new project:

stacy new --cf-space <your space ID> --cf-access-token <your API access token> allaboutpets

This will create a project directory called "allaboutpets" in your current directory. The "allaboutpets" is known as the site ID.

Inside your project directory, go to /static and replace styles.css with something like this:

html, body { height: 100%; }
body { margin: 0; font-family: "Helvetica Neue", sans-serif; }

h1, h2, figure, p { margin: 0; }

body > header { padding: 16px 48px; }
body > header > h1 { text-align: center; }

main { padding: 0 48px 48px 48px; }

article:not(:first-child) { margin-top: 16px; }

article > header { margin-bottom: 16px; border-bottom: 1px solid; }

article > .content { display: flex; }
article > .content > figure > img { width: 120px; }
article > .content > .description { margin-left: 32px; font-size: large; }

The contents of the /static directory are copied over to the target website as-is. Therefore, this is a good place for your stylesheets, images used in the website design, fonts, or even some static HTML pages that are not going to be maintained by the authors in Contentful.

Now, in the /templates directory of your project let's create templates for our two content types: the page and the article.

Let's start with the article. As you remember, our content type ID in Contentful is "article", so the template file has to be article.hbs. The name of the template file (sans the extension) must match exactly to the content type ID (not name!) to be associated with it. Put the following in article.hbs:

<article>
  <header>
    <h2>{{title}}</h2>
  </header>
  <div class="content">
    <figure>
      {{{asset picture}}}
    </figure>
    <div class="description">{{{markdown description}}}</div>
  </div>
</article>

As you can see, we can use our entry fields defined in the Article content type directly in the template. A couple of notes though:

  • We used asset helper for the picture. The asset helper is one of the custom Handlebars helpers Stacy provides for you. This one renders an HTML <img> element for a media field. See Stacy manual for the full list of helpers.

    Since the asset helper outputs HTML, triple-braces must be used so that Handlebars does not try to escape it.

  • The description field is rendered using another Stacy helper markdown. In Contentful long text fields are stored using Markdown. Stacy's markdown helper converts the Markdown syntax into HTML. As with the asset helper, note the triple-braces needed since markdown outputs HTML.

  • Contentful field IDs are used to refer to the entry fields, not the names.

Now, let create a template for our Page content type. In page.hbs put the following:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>{{caption}}</title>
    <link href="styles.css" rel="stylesheet">
  </head>
  <body>
    <header>
      <h1>{{caption}}</h1>
    </header>
    <main>
      {{#each articles}}{{{module this}}}{{/each}}
    </main>
  </body>
</html>

Note that we use another Stacy helper module. This helper includes the module referred by the reference field. Also note that triple-braces are used to that Handlebars does not escape the included module's HTML.

We are ready to try our website now. Let's start local Stacy server using:

stacy serve

Once running, in your browser open http://localhost:8080 and you should see your website!

While Stacy is running the local server, you can make changes in the templates, files in the /static directory or change the content in Contentful. Reload the page in the browser and you will immediately see the changes.

To stop the server, hit Ctrl+C.

Step 4: Create Stacy Infrastructure in AWS

Once you are satisfied with the website, you can publish it in AWS. Stacy publishes your site in an Amazon S3 bucket called target bucket. The website can be made available on the Internet either directly from it or via Amazon CloudFront. Once the site is published, Stacy receives notifications from Contentful about content changes via entry and asset publish and unpublish events. When it receives these notifications, it automatically regenerates pages affected by the content change and updates them in the target S3 bucket. This allows your content authors to maintain the website without involvement from the website developers.

To do all the above, Stacy needs certain infrastructure in your AWS account. Before we can create it, we need to meet certain prerequisites:

  • In your AWS account, create an S3 bucket for your website—the target bucket. Make sure that the bucket is configured to serve web content either directly or via CloudFront (see Hosting a Static Website on Amazon S3 for details).

    Alternatively, you can use an existing bucket and configure Stacy to publish your website in a subfolder in it.

  • Create another S3 bucket (with the default configuration) for Stacy's AWS Lambda function package. This package includes the Stacy's publisher, which is the piece that responds to publish and unpublish events from Contentful and updates the content in the target S3 bucket.

For our purposes, let's assume you created the target S3 bucket with name "allaboutpets" and the Lambda functions bucket with name "allaboutpets-lambda".

Now, build the publisher package in your project:

stacy build-publisher

This created a zip archive called stacy-allaboutpets-publisher.zip in your project's /build directory. Upload this zip file to your Lambda S3 bucket (the "allaboutpets-lambda" bucket) either using the AWS Console or the CLI:

aws s3 cp build/stacy-allaboutpets-publisher.zip s3://allaboutpets-lambda

Once you have the buckets and the publisher Lambda package in place, you can create Stacy infrastructure. In your project, Stacy has generated an AWS Cloud​Formation template at /misc/cfn-template.json. Use it to create a CloudFormation stack in your AWS account. When you create the stack, it uses some required and optional parameters to configure it. You will have to enter the name of the Lambda functions S3 bucket ("allaboutpets-lambda"), the target S3 bucket ("allaboutpets") and Contentful Content Delivery API access token. You can leave the rest of the stack parameters with their default values.

To create the stack you can either use AWS Console or use AWS CLI. For example:

aws cloudformation create-stack --stack-name stacy-allaboutpets --template-body file:misc/cfn-template.json --capabilities CAPABILITY_NAMED_IAM --parameters "ParameterKey=LambdaFunctionsBucket,ParameterValue=allaboutpets-lambda" "ParameterKey=TargetBucket,ParameterValue=allaboutpets" "ParameterKey=ContentfulAccessToken,ParameterValue=xxxxxxxxx"

Then wait for the stack creation completion:

aws cloudformation wait stack-create-complete --stack-name stacy-allaboutpets

Once the stack is created, you have to adjust target S3 bucket policy to allow Stacy's publisher update files in it. The bucket policy should include something like the following:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "<publisher IAM role ARN>"
            },
            "Action": [
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::allaboutpets/*"
        }
    ]
}

You can find the publisher IAM role ARN in the CloudFormation stack's output parameter called PublisherRoleArn, which in turn can be found in the AWS Console, or via the AWS CLI:

aws cloudformation describe-stacks --stack-name stacy-allaboutpets

Once that's done, you have completed setting up Stacy infrastructure in AWS and everything is ready for your website deployment.

Step 5: Publish the Website

Once you have your AWS infrastructure in place, you can publish your website. To do that, you have to connect your project development environment with your target AWS environment. Find .env file in your project directory and open it. In it you will find a bunch of variable that start with "AWS_" prefix. Edit them and provide correct values. Value for the AWS_PUBLISH_EVENT_SOURCE_MAPPING variable you can find in the CloudFormation stack's output parameter called PublishEventSourceMappingId.

After .env is configured, you can perform the initial website publishing by using:

stacy publish --keep-publisher-enabled

Your website should be now in your target S3 bucket!

As a website developer, you will use Stacy's publish command every time you make changes in the project (templates, static content). It completely updates the published content and the Stacy publisher function.

Step 6: Configure Contentful Webhook

A major feature of Stacy is automatic regeneration of published content when authors change content in Contenful. To enable that we have to configure a Contentful Webhook.

Stacy exposes an endpoing in Amazon API Gateway that receives Contentful's publish and unpublish events for entries and assets. We need to find the endpoint's URL and the special API key needed to call it. Go to AWS Console and select API Gateway service. Find "Stacy: allaboutpets" API in the APIs section, go to Stages and expand prod stage. There, take the endpoint's Invoke URL:

API Gateway Endpoint

Now, go to the API Keys and select "Stacy: allaboutpets" key. Click Show next to the API key and take the key value.

Now go to your Contentful space, navigate to Space settingsWebhooks and click Add Webhook. Give it a name (e.g. "Stacy Publisher") and enter the API Gateway URL in the URL input (leave the method "POST").

Then, in the Triggers section, pick Select specific triggering events option and check four checkboxes in rows Entry and Asset and columns Publish and Unpublish.

Then, in the Headers section, click Add secret header link. For the header key enter "X-API-Key" and in the value field enter the API Gateway key.

Once you save the webhook, automatic Stacy publisher becomes enabled and you can edit content in Contentful and see the updates reflected in your published website.

This completes this tutorial. Happy websiting!