Initial commit
41
.eleventy.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
const htmlmin = require('html-minifier');
|
||||
const dateFns = require('date-fns');
|
||||
const lazyImagesPlugin = require('eleventy-plugin-lazyimages');
|
||||
const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight');
|
||||
|
||||
module.exports = function (eleventyConfig) {
|
||||
eleventyConfig.addPlugin(syntaxHighlight);
|
||||
|
||||
eleventyConfig.addPlugin(lazyImagesPlugin, {
|
||||
transformImgPath: (imgPath) => `./src/${imgPath}`,
|
||||
});
|
||||
|
||||
eleventyConfig.setEjsOptions({
|
||||
rmWhitespace: true,
|
||||
context: {
|
||||
dateFns,
|
||||
},
|
||||
});
|
||||
|
||||
eleventyConfig.setBrowserSyncConfig({
|
||||
files: './_site/assets/styles/main.css',
|
||||
});
|
||||
|
||||
eleventyConfig.addTransform('htmlmin', (content, outputPath) => {
|
||||
if (outputPath.endsWith('.html')) {
|
||||
const minified = htmlmin.minify(content, {
|
||||
useShortDoctype: true,
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
minifyJS: true,
|
||||
});
|
||||
return minified;
|
||||
}
|
||||
|
||||
return content;
|
||||
});
|
||||
|
||||
return {
|
||||
dir: { input: 'src', output: '_site', data: '_data' },
|
||||
};
|
||||
};
|
||||
2
.eslintignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
_site
|
||||
3
.eslintrc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": ["airbnb-base"]
|
||||
}
|
||||
16
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Dependencies
|
||||
/node_modules
|
||||
|
||||
# Output directories
|
||||
/_site
|
||||
|
||||
# Generated file
|
||||
/src/_includes/layouts/webpack.ejs
|
||||
.lazyimages.json
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
2
.prettierignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
_site
|
||||
4
.prettierrc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
}
|
||||
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Rem W.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
117
README.md
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# Eleventy Starter Boilerplate
|
||||
|
||||
🚀 Eleventy Starter Boilerplate is production-ready with SEO-friendly for quickly starting a blog. ⚡️ Built with [Eleventy](https://www.11ty.dev), [ESLint](https://eslint.org), [Prettier](https://prettier.io), [Webpack](https://webpack.js.org), [PostCSS](https://postcss.org), [Tailwind CSS](https://tailwindcss.com).
|
||||
|
||||
Clone this project and use it to create your own [Eleventy](https://www.11ty.dev) blog.
|
||||
|
||||
### Features
|
||||
|
||||
Production-ready in mind:
|
||||
|
||||
- 🔥 [11ty](https://www.11ty.dev) for Static Site Generator
|
||||
- 🎨 Integrate with [Tailwind CSS](https://tailwindcss.com) (with [PurgeCSS](https://purgecss.com), remove unused CSS)
|
||||
- 💅 [PostCSS](https://postcss.org) for processing [Tailwind CSS](https://tailwindcss.com)
|
||||
- ⚡️ Lazy load images with [lazysizes](https://github.com/aFarkas/lazysizes)
|
||||
- ✨ Compress image with [Imagemin](https://github.com/imagemin/imagemin)
|
||||
- 🎈 Syntax Highlighting with [Prism.js](https://prismjs.com)
|
||||
- ☕ Minify HTML & CSS with [HTMLMinifier](https://www.npmjs.com/package/html-minifier) and [cssnano](https://cssnano.co)
|
||||
- ✏️ Linter with [ESLint](https://eslint.org)
|
||||
- 🛠 Code Formatter with [Prettier](https://prettier.io)
|
||||
- 💨 Live reload
|
||||
- 📦 Module Bundler with [Webpack](https://webpack.js.org)
|
||||
- 🦊 Templating with [EJS](https://ejs.co)
|
||||
- 🤖 SEO metadata and [Open Graph](https://ogp.me/) tags
|
||||
- ⚙️ [JSON-LD](https://developers.google.com/search/docs/guides/intro-structured-data) for richer indexing
|
||||
- 🗺 Sitemap.xml
|
||||
- ⚠️ 404 page
|
||||
- 📖 Pagination
|
||||
- ✅ Cache busting
|
||||
- 💯 Maximize lighthouse score
|
||||
|
||||
### Philosophy
|
||||
|
||||
- Minimal code (HTML, CSS & JS). Add what you need
|
||||
- SEO-friendly
|
||||
- 🚀 Production-ready
|
||||
|
||||
### Requirements
|
||||
|
||||
- Node.js and npm
|
||||
|
||||
### Getting started
|
||||
|
||||
Run the following command on your local environment:
|
||||
|
||||
```
|
||||
git clone --depth=1 https://github.com/ixartz/Eleventy-Starter-Boilerplate.git my-project-name
|
||||
cd my-project-name
|
||||
npm install
|
||||
```
|
||||
|
||||
Then, you can run locally in development mode with live reload:
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open http://localhost:8080 with your favorite browser to see your blog.
|
||||
|
||||
### Project structure
|
||||
|
||||
```
|
||||
.
|
||||
├── public # Static files
|
||||
│ └── assets
|
||||
│ └── images # Images not needed by Webpack
|
||||
└── src
|
||||
├── _data # Eleventy data folder
|
||||
├── _includes
|
||||
│ └── layouts # HTML layout files
|
||||
├── assets # Assets folder that needs to be processed by Webpack
|
||||
│ ├── images
|
||||
│ │ └── posts # Images used in your blog posts (will be compressed by Webpack)
|
||||
│ └── styles # Your blog CSS files
|
||||
└── posts # Your blog posts
|
||||
```
|
||||
|
||||
### Customization
|
||||
|
||||
You can easily configure Eleventy Starter Boilerplate. Please change the following file:
|
||||
|
||||
- `public/assets/images/logo.png`: your blog logo
|
||||
- `public/apple-touch-icon.png`, `public/favicon.ico`, `public/favicon-16x16.png` and `public/favicon-32x32.png`: your blog favicon, you can generate from https://favicon.io/favicon-converter/
|
||||
- `src/_data/site.json`: your blog configuration
|
||||
- `src/_includes/layouts`: your blog HTML layout
|
||||
- `src/assets/styles/main.css`: your blog CSS file using Tailwind CSS
|
||||
|
||||
### Deploy to production
|
||||
|
||||
You can see the results locally in production mode with:
|
||||
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
The generated HTML and CSS files are minified. It will also removed unused CSS from [Tailwind CSS](https://tailwindcss.com).
|
||||
|
||||
You can create an optimized production build with:
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
Now, your blog is ready to be deployed. All generated files are located at `_site` folder, which you can deploy with any hosting service.
|
||||
|
||||
### Contributions
|
||||
|
||||
Everyone is welcome to contribute to this project. Feel free to open an issue if you have question or found a bug.
|
||||
|
||||
### License
|
||||
|
||||
Licensed under the MIT License, Copyright © 2020
|
||||
|
||||
See [LICENSE](LICENSE) for more information.
|
||||
|
||||
---
|
||||
|
||||
Made with ♥ by [Ixartz](https://github.com/ixartz)
|
||||
16424
package-lock.json
generated
Normal file
67
package.json
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"name": "my-blog",
|
||||
"version": "1.0.0",
|
||||
"description": "My blog",
|
||||
"scripts": {
|
||||
"build-dev:webpack": "webpack",
|
||||
"watch:webpack": "webpack --watch",
|
||||
"watch:eleventy": "ELEVENTY_ENV=development eleventy --serve",
|
||||
"dev": "npm-run-all clean build-dev:webpack --parallel watch:*",
|
||||
"build:webpack": "NODE_ENV=production webpack --mode production",
|
||||
"build:eleventy": "ELEVENTY_ENV=production eleventy",
|
||||
"build": "run-s clean build:*",
|
||||
"serve:local": "serve _site",
|
||||
"serve": "run-s build serve:local",
|
||||
"clean": "rimraf _site",
|
||||
"format:js": "prettier '**/*.js' --write && eslint '**/*.js' --fix",
|
||||
"format:json": "prettier '**/*.json' --write",
|
||||
"format": "run-s format:*",
|
||||
"lint": "eslint --ext .js ."
|
||||
},
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "^0.11.0",
|
||||
"@11ty/eleventy-plugin-syntaxhighlight": "^3.0.1",
|
||||
"autoprefixer": "^9.8.0",
|
||||
"copy-webpack-plugin": "^6.0.2",
|
||||
"css-loader": "^3.5.3",
|
||||
"cssnano": "^4.1.10",
|
||||
"date-fns": "^2.14.0",
|
||||
"eleventy-plugin-lazyimages": "^1.1.2",
|
||||
"eslint": "^7.2.0",
|
||||
"eslint-config-airbnb-base": "^14.2.0",
|
||||
"eslint-plugin-import": "^2.21.2",
|
||||
"file-loader": "^6.0.0",
|
||||
"glob": "^7.1.6",
|
||||
"html-minifier": "^4.0.0",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"husky": "^4.2.5",
|
||||
"image-webpack-loader": "^6.0.0",
|
||||
"lint-staged": "^10.2.9",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"prettier": "^2.0.5",
|
||||
"rimraf": "^3.0.2",
|
||||
"serve": "^11.3.2",
|
||||
"tailwindcss": "^1.4.6",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-fix-style-only-entries": "^0.5.0"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"prettier --write",
|
||||
"eslint --fix",
|
||||
"eslint"
|
||||
],
|
||||
"*.json": [
|
||||
"prettier --write"
|
||||
]
|
||||
}
|
||||
}
|
||||
19
postcss.config.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, global-require */
|
||||
const plugins = [require('tailwindcss'), require('autoprefixer')];
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
plugins.push(
|
||||
require('cssnano')({
|
||||
preset: [
|
||||
'default',
|
||||
{
|
||||
discardComments: {
|
||||
removeAll: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = { plugins };
|
||||
BIN
public/apple-touch-icon.png
Executable file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
public/assets/images/logo-32x32.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
public/assets/images/logo.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
public/favicon-16x16.png
Executable file
|
After Width: | Height: | Size: 445 B |
BIN
public/favicon-32x32.png
Executable file
|
After Width: | Height: | Size: 1,001 B |
BIN
public/favicon.ico
Executable file
|
After Width: | Height: | Size: 15 KiB |
9
src/404.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
title: 404 - Page not found
|
||||
description: Page not found
|
||||
permalink: 404.html
|
||||
---
|
||||
|
||||
# 404
|
||||
|
||||
Page not found
|
||||
4
src/_data/layout.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Set default layout
|
||||
// https://github.com/11ty/eleventy/issues/380#issuecomment-568033456
|
||||
|
||||
module.exports = 'layouts/base.ejs';
|
||||
8
src/_data/site.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"site_name": "Hello",
|
||||
"title": "Hello personal blog",
|
||||
"description": "Blog description",
|
||||
"url": "https://example.com",
|
||||
"locale": "en",
|
||||
"author": "Anonymous"
|
||||
}
|
||||
54
src/_includes/layouts/base.ejs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<title><%= title %></title>
|
||||
<meta
|
||||
name="description"
|
||||
content="<%= (!!locals.description) ? description : site.description %>"
|
||||
/>
|
||||
<meta name="author" content="<%= site.author %>" />
|
||||
<meta property="og:title" content="<%= title %>" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="<%= (!!locals.description) ? description : site.description %>"
|
||||
/>
|
||||
<meta property="og:locale" content="<%= site.locale %>" />
|
||||
<meta property="og:site_name" content="<%= site.site_name %>" />
|
||||
<% if (locals.tags == "posts") { %>
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="article:published_time" content="<%= date.toISOString() %>" />
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"description": "<%= (!!locals.description) ? description : site.description %>",
|
||||
"author": { "@type": "Person", "name": "<%= site.author %>" },
|
||||
"@type": "BlogPosting",
|
||||
"url": "<%= `${site.url}${page.url}` %>",
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "<%= `${site.url}/assets/images/logo.png` %>"
|
||||
},
|
||||
"name": "<%= site.author %>"
|
||||
},
|
||||
"headline": "<%= title %>",
|
||||
"datePublished": "<%= date.toISOString() %>",
|
||||
"mainEntityOfPage": {
|
||||
"@type": "WebPage",
|
||||
"@id": "<%= `${site.url}${page.url}` %>"
|
||||
},
|
||||
"@context": "http://schema.org"
|
||||
}
|
||||
</script>
|
||||
<% } %> <%- include('webpack.ejs') %>
|
||||
</head>
|
||||
<body>
|
||||
<%- content %>
|
||||
</body>
|
||||
</html>
|
||||
18
src/_includes/layouts/post.ejs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
layout: layouts/base.ejs
|
||||
---
|
||||
|
||||
<article class="post">
|
||||
<header>
|
||||
<h1 class="font-bold text-3xl"><%= title %></h1>
|
||||
<div class="text-gray-600">
|
||||
<%= this.dateFns.format(new Date(date), 'LLLL d, yyyy') %>
|
||||
</div>
|
||||
</header>
|
||||
<section class="pt-3 pb-3">
|
||||
<%- content %>
|
||||
</section>
|
||||
<footer>
|
||||
<a href="/">Back to home</a>
|
||||
</footer>
|
||||
</article>
|
||||
BIN
src/assets/images/posts/error.png
Executable file
|
After Width: | Height: | Size: 4.7 KiB |
8
src/assets/styles/main.css
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
@tailwind base;
|
||||
|
||||
a {
|
||||
@apply text-blue-700 underline font-bold;
|
||||
}
|
||||
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
143
src/assets/styles/prism-atom-dark.css
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
* atom-dark theme for `prism.js`
|
||||
* Based on Atom's `atom-dark` theme: https://github.com/atom/atom-dark-syntax
|
||||
* @author Joe Gibson (@gibsjose)
|
||||
*/
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: #c5c8c6;
|
||||
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
|
||||
font-family: Inconsolata, Monaco, Consolas, 'Courier New', Courier, monospace;
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
border-radius: 0.3em;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #1d1f21;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #7C7C7C;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #c5c8c6;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.keyword,
|
||||
.token.tag {
|
||||
color: #96CBFE;
|
||||
}
|
||||
|
||||
.token.class-name {
|
||||
color: #FFFFB6;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.token.boolean,
|
||||
.token.constant {
|
||||
color: #99CC99;
|
||||
}
|
||||
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #f92672;
|
||||
}
|
||||
|
||||
.token.number {
|
||||
color: #FF73FD;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #A8FF60;
|
||||
}
|
||||
|
||||
.token.variable {
|
||||
color: #C6C5FE;
|
||||
}
|
||||
|
||||
.token.operator {
|
||||
color: #EDEDED;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
color: #FFFFB6;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.token.url {
|
||||
color: #96CBFE;
|
||||
}
|
||||
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #87C38A;
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value {
|
||||
color: #F9EE98;
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #DAD085;
|
||||
}
|
||||
|
||||
.token.regex {
|
||||
color: #E9C062;
|
||||
}
|
||||
|
||||
.token.important {
|
||||
color: #fd971f;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
29
src/index.ejs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
pagination:
|
||||
data: collections.posts
|
||||
size: 5
|
||||
alias: list
|
||||
reverse: true
|
||||
permalink: '<% if (pagination.pageNumber > 0) { %><%= `page${pagination.pageNumber + 1}/index.html` %><% } else { %>index.html<% } %>'
|
||||
eleventyComputed:
|
||||
title: '<% if (pagination.pageNumber > 0) { %><%= `Page ${pagination.pageNumber + 1} | ${site.title}` %><% } else { %><%= site.title %><% } %>'
|
||||
---
|
||||
|
||||
<h1 class="font-bold text-3xl"><%= site.title %></h1>
|
||||
|
||||
<ul>
|
||||
<% list.forEach((post) => { %>
|
||||
<li>
|
||||
<a href="<%= post.url %>"><%= post.data.title %></a>
|
||||
- <%= this.dateFns.format(new Date(post.data.date), 'LLLL d, yyyy') %>
|
||||
</li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
|
||||
<div class="pt-3">
|
||||
<% if (pagination.previous) { %>
|
||||
<a href="<%= pagination.previous.replace(/index.html$/, "") %>">Newer Posts</a>
|
||||
<% } %> <% if (pagination.next) { %>
|
||||
<a href="<%= pagination.next.replace(/index.html$/, "") %>">Older Posts</a>
|
||||
<% } %>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
---
|
||||
title: 'Eleventy Starter Boilerplate Presentation'
|
||||
description: Everything you need to use this Eleventy Boilerplate template
|
||||
date: 2020-01-01 00:00:00
|
||||
---
|
||||
|
||||
# Eleventy Starter Boilerplate
|
||||
|
||||
🚀 Eleventy Starter Boilerplate is production-ready with SEO-friendly for quickly starting a blog. ⚡️ Built with [Eleventy](https://www.11ty.dev), [ESLint](https://eslint.org), [Prettier](https://prettier.io), [Webpack](https://webpack.js.org), [PostCSS](https://postcss.org), [Tailwind CSS](https://tailwindcss.com).
|
||||
|
||||
Clone this project and use it to create your own [Eleventy](https://www.11ty.dev) blog.
|
||||
|
||||
### Features
|
||||
|
||||
Production-ready in mind:
|
||||
|
||||
- 🔥 [11ty](https://www.11ty.dev) for Static Site Generator
|
||||
- 🎨 Integrate with [Tailwind CSS](https://tailwindcss.com) (with [PurgeCSS](https://purgecss.com), remove unused CSS)
|
||||
- 💅 [PostCSS](https://postcss.org) for processing [Tailwind CSS](https://tailwindcss.com)
|
||||
- ⚡️ Lazy load images with [lazysizes](https://github.com/aFarkas/lazysizes)
|
||||
- ✨ Compress image with [Imagemin](https://github.com/imagemin/imagemin)
|
||||
- 🎈 Syntax Highlighting with [Prism.js](https://prismjs.com)
|
||||
- ☕ Minify HTML & CSS with [HTMLMinifier](https://www.npmjs.com/package/html-minifier) and [cssnano](https://cssnano.co)
|
||||
- ✏️ Linter with [ESLint](https://eslint.org)
|
||||
- 🛠 Code Formatter with [Prettier](https://prettier.io)
|
||||
- 💨 Live reload
|
||||
- 📦 Module Bundler with [Webpack](https://webpack.js.org)
|
||||
- 🦊 Templating with [EJS](https://ejs.co)
|
||||
- 🤖 SEO metadata and [Open Graph](https://ogp.me/) tags
|
||||
- ⚙️ [JSON-LD](https://developers.google.com/search/docs/guides/intro-structured-data) for richer indexing
|
||||
- 🗺 Sitemap.xml
|
||||
- ⚠️ 404 page
|
||||
- 📖 Pagination
|
||||
- ✅ Cache busting
|
||||
- 💯 Maximize lighthouse score
|
||||
|
||||
### Philosophy
|
||||
|
||||
- Minimal code (HTML, CSS & JS). Add what you need
|
||||
- SEO-friendly
|
||||
- 🚀 Production-ready
|
||||
|
||||
### Requirements
|
||||
|
||||
- Node.js and npm
|
||||
|
||||
### Getting started
|
||||
|
||||
Run the following command on your local environment:
|
||||
|
||||
```shell
|
||||
git clone --depth=1 https://github.com/ixartz/Eleventy-Starter-Boilerplate.git my-project-name
|
||||
cd my-project-name
|
||||
npm install
|
||||
```
|
||||
|
||||
Then, you can run locally in development mode with live reload:
|
||||
|
||||
```shell
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open http://localhost:8080 with your favorite browser to see your blog.
|
||||
|
||||
### Project structure
|
||||
|
||||
```shell
|
||||
.
|
||||
├── public # Static files
|
||||
│ └── assets
|
||||
│ └── images # Images not needed by Webpack
|
||||
└── src
|
||||
├── _data # Eleventy data folder
|
||||
├── _includes
|
||||
│ └── layouts # HTML layout files
|
||||
├── assets # Assets folder that needs to be processed by Webpack
|
||||
│ ├── images
|
||||
│ │ └── posts # Images used in your blog posts (will be compressed by Webpack)
|
||||
│ └── styles # Your blog CSS files
|
||||
└── posts # Your blog posts
|
||||
```
|
||||
|
||||
### Customization
|
||||
|
||||
You can easily configure Eleventy Starter Boilerplate. Please change the following file:
|
||||
|
||||
- `public/assets/images/logo.png`: your blog logo
|
||||
- `public/apple-touch-icon.png`, `public/favicon.ico`, `public/favicon-16x16.png` and `public/favicon-32x32.png`: your blog favicon, you can generate from https://favicon.io/favicon-converter/
|
||||
- `src/_data/site.json`: your blog configuration
|
||||
- `src/_includes/layouts`: your blog HTML layout
|
||||
- `src/assets/styles/main.css`: your blog CSS file using Tailwind CSS
|
||||
|
||||
### Deploy to production
|
||||
|
||||
You can see the results locally in production mode with:
|
||||
|
||||
```shell
|
||||
npm run serve
|
||||
```
|
||||
|
||||
The generated HTML and CSS files are minified. It will also removed unused CSS from [Tailwind CSS](https://tailwindcss.com).
|
||||
|
||||
You can create an optimized production build with:
|
||||
|
||||
```shell
|
||||
npm run build
|
||||
```
|
||||
|
||||
Now, your blog is ready to be deployed. All generated files are located at `_site` folder, which you can deploy with any hosting service.
|
||||
|
||||
### Contributions
|
||||
|
||||
Everyone is welcome to contribute to this project. Feel free to open an issue if you have question or found a bug.
|
||||
|
||||
### License
|
||||
|
||||
Licensed under the MIT License, Copyright © 2020
|
||||
|
||||
See [LICENSE](https://github.com/ixartz/Eleventy-Starter-Boilerplate/blob/master/LICENSE) for more information.
|
||||
|
||||
---
|
||||
|
||||
Made with ♥ by [Ixartz](https://github.com/ixartz)
|
||||
19
src/posts/2020-02-02-my-first-post.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
title: 'My first post'
|
||||
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
date: 2020-02-02 00:00:00
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
|
||||
Example with image:
|
||||
|
||||

|
||||
|
||||
Example code block:
|
||||
|
||||
```js
|
||||
function myFunction() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
19
src/posts/2020-03-03-my-second-post.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
title: 'My second post'
|
||||
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
date: 2020-03-03 00:00:00
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
|
||||
Example with image:
|
||||
|
||||

|
||||
|
||||
Example code block:
|
||||
|
||||
```js
|
||||
function myFunction() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
19
src/posts/2020-06-06-my-third-post.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
title: 'My third post'
|
||||
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
date: 2020-06-06 00:00:00
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
|
||||
Example with image:
|
||||
|
||||

|
||||
|
||||
Example code block:
|
||||
|
||||
```js
|
||||
function myFunction() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
19
src/posts/2020-07-07-my-forth-post.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
title: 'My forth post'
|
||||
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
date: 2020-07-07 00:00:00
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
|
||||
Example with image:
|
||||
|
||||

|
||||
|
||||
Example code block:
|
||||
|
||||
```js
|
||||
function myFunction() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
19
src/posts/2020-08-08-my-fifth-post.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
title: 'My fifth post'
|
||||
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
date: 2020-08-08 00:00:00
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
|
||||
Example with image:
|
||||
|
||||

|
||||
|
||||
Example code block:
|
||||
|
||||
```js
|
||||
function myFunction() {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
5
src/posts/posts.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"layout": "layouts/post.ejs",
|
||||
"permalink": "{{ page.fileSlug }}/index.html",
|
||||
"tags": "posts"
|
||||
}
|
||||
7
src/robots.ejs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
permalink: robots.txt
|
||||
eleventyExcludeFromCollections: true
|
||||
layout: null
|
||||
---
|
||||
|
||||
Sitemap: <%= `${site.url}/sitemap.xml` %>
|
||||
14
src/sitemap.ejs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
permalink: sitemap.xml
|
||||
eleventyExcludeFromCollections: true
|
||||
layout: null
|
||||
---
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<% collections.all.forEach((page) => { %>
|
||||
<url>
|
||||
<loc><%= `${site.url}${page.url}` %></loc>
|
||||
</url>
|
||||
<% }) %>
|
||||
</urlset>
|
||||
8
tailwind.config.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
purge: ['./src/**/*.ejs'],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
variants: {},
|
||||
plugins: [],
|
||||
};
|
||||
89
webpack.config.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
|
||||
|
||||
const entries = glob.sync(path.resolve(__dirname, 'src/assets/images/posts/*.{png,gif,jpg,jpeg}'));
|
||||
entries.push(path.resolve(__dirname, 'src/assets/styles/main.css'));
|
||||
|
||||
// TODO: Remove if the blog does not need syntax highlight
|
||||
entries.push(path.resolve(__dirname, 'src/assets/styles/prism-atom-dark.css'));
|
||||
|
||||
let cssFileName = 'styles/[name].css';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
cssFileName = 'styles/[name].[contenthash].css';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
entry: entries,
|
||||
output: {
|
||||
path: path.resolve(__dirname, '_site/assets'),
|
||||
publicPath: '/',
|
||||
},
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [{ from: path.resolve(__dirname, 'public'), to: path.resolve(__dirname, '_site') }],
|
||||
}),
|
||||
new webpack.HashedModuleIdsPlugin(),
|
||||
new FixStyleOnlyEntriesPlugin({
|
||||
extensions: ['less', 'scss', 'css', 'styl', 'sass', 'png', 'gif', 'jpg', 'jpeg'], // Empty js should also not be generated with image
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: cssFileName,
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.resolve(__dirname, 'webpack.html'),
|
||||
filename: path.resolve(__dirname, 'src/_includes/layouts/webpack.ejs'),
|
||||
inject: false,
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /node_modules/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(gif|png|jpg|jpeg)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'images/posts/[name].[ext]',
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'image-webpack-loader',
|
||||
options: {
|
||||
mozjpeg: {
|
||||
progressive: true,
|
||||
quality: 65,
|
||||
},
|
||||
// optipng.enabled: false will disable optipng
|
||||
optipng: {
|
||||
enabled: false,
|
||||
},
|
||||
pngquant: {
|
||||
quality: [0.65, 0.9],
|
||||
speed: 4,
|
||||
},
|
||||
gifsicle: {
|
||||
interlaced: true,
|
||||
},
|
||||
// the webp option will enable WEBP
|
||||
webp: {
|
||||
quality: 75,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
4
webpack.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<%= htmlWebpackPlugin.files.css.map((css) => `<link
|
||||
href="/assets${css}"
|
||||
rel="stylesheet"
|
||||
/>`).join('') %>
|
||||