Skip to content

Commit

Permalink
feat: add exports (#1044)
Browse files Browse the repository at this point in the history
| [![PR App][icn]][demo] | Ref RM-11730, RM-11731 |
| :--------------------: | :----------: |

## 🧰 Changes

Adds support for multiple exports.

Prior to this, we were simply ignoring any non-default exports. This
pulls the exports from the passed in components, and adds them to the
hook that provides component lookup.

## 🧬 QA & Testing

- [Broken on production][prod].
- [Working in this PR app][demo].

[demo]: https://markdown-pr-PR_NUMBER.herokuapp.com
[prod]: https://SUBDOMAIN.readme.io
[icn]:
https://user-images.githubusercontent.com/886627/160426047-1bee9488-305a-4145-bb2b-09d8b757d38a.svg
  • Loading branch information
kellyjosephprice authored Jan 21, 2025
1 parent ecb7f61 commit bf9ed34
Show file tree
Hide file tree
Showing 24 changed files with 59 additions and 74 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x]
node-version: [20.x, 22.x]
react: [18]

steps:
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine3.18
ARG NODE_VERSION=22.13
FROM node:${NODE_VERSION}-alpine

ARG NODE_VERSION
ENV NODE_VERSION=$NODE_VERSION
Expand All @@ -13,7 +13,7 @@ RUN apk update && apk add \
font-roboto \
chromium

RUN npm install -g npm@latest
RUN npm install -g npm@10.5

ENV DOCKER_WORKSPACE=/markdown
WORKDIR ${DOCKER_WORKSPACE}
Expand Down
38 changes: 0 additions & 38 deletions Dockerfile.legacy

This file was deleted.

9 changes: 0 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,7 @@ DOCKER_WORKSPACE := "/markdown"
MOUNTS = --volume ${PWD}:${DOCKER_WORKSPACE} \
--volume ${DOCKER_WORKSPACE}/node_modules

ifeq ($(USE_LEGACY), true)
dockerfile = -f Dockerfile.legacy
endif

ifeq ($(USE_LEGACY), true)
dockerfile = -f Dockerfile.legacy
endif

build:
@echo USE_LEGACY=$(USE_LEGACY)
docker build -t markdown $(dockerfile) --build-arg REACT_VERSION=${REACT_VERSION} .

# This lets us call `make run test.browser`. Make expects cmdline args
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 __tests__/browser/markdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('visual regression tests', () => {
// skipping this because they sporadically failure with network timing
// issues
//'embeds',
'exportTests',
//'features',
'headings',
'images',
Expand Down
33 changes: 18 additions & 15 deletions __tests__/custom-components/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import React from 'react';
import { render, screen } from '@testing-library/react';
import { execute } from '../helpers';

describe('Custom Components', () => {
const Example = { default: () => <div>It works!</div> };
const Composite = {
default: () => (
<>
<div>Does it work?</div>
<Example.default />
</>
),
};
describe('Custom Components', async () => {
const Example = await execute(`It works!`, {}, {}, { getDefault: false });
const Multiple = await execute(
`
export const First = () => <div>First</div>;
export const Second = () => <div>Second</div>;
`,
{},
{},
{ getDefault: false },
);

it('renders custom components', async () => {
const doc = `
Expand All @@ -24,14 +25,16 @@ describe('Custom Components', () => {
expect(screen.getByText('It works!')).toBeVisible();
});

it('renders custom components recursively', async () => {
it('renders a custom component with multiple exports', async () => {
const doc = `
<Composite />
`;
<First />
const Page = await execute(doc, undefined, { components: { Example, Composite } });
<Second />
`;
const Page = await execute(doc, undefined, { components: { Multiple } });
render(<Page />);

expect(screen.getByText('It works!')).toBeVisible();
expect(screen.getByText('First')).toBeVisible();
expect(screen.getByText('Second')).toBeVisible();
});
});
7 changes: 4 additions & 3 deletions __tests__/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ export const silenceConsole =
}
};

export const execute = async (doc: string, compileOpts = {}, runOpts = {}) => {
export const execute = async (doc: string, compileOpts = {}, runOpts = {}, { getDefault = true } = {}) => {
const code = compile(doc, compileOpts);
const module = await run(code, runOpts);
return module.default;
const mod = await run(code, runOpts);

return getDefault ? mod.default : mod;
};

export const migrate = (doc: string) => {
Expand Down
9 changes: 9 additions & 0 deletions docs/export-tests.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Same component file, but different export name

```
- <One />
- <Two />
```

- <One />
- <Two />
5 changes: 5 additions & 0 deletions example/Doc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export const Test = ({ color = 'thistle' } = {}) => {
export default Test;
`,
MultipleExports: `
export const One = () => "One";
export const Two = () => "Two";
`,
};

const executedComponents = {};
Expand Down
3 changes: 3 additions & 0 deletions example/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import codeBlocks from '../docs/code-blocks.md';
// @ts-ignore
import embeds from '../docs/embeds.md';
// @ts-ignore
import exportTests from '../docs/export-tests.mdx';
// @ts-ignore
import features from '../docs/features.md';
// @ts-ignore
import gettingStarted from '../docs/getting-started.md';
Expand Down Expand Up @@ -44,6 +46,7 @@ const fixtures = Object.entries({
codeBlockTests,
codeBlocks,
embeds,
exportTests,
features,
gettingStarted,
headings,
Expand Down
20 changes: 15 additions & 5 deletions lib/run.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,20 @@ const makeUseMDXComponents = (more: ReturnType<UseMdxComponents> = {}): UseMdxCo
const run = async (string: string, _opts: RunOpts = {}) => {
const { Fragment } = runtime as any;
const { components = {}, terms, variables, baseUrl, ...opts } = _opts;
const defaults = Object.fromEntries(
Object.entries(components).map(([tag, module]) => [tag, 'default' in module ? module.default : module]),
);
const executedComponents = Object.entries(components).reduce((memo, [tag, mod]) => {
const { default: Content, toc, Toc, ...rest } = mod;
memo[tag] = Content;

const exec = (text: string, { useMDXComponents = makeUseMDXComponents(defaults) }: RunOpts = {}) => {
if (rest) {
Object.entries(rest).forEach(([subTag, component]) => {
memo[subTag] = component;
});
}

return memo;
}, {});

const exec = (text: string, { useMDXComponents = makeUseMDXComponents(executedComponents) }: RunOpts = {}) => {
return mdxRun(text, {
...runtime,
Fragment,
Expand All @@ -65,7 +74,7 @@ const run = async (string: string, _opts: RunOpts = {}) => {
}) as Promise<RMDXModule>;
};

const { toc, default: Content } = await exec(string);
const { Toc: _Toc, toc, default: Content, ...exports } = await exec(string);

const tocMdx = tocToMdx(toc, components);
const { default: Toc } = await exec(compile(tocMdx), { useMDXComponents: () => ({ p: Fragment }) });
Expand All @@ -84,6 +93,7 @@ const run = async (string: string, _opts: RunOpts = {}) => {
<Toc />
</Components.TableOfContents>
),
...exports,
};
};

Expand Down

0 comments on commit bf9ed34

Please sign in to comment.