├── .eleventy.js ├── .eslintignore ├── .eslintrc.cjs ├── .github ├── actions │ ├── example-build │ │ └── action.yml │ ├── lint │ │ └── action.yml │ ├── publint │ │ └── action.yml │ ├── setup │ │ └── action.yml │ └── test │ │ └── action.yml ├── dependabot.yml └── workflows │ ├── release.yml │ └── review.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc.js ├── .releaserc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets └── og-image.png ├── example ├── .eleventy.js ├── example-draft.njk ├── example-page.njk └── og-image.og.njk ├── index.d.ts ├── package-lock.json ├── package.json ├── src ├── OgImage.js └── utils │ ├── index.js │ ├── mergeOptions.js │ └── sortObject.js └── test ├── OgImage.test.js ├── mergeOptions.test.js ├── og-test.og.njk ├── snapshots ├── OgImage.test.js.md └── OgImage.test.js.snap ├── sortObject.test.js └── utils ├── directoriesConfig.js └── testConstructor.js /.eleventy.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty */ 2 | import { promises as fs } from 'node:fs'; 3 | import path from 'node:path'; 4 | import { TemplatePath } from '@11ty/eleventy-utils'; 5 | import { mergeOptions } from './src/utils/index.js'; 6 | import { OgImage } from './src/OgImage.js'; 7 | 8 | /** 9 | * @param {import('@11ty/eleventy/src/UserConfig').default} eleventyConfig 10 | * @param {EleventyPluginOgImageOptions} pluginOptions 11 | */ 12 | export default async function (eleventyConfig, pluginOptions) { 13 | /** @type {DirectoriesConfig} */ 14 | let directoriesConfig; 15 | 16 | /** @type {EleventyPluginOgImageMergedOptions} */ 17 | let mergedOptions; 18 | 19 | // Until https://github.com/11ty/eleventy/issues/2729 is fixed 20 | eleventyConfig.on('eleventy.directories', (dir) => { 21 | directoriesConfig = dir; 22 | mergedOptions = mergeOptions({ directoriesConfig, pluginOptions }); 23 | }); 24 | 25 | /** @type {import('@11ty/eleventy/src/TemplateConfig').default} */ 26 | let templateConfig; 27 | 28 | eleventyConfig.on('eleventy.config', (newTemplateConfig) => { 29 | templateConfig = newTemplateConfig; 30 | }); 31 | 32 | /** @type {boolean} */ 33 | let previewMode; 34 | 35 | eleventyConfig.on('eleventy.before', async ({ runMode }) => { 36 | try { 37 | await fs.mkdir(mergedOptions.outputDir, { recursive: true }); 38 | } catch {} 39 | 40 | previewMode = ['watch', 'serve'].includes(runMode); 41 | 42 | if (previewMode) { 43 | try { 44 | await fs.mkdir(mergedOptions.previewDir, { recursive: true }); 45 | } catch {} 46 | } else { 47 | try { 48 | await fs.rm(mergedOptions.previewDir, { recursive: true, force: true }); 49 | } catch {} 50 | } 51 | }); 52 | 53 | eleventyConfig.ignores.add(mergeOptions({ pluginOptions }).inputFileGlob); 54 | 55 | eleventyConfig.addAsyncShortcode( 56 | 'ogImage', 57 | /** 58 | * @param {string} shortcodeInputPath 59 | * @param {Record} [data] 60 | * @returns {Promise} 61 | */ 62 | async function ogImageShortcode(shortcodeInputPath, data) { 63 | if (this.page.url === false) { 64 | return null; 65 | } 66 | 67 | const { satoriOptions, sharpOptions, ...options } = mergedOptions; 68 | 69 | const joinedInputPath = TemplatePath.standardizeFilePath(path.join(directoriesConfig.input, shortcodeInputPath)); 70 | 71 | try { 72 | await fs.access(joinedInputPath); 73 | } catch { 74 | throw new Error(`Could not find file for the \`ogImage\` shortcode, looking for: ${joinedInputPath}`); 75 | } 76 | 77 | const ogImage = new (pluginOptions.OgImage || OgImage)({ 78 | inputPath: joinedInputPath, 79 | data: { 80 | page: this.page, 81 | eleventy: this.eleventy, 82 | eleventyPluginOgImage: { 83 | inputPath: joinedInputPath, 84 | width: satoriOptions.width, 85 | height: satoriOptions.height, 86 | outputFileExtension: options.outputFileExtension, 87 | }, 88 | ...data, 89 | }, 90 | options: mergedOptions, 91 | templateConfig, 92 | }); 93 | 94 | const outputFilePath = await ogImage.outputFilePath(); 95 | const cacheFilePath = await ogImage.cacheFilePath(); 96 | 97 | if (cacheFilePath !== outputFilePath) { 98 | try { 99 | await fs.copyFile(cacheFilePath, outputFilePath); 100 | } catch {} 101 | } 102 | 103 | try { 104 | await fs.access(outputFilePath); 105 | } catch { 106 | const image = await ogImage.render(); 107 | 108 | await image.toFile(outputFilePath); 109 | 110 | eleventyConfig.logger.log( 111 | `Writing ${TemplatePath.stripLeadingDotSlash(outputFilePath)} from ${joinedInputPath}`, 112 | ); 113 | } 114 | 115 | if (previewMode) { 116 | const previewFilePath = ogImage.previewFilePath(); 117 | 118 | try { 119 | await fs.mkdir(path.dirname(previewFilePath), { recursive: true }); 120 | } catch {} 121 | 122 | await fs.copyFile(outputFilePath, previewFilePath); 123 | await fs.writeFile(`${previewFilePath}.html`, await ogImage.previewHtml()); 124 | } 125 | 126 | return ogImage.shortcodeOutput(); 127 | }, 128 | ); 129 | } 130 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | !.eleventy.js 2 | index.d.ts 3 | .eslintrc.cjs 4 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | require('@kiwikilian/eslint-config/patch/modern-module-resolution'); 2 | 3 | module.exports = { 4 | extends: ['@kiwikilian/eslint-config/profile/node'], 5 | 6 | parserOptions: { 7 | ecmaVersion: 'latest', 8 | sourceType: 'module', 9 | }, 10 | 11 | rules: { 12 | 'import/extensions': [ 13 | 'error', 14 | { 15 | js: 'ignorePackages', 16 | }, 17 | ], 18 | 'import/no-extraneous-dependencies': [ 19 | 'error', 20 | { devDependencies: ['./example/**', './example/.eleventy.js', './test/**'] }, 21 | ], 22 | }, 23 | 24 | overrides: [ 25 | { 26 | files: '.eleventy.js', 27 | rules: { 28 | 'func-names': ['off'], 29 | 'import/no-default-export': ['off'], 30 | }, 31 | }, 32 | { 33 | files: './test/**', 34 | rules: { 35 | 'import/no-unresolved': ['off'], 36 | }, 37 | }, 38 | ], 39 | }; 40 | -------------------------------------------------------------------------------- /.github/actions/example-build/action.yml: -------------------------------------------------------------------------------- 1 | name: Example Build 2 | description: Build the example project 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - uses: ./.github/actions/setup 8 | - run: npm run example:build 9 | shell: bash 10 | -------------------------------------------------------------------------------- /.github/actions/lint/action.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | description: Run linting 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - uses: ./.github/actions/setup 8 | - run: npm run lint 9 | shell: bash 10 | -------------------------------------------------------------------------------- /.github/actions/publint/action.yml: -------------------------------------------------------------------------------- 1 | name: Publint 2 | description: Run packaging linting 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - uses: ./.github/actions/setup 8 | - run: npx publint --strict 9 | shell: bash 10 | -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup 2 | description: Setup a Node.js and install dependencies 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - uses: actions/setup-node@v4 8 | with: 9 | cache: npm 10 | node-version-file: '.nvmrc' 11 | - run: npm ci 12 | shell: bash 13 | -------------------------------------------------------------------------------- /.github/actions/test/action.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | description: Run ava tests 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - uses: ./.github/actions/setup 8 | - run: npm test 9 | shell: bash 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | assignees: [KiwiKilian] 8 | 9 | - package-ecosystem: github-actions 10 | directories: [/, ".github/actions/**"] 11 | schedule: 12 | interval: weekly 13 | assignees: [KiwiKilian] 14 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - next 8 | - next-major 9 | - alpha 10 | - beta 11 | 12 | jobs: 13 | setup: 14 | name: Setup 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: ./.github/actions/setup 19 | lint: 20 | name: Lint 21 | needs: setup 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v4 25 | - uses: ./.github/actions/lint 26 | test: 27 | name: Test 28 | needs: setup 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: ./.github/actions/test 33 | example-build: 34 | name: Example Build 35 | needs: setup 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | - uses: ./.github/actions/example-build 40 | release: 41 | name: Release 42 | needs: [lint, test, example-build] 43 | runs-on: ubuntu-latest 44 | permissions: 45 | contents: write 46 | issues: write 47 | pull-requests: write 48 | id-token: write 49 | steps: 50 | - uses: actions/checkout@v4 51 | - uses: ./.github/actions/setup 52 | - name: Audit Signatures 53 | run: npm audit signatures 54 | - name: Release 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 58 | run: npx semantic-release 59 | -------------------------------------------------------------------------------- /.github/workflows/review.yml: -------------------------------------------------------------------------------- 1 | name: Review 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | setup: 8 | name: Setup 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: ./.github/actions/setup 13 | lint: 14 | name: Lint 15 | needs: setup 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: ./.github/actions/lint 20 | publint: 21 | name: Publint 22 | needs: setup 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: ./.github/actions/publint 27 | test: 28 | name: Test 29 | needs: setup 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v4 33 | - uses: ./.github/actions/test 34 | example-build: 35 | name: Example Build 36 | needs: setup 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v4 40 | - uses: ./.github/actions/example-build 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build results 2 | /example/_site/ 3 | /example/.cache/ 4 | 5 | # IDEs 6 | /.idea/ 7 | /.vscode/ 8 | 9 | # Package managers 10 | /node_modules/ 11 | .npm 12 | 13 | # Logs 14 | logs 15 | *.log 16 | npm-debug.log* 17 | yarn-debug.log* 18 | yarn-error.log* 19 | 20 | # Artefacts 21 | .DS_Store 22 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.18.0 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Build results 2 | /example/_site/ -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | import prettierConfig from '@kiwikilian/prettier-config' with { type: 'json' }; 2 | 3 | /** @type {import('prettier').Config} */ 4 | export default { 5 | ...prettierConfig, 6 | plugins: ['prettier-plugin-jsdoc', 'prettier-plugin-jinja-template'], 7 | overrides: [ 8 | { 9 | files: ['**/*.njk'], 10 | options: { 11 | parser: 'jinja-template', 12 | }, 13 | }, 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@semantic-release/commit-analyzer", 4 | "@semantic-release/release-notes-generator", 5 | "@semantic-release/changelog", 6 | "@semantic-release/npm", 7 | "@semantic-release/github", 8 | "@semantic-release/git" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [4.0.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0...v4.0.1) (2024-11-07) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * improve types ([b384921](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/b384921af2daa672be75e2af773e3f384aa56b90)) 7 | 8 | # [4.0.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v3.1.0...v4.0.0) (2024-10-05) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * align logging paths ([5491207](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/5491207214f961647249f5f83f7bd307b494a840)) 14 | * allow empty options for mergeOptions ([380a3c3](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/380a3c31b80d5100b36e47b5e712fb9a2dc5cf01)) 15 | * generateHTML and outputURL capitalization ([5e911b0](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/5e911b0e785c7ec1fd8cbb140acd6664bc82318a)) 16 | * generateHTML type ([f86acd4](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/f86acd4ba4cc25a1f8003c0c9f7ac7a00cf4a6d0)) 17 | * hashes without special chars with hex digest ([47fb387](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/47fb387e9515c188a8710878c80e57a0de3a6cca)) 18 | * join directories with output and preview dir ([155c7d8](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/155c7d866d77b4c127ae709eb06388ddc2a0316a)) 19 | * outputUrl on windows with forward slash ([e1bff34](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/e1bff342a878876f6bc840e94edfa39b1ca7fa72)), closes [#234](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/234) 20 | * release ([8d74d25](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/8d74d252673d2592f58062799721647ef7fd392c)) 21 | * RenderPlugin.File import ([#267](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/267)) ([4906d64](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/4906d6420d964df728fe656a7db01449ab8fe907)) 22 | * type imports ([24aa37b](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/24aa37b8f86c16eb1ec947a5b331de60534c90ac)) 23 | * update docs about arrow functions ([e6639e5](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/e6639e5012df1cc0cc3d8c65ef7a990fa38b0e82)), closes [#239](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/239) [#241](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/241) 24 | * use released alpha version ([bb8519c](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/bb8519c7c1e57629804a3937bb1c4f0049c4309c)) 25 | 26 | 27 | ### Features 28 | 29 | * add cache file path ([9b3a1d6](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/9b3a1d60f7e24c7c95283de2b748b32383413575)) 30 | * add caching ([17b46f3](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/17b46f399c43dbabeedcf843b8bec4e6b87e93d7)) 31 | * add eleventyPluginOgImage data to rendering ([b63cc55](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/b63cc55ea57e7aef096181f4edeae6dcbcb4918f)), closes [#215](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/215) 32 | * add exports ([263499b](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/263499b065f81291c8716bd147917f456816e5e9)) 33 | * add previewHtml ([7406914](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/740691462418edc6e45dd6edb7dc6bb0ea708a6f)) 34 | * allow OgImage custom class ([d31d320](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/d31d32036556f84fbfbf146e0aaa5f3dbcd63eb8)) 35 | * improve preview path handling ([4462d10](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/4462d107d5c008b6ef2e650277c3a60c15976467)) 36 | * improve types of this for function parameters ([5b0b269](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/5b0b269814e40cbea00ffcebbc9aaccda35e4cb5)) 37 | * pass instance as parameter ([b04eaf6](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/b04eaf6016038632136879ee33460611bab5c61a)), closes [#252](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/252) 38 | * pass shortcode scoped data to OG templates ([a240aee](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/a240aee5ca49015605c307dc58d64e5ca64373d8)), closes [#211](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/211) 39 | * reduce recalculations ([6a69780](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/6a697800d98af9d4e5b67de86aa4fed04d96cf3c)) 40 | * release with npm provenance ([7123708](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/712370899fca3763b82e02d6aee57fce384d9df7)) 41 | * rename generateHTML to shortcodeOutput ([a5cd8fd](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/a5cd8fd76ac0014e5ba2240875592d2159c554d3)) 42 | * rename getOutputFileSlug to outputFileSlug ([3923a5c](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/3923a5c47da83f8486b54d02f37b5dd4ef48ac2f)) 43 | * set previewDir based on outputDir ([93906ec](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/93906eca0ea989b6e78c6d8c7a2919dcce0d181e)) 44 | * update dependencies ([75aae59](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/75aae59f5c76a1089656927956d902f4c48be3a8)) 45 | * upgrade eleventy depency to stable v3 ([6e96800](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/6e9680084208eb2e853a2240820af1f8f03ee1f0)) 46 | * upgrade sharp ([0fa8b23](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/0fa8b23975a752522606eea6abbb2ce2d20220ba)) 47 | * urlPath default to outputDir ([fe9d54f](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/fe9d54fe7b18860d53cacc221d41055ae6b0804f)) 48 | * use fs promises ([0953dec](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/0953decd79b591f18a8b0344c43dd821c0898fef)) 49 | 50 | 51 | ### BREAKING CHANGES 52 | 53 | * outputFileSlug and shortcodeOutput options get OgImage instance as parameter instead of this 54 | * rename getOutputFileSlug to outputFileSlug 55 | * rename generateHTML to shortcodeOutput 56 | * Plugin structure changed to OgImage class 57 | * Options changed, consult docs before upgrading 58 | 59 | # [4.0.0-beta.10](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.9...v4.0.0-beta.10) (2024-10-05) 60 | 61 | 62 | ### Features 63 | 64 | * release with npm provenance ([7123708](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/712370899fca3763b82e02d6aee57fce384d9df7)) 65 | 66 | # [4.0.0-beta.9](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.8...v4.0.0-beta.9) (2024-10-05) 67 | 68 | 69 | ### Features 70 | 71 | * update dependencies ([75aae59](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/75aae59f5c76a1089656927956d902f4c48be3a8)) 72 | * upgrade eleventy depency to stable v3 ([6e96800](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/6e9680084208eb2e853a2240820af1f8f03ee1f0)) 73 | 74 | # [4.0.0-beta.8](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.7...v4.0.0-beta.8) (2024-07-31) 75 | 76 | 77 | ### Bug Fixes 78 | 79 | * RenderPlugin.File import ([#267](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/267)) ([4906d64](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/4906d6420d964df728fe656a7db01449ab8fe907)) 80 | 81 | # [4.0.0-beta.7](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.6...v4.0.0-beta.7) (2024-06-06) 82 | 83 | 84 | ### Features 85 | 86 | * pass instance as parameter ([b04eaf6](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/b04eaf6016038632136879ee33460611bab5c61a)), closes [#252](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/252) 87 | 88 | 89 | ### BREAKING CHANGES 90 | 91 | * outputFileSlug and shortcodeOutput options get OgImage instance as parameter instead of this 92 | 93 | # [4.0.0-beta.6](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.5...v4.0.0-beta.6) (2024-04-29) 94 | 95 | 96 | ### Bug Fixes 97 | 98 | * release ([8d74d25](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/8d74d252673d2592f58062799721647ef7fd392c)) 99 | 100 | # [4.0.0-beta.5](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.4...v4.0.0-beta.5) (2024-04-28) 101 | 102 | 103 | ### Features 104 | 105 | * add previewHtml ([7406914](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/740691462418edc6e45dd6edb7dc6bb0ea708a6f)) 106 | * rename generateHTML to shortcodeOutput ([a5cd8fd](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/a5cd8fd76ac0014e5ba2240875592d2159c554d3)) 107 | * rename getOutputFileSlug to outputFileSlug ([3923a5c](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/3923a5c47da83f8486b54d02f37b5dd4ef48ac2f)) 108 | 109 | 110 | ### BREAKING CHANGES 111 | 112 | * rename getOutputFileSlug to outputFileSlug 113 | * rename generateHTML to shortcodeOutput 114 | 115 | # [4.0.0-beta.4](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2024-04-15) 116 | 117 | 118 | ### Bug Fixes 119 | 120 | * update docs about arrow functions ([e6639e5](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/e6639e5012df1cc0cc3d8c65ef7a990fa38b0e82)), closes [#239](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/239) [#241](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/241) 121 | 122 | # [4.0.0-beta.3](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.2...v4.0.0-beta.3) (2024-04-08) 123 | 124 | 125 | ### Bug Fixes 126 | 127 | * generateHTML and outputURL capitalization ([5e911b0](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/5e911b0e785c7ec1fd8cbb140acd6664bc82318a)) 128 | 129 | # [4.0.0-beta.2](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2024-04-07) 130 | 131 | 132 | ### Features 133 | 134 | * use fs promises ([0953dec](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/0953decd79b591f18a8b0344c43dd821c0898fef)) 135 | 136 | # [4.0.0-beta.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v3.2.0-beta.5...v4.0.0-beta.1) (2024-04-07) 137 | 138 | 139 | ### Bug Fixes 140 | 141 | * allow empty options for mergeOptions ([380a3c3](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/380a3c31b80d5100b36e47b5e712fb9a2dc5cf01)) 142 | * generateHTML type ([f86acd4](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/f86acd4ba4cc25a1f8003c0c9f7ac7a00cf4a6d0)) 143 | * join directories with output and preview dir ([155c7d8](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/155c7d866d77b4c127ae709eb06388ddc2a0316a)) 144 | 145 | 146 | ### Features 147 | 148 | * add cache file path ([9b3a1d6](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/9b3a1d60f7e24c7c95283de2b748b32383413575)) 149 | * add caching ([17b46f3](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/17b46f399c43dbabeedcf843b8bec4e6b87e93d7)) 150 | * add exports ([263499b](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/263499b065f81291c8716bd147917f456816e5e9)) 151 | * allow OgImage custom class ([d31d320](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/d31d32036556f84fbfbf146e0aaa5f3dbcd63eb8)) 152 | * improve preview path handling ([4462d10](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/4462d107d5c008b6ef2e650277c3a60c15976467)) 153 | * improve types of this for function parameters ([5b0b269](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/5b0b269814e40cbea00ffcebbc9aaccda35e4cb5)) 154 | * reduce recalculations ([6a69780](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/6a697800d98af9d4e5b67de86aa4fed04d96cf3c)) 155 | * set previewDir based on outputDir ([93906ec](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/93906eca0ea989b6e78c6d8c7a2919dcce0d181e)) 156 | * urlPath default to outputDir ([fe9d54f](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/fe9d54fe7b18860d53cacc221d41055ae6b0804f)) 157 | 158 | 159 | ### BREAKING CHANGES 160 | 161 | * Plugin structure changed to OgImage class 162 | * Options changed, consult docs before upgrading 163 | 164 | # [3.2.0-beta.5](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v3.2.0-beta.4...v3.2.0-beta.5) (2024-03-23) 165 | 166 | 167 | ### Bug Fixes 168 | 169 | * hashes without special chars with hex digest ([47fb387](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/47fb387e9515c188a8710878c80e57a0de3a6cca)) 170 | * outputUrl on windows with forward slash ([e1bff34](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/e1bff342a878876f6bc840e94edfa39b1ca7fa72)), closes [#234](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/234) 171 | 172 | # [3.2.0-beta.4](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v3.2.0-beta.3...v3.2.0-beta.4) (2024-01-14) 173 | 174 | 175 | ### Features 176 | 177 | * add eleventyPluginOgImage data to rendering ([b63cc55](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/b63cc55ea57e7aef096181f4edeae6dcbcb4918f)), closes [#215](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/215) 178 | 179 | # [3.2.0-beta.3](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v3.2.0-beta.2...v3.2.0-beta.3) (2024-01-07) 180 | 181 | 182 | ### Bug Fixes 183 | 184 | * align logging paths ([5491207](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/5491207214f961647249f5f83f7bd307b494a840)) 185 | 186 | 187 | ### Features 188 | 189 | * pass shortcode scoped data to OG templates ([a240aee](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/a240aee5ca49015605c307dc58d64e5ca64373d8)), closes [#211](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/211) 190 | 191 | # [3.2.0-beta.2](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v3.2.0-beta.1...v3.2.0-beta.2) (2023-12-23) 192 | 193 | 194 | ### Bug Fixes 195 | 196 | * type imports ([24aa37b](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/24aa37b8f86c16eb1ec947a5b331de60534c90ac)) 197 | * use released alpha version ([bb8519c](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/bb8519c7c1e57629804a3937bb1c4f0049c4309c)) 198 | 199 | # [3.2.0-beta.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v3.1.0...v3.2.0-beta.1) (2023-12-05) 200 | 201 | 202 | ### Features 203 | 204 | * upgrade sharp ([0fa8b23](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/0fa8b23975a752522606eea6abbb2ce2d20220ba)) 205 | 206 | # [3.1.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v3.0.0...v3.1.0) (2023-11-11) 207 | 208 | 209 | ### Bug Fixes 210 | 211 | * align outputFilePath format ([7567630](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/75676308ef0ee8d3c909e10740d183f593b6388a)) 212 | * resolve pathes relativ to input ([02647a8](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/02647a843c71d3994b8e7f61cf2f00d3325ca559)) 213 | * upgrade eleventy peerDependency and compatibility ([34223f0](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/34223f0dcf26906ea161da253bfa5e7240a40113)) 214 | 215 | 216 | ### Features 217 | 218 | * improve example font loading ([7261b66](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/7261b660896aed85d57f0e4fb5953090ec362fa3)) 219 | 220 | # [3.0.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v2.1.1...v3.0.0) (2023-10-29) 221 | 222 | 223 | ### Features 224 | 225 | * drop node 16 support ([83b88da](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/83b88da1570730d3c4547afd943e62f8ac788c41)) 226 | * switch to ESM module ([21219b6](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/21219b6520660b250e5cd784c178f631957572ff)) 227 | 228 | 229 | ### BREAKING CHANGES 230 | 231 | * This package is now ESM-only to drop postinstall build steps 232 | * node >= 18 required 233 | 234 | ## [2.1.3](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v2.1.2...v2.1.3) (2024-03-23) 235 | 236 | 237 | ### Bug Fixes 238 | 239 | * hashes without special chars with hex digest ([47fb387](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/47fb387e9515c188a8710878c80e57a0de3a6cca)) 240 | 241 | ## [2.1.2](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v2.1.1...v2.1.2) (2024-03-23) 242 | 243 | 244 | ### Bug Fixes 245 | 246 | * outputUrl on windows with forward slash ([e1bff34](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/e1bff342a878876f6bc840e94edfa39b1ca7fa72)), closes [#234](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/234) 247 | 248 | ## [2.1.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v2.1.0...v2.1.1) (2023-09-02) 249 | 250 | 251 | ### Bug Fixes 252 | 253 | * @11ty/eleventy >= 2.x.x is required ([#164](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/164)) ([f2d6aa8](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/f2d6aa83da8b4c0eb9faf726236fdb227d0785c7)) 254 | * omit output for permalink false ([#163](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/163)) ([432edd0](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/432edd0ad35de86998569ebdabc57a763cfc3eea)) 255 | 256 | # [2.1.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v2.0.1...v2.1.0) (2023-08-30) 257 | 258 | 259 | ### Features 260 | 261 | * add getOutputFileSlug ([#160](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/160)) ([f55cbdc](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/f55cbdcfd561bae388207589ed595a3aa2d99865)) 262 | 263 | ## [2.0.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v2.0.0...v2.0.1) (2023-06-13) 264 | 265 | 266 | ### Bug Fixes 267 | 268 | * unify logging ([#131](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/131)) ([de6ca1d](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/de6ca1d0a1a694016e0292b502a9680534d4abc9)) 269 | 270 | # [2.0.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.6.2...v2.0.0) (2023-06-01) 271 | 272 | 273 | ### Features 274 | 275 | * add development mode ([#123](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/123)) ([8711954](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/8711954c7e5dc58b507b972252a32389dc0fbef7)) 276 | 277 | 278 | ### BREAKING CHANGES 279 | 280 | * switch `renderOgImage` parameters to object style 281 | 282 | ## [1.6.2](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.6.1...v1.6.2) (2023-05-24) 283 | 284 | 285 | ### Bug Fixes 286 | 287 | * exports of types ([#120](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/120)) ([e679ebb](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/e679ebb1a7f822ccd518b1af4c17d0629303581f)) 288 | 289 | ## [1.6.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.6.0...v1.6.1) (2023-03-03) 290 | 291 | 292 | ### Bug Fixes 293 | 294 | * use export to resolve yoga.wasm ([#78](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/78)) ([fdb4d20](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/fdb4d20fd369baac62be428efd3930c040e0c1cb)) 295 | 296 | # [1.6.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.5.0...v1.6.0) (2023-02-23) 297 | 298 | 299 | ### Features 300 | 301 | * clear outputDir on eleventy.build event ([#74](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/74)) ([3e60531](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/3e60531e01f333c637cd9f330ff1e63bdd2d2945)) 302 | 303 | # [1.5.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.4.2...v1.5.0) (2023-02-20) 304 | 305 | 306 | ### Features 307 | 308 | * use yoga-wasm-web ([#72](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/72)) ([d189d35](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/d189d351325f1b1b7f550273638977d849b4c37c)) 309 | 310 | ## [1.4.2](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.4.1...v1.4.2) (2023-01-25) 311 | 312 | 313 | ### Bug Fixes 314 | 315 | * @11ty/eleventy as peerDependency ([#57](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/57)) ([48b2353](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/48b2353c22ffea76240b9d208ab3da579e690862)) 316 | 317 | ## [1.4.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.4.0...v1.4.1) (2023-01-16) 318 | 319 | 320 | ### Bug Fixes 321 | 322 | * align node minimum version with eleventy ([#50](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/50)) ([1a55b78](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/1a55b78767fcd42e0f21def605e8b884231fa172)) 323 | 324 | # [1.4.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.3.0...v1.4.0) (2023-01-11) 325 | 326 | 327 | ### Bug Fixes 328 | 329 | * satori with yoga-layout-prebuilt ([5a91800](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/5a918009bc2e224a368e6aa1384deebb6010b753)) 330 | 331 | 332 | ### Features 333 | 334 | * inputFileGlob now ignores in subDirectories ([#48](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/48)) ([aef85eb](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/aef85eb5238162d5d2c6a287dc45178ba2930da2)) 335 | 336 | # [1.3.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.2.0...v1.3.0) (2023-01-04) 337 | 338 | 339 | ### Features 340 | 341 | * render og image with templateConfig ([#40](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/40)) ([6884b90](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/6884b90c1e2423527a9b3c864480fee576727e1c)) 342 | 343 | # [1.2.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.1.1...v1.2.0) (2022-12-30) 344 | 345 | 346 | ### Features 347 | 348 | * add generateHTML option ([#34](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/34)) ([aec8082](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/aec808227bc69866acdf2db11fbc9c7ef94fb113)) 349 | 350 | ## [1.1.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.1.0...v1.1.1) (2022-12-12) 351 | 352 | 353 | ### Bug Fixes 354 | 355 | * remove ultrahtml override ([#26](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/26)) ([220a965](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/220a965ce319852fd75a913bed4dd0133c7ce698)) 356 | 357 | # [1.1.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.0.1...v1.1.0) (2022-11-05) 358 | 359 | 360 | ### Features 361 | 362 | * improve output behavior ([fc272c5](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/fc272c50b27bba75d0e2e075bb11b40ad2b76504)), closes [#6](https://github.com/KiwiKilian/eleventy-plugin-og-image/issues/6) 363 | 364 | ## [1.0.1](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v1.0.0...v1.0.1) (2022-11-03) 365 | 366 | 367 | ### Bug Fixes 368 | 369 | * Enable CSS inlining ([592dec0](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/592dec0f86f5e5aa2970c1b929251a11d10af057)) 370 | 371 | # [1.0.0](https://github.com/KiwiKilian/eleventy-plugin-og-image/compare/v0.1.1...v1.0.0) (2022-10-30) 372 | 373 | 374 | ### Features 375 | 376 | * Add shortcode ([ce4df37](https://github.com/KiwiKilian/eleventy-plugin-og-image/commit/ce4df37c0b73b6e6dc0f1e1cc5b4f08ede194b3e)) 377 | 378 | 379 | ### BREAKING CHANGES 380 | 381 | * Use shortcode instead of template functionality 382 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Kilian Finger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Eleventy Plugin OG Image [![npm](https://img.shields.io/npm/v/eleventy-plugin-og-image?color=blue)](https://www.npmjs.com/package/eleventy-plugin-og-image) 2 | 3 | This plugin helps to create Open Graph images in [Eleventy](https://www.11ty.dev/) using HTML[^1] within any supported template language and CSS[^2] via [satori](https://github.com/vercel/satori). No headless browser will be harmed 😉. 4 | 5 | ## Usage 6 | 7 | Install the package: 8 | 9 | ```shell 10 | npm install eleventy-plugin-og-image --save-dev 11 | ``` 12 | 13 | ### ESM 14 | 15 | It's preferred to use this plugin within ESM Eleventy projects. Read more about ESM vs CommonJS on the [Eleventy documentation](https://www.11ty.dev/docs/cjs-esm/). 16 | 17 | ```js 18 | import EleventyPluginOgImage from 'eleventy-plugin-og-image'; 19 | 20 | export default async function (eleventyConfig) { 21 | eleventyConfig.addPlugin(EleventyPluginOgImage, { 22 | satoriOptions: { 23 | fonts: [ 24 | { 25 | name: 'Inter', 26 | data: fs.readFileSync('../path/to/font-file/inter.woff'), 27 | weight: 700, 28 | style: 'normal', 29 | }, 30 | ], 31 | }, 32 | }); 33 | } 34 | ``` 35 | 36 | ### CommonJS 37 | 38 | > [!NOTE] 39 | > This plugin is written in ESM, therefore `require` is not possible. If the .eleventy.js config uses CommonJS, switch to async and create a dynamic import as shown below. 40 | 41 | ```js 42 | module.exports = async function (eleventyConfig) { 43 | const EleventyPluginOgImage = (await import('eleventy-plugin-og-image')).default; 44 | 45 | eleventyConfig.addPlugin(EleventyPluginOgImage, { 46 | // See above for example config 47 | }); 48 | }; 49 | ``` 50 | 51 | ### Add a Template 52 | 53 | Create an OG-image-template anywhere in the input directory. Use only the supported HTML elements[^1] and CSS properties[^2]. CSS in ` 72 | 73 |
74 |

{{ title }}

75 |
76 | ``` 77 | 78 | Call the `ogImage` shortcode inside the `` in a template or layout. The first argument is the `filePath` of the OG-image-template (required, relative to the Eleventy input directory). The second argument is for `data` (optional). Usage example in Nunjucks, e.g. `example-page.njk`: 79 | 80 | ```njk 81 | {% ogImage "./og-image.og.njk", { title: "Hello World!" } %} 82 | ``` 83 | 84 | ### Result 85 | 86 | Generated OG image `_site/og-images/s0m3h4sh.png`: 87 | 88 | ![Generated OG image](./assets/og-image.png) 89 | 90 | HTML output generated by the shortcode into `_site/example-page/index.html` (can be modified via the `shortcodeOutput` option): 91 | 92 | ```html 93 | 94 | ``` 95 | 96 | For applied usage see the [example](./example). 97 | 98 | > [!TIP] 99 | > The template language of the page and OG-image-template can be mixed or matched. 100 | 101 | ## Configuration 102 | 103 | The following options can be passed when adding the plugin: 104 | 105 | | Property | Type | Default | | 106 | | --------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------ | 107 | | `inputFileGlob` | `glob` | `**/*.og.*` | This must match the OG-image-templates to prevent HTML compilation. | 108 | | `hashLength` | `number` | `8` | | 109 | | `outputFileExtension` | [sharp output file formats](https://sharp.pixelplumbing.com/api-output#toformat) | `png` | | 110 | | `outputDir` | `string` | `og-images` | Directory into which OG images will be emitted. Relative to eleventy `output`. | 111 | | `previewDir` | `string` | `${outputDir}/preview` | Directory used for preview during `watch` or `serve`. Relative to eleventy `output`. | 112 | | `urlPath` | `string` | `${outputDir}` | URL-prefix which will be used in returned meta-tags. | 113 | | `outputFileSlug` | `function` | [See source](src/utils/mergeOptions.js) | Generation of the output file slug, must be url safe and exclude the file extension. | 114 | | `shortcodeOutput` | `function` | [See source](src/utils/mergeOptions.js) | Change the HTML returned by the shortcode in pages. | 115 | | `satoriOptions` | [satori options](https://github.com/search?q=repo:vercel/satori+%22export+type+SatoriOptions%22&type=code) | `{ width: 1200, height: 630, fonts: [] }` | If an OG-image-template contains text, it's **required** to load a font ([example](#esm)). | 116 | | `sharpOptions` | [sharp output options](https://sharp.pixelplumbing.com/api-output#toformat) | `undefined` | Options must be corresponding to chosen `outputFileExtension`. | 117 | | `OgImage` | `class CustomOgImage extends OgImage` | [`OgImage`](src/OgImage.js) | [Extend the `OgImage`](#extending-ogimage-class) class for maximum customization. | 118 | 119 | ## Preview Mode 120 | 121 | During development with `watch` or `serve` the OG image files are also copied into the `previewDir`, named by the url slug of the pages they are generated from. Next to it there is a HTML placed which shows the generated HTML, SVG and output image. The `previewDir` will be deleted during a production build. 122 | 123 | ## Caching 124 | 125 | For better performance OG images are cached based on a hash from generated HTML and output options. If the file already exists, further transformations are skipped. 126 | 127 | ## Advanced Usage 128 | 129 | ### Extending OgImage Class 130 | 131 | It's possible to extend and overwrite any of the functions from the [`OgImage`](src/OgImage.js) class. The custom class is passed as the `OgImage` parameter to the plugin. 132 | 133 | ```js 134 | import EleventyPluginOgImage from 'eleventy-plugin-og-image'; 135 | import { OgImage } from 'eleventy-plugin-og-image/og-image'; 136 | 137 | export class CustomOgImage extends BaseOgImage { 138 | async shortcodeOutput() { 139 | return this.outputUrl(); 140 | } 141 | } 142 | 143 | /** @param {import('@11ty/eleventy/src/UserConfig').default} eleventyConfig */ 144 | export default async function (eleventyConfig) { 145 | eleventyConfig.addPlugin(EleventyPluginOgImage, { 146 | OgImage: CustomOgImage, 147 | }); 148 | } 149 | ``` 150 | 151 | ### Custom Shortcode 152 | 153 | A custom shortcode can be created by using the `OgImage` class. 154 | 155 | ```js 156 | import { OgImage } from 'eleventy-plugin-og-image/og-image'; 157 | 158 | const image = await new OgImage({ inputPath, data, options, templateConfig }).render(); 159 | ``` 160 | 161 | ### Capture Output URL 162 | 163 | The plugins shortcode create a `meta` tag per default, modify the `shortcodeOutput` option or class function to directly return the `outputUrl`: 164 | 165 | ```js 166 | eleventyConfig.addPlugin(EleventyPluginOgImage, { 167 | async shortcodeOutput(ogImage) { 168 | return ogImage.outputUrl(); 169 | }, 170 | }); 171 | ``` 172 | 173 | Furthermore, it's possible to capture the `outputUrl` to a variable, e.g. in Nunjucks: 174 | 175 | ```njk 176 | {% setAsync "ogOutputUrl" -%} 177 | {% ogImage "./og-image.og.njk", { title: "Hello World!" } %} 178 | {%- endsetAsync %} 179 | ``` 180 | 181 | And use it anywhere afterward with `{{ ogOutputUrl }}`. 182 | 183 | ## Acknowledgements & Attributions 184 | 185 | This plugin is deeply inspired by [@vercel/og](https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation). 186 | 187 | Furthermore, it would not be possible without: 188 | 189 | - [satori](https://github.com/vercel/satori) 190 | - [resvg](https://github.com/RazrFalcon/resvg/)/[resvg-js](https://github.com/yisibl/resvg-js) 191 | - [sharp](https://github.com/lovell/sharp) 192 | 193 | [^1]: Only a subset of HTML elements is [supported by satori](https://github.com/vercel/satori#html-elements). 194 | 195 | [^2]: Only a subset of CSS properties are supported by [yoga-layout](https://github.com/facebook/yoga), which is [used by satori](https://github.com/vercel/satori#css). 196 | -------------------------------------------------------------------------------- /assets/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiwiKilian/eleventy-plugin-og-image/8930e7bdfb7fdbe1c68ab6c9d57813f75c76d7fb/assets/og-image.png -------------------------------------------------------------------------------- /example/.eleventy.js: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'node:fs'; 2 | import module from 'node:module'; 3 | import twemoji from 'twemoji'; 4 | import EleventyPluginOgImage from '../.eleventy.js'; 5 | 6 | const require = module.createRequire(import.meta.url); 7 | 8 | /** @param {import('@11ty/eleventy/src/UserConfig').default} eleventyConfig */ 9 | export default async function (eleventyConfig) { 10 | eleventyConfig.addShortcode('testShortcode', () => 'Eleventy Plugin OG Image'); 11 | 12 | /** @type {import('eleventy-plugin-og-image').EleventyPluginOgImageOptions} */ 13 | const eleventyPluginOgImageOptions = { 14 | satoriOptions: { 15 | fonts: [ 16 | { 17 | name: 'Inter', 18 | data: await fs.readFile(require.resolve('@fontsource/inter/files/inter-latin-700-normal.woff')), 19 | weight: 700, 20 | style: 'normal', 21 | }, 22 | ], 23 | loadAdditionalAsset: async (languageCode, segment) => { 24 | if (languageCode === 'emoji') { 25 | const emojiUrl = `https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/${twemoji.convert.toCodePoint( 26 | segment, 27 | )}.svg`; 28 | const emojiSvg = await (await fetch(emojiUrl)).text(); 29 | 30 | return `data:image/svg+xml;base64,${Buffer.from(emojiSvg).toString('base64')}`; 31 | } 32 | 33 | return segment; 34 | }, 35 | }, 36 | }; 37 | 38 | eleventyConfig.addPlugin(EleventyPluginOgImage, eleventyPluginOgImageOptions); 39 | } 40 | -------------------------------------------------------------------------------- /example/example-draft.njk: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: false 3 | --- 4 | 5 | 6 | 7 | 8 | 9 | Eleventy Plugin OG Image 10 | 11 | 12 | {% ogImage "./og-image.og.njk", { title: "This is a draft. 📝" } %} 13 | 14 | 15 | 16 |

Eleventy Plugin OG Image

17 | 18 | 19 | -------------------------------------------------------------------------------- /example/example-page.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Eleventy Plugin OG Image 6 | 7 | 8 | {% ogImage "./og-image.og.njk", { title: "Hello World! 👋" } %} 9 | 10 | 11 | 12 |

Eleventy Plugin OG Image

13 | 14 | 15 | -------------------------------------------------------------------------------- /example/og-image.og.njk: -------------------------------------------------------------------------------- 1 | 36 | 37 |
38 |

{{ title }}

39 |
40 |

{% testShortcode %}

41 |
42 |
43 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import { SatoriOptions } from 'satori'; 2 | import { FormatEnum, Sharp } from 'sharp'; 3 | import TemplateConfig from '@11ty/eleventy/src/TemplateConfig'; 4 | 5 | export interface OgImage { 6 | inputPath: string; 7 | 8 | data: Record; 9 | 10 | options: EleventyPluginOgImageMergedOptions; 11 | 12 | templateConfig: typeof TemplateConfig; 13 | 14 | results: { 15 | html?: string; 16 | svg?: string; 17 | pngBuffer?: Buffer; 18 | }; 19 | 20 | html(): Promise; 21 | 22 | svg(): Promise; 23 | 24 | pngBuffer(): Promise; 25 | 26 | render(): Promise; 27 | 28 | hash(): Promise; 29 | 30 | outputFileSlug(): Promise; 31 | 32 | outputFileName(): Promise; 33 | 34 | outputFilePath(): Promise; 35 | 36 | outputUrl(): Promise; 37 | 38 | cacheFilePath(): Promise; 39 | 40 | shortcodeOutput(): Promise; 41 | 42 | previewFilePath(): string; 43 | 44 | previewHtml(): Promise; 45 | } 46 | 47 | type DirectoriesConfig = { 48 | input: string; 49 | includes: string; 50 | data: string; 51 | layouts?: string; 52 | output: string; 53 | }; 54 | 55 | type SharpFormatOptions = Parameters[1]; 56 | 57 | type EleventyPluginOgImageOptions = { 58 | inputFileGlob?: string; 59 | hashLength?: number; 60 | outputFileExtension?: keyof FormatEnum; 61 | outputDir?: string; 62 | previewDir?: string; 63 | urlPath?: string; 64 | 65 | outputFileSlug?(ogImage: OgImage): Promise; 66 | shortcodeOutput?(ogImage: OgImage): Promise; 67 | 68 | OgImage?: OgImage; 69 | 70 | satoriOptions?: Partial; 71 | sharpOptions?: SharpFormatOptions; 72 | }; 73 | 74 | type EleventyPluginOgImageMergedOptions = Omit< 75 | Required, 76 | 'OgImage' | 'satoriOptions' | 'sharpOptions' 77 | > & 78 | Pick & { 79 | satoriOptions: SatoriOptions & { width: number; height: number }; 80 | }; 81 | 82 | export { EleventyPluginOgImageOptions, EleventyPluginOgImageMergedOptions, DirectoriesConfig }; 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eleventy-plugin-og-image", 3 | "version": "4.0.1", 4 | "description": "A plugin to create Open Graph Images from JSX for Eleventy.", 5 | "author": { 6 | "name": "Kilian Finger", 7 | "email": "npm@kilianfinger.com", 8 | "url": "https://www.kilianfinger.com/" 9 | }, 10 | "license": "MIT", 11 | "keywords": [ 12 | "11ty", 13 | "eleventy", 14 | "eleventy-plugin", 15 | "og:image" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/KiwiKilian/eleventy-plugin-og-image.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/KiwiKilian/eleventy-plugin-og-image/issues" 23 | }, 24 | "homepage": "https://github.com/KiwiKilian/eleventy-plugin-og-image#readme", 25 | "main": "./.eleventy.js", 26 | "type": "module", 27 | "exports": { 28 | ".": { 29 | "types": "./index.d.ts", 30 | "default": "./.eleventy.js" 31 | }, 32 | "./package.json": "./package.json", 33 | "./og-image": "./src/OgImage.js", 34 | "./utils": "./src/utils/index.js" 35 | }, 36 | "types": "./index.d.ts", 37 | "files": [ 38 | ".eleventy.js", 39 | "index.d.ts", 40 | "src" 41 | ], 42 | "publishConfig": { 43 | "provenance": true 44 | }, 45 | "scripts": { 46 | "semantic-release": "semantic-release", 47 | "test": "ava test/**/*.test.js", 48 | "lint": "eslint .", 49 | "prettier": "prettier --write .", 50 | "example": "npx @11ty/eleventy --config=example/.eleventy.js --input=example --output=example/_site", 51 | "example:start": "npm run example -- --serve", 52 | "example:build": "npm run example", 53 | "example:clean": "rimraf ./example/_site" 54 | }, 55 | "engines": { 56 | "node": ">=18" 57 | }, 58 | "11ty": { 59 | "compatibility": ">=3.0.0" 60 | }, 61 | "peerDependencies": { 62 | "@11ty/eleventy": ">=3.0.0" 63 | }, 64 | "dependencies": { 65 | "@11ty/eleventy-utils": "^2.0.1", 66 | "@resvg/resvg-js": "^2.6.2", 67 | "satori": "^0.13.0", 68 | "satori-html": "^0.3.2", 69 | "sharp": "^0.34.1", 70 | "yoga-wasm-web": "^0.3.3" 71 | }, 72 | "devDependencies": { 73 | "@11ty/eleventy": "3.1.0", 74 | "@fontsource/inter": "5.2.5", 75 | "@kiwikilian/eslint-config": "1.1.0", 76 | "@kiwikilian/prettier-config": "1.0.1", 77 | "@semantic-release/changelog": "6.0.3", 78 | "@semantic-release/git": "10.0.1", 79 | "ava": "6.3.0", 80 | "eslint": "8.57.1", 81 | "prettier": "3.5.3", 82 | "prettier-plugin-jinja-template": "2.1.0", 83 | "prettier-plugin-jsdoc": "1.3.2", 84 | "semantic-release": "24.2.5", 85 | "twemoji": "14.0.2" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/OgImage.js: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'node:fs'; 2 | import module from 'node:module'; 3 | import { RenderPlugin } from '@11ty/eleventy'; 4 | /* eslint-disable import/no-unresolved */ 5 | // https://github.com/import-js/eslint-plugin-import/issues/2132 6 | import { html as htmlToSatori } from 'satori-html'; 7 | import initYoga from 'yoga-wasm-web'; 8 | /* eslint-enable import/no-unresolved */ 9 | import satori, { init } from 'satori/wasm'; 10 | import { Resvg } from '@resvg/resvg-js'; 11 | import sharp from 'sharp'; 12 | import crypto from 'node:crypto'; 13 | import { TemplatePath } from '@11ty/eleventy-utils'; 14 | import path from 'node:path'; 15 | import url from 'node:url'; 16 | import { sortObject } from './utils/index.js'; 17 | 18 | const require = module.createRequire(import.meta.url); 19 | 20 | const Yoga = await initYoga(await fs.readFile(require.resolve('yoga-wasm-web/dist/yoga.wasm'))); 21 | init(Yoga); 22 | 23 | /** @implements {import('eleventy-plugin-og-image').OgImage} */ 24 | export class OgImage { 25 | /** @type {string} */ 26 | inputPath; 27 | 28 | /** @type {Record} */ 29 | data; 30 | 31 | /** @type {import('eleventy-plugin-og-image').EleventyPluginOgImageMergedOptions} */ 32 | options; 33 | 34 | /** @type {import('@11ty/eleventy/src/TemplateConfig').default} */ 35 | templateConfig; 36 | 37 | /** 38 | * @private 39 | * @type {{ html?: string; svg?: string; pngBuffer?: Buffer }} 40 | */ 41 | results = { 42 | html: undefined, 43 | svg: undefined, 44 | pngBuffer: undefined, 45 | }; 46 | 47 | /** 48 | * @param {string} inputPath 49 | * @param {Record} data 50 | * @param {import('eleventy-plugin-og-image').EleventyPluginOgImageMergedOptions} options 51 | * @param {import('@11ty/eleventy/src/TemplateConfig').default} templateConfig 52 | */ 53 | constructor({ inputPath, data, options, templateConfig }) { 54 | this.inputPath = inputPath; 55 | this.data = data; 56 | this.options = options; 57 | this.templateConfig = templateConfig; 58 | } 59 | 60 | /** @returns {Promise} */ 61 | async html() { 62 | if (!this.results.html) { 63 | this.results.html = await ( 64 | await RenderPlugin.File(this.inputPath, { templateConfig: this.templateConfig }) 65 | )(this.data); 66 | } 67 | 68 | return this.results.html; 69 | } 70 | 71 | /** @returns {Promise} */ 72 | async svg() { 73 | if (!this.results.svg) { 74 | this.results.svg = await satori(htmlToSatori(await this.html()), this.options.satoriOptions); 75 | } 76 | 77 | return this.results.svg; 78 | } 79 | 80 | /** @returns {Promise} */ 81 | async pngBuffer() { 82 | if (!this.results.pngBuffer) { 83 | this.results.pngBuffer = await new Resvg(await this.svg(), { font: { loadSystemFonts: false } }).render().asPng(); 84 | } 85 | 86 | return this.results.pngBuffer; 87 | } 88 | 89 | /** 90 | * Returns the configured output format 91 | * 92 | * @returns {Promise} 93 | */ 94 | async render() { 95 | return sharp(await this.pngBuffer()).toFormat(this.options.outputFileExtension, this.options.sharpOptions); 96 | } 97 | 98 | /** @returns {Promise} */ 99 | async hash() { 100 | const hash = crypto.createHash('sha256'); 101 | 102 | hash.update(await this.html()); 103 | hash.update(JSON.stringify(sortObject(this.options.satoriOptions || {}))); 104 | hash.update(JSON.stringify(sortObject(this.options.sharpOptions || {}))); 105 | 106 | return hash.digest('hex').substring(0, this.options.hashLength); 107 | } 108 | 109 | /** @returns {Promise} */ 110 | async outputFileSlug() { 111 | return this.options.outputFileSlug(this); 112 | } 113 | 114 | /** @returns {Promise} */ 115 | async outputFileName() { 116 | return `${await this.outputFileSlug()}.${this.options.outputFileExtension}`; 117 | } 118 | 119 | /** @returns {Promise} */ 120 | async outputFilePath() { 121 | return TemplatePath.standardizeFilePath(path.join(this.options.outputDir, await this.outputFileName())); 122 | } 123 | 124 | /** @returns {Promise} */ 125 | async outputUrl() { 126 | const fileUrl = new url.URL('file://'); 127 | fileUrl.pathname = path.join(this.options.urlPath, await this.outputFileName()); 128 | 129 | return fileUrl.pathname; 130 | } 131 | 132 | /** @returns {Promise} */ 133 | async cacheFilePath() { 134 | return this.outputFilePath(); 135 | } 136 | 137 | /** @returns {Promise} */ 138 | async shortcodeOutput() { 139 | return this.options.shortcodeOutput(this); 140 | } 141 | 142 | /** @returns {string} */ 143 | previewFilePath() { 144 | return TemplatePath.standardizeFilePath( 145 | path.join( 146 | this.options.previewDir, 147 | `${this.data.page.url.replace(/\/$/, '') || 'index'}.${this.options.outputFileExtension}`, 148 | ), 149 | ); 150 | } 151 | 152 | /** @returns {Promise} */ 153 | async previewHtml() { 154 | return ` 155 | 156 | OG Image: ${this.data.page.url} 157 | 158 | 172 | 173 | 174 |
${await this.html()}
175 | ${await this.svg()} 176 | 180 | 181 | 182 | `; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | import { mergeOptions } from './mergeOptions.js'; 2 | import { sortObject } from './sortObject.js'; 3 | 4 | export { mergeOptions, sortObject }; 5 | -------------------------------------------------------------------------------- /src/utils/mergeOptions.js: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | 3 | /** 4 | * Merges the plugin options with defaults 5 | * 6 | * @param {DirectoriesConfig} [directoriesConfig] 7 | * @param {EleventyPluginOgImageOptions} [pluginOptions] 8 | * @returns {EleventyPluginOgImageMergedOptions} 9 | */ 10 | export function mergeOptions({ directoriesConfig, pluginOptions }) { 11 | const { outputDir, previewDir, urlPath, OgImage, satoriOptions, ...options } = pluginOptions || {}; 12 | 13 | const eleventyOutput = directoriesConfig ? directoriesConfig.output : ''; 14 | const joinedOutputDir = path.join(eleventyOutput, outputDir || 'og-images'); 15 | 16 | return { 17 | inputFileGlob: '**/*.og.*', 18 | hashLength: 8, 19 | outputFileExtension: 'png', 20 | outputDir: joinedOutputDir, 21 | previewDir: path.join(...(previewDir ? [eleventyOutput, previewDir] : [joinedOutputDir, 'preview'])), 22 | urlPath: urlPath || outputDir || 'og-images', 23 | 24 | /** @param {OgImage} ogImage */ 25 | outputFileSlug: (ogImage) => ogImage.hash(), 26 | 27 | /** @param {OgImage} ogImage */ 28 | shortcodeOutput: async (ogImage) => ``, 29 | 30 | ...options, 31 | 32 | satoriOptions: { 33 | width: 1200, 34 | height: 630, 35 | fonts: [], 36 | ...satoriOptions, 37 | }, 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/utils/sortObject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sorts an object recursively 3 | * 4 | * @param {object} unordered 5 | * @returns {object} 6 | */ 7 | export function sortObject(unordered) { 8 | const keys = Object.keys(unordered).sort(); 9 | 10 | return keys.reduce((object, key) => { 11 | object[key] = typeof unordered[key] === 'object' ? sortObject(unordered[key]) : unordered[key]; 12 | 13 | return object; 14 | }, {}); 15 | } 16 | -------------------------------------------------------------------------------- /test/OgImage.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import sharp from 'sharp'; 3 | import { OgImage } from '../src/OgImage.js'; 4 | import { testConstructor } from './utils/testConstructor.js'; 5 | 6 | test('html returns html string', async (t) => { 7 | const ogImage = new OgImage(testConstructor); 8 | 9 | const html = await ogImage.html(); 10 | 11 | t.snapshot(html); 12 | 13 | t.is(typeof html, 'string'); 14 | t.regex(html, /
<\/div>\n$/); 15 | }); 16 | 17 | test('svg returns svg string', async (t) => { 18 | const ogImage = new OgImage(testConstructor); 19 | 20 | const svg = await ogImage.svg(); 21 | 22 | t.snapshot(svg); 23 | 24 | t.is(typeof svg, 'string'); 25 | t.regex(svg, /^ { 29 | const ogImage = new OgImage(testConstructor); 30 | 31 | const pngBuffer = await ogImage.pngBuffer(); 32 | 33 | t.true(pngBuffer instanceof Buffer); 34 | }); 35 | 36 | test('render returns sharp object', async (t) => { 37 | const ogImage = new OgImage(testConstructor); 38 | 39 | const sharpRender = await ogImage.render(); 40 | 41 | t.true(sharpRender instanceof sharp); 42 | }); 43 | 44 | test('respects dimensions', async (t) => { 45 | const ogImage = new OgImage({ 46 | ...testConstructor, 47 | options: { 48 | ...testConstructor.options, 49 | satoriOptions: { width: 120, height: 63 }, 50 | }, 51 | }); 52 | 53 | const { width, height } = await (await ogImage.render()).metadata(); 54 | 55 | t.is(width, 120); 56 | t.is(height, 63); 57 | }); 58 | 59 | test('returns cached result', async (t) => { 60 | const ogImage = new OgImage(testConstructor); 61 | 62 | const firstPngBuffer = await ogImage.pngBuffer(); 63 | const secondPngBuffer = await ogImage.pngBuffer(); 64 | 65 | t.is(firstPngBuffer, secondPngBuffer); 66 | }); 67 | 68 | const PAGE_URL = 'example/url'; 69 | const HASH = '759d60a8'; 70 | 71 | test('hash returns hash', async (t) => { 72 | const ogImage = new OgImage(testConstructor); 73 | 74 | const hash = await ogImage.hash(); 75 | 76 | t.is(hash, HASH); 77 | }); 78 | 79 | test('outputFileSlug returns hash', async (t) => { 80 | const ogImage = new OgImage({ ...testConstructor, data: { page: { url: PAGE_URL } } }); 81 | 82 | t.is(await ogImage.outputFileSlug(), HASH); 83 | }); 84 | 85 | test('outputFileName returns file name', async (t) => { 86 | const ogImage = new OgImage(testConstructor); 87 | 88 | t.is(await ogImage.outputFileName(), `${HASH}.png`); 89 | }); 90 | 91 | test('outputFilePath returns file path', async (t) => { 92 | const ogImage = new OgImage(testConstructor); 93 | 94 | t.is(await ogImage.outputFilePath(), `./_site/og-images/${HASH}.png`); 95 | }); 96 | 97 | test('previewFilePath returns path', (t) => { 98 | const ogImage = new OgImage({ ...testConstructor, data: { page: { url: PAGE_URL } } }); 99 | 100 | t.is(ogImage.previewFilePath(), `./_site/og-images/preview/${PAGE_URL}.png`); 101 | }); 102 | -------------------------------------------------------------------------------- /test/mergeOptions.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { mergeOptions } from '../src/utils/index.js'; 3 | import { directoriesConfig } from './utils/directoriesConfig.js'; 4 | 5 | test('works without pluginOptions', (t) => { 6 | const { satoriOptions, sharpOptions, ...options } = mergeOptions({ directoriesConfig }); 7 | 8 | t.truthy(options); 9 | t.truthy(satoriOptions); 10 | }); 11 | 12 | test('creates default options', (t) => { 13 | const { satoriOptions, sharpOptions, ...options } = mergeOptions({ directoriesConfig }); 14 | 15 | t.is(options.outputFileExtension, 'png'); 16 | t.is(options.inputFileGlob, '**/*.og.*'); 17 | 18 | t.is(satoriOptions.width, 1200); 19 | t.is(satoriOptions.height, 630); 20 | 21 | t.falsy(sharpOptions); 22 | }); 23 | 24 | test('changes previewDir and urlPath if only outputDir is set', (t) => { 25 | const CUSTOM_OUTPUT_DIR = 'custom-output'; 26 | 27 | const { outputDir, previewDir, urlPath } = mergeOptions({ 28 | directoriesConfig, 29 | pluginOptions: { outputDir: CUSTOM_OUTPUT_DIR }, 30 | }); 31 | 32 | t.is(outputDir, `_site/${CUSTOM_OUTPUT_DIR}`); 33 | t.is(previewDir, `_site/${CUSTOM_OUTPUT_DIR}/preview`); 34 | t.is(urlPath, CUSTOM_OUTPUT_DIR); 35 | }); 36 | -------------------------------------------------------------------------------- /test/og-test.og.njk: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | -------------------------------------------------------------------------------- /test/snapshots/OgImage.test.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/OgImage.test.js` 2 | 3 | The actual snapshot is saved in `OgImage.test.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## html returns html string 8 | 9 | > Snapshot 1 10 | 11 | `␊ 19 | ␊ 20 |
␊ 21 | ` 22 | 23 | ## svg returns svg string 24 | 25 | > Snapshot 1 26 | 27 | '' 28 | -------------------------------------------------------------------------------- /test/snapshots/OgImage.test.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiwiKilian/eleventy-plugin-og-image/8930e7bdfb7fdbe1c68ab6c9d57813f75c76d7fb/test/snapshots/OgImage.test.js.snap -------------------------------------------------------------------------------- /test/sortObject.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { sortObject } from '../src/utils/index.js'; 3 | 4 | test('sorts keys', (t) => { 5 | t.is( 6 | JSON.stringify({ 7 | a: 'a', 8 | b: { 9 | a: 'a', 10 | b: 'b', 11 | }, 12 | }), 13 | JSON.stringify( 14 | sortObject({ 15 | b: { 16 | b: 'b', 17 | a: 'a', 18 | }, 19 | a: 'a', 20 | }), 21 | ), 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /test/utils/directoriesConfig.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eleventy-plugin-og-image').DirectoriesConfig} */ 2 | export const directoriesConfig = { input: '.', includes: '_includes', data: '_data', output: '_site' }; 3 | -------------------------------------------------------------------------------- /test/utils/testConstructor.js: -------------------------------------------------------------------------------- 1 | import { directoriesConfig } from './directoriesConfig.js'; 2 | import { mergeOptions } from '../../src/utils/index.js'; 3 | 4 | export const testConstructor = { 5 | inputPath: './test/og-test.og.njk', 6 | data: undefined, 7 | options: mergeOptions({ 8 | directoriesConfig, 9 | }), 10 | templateConfig: undefined, 11 | }; 12 | --------------------------------------------------------------------------------