Skip to content

Commit

Permalink
Refactor content collection transforms (withastro#6817)
Browse files Browse the repository at this point in the history
* feat: json collection POC

* wip: add test json file

* refactor: rework content flag transforms

* refactor: simplify propagatedAsset check

* chore: remove JSON playground code

* chore: respect build sourcemap option

* deps: magic-string, source-map

* chore: formatting

* fix: add sourcemaps to MDX plugin

* chore: changeset

* deps: remove magic-string from mdx

* chore: remove unecessary MagicString
  • Loading branch information
bholmesdev committed Apr 11, 2023
1 parent b1d07bc commit f882bc1
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 67 deletions.
6 changes: 6 additions & 0 deletions .changeset/dirty-panthers-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'astro': patch
'@astrojs/mdx': patch
---

Fix sourcemap warnings when using Content Collections and MDX with the `vite.build.sourcemap` option
1 change: 1 addition & 0 deletions packages/astro/src/content/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { contentObservable, getContentPaths, getDotAstroTypeReference } from './
export { astroContentAssetPropagationPlugin } from './vite-plugin-content-assets.js';
export { astroContentImportPlugin } from './vite-plugin-content-imports.js';
export { astroContentVirtualModPlugin } from './vite-plugin-content-virtual-mod.js';
export { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from './consts.js';
80 changes: 41 additions & 39 deletions packages/astro/src/content/vite-plugin-content-assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,9 @@ import {
} from './consts.js';
import { getContentEntryExts } from './utils.js';

function isPropagatedAsset(viteId: string, contentEntryExts: string[]): boolean {
const url = new URL(viteId, 'file:https://');
return (
url.searchParams.has(PROPAGATED_ASSET_FLAG) &&
contentEntryExts.some((ext) => url.pathname.endsWith(ext))
);
function isPropagatedAsset(viteId: string) {
const flags = new URLSearchParams(viteId.split('?')[1]);
return flags.has(PROPAGATED_ASSET_FLAG);
}

export function astroContentAssetPropagationPlugin({
Expand All @@ -37,51 +34,56 @@ export function astroContentAssetPropagationPlugin({
const contentEntryExts = getContentEntryExts(settings);
return {
name: 'astro:content-asset-propagation',
enforce: 'pre',
configureServer(server) {
if (mode === 'dev') {
devModuleLoader = createViteLoader(server);
}
},
load(id) {
if (isPropagatedAsset(id, contentEntryExts)) {
async transform(_, id, options) {
if (isPropagatedAsset(id)) {
const basePath = id.split('?')[0];
let stringifiedLinks: string, stringifiedStyles: string, stringifiedScripts: string;

// We can access the server in dev,
// so resolve collected styles and scripts here.
if (options?.ssr && devModuleLoader) {
if (!devModuleLoader.getModuleById(basePath)?.ssrModule) {
await devModuleLoader.import(basePath);
}
const { stylesMap, urls } = await getStylesForURL(
pathToFileURL(basePath),
devModuleLoader,
'development'
);

const hoistedScripts = await getScriptsForURL(
pathToFileURL(basePath),
settings.config.root,
devModuleLoader
);

stringifiedLinks = JSON.stringify([...urls]);
stringifiedStyles = JSON.stringify([...stylesMap.values()]);
stringifiedScripts = JSON.stringify([...hoistedScripts]);
} else {
// Otherwise, use placeholders to inject styles and scripts
// during the production bundle step.
// @see the `astro:content-build-plugin` below.
stringifiedLinks = JSON.stringify(LINKS_PLACEHOLDER);
stringifiedStyles = JSON.stringify(STYLES_PLACEHOLDER);
stringifiedScripts = JSON.stringify(SCRIPTS_PLACEHOLDER);
}

const code = `
export async function getMod() {
return import(${JSON.stringify(basePath)});
}
export const collectedLinks = ${JSON.stringify(LINKS_PLACEHOLDER)};
export const collectedStyles = ${JSON.stringify(STYLES_PLACEHOLDER)};
export const collectedScripts = ${JSON.stringify(SCRIPTS_PLACEHOLDER)};
export const collectedLinks = ${stringifiedLinks};
export const collectedStyles = ${stringifiedStyles};
export const collectedScripts = ${stringifiedScripts};
`;
return { code };
}
},
async transform(code, id, options) {
if (!options?.ssr) return;
if (devModuleLoader && isPropagatedAsset(id, contentEntryExts)) {
const basePath = id.split('?')[0];
if (!devModuleLoader.getModuleById(basePath)?.ssrModule) {
await devModuleLoader.import(basePath);
}
const { stylesMap, urls } = await getStylesForURL(
pathToFileURL(basePath),
devModuleLoader,
'development'
);

const hoistedScripts = await getScriptsForURL(
pathToFileURL(basePath),
settings.config.root,
devModuleLoader
);

return {
code: code
.replace(JSON.stringify(LINKS_PLACEHOLDER), JSON.stringify([...urls]))
.replace(JSON.stringify(STYLES_PLACEHOLDER), JSON.stringify([...stylesMap.values()]))
.replace(JSON.stringify(SCRIPTS_PLACEHOLDER), JSON.stringify([...hoistedScripts])),
};
return { code, map: { mappings: '' } };
}
},
};
Expand Down
43 changes: 18 additions & 25 deletions packages/astro/src/content/vite-plugin-content-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import {
type ContentConfig,
} from './utils.js';

function isContentFlagImport(viteId: string, contentEntryExts: string[]) {
const { searchParams, pathname } = new URL(viteId, 'file:https://');
return searchParams.has(CONTENT_FLAG) && contentEntryExts.some((ext) => pathname.endsWith(ext));
function isContentFlagImport(viteId: string) {
const flags = new URLSearchParams(viteId.split('?')[1]);
return flags.has(CONTENT_FLAG);
}

function getContentRendererByViteId(
Expand Down Expand Up @@ -65,26 +65,26 @@ export function astroContentImportPlugin({
const plugins: Plugin[] = [
{
name: 'astro:content-imports',
async load(viteId) {
if (isContentFlagImport(viteId, contentEntryExts)) {
const { fileId } = getFileInfo(viteId, settings.config);
async transform(_, viteId) {
if (isContentFlagImport(viteId)) {
const fileId = viteId.split('?')[0];
const { id, slug, collection, body, data, _internal } = await setContentEntryModuleCache({
fileId,
pluginContext: this,
});

const code = escapeViteEnvReferences(`
export const id = ${JSON.stringify(id)};
export const collection = ${JSON.stringify(collection)};
export const slug = ${JSON.stringify(slug)};
export const body = ${JSON.stringify(body)};
export const data = ${devalue.uneval(data) /* TODO: reuse astro props serializer */};
export const _internal = {
filePath: ${JSON.stringify(_internal.filePath)},
rawData: ${JSON.stringify(_internal.rawData)},
};
`);
return { code };
export const id = ${JSON.stringify(id)};
export const collection = ${JSON.stringify(collection)};
export const slug = ${JSON.stringify(slug)};
export const body = ${JSON.stringify(body)};
export const data = ${devalue.uneval(data) /* TODO: reuse astro props serializer */};
export const _internal = {
filePath: ${JSON.stringify(_internal.filePath)},
rawData: ${JSON.stringify(_internal.rawData)},
};`);

return { code, map: { mappings: '' } };
}
},
configureServer(viteServer) {
Expand All @@ -96,7 +96,7 @@ export const _internal = {
// Content modules depend on config, so we need to invalidate them.
for (const modUrl of viteServer.moduleGraph.urlToModuleMap.keys()) {
if (
isContentFlagImport(modUrl, contentEntryExts) ||
isContentFlagImport(modUrl) ||
Boolean(getContentRendererByViteId(modUrl, settings))
) {
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
Expand All @@ -108,13 +108,6 @@ export const _internal = {
}
});
},
async transform(code, id) {
if (isContentFlagImport(id, contentEntryExts)) {
// Escape before Rollup internal transform.
// Base on MUCH trial-and-error, inspired by MDX integration 2-step transform.
return { code: escapeViteEnvReferences(code) };
}
},
},
];

Expand Down
9 changes: 9 additions & 0 deletions packages/astro/src/vite-plugin-jsx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { error } from '../core/logger/core.js';
import { removeQueryString } from '../core/path.js';
import { detectImportSource } from './import-source.js';
import tagExportsPlugin from './tag.js';
import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from '../content/index.js';

const JSX_EXTENSIONS = new Set(['.jsx', '.tsx', '.mdx']);
const IMPORT_STATEMENTS: Record<string, string> = {
Expand Down Expand Up @@ -104,6 +105,11 @@ interface AstroPluginJSXOptions {
logging: LogOptions;
}

// Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54
const SPECIAL_QUERY_REGEX = new RegExp(
`[?&](?:worker|sharedworker|raw|url|${CONTENT_FLAG}|${PROPAGATED_ASSET_FLAG})\\b`
);

/** Use Astro config to allow for alternate or multiple JSX renderers (by default Vite will assume React) */
export default function jsx({ settings, logging }: AstroPluginJSXOptions): Plugin {
let viteConfig: ResolvedConfig;
Expand Down Expand Up @@ -133,6 +139,9 @@ export default function jsx({ settings, logging }: AstroPluginJSXOptions): Plugi
},
async transform(code, id, opts) {
const ssr = Boolean(opts?.ssr);
if (SPECIAL_QUERY_REGEX.test(id)) {
return null;
}
id = removeQueryString(id);
if (!JSX_EXTENSIONS.has(path.extname(id))) {
return null;
Expand Down
1 change: 1 addition & 0 deletions packages/integrations/mdx/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"remark-gfm": "^3.0.1",
"remark-smartypants": "^2.0.0",
"shiki": "^0.11.1",
"source-map": "^0.7.4",
"unist-util-visit": "^4.1.0",
"vfile": "^5.3.2"
},
Expand Down
6 changes: 5 additions & 1 deletion packages/integrations/mdx/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { VFile } from 'vfile';
import type { Plugin as VitePlugin } from 'vite';
import { getRehypePlugins, getRemarkPlugins, recmaInjectImportMetaEnvPlugin } from './plugins.js';
import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from './utils.js';
import { SourceMapGenerator } from 'source-map';

export type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | 'rehypePlugins'> & {
extendMarkdownConfig: boolean;
Expand Down Expand Up @@ -113,6 +114,9 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
...(mdxPluginOpts.recmaPlugins ?? []),
() => recmaInjectImportMetaEnvPlugin({ importMetaEnv }),
],
SourceMapGenerator: config.vite.build?.sourcemap
? SourceMapGenerator
: undefined,
});

return {
Expand Down Expand Up @@ -168,7 +172,7 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
import.meta.hot.decline();
}`;
}
return escapeViteEnvReferences(code);
return { code: escapeViteEnvReferences(code), map: null };
},
},
] as VitePlugin[],
Expand Down
36 changes: 34 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f882bc1

Please sign in to comment.