Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Add includeDimensions options #9

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ behaviour. If this is set to false, this behaviour is removed and URLs are no lo
allows to import images from `node_modules`. If this is disabled, local images can still be imported
by prepending the path with `./`.

### `includeDimensions`

It can be very useful to have the dimensions of images associated to the img tag. Including the image
size can avoid content shift. Toggle this option on to add height/width attributes to your tags when the images
are imported via relative import. You will also need to set `cwd` option for this to work

### `cwd`

The current working directory of the file being parsed. Used in combination with `includeDimensions` to load images
with their specific width/height attributes.

### License

[MIT](LICENSE.md) @ [Remco Haszing](https://github.com/remcohaszing)
32 changes: 32 additions & 0 deletions __fixtures__/size/expected.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*@jsxRuntime automatic @jsxImportSource react*/
import __0___image_png__ from './image.png';
function _createMdxContent(props) {
const _components = Object.assign(
{
p: 'p',
img: 'img',
},
props.components,
);
return (
<_components.p>
<_components.img
alt="Alt text"
src={__0___image_png__}
width="512"
height="512"
/>
</_components.p>
);
}
function MDXContent(props = {}) {
const { wrapper: MDXLayout } = props.components || {};
return MDXLayout ? (
<MDXLayout {...props}>
<_createMdxContent {...props} />
</MDXLayout>
) : (
_createMdxContent(props)
);
}
export default MDXContent;
Binary file added __fixtures__/size/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions __fixtures__/size/input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
![Alt text](./image.png)
4 changes: 4 additions & 0 deletions __fixtures__/size/options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"includeDimensions": true,
"imagesDirectory": "__fixtures__/size"
}
62 changes: 61 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { join } from 'path';

import { imageSize } from 'image-size';
import { Image, Parent, Root } from 'mdast';
import { MdxjsEsm, MdxJsxTextElement } from 'mdast-util-mdx';
import { Plugin } from 'unified';
Expand All @@ -13,20 +16,61 @@ export interface RemarkMdxImagesOptions {
* @default true
*/
resolve?: boolean;
/**
* Adds the width and height attributes to the image tag.
*
* @default false
*/
includeDimensions?: boolean;
/**
* The current working directory of the file being parsed. Used in combination with
* `includeDimensions` to load images with their specific width/height attributes.
*/
cwd?: string;
}

// eslint-disable-next-line unicorn/no-unsafe-regex
const urlPattern = /^(https?:)?\//;
const relativePathPattern = /\.\.?\//;
// eslint-disable-next-line unicorn/no-unsafe-regex
const absolutePathRegex = /^(?:[a-z]+:)?\/\//;

/**
* Gets the size of the image.
*
* @param src The image source.
* @returns the image dimensions
*/
function getImageSize(src: string):
| {
/**
* Width of the image.
*/
width?: number;
/**
* Height of the image.
*/
height?: number;
}
| undefined {
if (absolutePathRegex.test(src)) {
return undefined;
}

return imageSize(src);
}

/**
* A Remark plugin for converting Markdown images to MDX images using imports for the image source.
*/
const remarkMdxImages: Plugin<[RemarkMdxImagesOptions?], Root> =
({ resolve = true } = {}) =>
({ cwd, includeDimensions = false, resolve = true } = {}) =>
(ast) => {
const imports: MdxjsEsm[] = [];
const imported = new Map<string, string>();
if (includeDimensions && !cwd) {
throw new Error('The cwd option is required when includeDimensions is enabled.');
}

visit(ast, 'image', (node: Image, index: number | null, parent: Parent | null) => {
let { alt = null, title, url } = node;
Expand All @@ -38,6 +82,8 @@ const remarkMdxImages: Plugin<[RemarkMdxImagesOptions?], Root> =
}

let name = imported.get(url);
const size =
includeDimensions && imagesDirectory ? getImageSize(join(imagesDirectory, url)) : undefined;
if (!name) {
name = `__${imported.size}_${url.replace(/\W/g, '_')}__`;

Expand Down Expand Up @@ -93,6 +139,20 @@ const remarkMdxImages: Plugin<[RemarkMdxImagesOptions?], Root> =
if (title) {
textElement.attributes.push({ type: 'mdxJsxAttribute', name: 'title', value: title });
}
if (size?.width) {
textElement.attributes.push({
type: 'mdxJsxAttribute',
name: 'width',
value: String(size.width),
});
}
if (size?.height) {
textElement.attributes.push({
type: 'mdxJsxAttribute',
name: 'height',
value: String(size.height),
});
}
parent!.children.splice(index!, 1, textElement);
});
ast.children.unshift(...imports);
Expand Down
45 changes: 28 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
"dependencies": {
"@types/mdast": "^3.0.0",
"image-size": "^1.0.2",
"unified": "^10.0.0",
"unist-util-visit": "^4.0.0"
},
Expand Down