├── .nvmrc ├── .gitignore ├── src ├── images │ ├── eleventy.png │ ├── netlify.png │ └── cloudinary.png ├── _includes │ └── default.njk ├── styles.css └── index.md ├── .prettierrc.js ├── netlify.toml ├── .github ├── .kodiak.toml └── workflows │ └── upgrade-dependencies.yml ├── package.json ├── LICENSE ├── README.md └── .eleventy.js /.nvmrc: -------------------------------------------------------------------------------- 1 | 16 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /src/images/eleventy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhoizey/demo-11ty-netlify-cloudinary/main/src/images/eleventy.png -------------------------------------------------------------------------------- /src/images/netlify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhoizey/demo-11ty-netlify-cloudinary/main/src/images/netlify.png -------------------------------------------------------------------------------- /src/images/cloudinary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhoizey/demo-11ty-netlify-cloudinary/main/src/images/cloudinary.png -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 80, 3 | semi: true, 4 | singleQuote: true, 5 | tabWidth: 2, 6 | useTabs: false, 7 | trailingComma: "es5" 8 | }; 9 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [[redirects]] 2 | from = "/responsive/:width/*" 3 | to = "https://res.cloudinary.com/nho/image/fetch/q_auto,f_auto,w_:width,c_limit/https://demo-11ty-netlify-cloudinary.netlify.app/:splat" 4 | status = 200 5 | -------------------------------------------------------------------------------- /.github/.kodiak.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [merge] 4 | automerge_label = 'automerge 🤞' 5 | 6 | # https://kodiakhq.com/docs/recipes#better-merge-messages 7 | [merge.message] 8 | title = "pull_request_title" 9 | body = "pull_request_body" 10 | include_pr_number = true 11 | body_type = "markdown" 12 | strip_html_comments = true 13 | -------------------------------------------------------------------------------- /.github/workflows/upgrade-dependencies.yml: -------------------------------------------------------------------------------- 1 | name: Upgrade dependencies 2 | 3 | on: 4 | schedule: 5 | # https://crontab.guru/#0_8_*_*_1 6 | - cron: '0 8 * * 1' 7 | workflow_dispatch: 8 | 9 | concurrency: 10 | group: upgrade-dependencies 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | upgrade-dependencies: 15 | uses: nhoizey/upgrade-dependencies/.github/workflows/upgrade-dependencies.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /src/_includes/default.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
37 | ```
38 |
--------------------------------------------------------------------------------
/.eleventy.js:
--------------------------------------------------------------------------------
1 | module.exports = function (eleventyConfig) {
2 |
3 | // Make simple images responsive for production
4 | if (process.env.NODE_ENV === 'production') {
5 | const imagesResponsiver = require('eleventy-plugin-images-responsiver');
6 | const imageSize = require('image-size');
7 | const site = 'https://demo-11ty-netlify-cloudinary.netlify.app';
8 | eleventyConfig.addPlugin(imagesResponsiver, {
9 | default: {
10 | selector: 'img',
11 | resizedImageUrl: (src, width) => src.replace(site, `${site}/responsive/${width}`),
12 | runBefore: (image, document) => {
13 | // A hook that is run before the transformation
14 |
15 | // Get current image's src value
16 | let imageSrc = image.getAttribute('src');
17 |
18 | // Compute the image's dimensions and add them to the HTML
19 | // to prevent layout shift and help compute srcset values
20 | let imageDimensions = imageSize('./src' + imageSrc);
21 | image.setAttribute('width', imageDimensions.width);
22 | image.setAttribute('height', imageDimensions.height);
23 |
24 | image.setAttribute('src', `${site}${imageSrc}`);
25 |
26 | // Get the class value and set it as a preset for Images Responsiver
27 | image.dataset.responsiver = image.className;
28 | },
29 | },
30 | logo: {
31 | fallbackWidth: 320,
32 | minWidth: 90, // width on a 240px viewport with 1dppx density
33 | maxWidth: 400, // width on a 479px viewport width 2dppx density
34 | sizes: '(min-width: 47rem) 10rem, (min-width: 30rem) calc((90vw - 1rem) / 4), calc((90vw - 1rem) / 2)',
35 | attributes: {
36 | loading: 'lazy'
37 | },
38 | }
39 | });
40 | }
41 |
42 | // Add attributes support to Markdown-it
43 | const markdownIt = require("markdown-it");
44 | const markdownItAttributes = require('markdown-it-attrs');
45 | const markdownLib = markdownIt().use(markdownItAttributes);
46 | eleventyConfig.setLibrary("md", markdownLib);
47 |
48 | eleventyConfig
49 | .addPassthroughCopy('src/images')
50 | .addPassthroughCopy('src/styles.css');
51 |
52 | return {
53 | passthroughFileCopy: true,
54 | dir: {
55 | output: 'dist',
56 | input: 'src'
57 | },
58 | };
59 | };
60 |
--------------------------------------------------------------------------------
/src/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default.njk
3 | title: Welcome to this demo!
4 | ---
5 |
6 | This is a demonstration of how to get an optimized performance with responsive images while letting content author writing simple Markdown.
7 |
8 | ## Eleventy
9 |
10 | {.logo}
11 |
12 | This site is generated by [Eleventy](https://11ty.dev/).
13 |
14 | It uses [eleventy-plugin-images-responsiver](https://nhoizey.github.io/images-responsiver/eleventy-plugin-images-responsiver/), a plugin for Eleventy, to generate responsive image syntax with `srcset` and `sizes` attributes, so that loaded images are not too large (and heavy) for the area of the page they are supposed to fill.
15 |
16 | ## Cloudinary
17 |
18 | {.logo}
19 |
20 | The configuration of the plugin makes it generate multiple versions of the original images thanks to [Cloudinary](https://nho.io/cloudinary-signup)'s Fetch API and [URL based transformations](https://cloudinary.com/documentation/image_transformations).
21 |
22 | Any other image resizing tool (SaaS or not) could be used with adapted configuration.
23 |
24 | ## Netlify
25 |
26 | {.logo}
27 |
28 | The site is built and hosted by [Netlify](https://netlify.com/).
29 |
30 | The source code is managed [on GitHub](https://github.com/nhoizey/demo-11ty-netlify-cloudinary), and any push to the `main` branch triggers a build and deploy on Netlify.
31 |
32 | Netlify is also convenient here to [proxy requests](https://docs.netlify.com/routing/redirects/rewrites-proxies/#proxy-to-another-service) to Cloudinary, so that a single domain is "seen" by the browser, which is better for performance. Thanks [Phil Hawksworth](https://twitter.com/philhawksworth/status/1328340868726726656) and [Tim Kadlec](https://timkadlec.com/remembers/2020-11-17-netlify-proxy-requests/) for this nice trick! 👍
33 |
34 | ## What's the point of all this?
35 |
36 | After developers have configured the plugin, content authors "just" had to write this in the Markdown content:
37 |
38 | ```markdown
39 | {.logo}
40 | ```
41 |
42 | To get this responsive image in the HTML:
43 |
44 | ```html
45 |
62 | ```
63 |
64 | Ok, here I am both the developer and the content writer… 😅
65 |
66 | But even if I'm a developer, I like to use plain simple Markdown for images, so that:
67 |
68 | - it's much simpler to write,
69 | - they show up in my Markdown editor,
70 | - and they also show up on GitHub (exemple [here](https://github.com/nhoizey/nicolas-hoizey.com/blob/master/src/articles/2020/10/26/enhancing-archives-navigation-step-1/index.md)).
71 |
--------------------------------------------------------------------------------