diff --git a/packages/mdx/lib/plugin/recma-document.js b/packages/mdx/lib/plugin/recma-document.js index e0cedaf68..5ffa5af7f 100644 --- a/packages/mdx/lib/plugin/recma-document.js +++ b/packages/mdx/lib/plugin/recma-document.js @@ -26,7 +26,8 @@ * Whether to keep `import` (and `export … from`) statements or compile them * to dynamic `import()` instead. * @property {string} [baseUrl] - * Resolve relative `import` (and `export … from`) relative to this URL. + * Resolve `import`s (and `export … from`, and `import.meta.url`) relative to + * this URL. * @property {string} [pragma='React.createElement'] * Pragma for JSX (used in classic runtime). * @property {string} [pragmaFrag='React.Fragment'] @@ -42,6 +43,7 @@ import {analyze} from 'periscopic' import {stringifyPosition} from 'unist-util-stringify-position' import {positionFromEstree} from 'unist-util-position-from-estree' +import {walk} from 'estree-walker' import {create} from '../util/estree-util-create.js' import {specifiersToDeclarations} from '../util/estree-util-specifiers-to-declarations.js' import {declarationToExpression} from '../util/estree-util-declaration-to-expression.js' @@ -296,6 +298,28 @@ export function recmaDocument(options = {}) { tree.body = replacement + if (baseUrl) { + walk(tree, { + enter(_node) { + const node = /** @type {Node} */ (_node) + + if ( + node.type === 'MemberExpression' && + 'object' in node && + node.object.type === 'MetaProperty' && + node.property.type === 'Identifier' && + node.object.meta.name === 'import' && + node.object.property.name === 'meta' && + node.property.name === 'url' + ) { + /** @type {SimpleLiteral} */ + const replacement = {type: 'Literal', value: baseUrl} + this.replace(replacement) + } + } + }) + } + /** * @param {ExportNamedDeclaration|ExportAllDeclaration} node * @returns {void} diff --git a/packages/mdx/readme.md b/packages/mdx/readme.md index 17448e9d3..8992b2950 100644 --- a/packages/mdx/readme.md +++ b/packages/mdx/readme.md @@ -360,8 +360,8 @@ return {no, default: MDXContent} ###### `options.baseUrl` -Resolve relative `import` (and `export … from`) from this URL (`string?`, -example: `import.meta.url`). +Resolve `import`s (and `export … from`, and `import.meta.url`) from this URL +(`string?`, example: `import.meta.url`). Relative specifiers are non-absolute URLs that start with `/`, `./`, or `../`. For example: `/index.js`, `./folder/file.js`, or `../main.js`. diff --git a/packages/mdx/test/compile.js b/packages/mdx/test/compile.js index 70db8b800..4385ec205 100644 --- a/packages/mdx/test/compile.js +++ b/packages/mdx/test/compile.js @@ -536,6 +536,7 @@ test('compile', async () => { ) } + console.log('\nnote: the following warning is expected!\n') assert.equal( renderToStaticMarkup( React.createElement( @@ -545,6 +546,7 @@ test('compile', async () => { '', 'should render if a used member is defined locally (JSX in a function)' ) + console.log('\nnote: the preceding warning is expected!\n') try { renderToStaticMarkup( diff --git a/packages/mdx/test/evaluate.js b/packages/mdx/test/evaluate.js index b15aa590b..fa7fbe792 100644 --- a/packages/mdx/test/evaluate.js +++ b/packages/mdx/test/evaluate.js @@ -290,6 +290,17 @@ test('evaluate', async () => { 'should support an `export all from`, but prefer explicit exports, w/ `useDynamicImport`' ) + assert.equal( + ( + await evaluate( + 'export const x = new URL("example.png", import.meta.url).href', + {baseUrl: 'https://example.com', ...runtime} + ) + ).x, + 'https://example.com/example.png', + 'should support rewriting `import.meta.url` w/ `baseUrl`' + ) + assert.throws( () => { evaluateSync('export * from "a"', runtime)