Skip to content

Commit

Permalink
feat: prefer the local @mdx-js/mdx
Browse files Browse the repository at this point in the history
..and cache any resolved imports.
  • Loading branch information
aleclarson committed Apr 6, 2021
1 parent 98e89f7 commit 5fe7413
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 31 deletions.
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { requireMdx } from './resolveImport'
import { remarkMdxImport } from './remarkMdxImport'
import { stopService, transform } from './transform'
import { MdxOptions, MdxPlugin, RemarkPlugin } from './types'
import mdx from '@mdx-js/mdx'
import fs from 'fs'

export { MdxOptions, MdxPlugin }
Expand Down Expand Up @@ -55,7 +55,7 @@ function createPlugin(
getMdxOptions?.(filePath).remarkPlugins
)
remarkPlugins.push(mdxImportPlugin)
return mdx.createMdxAstCompiler({
return requireMdx(root).createMdxAstCompiler({
remarkPlugins: remarkPlugins as any[]
})
}
Expand Down
40 changes: 40 additions & 0 deletions src/resolveImport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import findDependency from 'find-dependency'

const importCache: {
[cacheKey: string]: string | undefined
} = {}

type MdxModule = typeof import('@mdx-js/mdx')

export function requireMdx(cwd: string): MdxModule {
return require(resolveImport('@mdx-js/mdx', cwd) || '@mdx-js/mdx')
}

/**
* Search the node_modules of `cwd` and its ancestors until a package is found.
* Skip global `node_modules` and `vite/node_modules` (since `vite` might be
* a local clone).
*/
export function resolveImport(
name: string,
cwd: string,
throwOnMissing?: boolean
) {
const cacheKey = cwd + '\0' + name
if (!importCache[cacheKey]) {
const resolved = findDependency(name, { cwd, skipGlobal: true })
if (throwOnMissing && !resolved) {
throw new Error(`[vite-plugin-mdx] "{name}" must be installed`)
}
importCache[cacheKey] = resolved
}
return importCache[cacheKey]
}

/**
* Throw an error if the given `name` cannot be found from `cwd`.
* Otherwise, return the `name`.
*/
export function assertImportExists(name: string, cwd: string) {
return resolveImport(name, cwd, true) && name
}
36 changes: 7 additions & 29 deletions src/transform.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { startService, Service } from 'esbuild'
import mdx from '@mdx-js/mdx'
import findDependency from 'find-dependency'
import { MdxOptions } from './types'
import { assertImportExists, requireMdx, resolveImport } from './resolveImport'

export { transform }
export { stopService }

const pluginName = 'vite-plugin-mdx'

async function transform(
code_mdx: string,
mdxOptions?: MdxOptions,
root = __dirname
) {
const mdx = requireMdx(root)
const code_jsx = await mdx(code_mdx, mdxOptions as any)
const code_es2019 = await jsxToES2019(code_jsx)
const code_final = injectImports(code_es2019, root)
Expand Down Expand Up @@ -49,45 +47,25 @@ async function jsxToES2019(code_jsx: string) {
}

function injectImports(code_es2019: string, root: string) {
if (findPackage('preact', root)) {
if (resolveImport('preact', root)) {
return [
`import { h } from 'preact'`,
`import { mdx } from '${getMdxImportPath('@mdx-js/preact', root)}'`,
`import { mdx } from '${assertImportExists('@mdx-js/preact', root)}'`,
'',
code_es2019
].join('\n')
}

if (findPackage('react', root)) {
if (resolveImport('react', root)) {
return [
`import React from 'react'`,
`import { mdx } from '${getMdxImportPath('@mdx-js/react', root)}'`,
`import { mdx } from '${assertImportExists('@mdx-js/react', root)}'`,
'',
code_es2019
].join('\n')
}

throw new Error(
`[Wrong Usage][${pluginName}] You need to \`npm install react\` or \`npm install preact\`.`
)
}

function getMdxImportPath(mdxPackageName: string, root: string): string {
const mdxPackageRoot = findPackage(mdxPackageName, root)
if (mdxPackageRoot) {
return mdxPackageName
}
throw new Error(
`[Wrong Usage][${pluginName}] You need to \`npm install ${mdxPackageName}\`.`
)
}

/**
* Search the node_modules of `cwd` and its ancestors until a package is found.
* Skip global node_modules and vite/node_modules (local clone might be used).
*/
function findPackage(name: string, cwd: string) {
return findDependency(name, { cwd, skipGlobal: true })
throw new Error(`[vite-plugin-mdx] "react" or "preact" must be installed`)
}

let _service: Promise<Service> | undefined
Expand Down

0 comments on commit 5fe7413

Please sign in to comment.