Skip to content

Commit

Permalink
Fix rewriting of components for custom elements
Browse files Browse the repository at this point in the history
This commit particularly solves elements names that include dashes: custom
elements, such as `custom-element-name`.
These can be written in JSX like so:

```jsx
<custom-element-name />
```

…which is fine.

But to support passing them in, we were previously rewriting such code to a
member id, to take a key from an object, like so:

```jsx
<_components.custom-element-name>
```

…which crashed.

This commit solves that by taking the component from the object in a temporary
variable, and using that valid variable name as a single component name.

```js
const _component0 = _components['custom-element-name']

<_component0 />
```

Closes GH-2100.
Closes GH-2101.

Co-authored-by: Titus Wormer <tituswormer@gmail.com>

Reviewed-by: Titus Wormer <tituswormer@gmail.com>
  • Loading branch information
bholmesdev authored Aug 17, 2022
1 parent 69a15b7 commit 9904838
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 11 deletions.
53 changes: 44 additions & 9 deletions packages/mdx/lib/plugin/recma-jsx-rewrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export function recmaJsxRewrite(options = {}) {
let createErrorHelper
/** @type {Scope|null} */
let currentScope
/** @type {Map<string | number, string>} */
const idToInvalidComponentName = new Map()

walk(tree, {
enter(_node) {
Expand Down Expand Up @@ -193,16 +195,24 @@ export function recmaJsxRewrite(options = {}) {
fnScope.tags.push(id)
}

node.openingElement.name = toJsxIdOrMemberExpression([
'_components',
id
])
/** @type {Array<string | number>} */
let jsxIdExpression = ['_components', id]
if (isIdentifierName(id) === false) {
let invalidComponentName = idToInvalidComponentName.get(id)
if (invalidComponentName === undefined) {
invalidComponentName = `_component${idToInvalidComponentName.size}`
idToInvalidComponentName.set(id, invalidComponentName)
}

jsxIdExpression = [invalidComponentName]
}

node.openingElement.name =
toJsxIdOrMemberExpression(jsxIdExpression)

if (node.closingElement) {
node.closingElement.name = toJsxIdOrMemberExpression([
'_components',
id
])
node.closingElement.name =
toJsxIdOrMemberExpression(jsxIdExpression)
}
}
}
Expand Down Expand Up @@ -259,7 +269,11 @@ export function recmaJsxRewrite(options = {}) {
/** @type {Array<Statement>} */
const statements = []

if (defaults.length > 0 || actual.length > 0) {
if (
defaults.length > 0 ||
actual.length > 0 ||
idToInvalidComponentName.size > 0
) {
if (providerImportSource) {
importProvider = true
parameters.push({
Expand Down Expand Up @@ -344,6 +358,27 @@ export function recmaJsxRewrite(options = {}) {
componentsInit = {type: 'Identifier', name: '_components'}
}

if (isNamedFunction(scope.node, '_createMdxContent')) {
for (const [id, componentName] of idToInvalidComponentName) {
// For JSX IDs that can’t be represented as JavaScript IDs (as in,
// those with dashes, such as `custom-element`), generate a
// separate variable that is a valid JS ID (such as `_component0`),
// and takes it from components:
// `const _component0 = _components['custom-element']`
declarations.push({
type: 'VariableDeclarator',
id: {type: 'Identifier', name: componentName},
init: {
type: 'MemberExpression',
object: {type: 'Identifier', name: '_components'},
property: {type: 'Literal', value: id},
computed: true,
optional: false
}
})
}
}

if (componentsPattern) {
declarations.push({
type: 'VariableDeclarator',
Expand Down
4 changes: 2 additions & 2 deletions packages/mdx/test/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -860,8 +860,8 @@ test('jsx', async () => {
'function _createMdxContent(props) {',
' const _components = Object.assign({',
' "a-b": "a-b"',
' }, props.components);',
' return <>{<_components.a-b></_components.a-b>}</>;',
' }, props.components), _component0 = _components["a-b"];',
' return <>{<_component0></_component0>}</>;',
'}',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
Expand Down

1 comment on commit 9904838

@vercel
Copy link

@vercel vercel bot commented on 9904838 Aug 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

mdx – ./

mdx-mdx.vercel.app
mdx-git-main-mdx.vercel.app
v2.mdxjs.com
mdxjs.com

Please sign in to comment.