Skip to content

Commit

Permalink
further refinement, break into separate files, update test to use ts
Browse files Browse the repository at this point in the history
  • Loading branch information
jescalan committed Dec 23, 2020
1 parent 28f0723 commit 42a4dcd
Show file tree
Hide file tree
Showing 11 changed files with 3,152 additions and 1,105 deletions.
4 changes: 3 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
__tests__
examples
.prettierrc
.prettierrc
tsconfig.json
babel.config.js
49 changes: 27 additions & 22 deletions __tests__/index.js → __tests__/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const spawn = require('cross-spawn')
const path = require('path')
const fs = require('fs')
const puppeteer = require('puppeteer')
const handler = require('serve-handler')
const http = require('http')
const rmfr = require('rmfr')
const renderToString = require('../render-to-string')
const React = require('react')
const { paragraphCustomAlerts } = require('@hashicorp/remark-plugins')
import { Server } from 'http'
import { Browser } from 'puppeteer'

import spawn from 'cross-spawn'
import path from 'path'
import fs from 'fs'
import puppeteer from 'puppeteer'
import handler from 'serve-handler'
import http from 'http'
import rmfr from 'rmfr'
import renderToString from '../render-to-string'
import React from 'react'
import { paragraphCustomAlerts } from '@hashicorp/remark-plugins'

jest.setTimeout(30000)

Expand All @@ -20,27 +23,26 @@ test('rehydrates correctly in browser', () => {
'<h1>foo</h1><div><h1>Headline</h1><p>hello <!-- -->jeff</p><button>Count: <!-- -->0</button><p>Some <strong class="custom-strong">markdown</strong> content</p><div class="alert alert-warning g-type-body" role="alert"><p>Alert</p></div></div>'
)
// hydrates correctly
let browser, server
let browser: Browser, server: Server
return new Promise(async (resolve) => {
browser = await puppeteer.launch()
const page = await browser.newPage()
page.on('console', (msg) => console.log(msg.text()))
server = await serveStatic('basic')
await page.exposeFunction('__NEXT_HYDRATED_CB', async () => {
// click the button, flakes with one click for some reason
await page.click('button')
// click the button
await page.click('button')
// wait for react to render
await page.waitFor(() => {
return document.querySelector('button').innerText !== 'Count: 0'
return document.querySelector('button')?.innerHTML === 'Count: 1'
})
// pull the text for a test confirm
const buttonCount = page.$eval('button', (el) => el.innerText)
const buttonCount = page.$eval('button', (el) => el.innerHTML)
resolve(buttonCount)
})
await page.goto('http://localhost:1235', { waitUntil: 'domcontentloaded' })
}).then(async (buttonText) => {
expect(buttonText).not.toEqual('Count: 0')
expect(buttonText).toEqual('Count: 1')

// close the browser and dev server
await browser.close()
Expand Down Expand Up @@ -75,7 +77,10 @@ test('renderToString with options', async () => {

test('renderToString with scope', async () => {
const result = await renderToString('<Test name={bar} />', {
components: { Test: ({ name }) => React.createElement('p', null, name) },
components: {
Test: ({ name }: { name: string }) =>
React.createElement('p', null, name),
},
scope: {
bar: 'test',
},
Expand All @@ -92,27 +97,27 @@ afterAll(async () => {
// utility functions
//

function buildFixture(fixture) {
function buildFixture(fixture: string) {
spawn.sync('next', ['build'], {
stdio: 'inherit',
cwd: path.join(__dirname, 'fixtures', fixture),
env: { ...process.env, NODE_ENV: undefined, __NEXT_TEST_MODE: true },
env: { ...process.env, NODE_ENV: undefined, __NEXT_TEST_MODE: 'true' },
})
spawn.sync('next', ['export'], {
stdio: 'inherit',
cwd: path.join(__dirname, 'fixtures', fixture),
env: { ...process.env, NODE_ENV: undefined, __NEXT_TEST_MODE: true },
env: { ...process.env, NODE_ENV: undefined, __NEXT_TEST_MODE: 'true' },
})
}

function readOutputFile(fixture, name) {
function readOutputFile(fixture: string, name: string) {
return fs.readFileSync(
path.join(__dirname, 'fixtures', fixture, 'out', `${name}.html`),
'utf8'
)
}

function serveStatic(fixture) {
function serveStatic(fixture: string): Promise<Server> {
return new Promise((resolve) => {
const server = http.createServer((req, res) =>
handler(req, res, {
Expand Down
6 changes: 6 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
}
14 changes: 14 additions & 0 deletions hydrate.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ReactNode } from 'react'
import { MdxRemote } from 'types'

export default function hydrate(
/** Rendered MDX output. The direct output of `renderToString`. */
source: MdxRemote.Source,
/**
* A map of names to React components.
* The key used will be the name accessible to MDX.
*
* For example: `{ ComponentName: Component }` will be accessible in the MDX as `<ComponentName/>`.
*/
options: { components: MdxRemote.Components }
): ReactNode
71 changes: 5 additions & 66 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1,10 @@
import * as React from 'react'
import { Plugin, Compiler } from 'unified'
import hydrate from 'hydrate'
import renderToString from 'render-to-string'

/** An object containing components to be made available within mdx content */
interface MdxRemoteComponentsType {
[componentName: string]: React.FunctionComponent | React.Component
}

/** Format of the output from renderToString and input to hydrate */
interface MdxRemoteSourceType {
compiledSource: string
renderedOutput: string
scope?: Record<string, unknown>
}

declare module 'next-mdx-remote' {
export type MdxRemoteSource = MdxRemoteSourceType
export type MdxRemoteComponents = MdxRemoteComponentsType
declare module 'next-mdx-remote/render-to-string' {
export default renderToString
}

declare module 'next-mdx-remote/hydrate' {
export default function hydrate(
/** Rendered MDX output. The direct output of `renderToString`. */
source: MdxRemoteSourceType,
/**
* A map of names to React components.
* The key used will be the name accessible to MDX.
*
* For example: `{ ComponentName: Component }` will be accessible in the MDX as `<ComponentName/>`.
*/
options: { components: MdxRemoteComponentsType }
): React.ReactNode
}

declare module 'next-mdx-remote/render-to-string' {
/**
* Runs the MDX renderer on the MDX string provided with the components and data provided.
*/
export default async function renderToString(
/** Raw MDX contents as a string. */
source: string,
/** Optional parameters, such as components, plugins, and data. */
params?: {
/**
* A object mapping names to React components.
* The key used will be the name accessible to MDX.
*
* For example: `{ ComponentName: Component }` will be accessible in the MDX as `<ComponentName/>`.
*/
components?: MdxRemoteComponentsType
/**
* An arbitrary object of data which will be supplied to the MDX.
*
* For example, in cases where you want to provide template variables to the MDX, like `my name is {name}`,
* you could provide scope as `{ name: "Some name" }`.
*/
scope?: Record<string, unknown>
/**
* These options are passed to the MDX compiler.
* See [the MDX docs.](https://github.com/mdx-js/mdx/blob/master/packages/mdx/index.js).
*/
mdxOptions?: {
remarkPlugins?: Plugin[]
rehypePlugins?: Plugin[]
hastPlugins?: Plugin[]
compilers?: Compiler[]
filepath?: string
}
}
): Promise<MdxRemoteSourceType>
export default hydrate
}
Loading

0 comments on commit 42a4dcd

Please sign in to comment.