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('') %>
|
||||||