From f72b6a70ed59114d2bd718bc66594799031f4558 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 12 Apr 2023 14:16:31 +0200 Subject: [PATCH 1/6] initial esm docs --- .../how-to/custom-configuration/es-modules.md | 56 +++++++++++++++++++ .../reference/config-files/gatsby-config.md | 4 +- .../reference/config-files/gatsby-node.md | 4 +- 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 docs/docs/how-to/custom-configuration/es-modules.md diff --git a/docs/docs/how-to/custom-configuration/es-modules.md b/docs/docs/how-to/custom-configuration/es-modules.md new file mode 100644 index 0000000000000..fb38897dd3213 --- /dev/null +++ b/docs/docs/how-to/custom-configuration/es-modules.md @@ -0,0 +1,56 @@ +--- +title: ES Modules (ESM) and Gatsby +examples: + - label: Using MDX + href: "https://github.com/gatsbyjs/gatsby/tree/master/examples/using-mdx" +--- + +## Introduction + +The ECMAScript module (ESM) format is the [official TC39 standard](https://tc39.es/ecma262/#sec-modules) for packaging JavaScript. For many years, [CommonJS (CJS)](https://nodejs.org/api/modules.html#modules-commonjs-modules) was the de facto standard in Node.js. You can author [`gatsby-config`](/docs/reference/config-files/gatsby-config/) and [`gatsby-node`](/docs/reference/config-files/gatsby-node/) in ESM syntax. + +This feature was added in `gatsby@5.3.0`. + +## Prerequisites + +- A Gatsby project set up with `gatsby@5.3.0` or later. (Need help creating one? Follow the [Quick Start](/docs/quick-start/)) + +## Usage in Gatsby + +Generally speaking you need to follow the official standard as explained in the [Node.js documentation](https://nodejs.org/api/esm.html). + +### `gatsby-config` + +Create a `gatsby-config.mjs` file. Here's an example `gatsby-config` using ESM syntax: + +```js:title=gatsby-config.mjs +const config = { + siteMetadata: { + title: `ESM in Gatsby`, + }, +} + +export default config +``` + +### `gatsby-node` + +Create a `gatsby-node.mjs` file and use any of the [Node APIs](/docs/reference/config-files/gatsby-node/) as usual. Here's an example `gatsby-node` using ESM syntax: + +```js:title=gatsby-node.mjs +export const onPostBuild = () => { + console.log("Build is done!") +} +``` + +## Migrating from CommonJS to ES Modules + +The documents [Interopability with CommonJS](https://nodejs.org/api/esm.html#interoperability-with-commonjs) and [Differences between ES Modules and CommonJS](https://nodejs.org/api/esm.html#differences-between-es-modules-and-commonjs) also apply to ESM in Gatsby. + +## Current limitations + +- The TypeScript variants of `gatsby-config` and `gatsby-node` do **not** support ESM yet. We plan on adding support in a future minor release by using the `.mts` extension. If you have questions or suggestions about this, please go to our [ESM in Gatsby files](https://github.com/gatsbyjs/gatsby/discussions/37069) umbrella discussion. + + However, you can use [Type Hinting](/docs/how-to/custom-configuration/typescript/#type-hinting-in-js-files) in the meantime. + +The [ESM in Gatsby files](https://github.com/gatsbyjs/gatsby/discussions/37069) umbrella discussion is also the right place for any questions about the `.mjs` usage. diff --git a/docs/docs/reference/config-files/gatsby-config.md b/docs/docs/reference/config-files/gatsby-config.md index af14ce52b8922..782d0479fdb28 100644 --- a/docs/docs/reference/config-files/gatsby-config.md +++ b/docs/docs/reference/config-files/gatsby-config.md @@ -2,7 +2,7 @@ title: Gatsby Config API --- -The file `gatsby-config.js`/`gatsby-config.ts` defines your site's metadata, plugins, and other general configuration. This file should be in the root of your Gatsby site. You can author the file in JavaScript or [TypeScript](/docs/how-to/custom-configuration/typescript/#gatsby-configts). +The file `gatsby-config.js`/`gatsby-config.ts` defines your site's metadata, plugins, and other general configuration. This file should be in the root of your Gatsby site. You can author the file in JavaScript (CommonJS or [ES Modules (ESM)](/docs/how-to/custom-configuration/es-modules/) syntax) or [TypeScript](/docs/how-to/custom-configuration/typescript/#gatsby-configts). If you created a Gatsby site with the `npm init gatsby` command, there should already be a sample configuration file in your site's directory. _Note: There are many sample configs which may be helpful to reference in the different [Gatsby Example Websites](https://github.com/gatsbyjs/gatsby/tree/master/examples)._ @@ -39,6 +39,8 @@ module.exports = { The [TypeScript and Gatsby documentation](/docs/how-to/custom-configuration/typescript/#gatsby-configts) shows how to set up a configuration file in TypeScript. +Read the [ES Modules (ESM) and Gatsby documentation](/docs/how-to/custom-configuration/es-modules/) if you don't want to use CommonJS syntax. + ## Configuration options Options available to set within `gatsby-config.js` include: diff --git a/docs/docs/reference/config-files/gatsby-node.md b/docs/docs/reference/config-files/gatsby-node.md index bd1b36c120017..ee4a51d9077db 100644 --- a/docs/docs/reference/config-files/gatsby-node.md +++ b/docs/docs/reference/config-files/gatsby-node.md @@ -9,7 +9,7 @@ apiCalls: NodeAPI Gatsby gives plugins and site builders many APIs for building your site. Code in the file `gatsby-node.js`/`gatsby-node.ts` is run once in the process of building your site. You can use its APIs to create pages dynamically, add data into GraphQL, or respond to events during the build lifecycle. To use the [Gatsby Node APIs](/docs/reference/config-files/gatsby-node/), create a file named `gatsby-node.js`/`gatsby-node.ts` in the root of your site. Export any of the APIs you wish to use in this file. -You can author the file in JavaScript or [TypeScript](/docs/how-to/custom-configuration/typescript/#gatsby-nodets). +You can author the file in JavaScript (CommonJS or [ES Modules (ESM)](/docs/how-to/custom-configuration/es-modules/) syntax) or [TypeScript](/docs/how-to/custom-configuration/typescript/#gatsby-nodets). Every Gatsby Node API gets passed a [set of helper functions](/docs/reference/config-files/node-api-helpers/). These let you access several methods like reporting, or perform actions like creating new pages. @@ -51,6 +51,8 @@ exports.createPages = async ({ graphql, actions }) => { The [TypeScript and Gatsby documentation](/docs/how-to/custom-configuration/typescript/#gatsby-nodets) shows how to set up a `gatsby-node` file in TypeScript. +Read the [ES Modules (ESM) and Gatsby documentation](/docs/how-to/custom-configuration/es-modules/) if you don't want to use CommonJS syntax. + ## Async vs. sync work If your plugin performs async operations (disk I/O, database access, calling remote APIs, etc.) you must either return a promise (explicitly using `Promise` API or implicitly using `async`/`await` syntax) or use the callback passed to the 3rd argument. Gatsby needs to know when plugins are finished as some APIs, to work correctly, require previous APIs to be complete first. See [Debugging Async Lifecycles](/docs/debugging-async-lifecycles/) for more info. From d8b185176f0cf89612636faa7df07545984e0fc6 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 12 Apr 2023 14:44:07 +0200 Subject: [PATCH 2/6] more docs --- .../how-to/custom-configuration/es-modules.md | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/docs/docs/how-to/custom-configuration/es-modules.md b/docs/docs/how-to/custom-configuration/es-modules.md index fb38897dd3213..6bcfeaf4ae8cd 100644 --- a/docs/docs/how-to/custom-configuration/es-modules.md +++ b/docs/docs/how-to/custom-configuration/es-modules.md @@ -45,8 +45,106 @@ export const onPostBuild = () => { ## Migrating from CommonJS to ES Modules +- Use `import`/`export` syntax instead of `require`/`module.exports` +- You can replicate the `__dirname` call with `import.meta.url`: + + ```js + import { dirname } from "path" + import { fileURLToPath } from "url" + + const __dirname = dirname(fileURLToPath(import.meta.url)) + ``` + +- You can replicate `require.resolve` with `createRequire`: + + ```js + import { createRequire } from "module" + + const require = createRequire(import.meta.url) + ``` + The documents [Interopability with CommonJS](https://nodejs.org/api/esm.html#interoperability-with-commonjs) and [Differences between ES Modules and CommonJS](https://nodejs.org/api/esm.html#differences-between-es-modules-and-commonjs) also apply to ESM in Gatsby. +Here's how you'd migrate a `gatsby-config.js` file to `gatsby-config.mjs`. + +**Before:** + +```js:title=gatsby-config.js +module.exports = { + siteMetadata: { + title: `Using CJS`, + }, + plugins: [ + { + resolve: `gatsby-source-filesystem`, + options: { + name: `posts`, + path: `${__dirname}/content/posts/`, + }, + }, + { + resolve: `gatsby-source-filesystem`, + options: { + name: `images`, + path: require.resolve(`./content/images`), + }, + }, + { + resolve: `gatsby-plugin-mdx`, + options: { + mdxOptions: { + remarkPlugins: [require(`remark-gfm`)], + }, + }, + }, + ], +} +``` + +**After:** + +```js:title=gatsby-config.mjs +import { createRequire } from "module" +import { dirname } from "path" +import { fileURLToPath } from "url" +import remarkGfm from "remark-gfm" + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const require = createRequire(import.meta.url) + +const config = { + siteMetadata: { + title: `Using ESM`, + }, + plugins: [ + { + resolve: `gatsby-source-filesystem`, + options: { + name: `posts`, + path: `${__dirname}/content/posts/`, + }, + }, + { + resolve: `gatsby-source-filesystem`, + options: { + name: `images`, + path: require.resolve(`./content/images`), + }, + }, + { + resolve: `gatsby-plugin-mdx`, + options: { + mdxOptions: { + remarkPlugins: [remarkGfm], + }, + }, + }, + ], +} + +export default config +``` + ## Current limitations - The TypeScript variants of `gatsby-config` and `gatsby-node` do **not** support ESM yet. We plan on adding support in a future minor release by using the `.mts` extension. If you have questions or suggestions about this, please go to our [ESM in Gatsby files](https://github.com/gatsbyjs/gatsby/discussions/37069) umbrella discussion. From 9559d32d8c5e6db8d8d73aba4b50d61bd765d579 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 12 Apr 2023 14:52:11 +0200 Subject: [PATCH 3/6] docs --- docs/docs/how-to/custom-configuration/es-modules.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/docs/how-to/custom-configuration/es-modules.md b/docs/docs/how-to/custom-configuration/es-modules.md index 6bcfeaf4ae8cd..d6587ea5748c6 100644 --- a/docs/docs/how-to/custom-configuration/es-modules.md +++ b/docs/docs/how-to/custom-configuration/es-modules.md @@ -46,6 +46,7 @@ export const onPostBuild = () => { ## Migrating from CommonJS to ES Modules - Use `import`/`export` syntax instead of `require`/`module.exports` +- File extensions in imports are [mandatory](https://nodejs.org/api/esm.html#mandatory-file-extensions) - You can replicate the `__dirname` call with `import.meta.url`: ```js @@ -70,9 +71,12 @@ Here's how you'd migrate a `gatsby-config.js` file to `gatsby-config.mjs`. **Before:** ```js:title=gatsby-config.js +const { siteUrl } = require(`./defaults`) + module.exports = { siteMetadata: { title: `Using CJS`, + siteUrl, }, plugins: [ { @@ -108,6 +112,7 @@ import { createRequire } from "module" import { dirname } from "path" import { fileURLToPath } from "url" import remarkGfm from "remark-gfm" +import { siteUrl } from "./defaults.mjs" const __dirname = dirname(fileURLToPath(import.meta.url)) const require = createRequire(import.meta.url) @@ -115,6 +120,7 @@ const require = createRequire(import.meta.url) const config = { siteMetadata: { title: `Using ESM`, + siteUrl, }, plugins: [ { From f6bacbe132579a790d05722277ea06b9dec6355e Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 12 Apr 2023 14:52:19 +0200 Subject: [PATCH 4/6] migrate using-mdx example --- .../{gatsby-config.js => gatsby-config.mjs} | 15 ++++++++---- .../{gatsby-node.js => gatsby-node.mjs} | 16 ++++++------- examples/using-mdx/package.json | 15 ++++++------ examples/using-mdx/remark-headings-plugin.js | 22 ----------------- examples/using-mdx/remark-headings-plugin.mjs | 24 +++++++++++++++++++ 5 files changed, 49 insertions(+), 43 deletions(-) rename examples/using-mdx/{gatsby-config.js => gatsby-config.mjs} (77%) rename examples/using-mdx/{gatsby-node.js => gatsby-node.mjs} (86%) delete mode 100644 examples/using-mdx/remark-headings-plugin.js create mode 100644 examples/using-mdx/remark-headings-plugin.mjs diff --git a/examples/using-mdx/gatsby-config.js b/examples/using-mdx/gatsby-config.mjs similarity index 77% rename from examples/using-mdx/gatsby-config.js rename to examples/using-mdx/gatsby-config.mjs index 1bb7b9065af4c..f3fe7bdb6bc0b 100644 --- a/examples/using-mdx/gatsby-config.js +++ b/examples/using-mdx/gatsby-config.mjs @@ -1,7 +1,13 @@ +import remarkGfm from "remark-gfm" +import { dirname } from "path" +import { fileURLToPath } from "url" + +const __dirname = dirname(fileURLToPath(import.meta.url)) + /** * @type {import('gatsby').GatsbyConfig} */ -module.exports = { +const config = { siteMetadata: { title: `Using MDX example`, description: `Kick off your next, great Gatsby project with MDX.`, @@ -27,10 +33,7 @@ module.exports = { resolve: `gatsby-plugin-mdx`, options: { mdxOptions: { - remarkPlugins: [ - require(`remark-gfm`), - require(`remark-unwrap-images`), - ], + remarkPlugins: [remarkGfm], }, gatsbyRemarkPlugins: [ { @@ -44,3 +47,5 @@ module.exports = { }, ], } + +export default config diff --git a/examples/using-mdx/gatsby-node.js b/examples/using-mdx/gatsby-node.mjs similarity index 86% rename from examples/using-mdx/gatsby-node.js rename to examples/using-mdx/gatsby-node.mjs index 5c7c81faced32..efe63656393f8 100644 --- a/examples/using-mdx/gatsby-node.js +++ b/examples/using-mdx/gatsby-node.mjs @@ -1,13 +1,13 @@ -const path = require("path") -const readingTime = require(`reading-time`) -const slugify = require(`@sindresorhus/slugify`) -const { compileMDXWithCustomOptions } = require(`gatsby-plugin-mdx`) -const { remarkHeadingsPlugin } = require(`./remark-headings-plugin`) +import path from "path" +import readingTime from "reading-time" +import slugify from "@sindresorhus/slugify" +import { compileMDXWithCustomOptions } from "gatsby-plugin-mdx" +import remarkHeadingsPlugin from "./remark-headings-plugin.mjs" /** * @type {import('gatsby').GatsbyNode['onCreateNode']} */ -exports.onCreateNode = ({ node, actions }) => { +export const onCreateNode = ({ node, actions }) => { const { createNodeField } = actions if (node.internal.type === `Mdx`) { createNodeField({ @@ -27,7 +27,7 @@ exports.onCreateNode = ({ node, actions }) => { /** * @type {import('gatsby').GatsbyNode['createSchemaCustomization']} */ -exports.createSchemaCustomization = async ({ getNode, getNodesByType, pathPrefix, reporter, cache, actions, schema, store }) => { +export const createSchemaCustomization = async ({ getNode, getNodesByType, pathPrefix, reporter, cache, actions, schema, store }) => { const { createTypes } = actions const headingsResolver = schema.buildObjectType({ @@ -91,7 +91,7 @@ exports.createSchemaCustomization = async ({ getNode, getNodesByType, pathPrefix /** * @type {import('gatsby').GatsbyNode['createPages']} */ -exports.createPages = async ({ graphql, actions, reporter }) => { +export const createPages = async ({ graphql, actions, reporter }) => { const { createPage } = actions const result = await graphql(` diff --git a/examples/using-mdx/package.json b/examples/using-mdx/package.json index 8812537bf2ec5..7f1fa2d82505a 100644 --- a/examples/using-mdx/package.json +++ b/examples/using-mdx/package.json @@ -5,22 +5,21 @@ "version": "0.0.1", "author": "LekoArts", "dependencies": { - "@mdx-js/react": "^2.1.2", - "@nivo/core": "0.78.0", - "@nivo/line": "0.78.0", - "@sindresorhus/slugify": "^1", + "@mdx-js/react": "^2.3.0", + "@nivo/core": "^0.80.0", + "@nivo/line": "^0.80.0", + "@sindresorhus/slugify": "^2.2.0", "gatsby": "next", "gatsby-plugin-mdx": "next", "gatsby-plugin-sharp": "next", "gatsby-remark-images": "next", "gatsby-source-filesystem": "next", - "mdast-util-to-string": "^2", + "mdast-util-to-string": "^3.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", "reading-time": "^1.5.0", - "remark-gfm": "^1", - "remark-unwrap-images": "^2", - "unist-util-visit": "^2" + "remark-gfm": "^3.0.1", + "unist-util-visit": "^4.1.2" }, "devDependencies": { "prettier": "^2.7.1" diff --git a/examples/using-mdx/remark-headings-plugin.js b/examples/using-mdx/remark-headings-plugin.js deleted file mode 100644 index 2bfd7d9a6d880..0000000000000 --- a/examples/using-mdx/remark-headings-plugin.js +++ /dev/null @@ -1,22 +0,0 @@ -const visit = require(`unist-util-visit`) -const toString = require(`mdast-util-to-string`) - -exports.remarkHeadingsPlugin = function remarkHeadingsPlugin() { - return async function transformer(tree, file) { - let headings = [] - - visit(tree, `heading`, heading => { - headings.push({ - value: toString(heading), - depth: heading.depth, - }) - }) - - const mdxFile = file - if (!mdxFile.data.meta) { - mdxFile.data.meta = {} - } - - mdxFile.data.meta.headings = headings - } -} diff --git a/examples/using-mdx/remark-headings-plugin.mjs b/examples/using-mdx/remark-headings-plugin.mjs new file mode 100644 index 0000000000000..041b3046d7a47 --- /dev/null +++ b/examples/using-mdx/remark-headings-plugin.mjs @@ -0,0 +1,24 @@ +import { visit } from "unist-util-visit" +import { toString } from "mdast-util-to-string" + +const transformer = (tree, file) => { + let headings = [] + + visit(tree, `heading`, heading => { + headings.push({ + value: toString(heading), + depth: heading.depth, + }) + }) + + const mdxFile = file + if (!mdxFile.data.meta) { + mdxFile.data.meta = {} + } + + mdxFile.data.meta.headings = headings +} + +const remarkHeadingsPlugin = () => transformer + +export default remarkHeadingsPlugin From 12a7f19865c7ce166f5331ce82ace54935b825bd Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 12 Apr 2023 15:12:55 +0200 Subject: [PATCH 5/6] update gatsby-plugin-mdx README --- packages/gatsby-plugin-mdx/README.md | 178 +++++++++++++-------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/packages/gatsby-plugin-mdx/README.md b/packages/gatsby-plugin-mdx/README.md index 2e0ae2082fcf1..57560302f6ad2 100644 --- a/packages/gatsby-plugin-mdx/README.md +++ b/packages/gatsby-plugin-mdx/README.md @@ -7,8 +7,6 @@ MDX is markdown for the component era. It lets you write JSX embedded inside mar
Table of contents -Table of contents - - [Installation](#installation) - [Usage](#usage) - [Configuration](#configuration) @@ -37,10 +35,21 @@ npm install gatsby-plugin-mdx gatsby-source-filesystem @mdx-js/react ## Usage -After installing `gatsby-plugin-mdx` you can add it to your plugins list in your `gatsby-config.js`. You'll also want to configure `gatsby-source-filesystem` to point at your `src/pages` directory. +> This README assumes you're using `gatsby@5.3.0` or later. If you're using an older Gatsby version or don't want to use ESM for your Gatsby files, refer to [this older version of the README](https://www.npmjs.com/package/gatsby-plugin-mdx/v/5.8.0). + +After installing `gatsby-plugin-mdx` you can add it to your plugins list in your `gatsby-config`. + +We highly **recommend** using [ES Modules (ESM)](https://www.gatsbyjs.com/docs/how-to/custom-configuration/es-modules/) syntax for your `gatsby-config` file as it'll enable you to use the latest packages from the `unified` ecosystem. + +You'll also want to configure `gatsby-source-filesystem` to point at your `src/pages` directory. -```js:title=gatsby-config.js -module.exports = { +```js:title=gatsby-config.mjs +import { dirname } from "path" +import { fileURLToPath } from "url" + +const __dirname = dirname(fileURLToPath(import.meta.url)) + +const config = { plugins: [ `gatsby-plugin-mdx`, { @@ -52,6 +61,8 @@ module.exports = { }, ], } + +export default config ``` By default, this configuration will allow you to automatically create pages with `.mdx` files in `src/pages`. @@ -66,8 +77,13 @@ If you have MDX files in another location than `src/pages` you'll need to add an To automatically create pages from MDX files outside of `src/pages` you'll need to configure `gatsby-plugin-page-creator` and `gatsby-source-filesystem` to point to this folder of files. -```js:title=gatsby-config.js -module.exports = { +```js:title=gatsby-config.mjs +import { dirname } from "path" +import { fileURLToPath } from "url" + +const __dirname = dirname(fileURLToPath(import.meta.url)) + +const config = { plugins: [ `gatsby-plugin-mdx`, { @@ -85,6 +101,8 @@ module.exports = { }, ], } + +export default config ``` Also check out the guide [Adding MDX Pages](https://www.gatsbyjs.com/docs/how-to/routing/mdx/) for more details. @@ -106,8 +124,8 @@ using `gatsby-source-filesystem`. To use `.md` or other file extensions, you can define an array of file extensions in the `gatsby-plugin-mdx` section of your `gatsby-config.js`. -```js:title=gatsby-config.js -module.exports = { +```js:title=gatsby-config.mjs +const config = { plugins: [ { resolve: `gatsby-plugin-mdx`, @@ -117,6 +135,8 @@ module.exports = { }, ], } + +export default config ``` ### `gatsby-remark-*` plugins @@ -125,8 +145,8 @@ This config option is used for compatibility with a set of plugins many people [ When using these `gatsby-remark-*` plugins, be sure to also install their required peer dependencies. You can find that information in their respective README. -```js:title=gatsby-config.js -module.exports = { +```js:title=gatsby-config.mjs +const config = { plugins: [ { resolve: `gatsby-plugin-mdx`, @@ -143,6 +163,8 @@ module.exports = { }, ], } + +export default config ``` Using a string reference is also supported for `gatsbyRemarkPlugins`. @@ -157,8 +179,13 @@ These configuration options are directly passed into the MDX compiler. See all available options in [the official documentation of `@mdx-js/mdx`](https://mdxjs.com/packages/mdx/#compilefile-options). -```js:title=gatsby-config.js -module.exports = { +```js:title=gatsby-config.mjs +import remarkGfm from "remark-gfm" +import remarkExternalLinks from "remark-external-links" +import rehypeSlug from "rehype-slug" +import rehypeAutolinkHeadings from "rehype-autolink-headings" + +const config = { plugins: [ { resolve: `gatsby-plugin-mdx`, @@ -166,61 +193,28 @@ module.exports = { mdxOptions: { remarkPlugins: [ // Add GitHub Flavored Markdown (GFM) support - require(`remark-gfm`), + remarkGfm, // To pass options, use a 2-element array with the // configuration in an object in the second element - [require(`remark-external-links`), { target: false }], + [remarkExternalLinks, { target: false }], ], rehypePlugins: [ // Generate heading ids for rehype-autolink-headings - require(`rehype-slug`), + rehypeSlug, // To pass options, use a 2-element array with the // configuration in an object in the second element - [require(`rehype-autolink-headings`), { behavior: `wrap` }], + [rehypeAutolinkHeadings, { behavior: `wrap` }], ], }, }, }, ], } -``` - -> The following note will be removed once Gatsby fully supports ESM - -**Please Note:** Most of the remark ecosystem is ESM which means that packages like `remark-gfm` currently don't work out of the box with Gatsby. You have two options until Gatsby fully supports ESM: -1. Use an older version of the `remark-*`/`rehype-*` package that is not ESM. Example: `remark-gfm` needs to be installed like this: `npm install remark-gfm@^1`. -1. Wrap the plugin with an async function (which doesn't work with every plugin): - - ```js - const wrapESMPlugin = name => - function wrapESM(opts) { - return async (...args) => { - const mod = await import(name) - const plugin = mod.default(opts) - return plugin(...args) - } - } - ``` +export default config +``` - You then can use it like this: - - ```js:title=gatsby-config.js - module.exports = { - plugins: [ - { - resolve: `gatsby-plugin-mdx`, - options: { - mdxOptions: { - rehypePlugins: [ - wrapESMPlugin(`rehype-slug`), - ], - }, - }, - }, - ], - } - ``` +**Please Note:** Most of the remark/rehype/unified ecosystem is published as ESM which means that you have to use [ES Modules (ESM) and Gatsby](https://www.gatsbyjs.com/docs/how-to/custom-configuration/es-modules/). ## Imports @@ -276,10 +270,10 @@ Use the [`createNodeField`](https://www.gatsbyjs.com/docs/reference/config-files ``` 1. In your `gatsby-node` add a new field: - ```js:title=gatsby-node.js - const readingTime = require(`reading-time`) + ```js:title=gatsby-node.mjs + import readingTime from "reading-time" - exports.onCreateNode = ({ node, actions }) => { + export const onCreateNode = ({ node, actions }) => { const { createNodeField } = actions if (node.internal.type === `Mdx`) { createNodeField({ @@ -315,16 +309,16 @@ See [timeToRead](#timeToRead). It returns `timeToRead.words`. This largely comes down to your own preference and how you want to wire things up. This here is one of many possible solutions to this: -1. Install `@sindresorhus/slugify` into your project (v1 as v2 is ESM-only): +1. Install `@sindresorhus/slugify` into your project: ```shell - npm install @sindresorhus/slugify@^1 + npm install @sindresorhus/slugify ``` 1. In your `gatsby-node` add a new field: - ```js:title=gatsby-node.js - const slugify = require(`@sindresorhus/slugify`) + ```js:title=gatsby-node.mjs + import slugify from "@sindresorhus/slugify" - exports.onCreateNode = ({ node, actions }) => { + export const onCreateNode = ({ node, actions }) => { const { createNodeField } = actions if (node.internal.type === `Mdx`) { createNodeField({ @@ -353,42 +347,44 @@ If you don't want to use the `frontmatter.title`, adjust what you input to `slug 1. Install necessary dependencies into your project: ```shell - npm install mdast-util-to-string@^2 unist-util-visit@^2 + npm install mdast-util-to-string unist-util-visit ``` -1. Create a new file called `remark-headings-plugin.js` at the site root: +1. Create a new file called `remark-headings-plugin.mjs` at the site root: - ```js - const visit = require(`unist-util-visit`) - const toString = require(`mdast-util-to-string`) + ```js:title=remark-headings-plugin.mjs + import { visit } from "unist-util-visit" + import { toString } from "mdast-util-to-string" - exports.remarkHeadingsPlugin = function remarkHeadingsPlugin() { - return async function transformer(tree, file) { - let headings = [] + const transformer = (tree, file) => { + let headings = [] - visit(tree, `heading`, heading => { - headings.push({ - value: toString(heading), - depth: heading.depth, - }) + visit(tree, `heading`, heading => { + headings.push({ + value: toString(heading), + depth: heading.depth, }) + }) - const mdxFile = file - if (!mdxFile.data.meta) { - mdxFile.data.meta = {} - } - - mdxFile.data.meta.headings = headings + const mdxFile = file + if (!mdxFile.data.meta) { + mdxFile.data.meta = {} } + + mdxFile.data.meta.headings = headings } + + const remarkHeadingsPlugin = () => transformer + + export default remarkHeadingsPlugin ``` 1. Add a new `headings` field resolver to your `Mdx` nodes through `createSchemaCustomization` API: - ```js:title=gatsby-node.js - const { compileMDXWithCustomOptions } = require(`gatsby-plugin-mdx`) - const { remarkHeadingsPlugin } = require(`./remark-headings-plugin`) + ```js:title=gatsby-node.mjs + import { compileMDXWithCustomOptions } from "gatsby-plugin-mdx" + import remarkHeadingsPlugin from "./remark-headings-plugin.mjs" - exports.createSchemaCustomization = async ({ getNode, getNodesByType, pathPrefix, reporter, cache, actions, schema, store }) => { + export const createSchemaCustomization = async ({ getNode, getNodesByType, pathPrefix, reporter, cache, actions, schema, store }) => { const { createTypes } = actions const headingsResolver = schema.buildObjectType({ @@ -571,8 +567,9 @@ If you used any related plugins like `gatsby-remark-images`, also update them to ### New options in `gatsby-config` - Move your `remarkPlugins` and `rehypePlugins` keys into the new `mdxOptions` config option: + ```diff - module.exports = { + const config = { plugins: [ { resolve: `gatsby-plugin-mdx`, @@ -587,7 +584,10 @@ If you used any related plugins like `gatsby-remark-images`, also update them to }, ], } + + export default config ``` + - There's a new option called `mdxOptions` which is passed directly to the MDX compiler. See all available options in [the official documentation of `@mdx-js/mdx`](https://mdxjs.com/packages/mdx/#compilefile-options). - Only `extensions`, `gatsbyRemarkPlugins`, and `mdxOptions` exist as options now. Every other option got removed, including `defaultLayouts`. See the [layouts guide](#layouts) to learn how to use layouts with `gatsby-plugin-mdx@^4.0.0`. - Make sure that any `gatsby-remark-*` plugins are only listed inside the `gatsbyRemarkPlugins` array of `gatsby-plugin-mdx`, not inside the `plugins` array of `gatsby-config` or in any other place. @@ -749,10 +749,10 @@ Here's an example of an updated query (if you re-implemented most features): Here's an example on how you'd alias your `fields` to keep the shape of the MDX node the same: -```js:title=gatsby-node.js -const readingTime = require(`reading-time`) +```js:title=gatsby-node.mjs +import readingTime from "reading-time" -exports.onCreateNode = ({ node, actions }) => { +export const onCreateNode = ({ node, actions }) => { const { createNodeField } = actions if (node.internal.type === `Mdx`) { createNodeField({ @@ -763,7 +763,7 @@ exports.onCreateNode = ({ node, actions }) => { } } -exports.createSchemaCustomization = ({ actions }) => { +export const createSchemaCustomization = ({ actions }) => { const { createTypes } = actions createTypes(`#graphql From 558aafbf32f912906457385cf2042a7d5bbfeb54 Mon Sep 17 00:00:00 2001 From: Lennart Date: Wed, 12 Apr 2023 16:02:59 +0200 Subject: [PATCH 6/6] use local plugin --- .../docs/how-to/custom-configuration/es-modules.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/docs/docs/how-to/custom-configuration/es-modules.md b/docs/docs/how-to/custom-configuration/es-modules.md index d6587ea5748c6..d2e0acc5f6c9f 100644 --- a/docs/docs/how-to/custom-configuration/es-modules.md +++ b/docs/docs/how-to/custom-configuration/es-modules.md @@ -87,11 +87,8 @@ module.exports = { }, }, { - resolve: `gatsby-source-filesystem`, - options: { - name: `images`, - path: require.resolve(`./content/images`), - }, + resolve: require.resolve("./local-plugin-with-path"), + options: {}, }, { resolve: `gatsby-plugin-mdx`, @@ -131,11 +128,8 @@ const config = { }, }, { - resolve: `gatsby-source-filesystem`, - options: { - name: `images`, - path: require.resolve(`./content/images`), - }, + resolve: require.resolve("./local-plugin-with-path"), + options: {}, }, { resolve: `gatsby-plugin-mdx`,