Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: correctly transform import.meta.env.* in MDX #4858

Merged
merged 12 commits into from
Sep 26, 2022
5 changes: 5 additions & 0 deletions .changeset/metal-hats-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/mdx': patch
---

Correctly parse import.meta.env in MDX files
2 changes: 2 additions & 0 deletions packages/integrations/mdx/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@mdx-js/rollup": "^2.1.1",
"acorn": "^8.8.0",
"es-module-lexer": "^0.10.5",
"estree-util-visit": "^1.2.0",
"github-slugger": "^1.4.0",
"gray-matter": "^4.0.3",
"kleur": "^4.1.4",
Expand All @@ -47,6 +48,7 @@
},
"devDependencies": {
"@types/chai": "^4.3.1",
"@types/estree": "^1.0.0",
"@types/mocha": "^9.1.1",
"@types/yargs-parser": "^21.0.0",
"astro": "workspace:*",
Expand Down
103 changes: 0 additions & 103 deletions packages/integrations/mdx/src/astro-data-utils.ts

This file was deleted.

54 changes: 43 additions & 11 deletions packages/integrations/mdx/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
import type { AstroIntegration } from 'astro';
import type { Plugin as VitePlugin } from 'vite';
import { compile as mdxCompile } from '@mdx-js/mdx';
import mdxPlugin, { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
import type { AstroIntegration } from 'astro';
import { parse as parseESM } from 'es-module-lexer';
import { blue, bold } from 'kleur/colors';
import { VFile } from 'vfile';
import type { Plugin as VitePlugin } from 'vite';
import { rehypeApplyFrontmatterExport } from './astro-data-utils.js';
import type { MdxOptions } from './utils.js';
import fs from 'node:fs/promises';
import { getFileInfo, handleExtendsNotSupported, parseFrontmatter } from './utils.js';
import {
getFileInfo,
recmaInjectImportMetaEnvPlugin,
rehypeApplyFrontmatterExport,
getRehypePlugins,
getRemarkPlugins,
handleExtendsNotSupported,
parseFrontmatter,
} from './utils.js';
} from './plugins.js';
import { PluggableList } from '@mdx-js/mdx/lib/core.js';

const RAW_CONTENT_ERROR =
'MDX does not support rawContent()! If you need to read the Markdown contents to calculate values (ex. reading time), we suggest injecting frontmatter via remark plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins';

const COMPILED_CONTENT_ERROR =
'MDX does not support compiledContent()! If you need to read the HTML contents to calculate values (ex. reading time), we suggest injecting frontmatter via rehype plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins';

export type MdxOptions = {
remarkPlugins?: PluggableList;
rehypePlugins?: PluggableList;
/**
* Choose which remark and rehype plugins to inherit, if any.
*
* - "markdown" (default) - inherit your project’s markdown plugin config ([see Markdown docs](https://docs.astro.build/en/guides/markdown-content/#configuring-markdown))
* - "astroDefaults" - inherit Astro’s default plugins only ([see defaults](https://docs.astro.build/en/reference/configuration-reference/#markdownextenddefaultplugins))
* - false - do not inherit any plugins
*/
extendPlugins?: 'markdown' | 'astroDefaults' | false;
};

export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
return {
name: '@astrojs/mdx',
Expand Down Expand Up @@ -58,28 +71,40 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
mdExtensions: [],
};

let importMetaEnv: Record<string, any> = {
SITE: config.site,
};

updateConfig({
vite: {
plugins: [
{
enforce: 'pre',
...mdxPlugin(mdxPluginOpts),
configResolved(resolved) {
importMetaEnv = { ...importMetaEnv, ...resolved.env };
},
// Override transform to alter code before MDX compilation
// ex. inject layouts
async transform(code, id) {
async transform(_, id) {
if (!id.endsWith('mdx')) return;

// Read code from file manually to prevent Vite from parsing `import.meta.env` expressions
const { fileId } = getFileInfo(id, config);
const code = await fs.readFile(fileId, 'utf-8');

const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
...mdxPluginOpts,
rehypePlugins: [
...(mdxPluginOpts.rehypePlugins ?? []),
() => rehypeApplyFrontmatterExport(frontmatter),
],
recmaPlugins: [() => recmaInjectImportMetaEnvPlugin({ importMetaEnv })],
});

return {
code: String(compiled.value),
code: escapeViteEnvReferences(String(compiled.value)),
map: compiled.map,
};
},
Expand Down Expand Up @@ -123,7 +148,7 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
import.meta.hot.decline();
}`;
}
return code;
return escapeViteEnvReferences(code);
},
},
] as VitePlugin[],
Expand All @@ -133,3 +158,10 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
},
};
}

// Converts the first dot in `import.meta.env` to its Unicode escape sequence,
// which prevents Vite from replacing strings like `import.meta.env.SITE`
// in our JS representation of loaded Markdown files
function escapeViteEnvReferences(code: string) {
return code.replace(/import\.meta\.env/g, 'import\\u002Emeta.env');
}
Loading