├── src ├── data │ └── .gitkeep ├── posts │ ├── my-first-post.md │ ├── my-third-post.md │ └── my-second-post.md ├── includes │ ├── footer.njk │ ├── header.njk │ └── meta.njk ├── assets │ ├── js │ │ └── index.js │ └── css │ │ └── index.css ├── about.njk ├── sitemap.njk ├── layouts │ └── base.njk ├── index.njk └── posts.njk ├── .eleventyignore ├── .env.sample ├── .gitignore ├── postcss.config.js ├── tailwind.config.js ├── README.md ├── package.json └── .eleventy.js /src/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eleventyignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | BASE_URL=https://example.com -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .env 3 | node_modules 4 | .DS_Store -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/posts/my-first-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | title: My First Post 4 | tags: post 5 | --- 6 | 7 | Hello from {{ title }}! -------------------------------------------------------------------------------- /src/posts/my-third-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | title: My Third Post 4 | tags: post 5 | --- 6 | 7 | Hello from {{ title }}! -------------------------------------------------------------------------------- /src/posts/my-second-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | title: My Second Post 4 | tags: post 5 | --- 6 | 7 | Hello from {{ title }}! -------------------------------------------------------------------------------- /src/includes/footer.njk: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/js/index.js: -------------------------------------------------------------------------------- 1 | import '../css/index.css'; 2 | 3 | import Alpine from 'alpinejs' 4 | 5 | window.Alpine = Alpine 6 | 7 | // Add Alpine extensions here 8 | 9 | Alpine.start() 10 | 11 | console.log('hello from index.js') -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./src/**/*.{njk,js,html,md,yml,yaml}", 5 | ], 6 | theme: { 7 | extend: {}, 8 | }, 9 | plugins: [], 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/about.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | eleventyNavigation: 4 | key: About 5 | order: 2 6 | meta: 7 | title: About us 8 | description: this is our about page. 9 | --- 10 | 11 | 12 |
13 | This is the about page 14 |
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 11ty + Vite + Tailwind + Alpine 2 | 3 | A static site generation starter with modern tooling and sensible defaults. 4 | 5 | ### Built in settings and features 6 | 7 | - Navigation plugin with data file for configuring html 8 | - SEO optimized meta include file with multiple fallbacks 9 | - Image plugin for performance 10 | - Sitemap generation -------------------------------------------------------------------------------- /src/assets/css/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | 7 | body { 8 | min-height: 100dvh; 9 | display: flex; 10 | flex-direction: column 11 | } 12 | 13 | #main { 14 | @apply py-16 px-4 mx-auto max-w-[800px]; 15 | } 16 | 17 | li.active { 18 | @apply underline; 19 | } 20 | } -------------------------------------------------------------------------------- /src/sitemap.njk: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /public/sitemap.xml 3 | eleventyExcludeFromCollections: true 4 | --- 5 | 6 | 7 | {% for page in collections.all %} 8 | 9 | {{ site.baseUrl }}{{ page.url | url }} 10 | {{ page.date.toISOString() }} 11 | 12 | {% endfor %} 13 | -------------------------------------------------------------------------------- /src/layouts/base.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ site.title }} - {{ title or meta.title }} 7 | {% include "meta.njk" %} 8 | 9 | 10 | 11 | 12 | {% include "header.njk" %} 13 | 14 |
15 | 16 | {{ content | safe }} 17 | 18 |
19 | 20 | {% include "footer.njk" %} 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | meta: 3 | title: Home page 4 | description: this is the home page meta description. 5 | layout: base 6 | eleventyNavigation: 7 | key: Home 8 | order: 1 9 | --- 10 | 11 |
12 | 13 |

Welcome

14 |

Test Alpine.js Interactivity below:

15 | 16 |
17 | 18 | 19 |
20 | 21 |
-------------------------------------------------------------------------------- /src/includes/header.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 8 |
9 | {{ collections.all | eleventyNavigation | eleventyNavigationToHtml({ 10 | 11 | listElement: "ul", 12 | listItemElement: "li", 13 | 14 | listClass: "flex gap-4", 15 | listItemClass: "", 16 | 17 | listItemHasChildrenClass: "has-submenu", 18 | anchorClass: "", 19 | 20 | activeListItemClass: "active", 21 | activeAnchorClass: "active", 22 | 23 | activeKey: eleventyNavigation.key, 24 | showExcerpt: false 25 | 26 | }) | safe }} 27 |
28 |
29 |
-------------------------------------------------------------------------------- /src/posts.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | eleventyNavigation: 4 | key: Articles 5 | order: 3 6 | pagination: 7 | data: collections.post 8 | size: 12 9 | alias: posts 10 | meta: 11 | title: Posts archive 12 | description: this is where you can find all our posts. 13 | --- 14 | 15 |
16 |

All Articles

17 | 24 | 25 |
26 | {% if pagination.href.previous %} 27 | Previous Page 28 | {% endif %} 29 | {% if pagination.href.next %} 30 | Next Page 31 | {% endif %} 32 |
33 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "11ty-alpine-vite-tailwind", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npx @11ty/eleventy --serve", 8 | "dev": "npx @11ty/eleventy --serve", 9 | "serve": "npx @11ty/eleventy --serve", 10 | "watch": "npx @11ty/eleventy --watch", 11 | "build": "npx @11ty/eleventy", 12 | "clean": "del-cli _site" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "devDependencies": { 18 | "@11ty/eleventy": "^2.0.1", 19 | "@11ty/eleventy-img": "^3.1.0", 20 | "@11ty/eleventy-navigation": "^0.3.5", 21 | "@11ty/eleventy-plugin-rss": "^1.2.0", 22 | "@11ty/eleventy-plugin-vite": "^4.0.0", 23 | "autoprefixer": "^10.4.14", 24 | "del-cli": "^5.0.0", 25 | "dotenv": "^16.0.3", 26 | "js-yaml": "^4.1.0", 27 | "postcss": "^8.4.21", 28 | "tailwindcss": "^3.3.1" 29 | }, 30 | "dependencies": { 31 | "alpinejs": "^3.12.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/includes/meta.njk: -------------------------------------------------------------------------------- 1 | {# We use eleventy-rss plugin absoluteUrl filter as helper for absolute URL generation #} 2 | 3 | {# General #} 4 | 5 | 6 | 7 | {# Open Graph #} 8 | 9 | 10 | 11 | 12 | 13 | 14 | {%- if meta.image -%} 15 | 16 | {%- endif -%} 17 | {# End Open Graph #} 18 | 19 | {# Twitter #} 20 | 21 | 22 | 23 | {%- if meta.image -%} 24 | 25 | {%- endif -%} 26 | {# End Twitter #} 27 | 28 | 29 | -------------------------------------------------------------------------------- /.eleventy.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const pluginRss = require("@11ty/eleventy-plugin-rss"); // needed for absoluteUrl SEO feature 3 | const eleventyNavigationPlugin = require("@11ty/eleventy-navigation"); 4 | const EleventyVitePlugin = require("@11ty/eleventy-plugin-vite"); 5 | const Image = require("@11ty/eleventy-img"); 6 | const yaml = require("js-yaml"); // Because yaml is nicer than json for editors 7 | require('dotenv').config(); 8 | 9 | const baseUrl = process.env.BASE_URL || "http://localhost:8080"; 10 | console.log('baseUrl is set to ...', baseUrl); 11 | 12 | const globalSiteData = { 13 | title: "11ty Starter Site", 14 | description: "This is a basic 11ty starter template with my most commonly used features and modern tooling", 15 | locale: 'en', 16 | baseUrl: baseUrl, 17 | } 18 | 19 | module.exports = function(eleventyConfig) { 20 | 21 | /* --- GLOBAL DATA --- */ 22 | 23 | eleventyConfig.addGlobalData("site", globalSiteData); 24 | 25 | /* --- YAML SUPPORT --- */ 26 | 27 | eleventyConfig.addDataExtension("yaml", contents => yaml.load(contents)); 28 | eleventyConfig.addDataExtension("yml", contents => yaml.load(contents)); 29 | 30 | /* --- PASSTHROUGHS --- */ 31 | 32 | eleventyConfig.addPassthroughCopy('src/assets/css') 33 | eleventyConfig.addPassthroughCopy('src/assets/js') 34 | 35 | 36 | /* --- PLUGINS --- */ 37 | 38 | eleventyConfig.addPlugin(pluginRss); // just includes absolute url helper function 39 | eleventyConfig.addPlugin(eleventyNavigationPlugin); 40 | eleventyConfig.addPlugin(EleventyVitePlugin, {}); 41 | 42 | /* --- SHORTCODES --- */ 43 | 44 | // Image shortcode config 45 | let defaultSizesConfig = "(min-width: 1200px) 1400px, 100vw"; // above 1200px use a 1400px image at least, below just use 100vw sized image 46 | 47 | eleventyConfig.addShortcode("image", async function(src, alt, sizes=defaultSizesConfig) { 48 | console.log(`Generating image(s) from: ${src}`) 49 | let metadata = await Image(src, { 50 | widths: [800, 1500], 51 | formats: ["webp", "jpeg"], 52 | urlPath: "/images/", 53 | outputDir: "./_site/images/", 54 | filenameFormat: function (id, src, width, format, options) { 55 | const extension = path.extname(src) 56 | const name = path.basename(src, extension) 57 | return `${name}-${width}w.${format}` 58 | } 59 | }); 60 | 61 | let imageAttributes = { 62 | alt, 63 | sizes, 64 | loading: "lazy", 65 | decoding: "async", 66 | }; 67 | 68 | return Image.generateHTML(metadata, imageAttributes); 69 | }); 70 | 71 | // Output year for copyright notices 72 | eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`); 73 | 74 | 75 | /* --- FILTERS --- */ 76 | 77 | // Custom Random Helper Filter (useful for ID attributes) 78 | eleventyConfig.addFilter("generateRandomIdString", function (prefix) { 79 | return prefix + "-" + Math.floor(Math.random() * 1000000); 80 | }); 81 | 82 | 83 | /* --- BASE CONFIG --- */ 84 | 85 | return { 86 | dir: { 87 | input: "src", 88 | output: "_site", 89 | includes: "includes", // this path is releative to input-path (src/) 90 | layouts: "layouts", // this path is releative to input-path (src/) 91 | data: "data", // this path is releative to input-path (src/) 92 | }, 93 | templateFormats: ["njk", "md"], 94 | htmlTemplateEngine: "njk", 95 | markdownTemplateEngine: "njk", 96 | }; 97 | }; --------------------------------------------------------------------------------