Skip to content

Commit

Permalink
Markdown and MDX configuration rework (#5684)
Browse files Browse the repository at this point in the history
* feat: change extendDefaults -> gfm

* deps: remove smartypants from md/remark

* tests: update markdown plugin tests

* fix: borked lockfile

* feat: allow all Markdown options in MDX config, with extend

* deps: remove smartypants from MDX

* chore: remove unused `mode` property

* chore: remark rehype types

* chore: dead code

* fix: order of default config properties

* refactor: move md defaults to remark

* fix: RemarkRehype type

* fix: apply defaults based on MD defaults

* chore: update plugin tests

* chore: add syntaxHighlight test

* refactor: remove drafts from config defaults

* docs: new MDX config options

* chore: add changeset

* edit: test both extends for syntax highlight

* refactor: remove MDX config deep merge

* docs: update README and changeset

* edit: avoid -> disable

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* edit: `drafts` clarification

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* edit: remove "scare quotes"

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* docs: MDX config options redraft

* docs: add migration

* chore: changeset heading levels

* refactor: githubFlavoredMarkdown -> gfm

* chore: remove unused imports

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
  • Loading branch information
bholmesdev and sarah11918 committed Jan 3, 2023
1 parent 163a9a9 commit a9c2920
Show file tree
Hide file tree
Showing 14 changed files with 2,194 additions and 1,671 deletions.
63 changes: 63 additions & 0 deletions .changeset/shaggy-keys-turn.md
@@ -0,0 +1,63 @@
---
'astro': major
'@astrojs/markdown-remark': major
'@astrojs/mdx': minor
---

Refine Markdown and MDX configuration options for ease-of-use.

#### Markdown

- **Remove `remark-smartypants`** from Astro's default Markdown plugins.
- **Replace the `extendDefaultPlugins` option** with a simplified `gfm` boolean. This is enabled by default, and can be disabled to remove GitHub-Flavored Markdown.
- Ensure GitHub-Flavored Markdown is applied whether or not custom `remarkPlugins` or `rehypePlugins` are configured. If you want to apply custom plugins _and_ remove GFM, manually set `gfm: false` in your config.

#### MDX

- Support _all_ Markdown configuration options (except `drafts`) from your MDX integration config. This includes `syntaxHighlighting` and `shikiConfig` options to further customize the MDX renderer.
- Simplify `extendDefaults` to an `extendMarkdownConfig` option. MDX options will default to their equivalent in your Markdown config. By setting `extendMarkdownConfig` to false, you can "eject" to set your own syntax highlighting, plugins, and more.

#### Migration

To preserve your existing Markdown and MDX setup, you may need some configuration changes:

##### Smartypants manual installation

[Smartypants](https://github.com/silvenon/remark-smartypants) has been removed from Astro's default setup. If you rely on this plugin, [install `remark-smartypants`](https://github.com/silvenon/remark-smartypants#installing) and apply to your `astro.config.*`:

```diff
// astro.config.mjs
import { defineConfig } from 'astro/config';
+ import smartypants from 'remark-smartypants';

export default defineConfig({
markdown: {
+ remarkPlugins: [smartypants],
}
});
```

##### Migrate `extendDefaultPlugins` to `gfm`

You may have disabled Astro's built-in plugins (GitHub-Flavored Markdown and Smartypants) with the `extendDefaultPlugins` option. Since Smartypants has been removed, this has been renamed to `gfm`.

```diff
// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
markdown: {
- extendDefaultPlugins: false,
+ gfm: false,
}
});
```


Additionally, applying remark and rehype plugins **no longer disables** `gfm`. You will need to opt-out manually by setting `gfm` to `false`.

##### Migrate MDX's `extendPlugins` to `extendMarkdownConfig`

You may have used the `extendPlugins` option to manage plugin defaults in MDX. This has been replaced by 2 flags:
- `extendMarkdownConfig` (`true` by default) to toggle Markdown config inheritance. This replaces the `extendPlugins: 'markdown'` option.
- `gfm` (`true` by default) to toggle GitHub-Flavored Markdown in MDX. This replaces the `extendPlugins: 'defaults'` option.
20 changes: 5 additions & 15 deletions packages/astro/src/@types/astro.ts
Expand Up @@ -734,10 +734,6 @@ export interface AstroUserConfig {
* @description
* Pass [remark plugins](https://github.com/remarkjs/remark) to customize how your Markdown is built. You can import and apply the plugin function (recommended), or pass the plugin name as a string.
*
* :::caution
* Providing a list of plugins will **remove** our default plugins. To preserve these defaults, see the [`extendDefaultPlugins`](#markdownextenddefaultplugins) flag.
* :::
*
* ```js
* import remarkToc from 'remark-toc';
* {
Expand All @@ -755,10 +751,6 @@ export interface AstroUserConfig {
* @description
* Pass [rehype plugins](https://github.com/remarkjs/remark-rehype) to customize how your Markdown's output HTML is processed. You can import and apply the plugin function (recommended), or pass the plugin name as a string.
*
* :::caution
* Providing a list of plugins will **remove** our default plugins. To preserve these defaults, see the [`extendDefaultPlugins`](#markdownextenddefaultplugins) flag.
* :::
*
* ```js
* import rehypeMinifyHtml from 'rehype-minify';
* {
Expand All @@ -771,23 +763,21 @@ export interface AstroUserConfig {
rehypePlugins?: RehypePlugins;
/**
* @docs
* @name markdown.extendDefaultPlugins
* @name markdown.gfm
* @type {boolean}
* @default `false`
* @default `true`
* @description
* Astro applies the [GitHub-flavored Markdown](https://github.com/remarkjs/remark-gfm) and [Smartypants](https://github.com/silvenon/remark-smartypants) plugins by default. When adding your own remark or rehype plugins, you can preserve these defaults by setting the `extendDefaultPlugins` flag to `true`:
* Astro uses [GitHub-flavored Markdown](https://github.com/remarkjs/remark-gfm) by default. To disable this, set the `gfm` flag to `false`:
*
* ```js
* {
* markdown: {
* extendDefaultPlugins: true,
* remarkPlugins: [exampleRemarkPlugin],
* rehypePlugins: [exampleRehypePlugin],
* gfm: false,
* }
* }
* ```
*/
extendDefaultPlugins?: boolean;
gfm?: boolean;
/**
* @docs
* @name markdown.remarkRehype
Expand Down
13 changes: 3 additions & 10 deletions packages/astro/src/core/config/schema.ts
@@ -1,4 +1,5 @@
import type { RehypePlugin, RemarkPlugin, RemarkRehype } from '@astrojs/markdown-remark';
import { markdownConfigDefaults } from '@astrojs/markdown-remark';
import type * as Postcss from 'postcss';
import type { ILanguageRegistration, IThemeRegistration, Theme } from 'shiki';
import type { AstroUserConfig, ViteUserConfig } from '../../@types/astro';
Expand Down Expand Up @@ -33,15 +34,7 @@ const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = {
integrations: [],
markdown: {
drafts: false,
syntaxHighlight: 'shiki',
shikiConfig: {
langs: [],
theme: 'github-dark',
wrap: false,
},
remarkPlugins: [],
rehypePlugins: [],
remarkRehype: {},
...markdownConfigDefaults,
},
vite: {},
legacy: {
Expand Down Expand Up @@ -184,7 +177,7 @@ export const AstroConfigSchema = z.object({
.custom<RemarkRehype>((data) => data instanceof Object && !Array.isArray(data))
.optional()
.default(ASTRO_CONFIG_DEFAULTS.markdown.remarkRehype),
extendDefaultPlugins: z.boolean().default(false),
gfm: z.boolean().default(ASTRO_CONFIG_DEFAULTS.markdown.gfm),
})
.default({}),
vite: z
Expand Down
34 changes: 28 additions & 6 deletions packages/astro/test/astro-markdown-plugins.test.js
Expand Up @@ -46,29 +46,51 @@ describe('Astro Markdown plugins', () => {
expect($('#hello-world').hasClass('title')).to.equal(true);
});

for (const extendDefaultPlugins of [true, false]) {
it(`Handles default plugins when extendDefaultPlugins = ${extendDefaultPlugins}`, async () => {
// Asserts Astro 1.0 behavior is removed. Test can be removed in Astro 3.0.
it('Still applies GFM when user plugins are provided', async () => {
const fixture = await buildFixture({
markdown: {
remarkPlugins: [remarkExamplePlugin],
rehypePlugins: [[addClasses, { 'h1,h2,h3': 'title' }]],
},
});
const html = await fixture.readFile('/with-gfm/index.html');
const $ = cheerio.load(html);

// test 1: GFM autolink applied correctly
expect($('a[href="https://example.com"]')).to.have.lengthOf(1);

// test 2: remark plugins still applied
expect(html).to.include('Remark plugin applied!');

// test 3: rehype plugins still applied
expect($('#github-flavored-markdown-test')).to.have.lengthOf(1);
expect($('#github-flavored-markdown-test').hasClass('title')).to.equal(true);
});

for (const gfm of [true, false]) {
it(`Handles GFM when gfm = ${gfm}`, async () => {
const fixture = await buildFixture({
markdown: {
remarkPlugins: [remarkExamplePlugin],
rehypePlugins: [[addClasses, { 'h1,h2,h3': 'title' }]],
extendDefaultPlugins,
gfm,
},
});
const html = await fixture.readFile('/with-gfm/index.html');
const $ = cheerio.load(html);

// test 1: GFM autolink applied correctly
if (extendDefaultPlugins === true) {
if (gfm === true) {
expect($('a[href="https://example.com"]')).to.have.lengthOf(1);
} else {
expect($('a[href="https://example.com"]')).to.have.lengthOf(0);
}

// test 2: (sanity check) remark plugins still applied
// test 2: remark plugins still applied
expect(html).to.include('Remark plugin applied!');

// test 3: (sanity check) rehype plugins still applied
// test 3: rehype plugins still applied
expect($('#github-flavored-markdown-test')).to.have.lengthOf(1);
expect($('#github-flavored-markdown-test').hasClass('title')).to.equal(true);
});
Expand Down
156 changes: 70 additions & 86 deletions packages/integrations/mdx/README.md
Expand Up @@ -78,116 +78,100 @@ Visit the [MDX docs](https://mdxjs.com/docs/what-is-mdx/) to learn about using s

Once the MDX integration is installed, no configuration is necessary to use `.mdx` files in your Astro project.

You can extend how your MDX is rendered by adding remark, rehype and recma plugins.
You can configure how your MDX is rendered with the following options:

- [`extendPlugins`](#extendplugins)
- [`remarkRehype`](#remarkrehype)
- [`remarkPlugins`](#remarkplugins)
- [`rehypePlugins`](#rehypeplugins)
- [Options inherited from Markdown config](#options-inherited-from-markdown-config)
- [`extendMarkdownConfig`](#extendmarkdownconfig)
- [`recmaPlugins`](#recmaplugins)

### `extendPlugins`
### Options inherited from Markdown config

You can customize how MDX files inherit your project’s existing Markdown configuration using the `extendPlugins` option.
All [`markdown` configuration options](https://docs.astro.build/en/reference/configuration-reference/#markdown-options) except `drafts` can be configured separately in the MDX integration. This includes remark and rehype plugins, syntax highlighting, and more. Options will default to those in your Markdown config ([see the `extendMarkdownConfig` option](#extendmarkdownconfig) to modify this).

#### `markdown` (default)
:::note
There is no separate MDX configuration for [including pages marked as draft in the build](https://docs.astro.build/en/reference/configuration-reference/#markdowndrafts). This Markdown setting will be respected by both Markdown and MDX files and cannot be overriden for MDX files specifically.
:::

Astro's MDX files will inherit all [`markdown` options](https://docs.astro.build/en/reference/configuration-reference/#markdown-options) in your Astro configuration file, which includes the [GitHub-Flavored Markdown](https://github.com/remarkjs/remark-gfm) and [Smartypants](https://github.com/silvenon/remark-smartypants) plugins by default.

Any additional plugins you apply in your MDX config will be applied *after* your configured Markdown plugins.

#### `astroDefaults`

Astro's MDX files will apply only [Astro's default plugins](/en/reference/configuration-reference/#markdownextenddefaultplugins), without inheriting the rest of your Markdown config.

This example will apply the default [GitHub-Flavored Markdown](https://github.com/remarkjs/remark-gfm) and [Smartypants](https://github.com/silvenon/remark-smartypants) plugins alongside [`remark-toc`](https://github.com/remarkjs/remark-toc) to your MDX files, while ignoring any `markdown.remarkPlugins` configuration:

```js "extendPlugins: 'astroDefaults'"
```ts
// astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import remarkToc from 'remark-toc';
import rehypeMinifyHtml from 'rehype-minify-html';

export default {
markdown: {
remarkPlugins: [/** ignored */]
},
integrations: [mdx({
remarkPlugins: [remarkToc],
// Astro defaults applied
extendPlugins: 'astroDefaults',
})],
}
export default defineConfig({
integrations: [
mdx({
syntaxHighlight: 'shiki',
shikiConfig: { theme: 'dracula' },
remarkPlugins: [remarkToc],
rehypePlugins: [rehypeMinifyHtml],
remarkRehype: { footnoteLabel: 'Footnotes' },
gfm: false,
})
]
})
```

#### `false`
:::caution
MDX does not support passing remark and rehype plugins as a string. You should install, import, and apply the plugin function instead.
:::

Astro's MDX files will not inherit any [`markdown` options](https://docs.astro.build/en/reference/configuration-reference/#markdown-options), nor will any Astro Markdown defaults be applied:
📚 See the [Markdown Options reference](https://docs.astro.build/en/reference/configuration-reference/#markdown-options) for a complete list of options.

```js "extendPlugins: false"
// astro.config.mjs
import remarkToc from 'remark-toc';

export default {
integrations: [mdx({
remarkPlugins: [remarkToc],
// Astro defaults not applied
extendPlugins: false,
})],
}
```
### `extendMarkdownConfig`

### `remarkRehype`
- **Type:** `boolean`
- **Default:** `true`

Markdown content is transformed into HTML through remark-rehype which has [a number of options](https://github.com/remarkjs/remark-rehype#options).
MDX will extend [your project's existing Markdown configuration](https://docs.astro.build/en/reference/configuration-reference/#markdown-options) by default. To override individual options, you can specify their equivalent in your MDX configuration.

You can set remark-rehype options in your config file:
For example, say you need to disable GitHub-Flavored Markdown and apply a different set of remark plugins for MDX files. You can apply these options like so, with `extendMarkdownConfig` enabled by default:

```js
```ts
// astro.config.mjs
export default {
integrations: [mdx({
remarkRehype: {
footnoteLabel: 'Catatan kaki',
footnoteBackLabel: 'Kembali ke konten',
},
})],
};
```
This inherits the configuration of [`markdown.remarkRehype`](https://docs.astro.build/en/reference/configuration-reference/#markdownremarkrehype). This behavior can be changed by configuring `extendPlugins`.

### `remarkPlugins`

Browse [awesome-remark](https://github.com/remarkjs/awesome-remark) for a full curated list of [remark plugins](https://github.com/remarkjs/remark/blob/main/doc/plugins.md) to extend your Markdown's capabilities.

This example applies the [`remark-toc`](https://github.com/remarkjs/remark-toc) plugin to `.mdx` files. To customize plugin inheritance from your Markdown config or Astro's defaults, [see the `extendPlugins` option](#extendplugins).

```js
// astro.config.mjs
import remarkToc from 'remark-toc';
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default {
integrations: [mdx({
remarkPlugins: [remarkToc],
})],
}
export default defineConfig({
markdown: {
syntaxHighlight: 'prism',
remarkPlugins: [remarkPlugin1],
gfm: true,
},
integrations: [
mdx({
// `syntaxHighlight` inherited from Markdown

// Markdown `remarkPlugins` ignored,
// only `remarkPlugin2` applied.
remarkPlugins: [remarkPlugin2],
// `gfm` overridden to `false`
gfm: false,
})
]
});
```

### `rehypePlugins`

Browse [awesome-rehype](https://github.com/rehypejs/awesome-rehype) for a full curated list of [Rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md) to transform the HTML that your Markdown generates.
You may also need to disable `markdown` config extension in MDX. For this, set `extendMarkdownConfig` to `false`:

We apply our own (non-removable) [`collect-headings`](https://github.com/withastro/astro/blob/main/packages/integrations/mdx/src/rehype-collect-headings.ts) plugin. This applies IDs to all headings (i.e. `h1 -> h6`) in your MDX files to [link to headings via anchor tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#linking_to_an_element_on_the_same_page).

This example applies the [`rehype-accessible-emojis`](https://www.npmjs.com/package/rehype-accessible-emojis) plugin to `.mdx` files. To customize plugin inheritance from your Markdown config or Astro's defaults, [see the `extendPlugins` option](#extendplugins).

```js
```ts
// astro.config.mjs
import rehypeAccessibleEmojis from 'rehype-accessible-emojis';
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default {
integrations: [mdx({
rehypePlugins: [rehypeAccessibleEmojis],
})],
}
export default defineConfig({
markdown: {
remarkPlugins: [remarkPlugin1],
},
integrations: [
mdx({
// Markdown config now ignored
extendMarkdownConfig: false,
// No `remarkPlugins` applied
})
]
});
```

### `recmaPlugins`
Expand Down
1 change: 0 additions & 1 deletion packages/integrations/mdx/package.json
Expand Up @@ -43,7 +43,6 @@
"rehype-raw": "^6.1.1",
"remark-frontmatter": "^4.0.1",
"remark-gfm": "^3.0.1",
"remark-smartypants": "^2.0.0",
"shiki": "^0.11.1",
"unist-util-visit": "^4.1.0",
"vfile": "^5.3.2"
Expand Down

0 comments on commit a9c2920

Please sign in to comment.