One place for hosting & domains

      Deploy

      How to Create and Deploy Your First Eleventy Website


      The author selected the Internet Archive to receive a donation as part of the Write for DOnations program.

      Eleventy (also known as 11ty) is a static site generator (SSG) for building websites. It was launched in 2017 by Zach Leatherman as a JavaScript-based alternative to Jekyll, one of the first mainstream SSGs, which is written in Ruby. Eleventy has gained a reputation as one of the most flexible and performant options for building static websites, leading to steadily rising adoption rates in the Jamstack ecosystem.

      It’s important to note that Eleventy is not a JavaScript framework, and it does not include any client-side JavaScript. It takes template files specified in HTML, Markdown, or your choice of templating language, and outputs a complete, static website ready to be deployed to a web server of your choice.

      While most other SSGs are restricted to just one templating language, Eleventy supports multiple templating languages, such as HTML, Liquid, Markdown, Nunjucks, Handlebars, moustache, EJS, Haml, Pug, etc., and you can even combine them in the same project. This flexibility is one of the things that makes Eleventy stand out from its competition.

      In this tutorial, you’ll develop a static website from scratch with Eleventy and deploy it to DigitalOcean’s App Platform for free.

      Prerequisites

      To complete this tutorial, you will need:

      Step 1 — Setting Up the Project

      Unlike competitors such as Jekyll and Hugo, Eleventy does not provide a way to scaffold a new project, so you’ll need to create a regular Node.js project, and then add Eleventy as a dependency.

      The first step is to launch the terminal on your computer, create a new directory somewhere on your filesystem, and change into it as shown below.

      • mkdir eleventy-blog
      • cd eleventy-blog

      At the root of the eleventy-blog directory, initialize the project with a package.json file with npm init -y, and install Eleventy as a development dependency by passing the -D flag to the install subcommand.

      • npm init -y
      • npm install -D @11ty/eleventy

      Once the Eleventy package is installed, inspect the contents of your project directory with ls. It will contain a package.json file, a package-lock.json file, and a node_modules directory.

      The output should look similar to this:

      Output

      node_modules package-lock.json package.json

      Open the package.json file in your favorite text editor, then replace the existing scripts property with the highlighted lines below.

      eleventy-blog/package.json

      {
        "name": "eleventy-blog",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "build": "eleventy",
          "start": "eleventy --serve"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "devDependencies": {
          "@11ty/eleventy": "^0.12.1"
        }
      }
      

      There are two scripts here: build for building the website files, and start for running the Eleventy web server on http://localhost:8080.

      Save the file, and then run the command below to build the website:

      The output should look similar to this:

      Output

      > eleventy-blog@1.0.0 build > eleventy Wrote 0 files in 0.04 seconds (v0.12.1)

      The output indicates that you haven’t created any files yet, so there is nothing to build. In the next step, you’ll begin adding the necessary files that are needed for the website.

      The final directory structure of the project you’ll be working on is shown below. You’ll start from an empty directory, and incrementally add new features until you arrive at this structure.

      .
      ├── about
      │   └── index.md
      ├── css
      │   └── style.css
      ├── _data
      │   └── site.json
      ├── _includes
      │   ├── layouts
      │   │   ├── base.njk
      │   │   ├── page.njk
      │   │   └── post.njk
      │   └── nav.njk
      ├── index.njk
      ├── node_modules
      ├── package.json
      ├── package-lock.json
      ├── posts
      │   ├── first-post.md
      │   ├── second-post.md
      │   └── third-post.md
      └── _site
          ├── about
          │   └── index.html
          ├── css
          │   └── style.css
          ├── index.html
          └── posts
              ├── first-post
              │   └── index.html
              ├── second-post
              │   └── index.html
              └── third-post
                  └── index.html
      

      In this step, you created a Node.js project and added Eleventy as a dependency. In the next step, you’ll choose a templating language.

      Step 2 — Choosing a Templating Language

      For the purpose of this tutorial, we’ll use the Nunjucks template, a common choice for many Eleventy projects. (Depending on your preference, you could also choose a different templating language.)

      In the root of your project directory, create an index.njk file and open it in your text editor. Add a “Hello world” message to the file as shown below, then save the file.

      eleventy-blog/index.njk

      <h1>Hello, world!</h1>
      

      Once saved, run the build command again. It will convert the index.njk file to an index.html file and output it into a new _site directory at the root of the project.

      The output should look similar to this:

      Output

      > eleventy-blog@1.0.0 build > eleventy Writing _site/index.html from ./index.njk. Wrote 1 file in 0.08 seconds (v0.12.1)

      At this point, you can view the website in the browser by starting a development server at http://localhost:8080 as shown below.

      The output should look similar to this:

      Output

      > eleventy-blog@1.0.0 start > eleventy --serve Writing _site/index.html from ./index.njk. Wrote 1 file in 0.08 seconds (v0.12.1) Watching.. [Browsersync] Access URLs: ----------------------------------- Local: http://localhost:8080 External: http://172.29.217.37:8080 ----------------------------------- UI: http://localhost:3001 UI External: http://localhost:3001 ----------------------------------- [Browsersync] Serving files from: _site

      If you wish to use a different port, you can specify it through the --port option, as shown here:

      • npm start -- --port 4040 to set a different port

      The -- separator in the command above is used to distinguish the parameters passed to npm command itself from those passed to the script. After starting the development server, open http://localhost:8080 in your web browser to see the site in action. You can exit the server at any time by pressing Ctrl + C on your keyboard.

      Eleventy hello world in Microsoft Edge

      In this step, you used Nunjucks as the templating language and began building a website. In the next section, you’ll learn about layouts in Eleventy and create a homepage for the website.

      Step 3 — Creating the Homepage

      In order to make your project more flexible and scalable from the start, you’ll need to create a base template that will be applied to all the pages of the site. Conventionally, this is called the base layout, and it needs to go into a layouts directory nested within an _includes directory. Create the _includes/layouts directory using the command below:

      • mkdir -p _includes/layouts

      In the _includes/layouts directory, create a base.njk file and open it in your text editor. Copy and paste the following code into the file. This is basic HTML5 boilerplate that will serve as the foundation for all the pages on the website.

      _includes/layouts/base.njk

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{{ title }}</title>
      </head>
      <body>
        <header>
          <h1>{{ title }}</h1>
        </header>
        <main>
          {{ content | safe }}
        </main>
      </body>
      </html>
      

      The contents in double curly braces are Nunjucks variables that will be replaced accordingly when a derivative page is being built. The {{ title }} variable will be supplied through the page’s front matter block while the {{ content }} will be replaced with all incoming page content that is not part of the front matter. The latter is piped through the safe filter to prevent it from being escaped.

      Return to the index.njk file in your project root, and modify it as shown below:

      eleventy-blog/index.njk

      ---
      title: Homepage
      layout: layouts/base.njk
      ---
      
      <h1>Welcome to this brand new Eleventy website!</h1>
      

      The contents on either side of the triple dashes constitute the front matter of the file, while the rest of the file is what will be passed to your layouts as its content. In the front matter, the title and layout of the file are specified accordingly.

      If your development server is still running, head over to your site’s localhost URL to view the changes, or start the server first with npm start before attempting to view it in a web browser.

      Eleventy homepage in action

      As you can see from the above screenshot, the base.njk template has taken effect on the homepage.

      In this step, you added a base template for the pages of your site, and created a homepage. However, it doesn’t yet have any styling beyond the browser defaults. In the next section, you’ll improve the design of the website by adding a navigation menu.

      The _includes directory is where you’ll place the different components of the website. The contents of this directory are partial files that can be placed in your layout files to facilitate reuse. In this section, you’ll create the navigation menu as a partial, and include it in the base layout.

      In the _includes directory, create a new file called nav.njk. Open it in your editor and populate it with the code below. It is the markup for the top navigation bar, and it includes the title of the site as well as links to the homepage and a yet-to-be created “About” page.

      eleventy-blog/_includes/nav.njk

      <nav class="navbar is-light" role="navigation" aria-label="main navigation">
        <div class="navbar-start">
          <div class="navbar-item has-text-weight-bold">
            My Eleventy Blog
          </div>
        </div>
        <div class="navbar-end">
          <a href="https://www.digitalocean.com/" class="navbar-item">
            Home
          </a>
      
          <a href="http://www.digitalocean.com/about" class="navbar-item">
            About Me
          </a>
        </div>
      </nav>
      

      Save and close the nav.njk file, and open the base template file (_includes/layouts/base.njk) in your editor. Go ahead and include the new navigation partial in this file through the include syntax shown below:

      eleventy-blog/_includes/layouts/base.njk

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>{{ title }}</title>
        </head>
        <body>
          <header>{% include "nav.njk" %}</header>
          <main>
            {{ content | safe }}
          </main>
        </body>
      </html>
      

      In the browser, the site should look like this:

      Navigation

      When you check the home page once again, the navigation menu should show up just like in the screenshot above. The title of the site “My Eleventy Blog” is hardcoded into the nav partial, but this is suboptimal because it’s likely that you will repeat the title elsewhere on the site, and changing it later becomes tedious since you’ll then have to find each place it was used.

      A better approach is to supply this value through a global data file. These are JSON files placed in a _data directory at the project root that provide global data accessible to all template files. At the project root, create a _data directory, followed by a site.json file within it. Open site.json in your text editor and specify the site’s title using the code below.

      eleventy-blog/_data/site.json

      {
        "title": "My Eleventy Blog",
        "url": "https://example.com/",
        "language": "en-US",
        "description": "A simple blog with awesome content"
      }
      

      At this point, you can save and close the file, then return to the nav.njk file in the _includes directory and replace the hardcoded site title with the appropriate variable.

      eleventy-blog/_includes/nav.njk

      . . .
      <div class="navbar-item has-text-weight-bold">
        {{ site.title }}
      </div>
      . . .
      

      The site should look exactly the same as before, but this small change makes setting and updating global data much easier. One thing to note about global variables is that they are scoped to the name of the JSON file, which is why we used {{ site.title }} above. You can create other data files as needed, and use them in your templates. For example, you can have an author.json file that contains your personal details such as your name, bio, and links to your social media profiles. Such data could then be accessed through variables (such as {{ author.bio }}) on any page of the website.

      Return to your index.njk file at the project root and update its contents as shown below so that it uses the site title and description:

      eleventy-blog/index.njk

      ---
      title: Homepage
      layout: layouts/base.njk
      ---
      
      <section class="hero is-medium is-primary is-bold">
        <div class="hero-body">
          <div class="container">
            <h1 class="title">{{ site.title }}</h1>
            <h2 class="subtitle">{{ site.description }}</h2>
          </div>
        </div>
      </section>
      

      In the browser, the site should look like this:

      Updated homepage

      In this step, you added a navigation menu to the website. However, the site is using default styling. In the next section, you’ll style the website using the Bulma CSS framework, which provides flexbox-based frontend components for building responsive websites.

      Step 5 — Adding a Stylesheet

      At the moment, Eleventy does not recognize CSS files for auto-inclusion in the build directory, so a few extra steps are needed to get this working. Specifically, you’ll need to create a stylesheet directory, and ensure that it is copied over to the build output (_site) when the site is built. You’ll also need to ensure that modifying a stylesheet triggers a rebuild and automatic refreshing in the web browser. You can achieved this by creating a configuration file for Eleventy.

      At the project root, create a css folder followed by a style.css file within it. Open style.css and import the Bulma CSS framework by using the code below:

      eleventy-blog/css/style.css

      @import "https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css";
      

      Save the file.

      Next, create an .eleventy.js file in your project root. This is the configuration file for Eleventy, similar to _config.yml files in Jekyll projects. Note that this file will be hidden in your filesystem since it’s prefixed with a period. You’ll need to use ls -a to get it to show up when listing the directory’s contents.

      Open .eleventy.js in your text editor and paste the following to include the css directory in the build, and also to watch the folder for changes:

      eleventy-blog/.eleventy.js

      module.exports = function (eleventyConfig) {
        // Copy the `css` directory to the output
        eleventyConfig.addPassthroughCopy('css');
      
        // Watch the `css` directory for changes
        eleventyConfig.addWatchTarget('css');
      };
      

      At this point, you need to stop the server with Ctrl+C, and start it again with npm start before the changes take effect. You’ll need to do this every time you modify the configuration file.

      If you check the site in your browser right now, you won’t notice any changes. That’s because the stylesheet has not yet been linked in any template. Go ahead and add it to the base.njk template as shown below.

      eleventy-blog/_includes/layouts/base.njk

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <link rel="stylesheet" href="https://www.digitalocean.com/css/style.css" />
          <title>{{ title }}</title>
        </head>
        <body>
          <header>{% include "nav.njk" %}</header>
          <main>
            {{ content | safe }}
          </main>
        </body>
      </html>
      

      After saving the file, the styles should kick in immediately.

      Styled homepage

      In this step, you added styling to the website using the Bulma CSS framework. In the next step, you’ll expand the site by creating an “About” page.

      Step 6 — Creating an About Page

      At the moment, there is a link to a non-existent “About” page in the navigation menu. You’ll change that by creating a unique layout for all static pages, and afterward, the “About” page itself. In the _includes/layouts folder, create a page.njk file. This will be the layout for all static pages on the site.

      Open the new file in your editor and populate it with the code below. The front matter layout property is used to indicate that the page layout should inherit from the previously created base.njk template. This is known as layout chaining, and it allows us to reuse a template while adding unique elements that are specific to the new template, which helps avoid unnecessary repetition of basic site structures.

      eleventy-blog/_includes/layouts/page.njk

      ---
      layout: layouts/base.njk
      ---
      
      <article class="page-layout">
        <div class="container">
          <div class="columns">
            <div class="column is-8 is-offset-2">
              <div class="content mt-5">
                <h1>{{ title }}</h1>
                {{ content | safe }}
              </div>
            </div>
          </div>
        </div>
      </article>
      

      Now that you have a page layout, you can create the “About” page. To do this, create a directory at the project root called about, and add a new index.md markdown file within it.

      Add the following code into the file:

      eleventy-blog/about/index.md

      ---
      title: About Me
      layout: layouts/page.njk
      ---
      
      I am a person that writes stuff.
      

      After saving the file, go to https://localhost:8080/about. The page should load correctly with the specified layout.

      About page

      Creating other pages, such as a contact page or newsletter page, can be done in the same way: create a directory with the name of the page, then add an index.md file at the root of the new directory. You can also use an HTML or Nunjucks file instead of Markdown if you prefer.

      In this step, you created a unique layout for static pages and added an “About” page to the site. In the next section, you’ll create and process blog posts on an Eleventy website.

      Step 7 — Creating Posts

      Creating a blog post is very similar to creating a page. You’ll start by creating a directory called posts at the project root to keep all posts.

      However, you will create a different layout for posts. It’s going to be similar to the layout for pages, but you will include a date to differentiate it. In a real-world project, it’s likely that you’ll want different layouts for posts and pages, so it’s good practice to create a new layout for each one.

      In the _includes/layouts directory, create a new post.njk file and open it in your text editor. Paste the code below into your post.njk layout file.

      eleventy-blog/_includes/layouts/post.njk

      ---
      layout: layouts/base.njk
      ---
      
      <section class="page-layout">
        <div class="container">
          <div class="columns">
            <div class="column is-8 is-offset-2">
              <article class="content mt-5">
                <h1 class="title">{{ title }}</h1>
                <p class="subtitle is-6">
                  Published on: <time datetime="{{ page.date }}">{{ page.date }}</time>
                </p>
                {{ content | safe }}
              </article>
            </div>
          </div>
        </div>
      </section>
      

      Similar to the page.njk template, the post template extends the base template with additions that make sense for posts (such as the date of publication).

      To use this template, create a new file in your posts directory called first-post.md, and open it in your text editor.

      Paste the following contents into the first-post.md file:

      eleventy-blog/posts/first-post.md

      ---
      title: My First Blog Post
      description: This is the first post on my blog
      tags: post
      date: 2021-06-19
      layout: layouts/post.njk
      ---
      
      You’ll find this post in your `posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `eleventy --serve`, which launches a web server and auto-regenerates your site when a file is updated.
      

      Save the file, then head over to http://localhost:8080/posts/first-post in your browser. Notice how the URL corresponds to the location of the file in the project (excluding the extension). This is how URLs are handled by default, but they can be changed to some other format through the permalink key.

      A blog post

      The post is displayed correctly, but notice how the date is currently formatted. This date format is difficult for users to read, but Eleventy provides no built-in formatting options for dates, unlike most other SSGs. This means that you have to use an external package to get a more human readable format in Eleventy.

      In this step, you created a unique layout for blog posts and added a blog post to the site. In the next section, you’ll create a custom filter that helps with date formatting.

      Step 8 — Using Filters in Eleventy

      Eleventy supports filters for transforming content in various ways. For example, the safe filter used earlier prevents the escaping of HTML content, and there are other built-in ones like slug for transforming text into URL-friendly strings. You can also add your own custom filters that can be used in any template. These customizations can be made through the configuration file.

      Go ahead and add a universal filter for formatting dates so that it can be used in the post template. Start by installing Luxon, a lightweight JavaScript library for date formatting:

      Afterward, open the .eleventy.js config file, and update its contents as follows:

      eleventy-blog/.eleventy.js

      const { DateTime } = require('luxon');
      
      module.exports = function (eleventyConfig) {
        // Copy the `css` directory to the output
        eleventyConfig.addPassthroughCopy('css');
      
        // Watch the `css` directory for changes
        eleventyConfig.addWatchTarget('css');
      
        eleventyConfig.addFilter('readableDate', (dateObj) => {
          return DateTime.fromJSDate(dateObj, { zone: 'utc' }).toFormat(
            'dd LLL yyyy'
          );
        });
      };
      

      The highlighted lines describe how to add a custom filter to Eleventy. First, you need to import whatever objects you need from any external libraries. The DateTime type from Luxon provides several methods for formatting purposes.

      Adding a filter involves calling the addFilter() method provided by the eleventyConfig argument. It takes the filter name as its first argument, and the callback function is what will be executed when the filter is used. In the above snippet, the filter is called readableDate, and the callback function is used to format a date object using the provided date tokens. This will yield a date in the following format: 19 Jul 2021.

      Save the config file and restart the server so that the changes take effect. Then use the readableDate filter in the post template as shown below to format the post date according to the specified layout.

      eleventy-blog/_includes/layouts/post.njk

      . . .
      <p class="subtitle is-6">
        Published on: <time datetime="{{ page.date }}">{{ page.date | readableDate }}</time>
      </p>
      . . .
      

      Once you open the post in your browser, you’ll notice that the date formatting has been updated.

      Screenshot showing nicely formatted date

      In this step, you added a filter to change the date formatting on blog posts. In the next section, you’ll display a list of posts on the homepage, as is conventional on most personal blogs.

      Step 9 — Displaying Posts on the Homepage

      To make it easier for visitors to your site to discover the posts on the blog, it’s a good idea to list them on the homepage. You will use Eleventy’s collections feature in order to implement this functionality.

      Before you proceed to update the index.njk file, you’ll need to create at least three additional posts to showcase on the homepage. You can copy the first post into new files, and change the title and description for each of them. Once you’re through with that, update your index.njk file as shown below:

      eleventy-blog/index.njk

      ---
      title: Homepage
      layout: layouts/base.njk
      ---
      
      <section class="hero is-medium is-primary is-bold">
        <div class="hero-body">
          <div class="container">
            <h1 class="title">{{ site.title }}</h1>
            <h2 class="subtitle">{{ site.description }}</h2>
          </div>
        </div>
      </section>
      
      <section class="postlist mt-3 pt-3">
        <div class="container">
          <h2 class="title has-text-centered mt-3 mb-6">Recent posts</h2>
          <div class="columns">
            {% for post in collections.post | reverse %}
              {% if loop.index0 < 3 %}
                <div class="column">
                  <div class="card">
                    <header class="card-header">
                      <p class="card-header-title">
                        {{ post.data.title }}
                      </p>
                    </header>
                    <div class="card-content">
                      <div class="content">
                        {{ post.data.description }}
                      </div>
                    </div>
                    <footer class="card-footer">
                      <a href="https://www.digitalocean.com/community/tutorials/{{ post.url }}" class="button is-fullwidth is-link card-footer-item">Read article</a>
                    </footer>
                  </div>
                </div>
                {% endif %}
            {% endfor %}
          </div>
        </div>
      </section>
      

      The for loop construct in the above snippet is from the Nunjucks templating language, and its one of the ways to iterate over a collection in Eleventy. It starts with {% for post in collection.post | reverse %} and ends with {% endfor %}. The post collection is created by Eleventy and consists of any page that has its tags front matter property set to post.

      The reverse filter is used here so that the iteration starts from the most recent post instead of the default order, which puts older posts first. Within the loop, the output of the collection is limited to three items, and the post local variable is used to access the title, description, and URL of each post in the collection.

      After saving the file, go to the homepage in the browser to see the results. It should look similar to the screenshot below.

      Eleventy recent posts output

      In this step, you created additional blog posts and used Eleventy’s collections feature to list them on the website’s homepage. You now have a styled website with a homepage, an “About” page, and some posts. Next, you’ll deploy it to production through GitHub and DigitalOcean’s App Platform.

      Step 10 — Pushing the Website to GitHub

      Before you can deploy your code to DigitalOcean’s App Platform, you need to get your site in a Git repository, and push that repository to GitHub. The first thing to do is initialize a Git repo in your project directory:

      Next, create a .gitignore file at the project root so that you can exclude the contents of the node_modules and _site directories from being tracked in the Git repo.

      .gitignore

      node_modules
      _site
      

      After saving the file, run the commands below to add all the project files to the staging area, then make your initial commit:

      • git add -A
      • git commit -m "Initial version of the site"

      The output should look similar to this:

      Output

      [master (root-commit) e4e2063] Initial version of the site 15 files changed, 6914 insertions(+) create mode 100644 .eleventy.js create mode 100644 .gitignore create mode 100644 _data/site.json create mode 100644 _includes/layouts/base.njk create mode 100644 _includes/layouts/page.njk create mode 100644 _includes/layouts/post.njk create mode 100644 _includes/nav.njk create mode 100644 about/index.md create mode 100644 css/style.css create mode 100644 index.njk create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 posts/first-post.md create mode 100644 posts/second-post.md create mode 100644 posts/third-post.md

      Navigate to GitHub, log in with your profile, and create a new empty repository for your project called eleventy-blog (it can be public or private). Once the GitHub repo is created, copy the link to the repo, and add it as a remote location for your project in the terminal:

      • git remote add origin https://github.com/username/eleventy-blog.git

      Before you push your changes to the remote location, rename the default branch to main to match what GitHub expects:

      Finally, run the command below to push the main branch to GitHub. Enter your GitHub account credentials when prompted.

      Note: If two-factor authentication is enabled for your GitHub account, you’ll need to use a personal access token or SSH key when accessing GitHub on the command line. For more information, see Using two-factor authentication with the command line.

      The output should look similar to this:

      Output

      Enumerating objects: 23, done. Counting objects: 100% (23/23), done. Delta compression using up to 4 threads Compressing objects: 100% (19/19), done. Writing objects: 100% (23/23), 64.41 KiB | 2.38 MiB/s, done. Total 23 (delta 3), reused 0 (delta 0) remote: Resolving deltas: 100% (3/3), done. To https://github.com/username/eleventy-blog.git * [new branch] main -> main

      In this step, you added your site to a Git repository, which you then pushed to GitHub. You are now ready to deploy your website to DigitalOcean’s App Platform.

      Step 11 — Deploying to DigitalOcean with App Platform

      Go ahead and log in to your DigitalOcean account, then head over to https://cloud.digitalocean.com/apps and click the green Create button on the top right. Choose the Apps option in the dropdown, then, on the resulting page, select GitHub as your source.

      DigitalOcean App Platform Source

      You’ll be redirected to GitHub and prompted to give DigitalOcean access to your repositories. You can choose all repositories, or just the ones you wish to deploy. Click Install and Authorize once you’ve made your choice. You should be redirected back to the Choose Source page once again.

      Install and Authorize DigitalOcean on GitHub

      On the Choose Source page, select GitHub, then choose the eleventy-blog repository from the Repository dropdown. Ensure that the selected branch is main, and the checkbox to autodeploy code changes is ticked, then click Next to continue.

      Configure GitHub source

      On the next page, your project will be auto detected as a Node.js project. You may need to change its Type to Static Site, and the Output Directory to _site as shown in the screenshot below. Click Next to continue once everything matches.

      Configure application

      Name your static site, and click Next to go to the Finalize and Launch screen.

      Name static website

      Static sites are free, so retain the default Starter selection under Plans, and press Launch Starter App at the bottom of the page.

      Launch starter app

      Your site will build immediately, and you should see a success message after a few minutes.

      Site deployed to DigitalOcean’s App Platform

      By default, your app will be given a sub-domain on ondigitalocean.app. Now that your site is deployed, you can visit the provided URL to view the live website in your browser. You can also register a custom domain for your site by following How to Manage Domains in App Platform.

      Conclusion

      In this tutorial, you built a static site with Eleventy and deployed to DigitalOcean’s App Platform. Moving forward, you can make changes to your website locally, push the changes to GitHub, and DigitalOcean will automatically update the live site. You can go to the app dashboard to see the progress of the build at any time.

      To build on what you’ve achieved in this tutorial, visit the Eleventy docs to learn more about how you can customize your site’s templates, and add features like responsive images, syntax highlighting, and caching. If you’d like to get started quickly without creating your own theme from scratch, check out the starter projects page.





      Source link

      How To Deploy a Pre-Trained Question and Answer TensorFlow.js Model on App Platform


      The author selected Code 2040 to receive a donation as part of the Write for DOnations program.

      Introduction

      As the field of machine learning (ML) grows, so does the list of environments for using this technology. One of these environments is the web browser, and in recent years, there has been a surge in data-related frameworks targeting web-based machine learning models. An example of these frameworks is TensorFlow.js, TensorFlow’s JavaScript counterpart library for training, executing, and deploying machine learning models in the browser. In an attempt to make TensorFlow.js accessible to developers with limited or no ML experience, the library comes with several pre-trained models that work out of the box.

      A pre-trained machine learning model is ready-to-use machine learning you don’t have to train. TensorFlow.js includes 14 that suit a variety of use cases. For example, there is an image classifying model for identifying common objects and a body segmentation model for identifying body parts. The principal convenience of these models is that, as the name states, you don’t have to train them. Instead, you load them in your application. Besides their ease of use and pre-trained nature, these are curated models—they are accurate and fast, sometimes trained by the algorithms’ authors and optimized for the web browser.

      In this tutorial, you will create a web application that serves a Question and Answer (QnA) pre-trained model using TensorFlow.js. The model you will deploy is a Bidirectional Encoder Representations from Transformers (BERT) model that uses a passage and a question as the input, and tries to answer the question from the passage.

      You will deploy the app in DigitalOcean’s App Platform, a managed solution for building, deploying, and scaling applications within a few clicks from sources such as GitHub. The app you will create consists of a static page with two input fields, one for the passage and one for the question. In the end, you will have a written and deployed—from GitHub—a Question and Answer application using one of TensorFlow.js’ pre-trained models and DigitalOcean’s App Platform.

      Prerequisites

      To complete this tutorial, you will need:

      Step 1 — Creating the App’s Interface and Importing the Required Libraries

      In this step, you will write the app’s HTML code, which will define its interface and import the libraries for the app. The first of these libraries is TensorFlow.js, and instead of installing the package locally, you will load it from a content delivery network or CDN. A CDN is a network of servers spanning multiple locations that store content they provide to the internet. This content includes JavaScript files, such as the TensorFlow.js library, and loading it from a CDN saves you from packing them in your application. Similarly, you will import the library containing the Question and Answer model. In the next step, you will write the app’s JavaScript, which uses the model to answer a given question.

      In this tutorial, you will structure an app that will look like this:

      The app

      The app has five major elements:

      • A button that loads a pre-defined passage you can use to test the app.
      • An input text field for a passage (if you choose to write or copy your own).
      • An input text field for the question.
      • A button that triggers the prediction that answers the question.
      • An area to display the model’s output beneath the Answer! button (currently blank white space).

      Start by creating a new directory named tfjs-qna-do at your preferred location. In this directory, using a text editor of your choice, create a new HTML file named index.html and paste in the following code:

      index.html

      <!DOCTYPE html>
      <html lang="en-US">
      
      <head>
          <meta charset="utf-8" />
          <!-- Load TensorFlow.js -->
          <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
          <!-- Load the QnA model -->
          <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/qna"></script>
          <link href="./style.css" rel="stylesheet">
      </head>
      
      <body>
          <div class="main-centered-container">
              <h1>TensorFlow.js Pre-trained "QnA" BERT model</h1>
              <h3 class="header-border">Introduction</h3>
              <p>This application hosts TensorFlow.js' pre-trained Question and Answer model, and it attempts to answer the question
              using a given passage. To use it, write a passage (any!) in the input area below and a question. Then, click the
              "answer!" button to answer the question using the given passage as a reference. You could also click the test
              button to load a pre-defined input text.</p>
      
              <h4>Try the test passage!</h4>
              <div id='test-buttons'></div>
      
              <div>
                  <h4>Enter the model's input passage here</h4>
                  <textarea id='input-text' rows="20" cols="100" placeholder="Write the input text..."></textarea>
              </div>
      
              <div>
                  <h4>Enter the question to ask</h4>
                  <textarea id='question' rows="5" cols="100" placeholder="Write the input text..."></textarea>
              </div>
              <h4>Click to answer the question</h4>
              <div id="answer-button"></div>
              <h4>The model's answers</h4>
              <div id='answer'></div>
      
              <script src="./index.js"></script>
      
      
          </div>
      </body>
      
      </html>
      

      Here’s how that HTML breaks down:

      • The initial <html> tag has the <head> tag that’s used for defining metadata, styles, and loading scripts. Its first element is <meta>, and here you will set the page’s charset encoding to utf-8. After it, there are two <script> tags for loading both TensorFlow.js and the Question and Answer model from a CDN.
      • Following the two <script> tags, there’s a <link> tag that loads a CSS file (which you will create next).
      • Next, there’s the HTML’s <body>—the document’s content. Inside of it, there’s a <div> tag of class main-centered-container containing the page’s elements. The first is a <h1> header with the application title and a smaller <h3> header, followed by a brief introduction explaining how it works.
      • Under the introduction, there’s a <h4> header and a <div> where you will append buttons that populate the passage input text field with sample text.
      • Then, there are the app’s input fields: one for the passage (what you want the model to read) and one for the question (what you want the model to answer). If you wish to resize them, change the rows and cols attributes.
      • After the text fields, there’s a <div> with id button where you will later append a button that, upon clicking, reads the text fields’ text and uses them as an input to the model.
      • Last, there is a <div> with id answer that’s used to display the model’s output and a <script> tag to include the JavaScript code you will write in the following section.

      Next, you’ll add CSS to the project. In the same directory where you added the index.html file, create a new file named style.css and add the following code:

      style.css

      body {
        margin: 50px 0;
        padding: 0;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial;
      }
      
      button {
        margin: 10px 10px;
        font-size: 100%;
      }
      
      p {
        line-height: 1.8;
      }
      
      .main-centered-container {
        padding: 60px;
        display: flex;
        flex-direction: column;
        margin: 0 auto;
        max-width: 960px;
      }
      
      .header-border {
        border: solid #d0d0d0;
        border-width: 0 0 1px;
        padding: 0 0 5px;
      }
      

      This CSS adds style to three HTML elements: body, buttons, and paragraphs (<p>). To body, it adds a margin, padding, and changes the default font. To button, it adds margin and increases the font size. To paragraph p, it modifies the line-height attribute. The CSS has a class main-centered-container that centers the content and another one, header-border, that adds a solid line to an element.

      In this step, you wrote the app’s HTML file. You imported the TensorFlow.js library and QnA model, and defined the elements you will use later to add the passage and the question you want to answer. In the following step, you will write the JavaScript code that reads the elements and triggers the predictions.

      Step 2 — Predicting with the Pre-Trained Model

      In this section, you will implement the web app’s JavaScript code that reads the app’s input fields, makes a prediction, and writes the predicted answers in HTML. You will do it in one function that’s triggered when you click the “answer” button. Once clicked, it will reference both input fields to get their values, use them as inputs to the model, and write its output in the <div> with id output you defined in Step 1. Then, you will run the app locally to test it before adding it to GitHub.

      In the project’s directory tfjs-qna-do/, create a new file named index.js, and declare the following variables:

      index.js

      let model;
      
      // The text field containing the input text
      let inputText;
      
      // The text field containing the question
      let questionText;
      
      // The div where we will write the model's answer
      let answersOutput;
      

      The first of the variables, model, is where you will store the QnA model; inputText and questionText are references to the input and question text fields; answersOutput is a reference to the output <div>.

      In addition to these variables, you will need a constant for storing the sample text you will use to test the app. We will use the Wikipedia article on DigitalOcean as a sample passage. Based on this passage, you could ask the model questions like “Where is DigitalOcean headquartered?” and hopefully, it will output “New York”.

      Copy this block into your index.js file:

      index.js

      // Sample passage from Wikipedia.
      const doText = `DigitalOcean, Inc. is an American cloud infrastructure provider[2] headquartered in New York City with data centers worldwide.[3] 
      DigitalOcean provides developers cloud services that help to deploy and scale applications that run simultaneously on multiple computers.
      DigitalOcean also runs Hacktoberfest which is a month-long celebration (October 1-31) of open source software run in partnership with GitHub and Twilio.
      `;
      

      Now, you will define the app’s functions, starting with createButton(). This function creates a button and appends it to an HTML element:

      index.js

      function createButton(innerText, id, listener, selector, disabled = false) {
        const btn = document.createElement('BUTTON');
        btn.innerText = innerText;
        btn.id = id;
        btn.disabled = disabled;
      
        btn.addEventListener('click', listener);
        document.querySelector(selector).appendChild(btn);
      }
      

      createButton() is a function that creates the app’s two buttons; since all the buttons work similarly, this function avoids repeating code. The function has five parameters:

      • innerText: the button’s text.
      • id: the button’s id.
      • listener: a callback function that’s executed when the user clicks the button.
      • selector: the <div> element where you will append the button.
      • disabled: a boolean value to disable or enable the button. This parameter’s default value is false.

      createButton() starts by creating an instance of a button and assigns it to the variable btn. Then, it sets the button’s innerText, id, and disabled attributes. The button uses a click event listener that executes a callback function whenever you click it. The function’s last line appends the button to the <div> element specified in the selector parameter.

      Next, you will create a new function named setupButtons() that calls createButton() two times to create the app’s buttons. Begin by creating the app’s Answer! button:

      index.js

      function setupButtons() {
        // Button to predict
        createButton('Answer!', 'answer-btn',
          () => {
            model.findAnswers(questionText.value, inputText.value).then((answers) => {
              // Write the answers to the output div as an unordered list.
              // It uses map create a new list of the answers while adding the list tags.
              // Then, we use join to concatenate the answers as an array with a line break
              // between answers.
              const answersList = answers.map((answer) => `<li>${answer.text} (confidence: ${answer.score})</li>`)
                .join('<br>');
      
              answersOutput.innerHTML = `<ul>${answersList}</ul>`;
            }).catch((e) => console.log(e));
          }, '#answer-button', true);
      }
      

      The first button the function creates is the one that triggers the predictions. Its first two arguments, innerText and id, are the button’s text and the identifier you want to assign to the button. The third argument is the listener’s callback (explained below). The fourth argument, selector, is the id of the <div> where you want to add the button (#answer-button), and the fifth argument, disabled, is set to true, which disables the button (to avoid predicting before the app loads the model).

      The listener’s callback is a function that’s executed once you click the Answer! button. Once clicked, the callback function first calls the pre-trained model’s function findAnswers(). (For more about the findAnswers() function, see the product documentation). findAnswers() uses as arguments the input passage (read from questionText) and the question (read from inputText). It returns the model’s output in an array that looks as follows:

      Model's output

      [ { "text": "New York City", "score": 19.08431625366211, "startIndex": 84, "endIndex": 97 }, { "text": "in New York City", "score": 8.737937569618225, "startIndex": 81, "endIndex": 97 }, { "text": "New York", "score": 7.998648166656494, "startIndex": 84, "endIndex": 92 }, { "text": "York City", "score": 7.5290607213974, "startIndex": 88, "endIndex": 97 }, { "text": "headquartered in New York City", "score": 6.888534069061279, "startIndex": 67, "endIndex": 97 } ]

      Each of the array’s elements is an object of four attributes:

      • text: the answer.
      • score: the model confidence level.
      • startIndex: the index of the passage’s first character that answers the question.
      • endIndex: the index of the answer’s last characters.

      Instead of displaying the output as the model returns it, the callback uses a map() function that creates a new array containing the model’s answers and scores while adding the list <li> HTML tags. Then, it joins the array’s elements with a <br> (line break) between answers and assigns the result to the answer <div> to display them as a list.

      Next, add a second call to createButton(). Add the highlighted portion to the setupButtons function beneath the first createButton:

      index.js

      function setupButtons() {
        // Button to predict
        createButton('Answer!', 'answer-btn',
          () => {
            model.findAnswers(questionText.value, inputText.value).then((answers) => {
              // Write the answers to the output div as an unordered list.
              // It uses map create a new list of the answers while adding the list tags.
              // Then, we use join to concatenate the answers as an array with a line break
              // between answers.
              const answersList = answers.map((answer) => `<li>${answer.text} (confidence: ${answer.score})</li>`)
                .join('<br>');
      
              answersOutput.innerHTML = `<ul>${answersList}</ul>`;
            }).catch((e) => console.log(e));
          }, '#answer-button', true);
      
        createButton('DigitalOcean', 'test-case-do-btn',
          () => {
           document.getElementById('input-text').value = doText;
          }, '#test-buttons', false);
      }
      

      This new call appends to the test-buttons <div> the button that loads the DigitalOcean sample text you defined earlier in the variable doText. The function’s first argument is the label for the button (DigitalOcean), the second argument is the id, the third is the listener’s callback that writes in the passage input text area the value of the doText variable, the fourth is the selector, and the last is a false value (to avoid disabling the button).

      Next, you will create a function, named init(), that calls the other functions:

      index.js

      async function init() {
        setupButtons();
        answersOutput = document.getElementById('answer');
        inputText = document.getElementById('input-text');
        questionText = document.getElementById('question');
      
        model = await qna.load();
        document.getElementById('answer-btn').disabled = false;
      }
      

      init() starts by calling setupButtons(). Then, it assigns some of the app’s HTML elements to the variables you defined at the top of the script. Next, it loads the QnA model and changes to false the disabled attribute of the answer (answer-btn) button.

      Last, call init():

      index.js

      init();
      

      You have finished the app. To test it, open your web browser and write the project’s directory absolute path with /index.html appended to it in the address bar. You could also open your file manager application (such as Finder on Mac) and click on “index.html” to open the web application. In this case, the address would look like your_filepath/tfjs-qna-do/index.html.

      To find the absolute path, go to the terminal and execute the following command from the project’s directory:

      Its output will look like this:

      Output

      /Users/your_filepath/tfjs-qna-do

      After launching the app, you will need to wait a few seconds while it downloads and loads the model. You will know it’s ready when the app enables the Answer! button. Then, you could either use the test passage button (DigitalOcean) or write your own passage, and then input a question.

      To test the app, click the “DigitalOcean” button. In the passage input area, you will see the sample text about DigitalOcean. In the question input area, write “Where is DigitalOcean headquartered?” From the passage, we can see the answer is “New York”. But will the model say the same? Click Answer! to find out.

      The output should look similar to this:

      Model's answers to "where is DO headquartered?"

      Correct! Although there are slight differences, four of the five answers say that DigitalOcean’s headquarters are in New York City.

      In this step, you completed and tested the web application. The JavaScript code you wrote reads the input passage and question and uses it as an input to the QnA model to answer the question. Next, you will add the code to GitHub.

      Step 3 — Pushing the App to GitHub

      In this section, you will add the web application to a GitHub repository. Later, you will connect the repository to DigitalOcean’s App Platform and deploy the app.

      Start by logging in to GitHub. From its main page, click the green button under your name or the plus sign on the screen’s upper right corner to create a new repository.

      Click to create a repository

      Click to create a repository

      Either choice takes you to the Create a new repository screen. In the Repository name field (after your username), name the repository tfjs-qna-do. Select its privacy setting, and click Create repository to create it.

      Create the repository

      Open a terminal and go to the project’s directory tfjs-qna-do/. There, execute the following command to create a new local Git repository:

      Next, stage the files you want to track with Git, which in this case, is everything in the directory:

      And commit them:

      • git commit -m "initial version of the app"

      Rename the repository’s principal branch to main:

      Then link your local repository with the remote one on GitHub:

      • git remote add origin git@github.com:your-github-username/tfjs-qna-do.git

      Last, push the local codebase to the remote repository:

      It will ask you to enter your GitHub credentials if this is the first time you are pushing code to it.

      Once you have pushed the code, return to the GitHub repository and refresh the page. You should see your code.

      The code in the repo

      In this step, you have pushed your web app’s code to a remote GitHub repository. Next, you will link this repository to your DigitalOcean account and deploy the app.

      Step 4 — Deploying the Web Application in DigitalOcean App Platform

      In this last section, you will deploy the Question and Answer app to DigitalOcean’s App Platform) from the GitHub repository created in Step 3.

      Start by logging into your DigitalOcean account. Once logged in, click the Create green button in the upper right corner and then on Apps; this takes you to the Create new app screen:

      Create a new DO App

      Here, choose GitHub as the source where the project resides.

      Choose the source

      If you haven’t linked your DigitalOcean account with GitHub, it will ask you to authorize DigitalOcean to access your GitHub. After doing so, select the repository you want to link: tfjs-qna-do.

      Link the repo

      Back on the App Platform window, select the app’s repository (tfjs-qna-do), the branch from where it will deploy the app (main), and check the Autodeploy code changes box; this option ensures that the application gets re-deployed every time you push code to the main branch.

      Choose the source (cont.)

      In the next screen, Configure your app, use the default configuration values. As an additional step, if you wish to change the web app’s HTTP requests route, from, for example, the default https://example.ondigitalocean.app/tfjs-qna-do, to https://example.ondigitalocean.app/my-custom-route, click on Edit under HTTP Routes and write my-custom-route in the ROUTES input.

      Configure the app

      Next, you will name the site. Again, you could leave the default tfjs-qna-do name or replace it with another one.

      Name the site

      Clicking Next will take you to the last screen, Finalize and launch, where you will select the app’s pricing tier. Since the app is a static webpage, App Platform will automatically select the free Starter plan. Last, click the Launch Starter App button to build and deploy the application.

      Finalize and launch

      While the app is deployed, you will see a screen similar to this:

      Deploying app

      And once deployed, you will see:

      Deployed

      To access the app, click on the app’s URL to access your app, which is now deployed in the cloud.

      Deployed app

      Conclusion

      As the field of machine learning expands, so do its use cases alongside the environments and platforms it reaches – including the web browser.

      In this tutorial, you have built and deployed a web application that uses a TensorFlow.js pre-trained model. Your Question and Answer web app takes as input a passage along with a question and uses a pre-trained BERT model to answer the question according to the passage. After developing the app, you linked your GitHub account with DigitalOcean and deployed the application in App Platform without needing additional code.

      As future work, you could trigger the app’s automatic deployment by adding a change to it and pushing it to GitHub. You could also add a new test passage and format the answer’s output as a table to improve its readability.

      For more information about TensorFlow.js, refer to its official documentation.



      Source link

      How to Deploy Your Application or Microservice on Kubernetes


      How to Join

      This Tech Talk is free and open to everyone. Register below to get a link to join the live stream or receive the video recording after it airs.

      Date Time RSVP
      July 28, 2021 11:00 a.m.–12:00 p.m. ET / 3:00–4:00 p.m. GMT

      About the Talk

      Migrating containerized workloads to Kubernetes? See which Kubernetes resources work best, and how you can get multiple replicas of your application running simply, and quickly.

      At the end of this Tech Talk, you will be able to deploy your application or microservice as a Kubernetes Deployment.

      What You’ll Learn

      • How Kubernetes deploys and manages groups of pods
      • How to distinguish between the different use cases for a Kubernetes Deployment, DaemonSet, and Job
      • How to create a YAML manifest for a Deployment
      • How to create and inspect a Kubernetes Deployment

      This Talk is Designed For

      • Anyone running containerized workloads in a non-Kubernetes environment
      • Anyone looking to gradually migrate to Kubernetes

      Prerequisites

      • You have containerized an application or microservice
      • You have basic knowledge of containers and Kubernetes

      Resources

      Kubernetes for Full-Stack Developers: Community Curriculum and eBook
      Kubernetes on DigitalOcean: Docs and Quickstart



      Source link