feat: add support for other markdown file extensions (#5164)
* fix: add `.markdown ` file extension support adds `.markdown` file extension support for markdown files * test: add test case * chore: adds changeset * test: move test and fixture to relevant locations * test: update test * feat: add multiple markdown file extension support * feat: add module declaration for different markdown file extensions * refactor: markdown module declarations for ease of TS refactoring * fix: add .js extension to module imports * test: update test * chore: update changeset * chore: update changeset * test: add new test cases * test: update tests * fix: correct typo
This commit is contained in:
parent
d151d9f3f2
commit
4a8a346ca9
22 changed files with 229 additions and 33 deletions
11
.changeset/many-rockets-admire.md
Normal file
11
.changeset/many-rockets-admire.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
'astro': minor
|
||||||
|
'@astrojs/rss': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Add support for markdown files with the following extensions:
|
||||||
|
- `.markdown`
|
||||||
|
- `.mdown`
|
||||||
|
- `.mkdn`
|
||||||
|
- `.mkd`
|
||||||
|
- `.mdwn`
|
|
@ -17,7 +17,7 @@ type RSSOptions = {
|
||||||
/**
|
/**
|
||||||
* List of RSS feed items to render. Accepts either:
|
* List of RSS feed items to render. Accepts either:
|
||||||
* a) list of RSSFeedItems
|
* a) list of RSSFeedItems
|
||||||
* b) import.meta.glob result. You can only glob ".md" files within src/pages/ when using this method!
|
* b) import.meta.glob result. You can only glob ".md" (or alternative extensions for markdown files like ".markdown") files within src/pages/ when using this method!
|
||||||
*/
|
*/
|
||||||
items: RSSFeedItem[] | GlobResult;
|
items: RSSFeedItem[] | GlobResult;
|
||||||
/** Specify arbitrary metadata on opening <xml> tag */
|
/** Specify arbitrary metadata on opening <xml> tag */
|
||||||
|
@ -58,7 +58,7 @@ function mapGlobResult(items: GlobResult): Promise<RSSFeedItem[]> {
|
||||||
const { url, frontmatter } = await getInfo();
|
const { url, frontmatter } = await getInfo();
|
||||||
if (url === undefined || url === null) {
|
if (url === undefined || url === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`[RSS] When passing an import.meta.glob result directly, you can only glob ".md" files within /pages! Consider mapping the result to an array of RSSFeedItems. See the RSS docs for usage examples: https://docs.astro.build/en/guides/rss/#2-list-of-rss-feed-objects`
|
`[RSS] When passing an import.meta.glob result directly, you can only glob ".md" (or alternative extensions for markdown files like ".markdown") files within /pages! Consider mapping the result to an array of RSSFeedItems. See the RSS docs for usage examples: https://docs.astro.build/en/guides/rss/#2-list-of-rss-feed-objects`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!Boolean(frontmatter.title) || !Boolean(frontmatter.pubDate)) {
|
if (!Boolean(frontmatter.title) || !Boolean(frontmatter.pubDate)) {
|
||||||
|
|
|
@ -198,7 +198,11 @@ describe('rss', () => {
|
||||||
});
|
});
|
||||||
chai.expect(false).to.equal(true, 'Should have errored');
|
chai.expect(false).to.equal(true, 'Should have errored');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
chai.expect(err.message).to.contain('you can only glob ".md" files within /pages');
|
chai
|
||||||
|
.expect(err.message)
|
||||||
|
.to.contain(
|
||||||
|
'you can only glob ".md" (or alternative extensions for markdown files like ".markdown") files within /pages'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
111
packages/astro/client-base.d.ts
vendored
111
packages/astro/client-base.d.ts
vendored
|
@ -1,19 +1,106 @@
|
||||||
/// <reference path="./import-meta.d.ts" />
|
/// <reference path="./import-meta.d.ts" />
|
||||||
|
|
||||||
declare module '*.md' {
|
type MD = import('./dist/@types/astro').MarkdownInstance<Record<string, any>>;
|
||||||
type MD = import('./dist/@types/astro').MarkdownInstance<Record<string, any>>;
|
interface ExportedMarkdownModuleEntities {
|
||||||
|
frontmatter: MD['frontmatter'];
|
||||||
export const frontmatter: MD['frontmatter'];
|
file: MD['file'];
|
||||||
export const file: MD['file'];
|
url: MD['url'];
|
||||||
export const url: MD['url'];
|
getHeadings: MD['getHeadings'];
|
||||||
export const getHeadings: MD['getHeadings'];
|
|
||||||
/** @deprecated Renamed to `getHeadings()` */
|
/** @deprecated Renamed to `getHeadings()` */
|
||||||
export const getHeaders: () => void;
|
getHeaders: () => void;
|
||||||
export const Content: MD['Content'];
|
Content: MD['Content'];
|
||||||
export const rawContent: MD['rawContent'];
|
rawContent: MD['rawContent'];
|
||||||
export const compiledContent: MD['compiledContent'];
|
compiledContent: MD['compiledContent'];
|
||||||
|
load: MD['default'];
|
||||||
|
}
|
||||||
|
|
||||||
const load: MD['default'];
|
declare module '*.md' {
|
||||||
|
const { load }: ExportedMarkdownModuleEntities;
|
||||||
|
export const {
|
||||||
|
frontmatter,
|
||||||
|
file,
|
||||||
|
url,
|
||||||
|
getHeadings,
|
||||||
|
getHeaders,
|
||||||
|
Content,
|
||||||
|
rawContent,
|
||||||
|
compiledContent,
|
||||||
|
}: ExportedMarkdownModuleEntities;
|
||||||
|
export default load;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.markdown' {
|
||||||
|
const { load }: ExportedMarkdownModuleEntities;
|
||||||
|
export const {
|
||||||
|
frontmatter,
|
||||||
|
file,
|
||||||
|
url,
|
||||||
|
getHeadings,
|
||||||
|
getHeaders,
|
||||||
|
Content,
|
||||||
|
rawContent,
|
||||||
|
compiledContent,
|
||||||
|
}: ExportedMarkdownModuleEntities;
|
||||||
|
export default load;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.mkdn' {
|
||||||
|
const { load }: ExportedMarkdownModuleEntities;
|
||||||
|
export const {
|
||||||
|
frontmatter,
|
||||||
|
file,
|
||||||
|
url,
|
||||||
|
getHeadings,
|
||||||
|
getHeaders,
|
||||||
|
Content,
|
||||||
|
rawContent,
|
||||||
|
compiledContent,
|
||||||
|
}: ExportedMarkdownModuleEntities;
|
||||||
|
export default load;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.mkd' {
|
||||||
|
const { load }: ExportedMarkdownModuleEntities;
|
||||||
|
export const {
|
||||||
|
frontmatter,
|
||||||
|
file,
|
||||||
|
url,
|
||||||
|
getHeadings,
|
||||||
|
getHeaders,
|
||||||
|
Content,
|
||||||
|
rawContent,
|
||||||
|
compiledContent,
|
||||||
|
}: ExportedMarkdownModuleEntities;
|
||||||
|
export default load;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.mdwn' {
|
||||||
|
const { load }: ExportedMarkdownModuleEntities;
|
||||||
|
export const {
|
||||||
|
frontmatter,
|
||||||
|
file,
|
||||||
|
url,
|
||||||
|
getHeadings,
|
||||||
|
getHeaders,
|
||||||
|
Content,
|
||||||
|
rawContent,
|
||||||
|
compiledContent,
|
||||||
|
}: ExportedMarkdownModuleEntities;
|
||||||
|
export default load;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.mdown' {
|
||||||
|
const { load }: ExportedMarkdownModuleEntities;
|
||||||
|
export const {
|
||||||
|
frontmatter,
|
||||||
|
file,
|
||||||
|
url,
|
||||||
|
getHeadings,
|
||||||
|
getHeaders,
|
||||||
|
Content,
|
||||||
|
rawContent,
|
||||||
|
compiledContent,
|
||||||
|
}: ExportedMarkdownModuleEntities;
|
||||||
export default load;
|
export default load;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
|
||||||
import type {
|
import type {
|
||||||
MarkdownHeading,
|
MarkdownHeading,
|
||||||
MarkdownMetadata,
|
MarkdownMetadata,
|
||||||
|
@ -246,6 +247,9 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Union type of supported markdown file extensions */
|
||||||
|
type MarkdowFileExtension = typeof SUPPORTED_MARKDOWN_FILE_EXTENSIONS[number];
|
||||||
|
|
||||||
export interface AstroGlobalPartial {
|
export interface AstroGlobalPartial {
|
||||||
/**
|
/**
|
||||||
* @deprecated since version 0.24. See the {@link https://astro.build/deprecated/resolve upgrade guide} for more details.
|
* @deprecated since version 0.24. See the {@link https://astro.build/deprecated/resolve upgrade guide} for more details.
|
||||||
|
@ -264,7 +268,9 @@ export interface AstroGlobalPartial {
|
||||||
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#astroglob)
|
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#astroglob)
|
||||||
*/
|
*/
|
||||||
glob(globStr: `${any}.astro`): Promise<AstroInstance[]>;
|
glob(globStr: `${any}.astro`): Promise<AstroInstance[]>;
|
||||||
glob<T extends Record<string, any>>(globStr: `${any}.md`): Promise<MarkdownInstance<T>[]>;
|
glob<T extends Record<string, any>>(
|
||||||
|
globStr: `${any}${MarkdowFileExtension}`
|
||||||
|
): Promise<MarkdownInstance<T>[]>;
|
||||||
glob<T extends Record<string, any>>(globStr: `${any}.mdx`): Promise<MDXInstance<T>[]>;
|
glob<T extends Record<string, any>>(globStr: `${any}.mdx`): Promise<MDXInstance<T>[]>;
|
||||||
glob<T extends Record<string, any>>(globStr: string): Promise<T[]>;
|
glob<T extends Record<string, any>>(globStr: string): Promise<T[]>;
|
||||||
/**
|
/**
|
||||||
|
@ -868,7 +874,7 @@ export interface AstroUserConfig {
|
||||||
* @default `false`
|
* @default `false`
|
||||||
* @version 1.0.0-rc.1
|
* @version 1.0.0-rc.1
|
||||||
* @description
|
* @description
|
||||||
* Enable Astro's pre-v1.0 support for components and JSX expressions in `.md` Markdown files.
|
* Enable Astro's pre-v1.0 support for components and JSX expressions in `.md` (and alternative extensions for markdown files like ".markdown") Markdown files.
|
||||||
* In Astro `1.0.0-rc`, this original behavior was removed as the default, in favor of our new [MDX integration](/en/guides/integrations-guide/mdx/).
|
* In Astro `1.0.0-rc`, this original behavior was removed as the default, in favor of our new [MDX integration](/en/guides/integrations-guide/mdx/).
|
||||||
*
|
*
|
||||||
* To enable this behavior, set `legacy.astroFlavoredMarkdown` to `true` in your [`astro.config.mjs` configuration file](/en/guides/configuring-astro/#the-astro-config-file).
|
* To enable this behavior, set `legacy.astroFlavoredMarkdown` to `true` in your [`astro.config.mjs` configuration file](/en/guides/configuring-astro/#the-astro-config-file).
|
||||||
|
|
|
@ -32,7 +32,7 @@ export function moduleIsTopLevelPage(info: ModuleInfo): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function walks the dependency graph, going up until it finds a page component.
|
// This function walks the dependency graph, going up until it finds a page component.
|
||||||
// This could be a .astro page or a .md page.
|
// This could be a .astro page, a .markdown or a .md (or really any file extension for markdown files) page.
|
||||||
export function* getTopLevelPages(
|
export function* getTopLevelPages(
|
||||||
id: string,
|
id: string,
|
||||||
ctx: { getModuleInfo: GetModuleInfo }
|
ctx: { getModuleInfo: GetModuleInfo }
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../constants.js';
|
||||||
import type { AstroConfig, AstroSettings } from '../../@types/astro';
|
import type { AstroConfig, AstroSettings } from '../../@types/astro';
|
||||||
|
|
||||||
import jsxRenderer from '../../jsx/renderer.js';
|
import jsxRenderer from '../../jsx/renderer.js';
|
||||||
|
@ -13,7 +14,7 @@ export function createSettings(config: AstroConfig, cwd?: string): AstroSettings
|
||||||
|
|
||||||
adapter: undefined,
|
adapter: undefined,
|
||||||
injectedRoutes: [],
|
injectedRoutes: [],
|
||||||
pageExtensions: ['.astro', '.md', '.html'],
|
pageExtensions: ['.astro', '.html', ...SUPPORTED_MARKDOWN_FILE_EXTENSIONS],
|
||||||
renderers: [jsxRenderer],
|
renderers: [jsxRenderer],
|
||||||
scripts: [],
|
scripts: [],
|
||||||
watchFiles: tsconfig?.exists ? [tsconfig.path, ...tsconfig.extendedPaths] : [],
|
watchFiles: tsconfig?.exists ? [tsconfig.path, ...tsconfig.extendedPaths] : [],
|
||||||
|
|
|
@ -1,2 +1,12 @@
|
||||||
// process.env.PACKAGE_VERSION is injected when we build and publish the astro package.
|
// process.env.PACKAGE_VERSION is injected when we build and publish the astro package.
|
||||||
export const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development';
|
export const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development';
|
||||||
|
|
||||||
|
// possible extensions for markdown files
|
||||||
|
export const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
|
||||||
|
'.markdown',
|
||||||
|
'.mdown',
|
||||||
|
'.mkdn',
|
||||||
|
'.mkd',
|
||||||
|
'.mdwn',
|
||||||
|
'.md',
|
||||||
|
] as const;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import npath from 'path';
|
import npath from 'path';
|
||||||
import vite from 'vite';
|
import vite from 'vite';
|
||||||
|
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js';
|
||||||
import { unwrapId } from '../../util.js';
|
import { unwrapId } from '../../util.js';
|
||||||
import { STYLE_EXTENSIONS } from '../util.js';
|
import { STYLE_EXTENSIONS } from '../util.js';
|
||||||
|
|
||||||
|
@ -7,7 +8,7 @@ import { STYLE_EXTENSIONS } from '../util.js';
|
||||||
* List of file extensions signalling we can (and should) SSR ahead-of-time
|
* List of file extensions signalling we can (and should) SSR ahead-of-time
|
||||||
* See usage below
|
* See usage below
|
||||||
*/
|
*/
|
||||||
const fileExtensionsToSSR = new Set(['.astro', '.md']);
|
const fileExtensionsToSSR = new Set(['.astro', ...SUPPORTED_MARKDOWN_FILE_EXTENSIONS]);
|
||||||
|
|
||||||
const STRIP_QUERY_PARAMS_REGEX = /\?.*$/;
|
const STRIP_QUERY_PARAMS_REGEX = /\?.*$/;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { warn } from '../../logger/core.js';
|
||||||
import { removeLeadingForwardSlash } from '../../path.js';
|
import { removeLeadingForwardSlash } from '../../path.js';
|
||||||
import { resolvePages } from '../../util.js';
|
import { resolvePages } from '../../util.js';
|
||||||
import { getRouteGenerator } from './generator.js';
|
import { getRouteGenerator } from './generator.js';
|
||||||
|
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js';
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
interface Item {
|
interface Item {
|
||||||
|
@ -206,7 +207,11 @@ export function createRouteManifest(
|
||||||
): ManifestData {
|
): ManifestData {
|
||||||
const components: string[] = [];
|
const components: string[] = [];
|
||||||
const routes: RouteData[] = [];
|
const routes: RouteData[] = [];
|
||||||
const validPageExtensions: Set<string> = new Set(['.astro', '.md', ...settings.pageExtensions]);
|
const validPageExtensions: Set<string> = new Set([
|
||||||
|
'.astro',
|
||||||
|
...SUPPORTED_MARKDOWN_FILE_EXTENSIONS,
|
||||||
|
...settings.pageExtensions,
|
||||||
|
]);
|
||||||
const validEndpointExtensions: Set<string> = new Set(['.js', '.ts']);
|
const validEndpointExtensions: Set<string> = new Set(['.js', '.ts']);
|
||||||
|
|
||||||
function walk(dir: string, parentSegments: RoutePart[][], parentParams: string[]) {
|
function walk(dir: string, parentSegments: RoutePart[][], parentParams: string[]) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { fileURLToPath, pathToFileURL } from 'url';
|
||||||
import { ErrorPayload, normalizePath, ViteDevServer } from 'vite';
|
import { ErrorPayload, normalizePath, ViteDevServer } from 'vite';
|
||||||
import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro';
|
import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro';
|
||||||
import { prependForwardSlash, removeTrailingForwardSlash } from './path.js';
|
import { prependForwardSlash, removeTrailingForwardSlash } from './path.js';
|
||||||
|
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './constants.js';
|
||||||
|
|
||||||
/** Returns true if argument is an object of any prototype/class (but not null). */
|
/** Returns true if argument is an object of any prototype/class (but not null). */
|
||||||
export function isObject(value: unknown): value is Record<string, any> {
|
export function isObject(value: unknown): value is Record<string, any> {
|
||||||
|
@ -17,6 +18,23 @@ export function isObject(value: unknown): value is Record<string, any> {
|
||||||
export function isURL(value: unknown): value is URL {
|
export function isURL(value: unknown): value is URL {
|
||||||
return Object.prototype.toString.call(value) === '[object URL]';
|
return Object.prototype.toString.call(value) === '[object URL]';
|
||||||
}
|
}
|
||||||
|
/** Check if a file is a markdown file based on its extension */
|
||||||
|
export function isMarkdownFile(
|
||||||
|
fileId: string,
|
||||||
|
option: { criteria: 'endsWith' | 'includes'; suffix?: string }
|
||||||
|
): boolean {
|
||||||
|
const _suffix = option.suffix ?? '';
|
||||||
|
if (option.criteria === 'endsWith') {
|
||||||
|
for (let markdownFileExtension of SUPPORTED_MARKDOWN_FILE_EXTENSIONS) {
|
||||||
|
if (fileId.endsWith(`${markdownFileExtension}${_suffix}`)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (let markdownFileExtension of SUPPORTED_MARKDOWN_FILE_EXTENSIONS) {
|
||||||
|
if (fileId.includes(`${markdownFileExtension}${_suffix}`)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/** Wraps an object in an array. If an array is passed, ignore it. */
|
/** Wraps an object in an array. If an array is passed, ignore it. */
|
||||||
export function arraify<T>(target: T | T[]): T[] {
|
export function arraify<T>(target: T | T[]): T[] {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { NodePath } from 'ast-types/lib/node-path';
|
||||||
import { parse, print, types, visit } from 'recast';
|
import { parse, print, types, visit } from 'recast';
|
||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
import type { AstroSettings } from '../@types/astro';
|
import type { AstroSettings } from '../@types/astro';
|
||||||
|
import { isMarkdownFile } from '../core/util.js';
|
||||||
|
|
||||||
// Check for `Astro.glob()`. Be very forgiving of whitespace. False positives are okay.
|
// Check for `Astro.glob()`. Be very forgiving of whitespace. False positives are okay.
|
||||||
const ASTRO_GLOB_REGEX = /Astro2?\s*\.\s*glob\s*\(/;
|
const ASTRO_GLOB_REGEX = /Astro2?\s*\.\s*glob\s*\(/;
|
||||||
|
@ -16,8 +17,8 @@ export default function astro(_opts: AstroPluginOptions): Plugin {
|
||||||
return {
|
return {
|
||||||
name: 'astro:postprocess',
|
name: 'astro:postprocess',
|
||||||
async transform(code, id) {
|
async transform(code, id) {
|
||||||
// Currently only supported in ".astro" & ".md" files
|
// Currently only supported in ".astro" and ".md" (or any alternative markdown file extension like `.markdown`) files
|
||||||
if (!id.endsWith('.astro') && !id.endsWith('.md')) {
|
if (!id.endsWith('.astro') && !isMarkdownFile(id, { criteria: 'endsWith' })) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import esbuild from 'esbuild';
|
||||||
import * as colors from 'kleur/colors';
|
import * as colors from 'kleur/colors';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { error } from '../core/logger/core.js';
|
import { error } from '../core/logger/core.js';
|
||||||
import { parseNpmName } from '../core/util.js';
|
import { isMarkdownFile, parseNpmName } from '../core/util.js';
|
||||||
import tagExportsPlugin from './tag.js';
|
import tagExportsPlugin from './tag.js';
|
||||||
|
|
||||||
type FixedCompilerOptions = TsConfigJson.CompilerOptions & {
|
type FixedCompilerOptions = TsConfigJson.CompilerOptions & {
|
||||||
|
@ -193,7 +193,7 @@ export default function jsx({ settings, logging }: AstroPluginJSXOptions): Plugi
|
||||||
|
|
||||||
const { mode } = viteConfig;
|
const { mode } = viteConfig;
|
||||||
// Shortcut: only use Astro renderer for MD and MDX files
|
// Shortcut: only use Astro renderer for MD and MDX files
|
||||||
if (id.includes('.mdx') || id.includes('.md')) {
|
if (id.includes('.mdx') || isMarkdownFile(id, { criteria: 'includes' })) {
|
||||||
const { code: jsxCode } = await esbuild.transform(code, {
|
const { code: jsxCode } = await esbuild.transform(code, {
|
||||||
loader: getEsbuildLoader(path.extname(id)) as esbuild.Loader,
|
loader: getEsbuildLoader(path.extname(id)) as esbuild.Loader,
|
||||||
jsx: 'preserve',
|
jsx: 'preserve',
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { pagesVirtualModuleId } from '../core/app/index.js';
|
||||||
import { cachedCompilation, CompileProps } from '../core/compile/index.js';
|
import { cachedCompilation, CompileProps } from '../core/compile/index.js';
|
||||||
import { collectErrorMetadata } from '../core/errors.js';
|
import { collectErrorMetadata } from '../core/errors.js';
|
||||||
import type { LogOptions } from '../core/logger/core.js';
|
import type { LogOptions } from '../core/logger/core.js';
|
||||||
|
import { isMarkdownFile } from '../core/util.js';
|
||||||
import type { PluginMetadata as AstroPluginMetadata } from '../vite-plugin-astro/types';
|
import type { PluginMetadata as AstroPluginMetadata } from '../vite-plugin-astro/types';
|
||||||
import { getFileInfo } from '../vite-plugin-utils/index.js';
|
import { getFileInfo } from '../vite-plugin-utils/index.js';
|
||||||
import {
|
import {
|
||||||
|
@ -79,10 +80,10 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin {
|
||||||
styleTransformer.viteDevServer = server;
|
styleTransformer.viteDevServer = server;
|
||||||
},
|
},
|
||||||
async resolveId(id, importer, options) {
|
async resolveId(id, importer, options) {
|
||||||
// Resolve any .md files with the `?content` cache buster. This should only come from
|
// Resolve any .md (or alternative extensions of markdown files like .markdown) files with the `?content` cache buster. This should only come from
|
||||||
// an already-resolved JS module wrapper. Needed to prevent infinite loops in Vite.
|
// an already-resolved JS module wrapper. Needed to prevent infinite loops in Vite.
|
||||||
// Unclear if this is expected or if cache busting is just working around a Vite bug.
|
// Unclear if this is expected or if cache busting is just working around a Vite bug.
|
||||||
if (id.endsWith(`.md${MARKDOWN_CONTENT_FLAG}`)) {
|
if (isMarkdownFile(id, { criteria: 'endsWith', suffix: MARKDOWN_CONTENT_FLAG })) {
|
||||||
const resolvedId = await this.resolve(id, importer, { skipSelf: true, ...options });
|
const resolvedId = await this.resolve(id, importer, { skipSelf: true, ...options });
|
||||||
return resolvedId?.id.replace(MARKDOWN_CONTENT_FLAG, '');
|
return resolvedId?.id.replace(MARKDOWN_CONTENT_FLAG, '');
|
||||||
}
|
}
|
||||||
|
@ -90,7 +91,7 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin {
|
||||||
// that defers the markdown -> HTML rendering until it is needed. This is especially useful
|
// that defers the markdown -> HTML rendering until it is needed. This is especially useful
|
||||||
// when fetching and then filtering many markdown files, like with import.meta.glob() or Astro.glob().
|
// when fetching and then filtering many markdown files, like with import.meta.glob() or Astro.glob().
|
||||||
// Otherwise, resolve directly to the actual component.
|
// Otherwise, resolve directly to the actual component.
|
||||||
if (id.endsWith('.md') && !isRootImport(importer)) {
|
if (isMarkdownFile(id, { criteria: 'endsWith' }) && !isRootImport(importer)) {
|
||||||
const resolvedId = await this.resolve(id, importer, { skipSelf: true, ...options });
|
const resolvedId = await this.resolve(id, importer, { skipSelf: true, ...options });
|
||||||
if (resolvedId) {
|
if (resolvedId) {
|
||||||
return resolvedId.id + MARKDOWN_IMPORT_FLAG;
|
return resolvedId.id + MARKDOWN_IMPORT_FLAG;
|
||||||
|
@ -103,7 +104,7 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin {
|
||||||
// A markdown file has been imported via ESM!
|
// A markdown file has been imported via ESM!
|
||||||
// Return the file's JS representation, including all Markdown
|
// Return the file's JS representation, including all Markdown
|
||||||
// frontmatter and a deferred `import() of the compiled markdown content.
|
// frontmatter and a deferred `import() of the compiled markdown content.
|
||||||
if (id.endsWith(`.md${MARKDOWN_IMPORT_FLAG}`)) {
|
if (isMarkdownFile(id, { criteria: 'endsWith', suffix: MARKDOWN_IMPORT_FLAG })) {
|
||||||
const { fileId, fileUrl } = getFileInfo(id, config);
|
const { fileId, fileUrl } = getFileInfo(id, config);
|
||||||
|
|
||||||
const source = await fs.promises.readFile(fileId, 'utf8');
|
const source = await fs.promises.readFile(fileId, 'utf8');
|
||||||
|
@ -143,7 +144,7 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin {
|
||||||
// A markdown file is being rendered! This markdown file was either imported
|
// A markdown file is being rendered! This markdown file was either imported
|
||||||
// directly as a page in Vite, or it was a deferred render from a JS module.
|
// directly as a page in Vite, or it was a deferred render from a JS module.
|
||||||
// This returns the compiled markdown -> astro component that renders to HTML.
|
// This returns the compiled markdown -> astro component that renders to HTML.
|
||||||
if (id.endsWith('.md')) {
|
if (isMarkdownFile(id, { criteria: 'endsWith' })) {
|
||||||
const filename = normalizeFilename(id);
|
const filename = normalizeFilename(id);
|
||||||
const source = await fs.promises.readFile(filename, 'utf8');
|
const source = await fs.promises.readFile(filename, 'utf8');
|
||||||
const renderOpts = config.markdown;
|
const renderOpts = config.markdown;
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type { AstroSettings } from '../@types/astro';
|
||||||
import { collectErrorMetadata } from '../core/errors.js';
|
import { collectErrorMetadata } from '../core/errors.js';
|
||||||
import type { LogOptions } from '../core/logger/core.js';
|
import type { LogOptions } from '../core/logger/core.js';
|
||||||
import { warn } from '../core/logger/core.js';
|
import { warn } from '../core/logger/core.js';
|
||||||
|
import { isMarkdownFile } from '../core/util.js';
|
||||||
import type { PluginMetadata } from '../vite-plugin-astro/types.js';
|
import type { PluginMetadata } from '../vite-plugin-astro/types.js';
|
||||||
import { getFileInfo, safelyGetAstroData } from '../vite-plugin-utils/index.js';
|
import { getFileInfo, safelyGetAstroData } from '../vite-plugin-utils/index.js';
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
|
||||||
// passing to the transform hook. This lets us get the truly raw value
|
// passing to the transform hook. This lets us get the truly raw value
|
||||||
// to escape "import.meta.env" ourselves.
|
// to escape "import.meta.env" ourselves.
|
||||||
async load(id) {
|
async load(id) {
|
||||||
if (id.endsWith('.md')) {
|
if (isMarkdownFile(id, { criteria: 'endsWith' })) {
|
||||||
const { fileId, fileUrl } = getFileInfo(id, settings.config);
|
const { fileId, fileUrl } = getFileInfo(id, settings.config);
|
||||||
const rawFile = await fs.promises.readFile(fileId, 'utf-8');
|
const rawFile = await fs.promises.readFile(fileId, 'utf-8');
|
||||||
const raw = safeMatter(rawFile, id);
|
const raw = safeMatter(rawFile, id);
|
||||||
|
@ -63,7 +64,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
|
||||||
warn(
|
warn(
|
||||||
logging,
|
logging,
|
||||||
'markdown',
|
'markdown',
|
||||||
`[${id}] Astro now supports MDX! Support for components in ".md" files using the "setup" frontmatter is no longer enabled by default. Migrate this file to MDX or add the "legacy.astroFlavoredMarkdown" config flag to re-enable support.`
|
`[${id}] Astro now supports MDX! Support for components in ".md" (or alternative extensions like ".markdown") files using the "setup" frontmatter is no longer enabled by default. Migrate this file to MDX or add the "legacy.astroFlavoredMarkdown" config flag to re-enable support.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
3
packages/astro/test/fixtures/markdown/src/pages/dot-markdown-page.markdown
vendored
Normal file
3
packages/astro/test/fixtures/markdown/src/pages/dot-markdown-page.markdown
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Page with alternative .markdown extension
|
||||||
|
|
||||||
|
Hope this loads fine 🤞
|
3
packages/astro/test/fixtures/markdown/src/pages/dot-mdown-page.mdown
vendored
Normal file
3
packages/astro/test/fixtures/markdown/src/pages/dot-mdown-page.mdown
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Page with alternative .mdown extension
|
||||||
|
|
||||||
|
Hope this loads fine 🤞
|
3
packages/astro/test/fixtures/markdown/src/pages/dot-mdwn-page.mdwn
vendored
Normal file
3
packages/astro/test/fixtures/markdown/src/pages/dot-mdwn-page.mdwn
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Page with alternative .mdwn extension
|
||||||
|
|
||||||
|
Hope this loads fine 🤞
|
3
packages/astro/test/fixtures/markdown/src/pages/dot-mkd-page.mkd
vendored
Normal file
3
packages/astro/test/fixtures/markdown/src/pages/dot-mkd-page.mkd
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Page with alternative .mkd extension
|
||||||
|
|
||||||
|
Hope this loads fine 🤞
|
3
packages/astro/test/fixtures/markdown/src/pages/dot-mkdn-page.mkdn
vendored
Normal file
3
packages/astro/test/fixtures/markdown/src/pages/dot-mkdn-page.mkdn
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Page with alternative .mkdn extension
|
||||||
|
|
||||||
|
Hope this loads fine 🤞
|
|
@ -17,6 +17,41 @@ describe('Markdown tests', () => {
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Can load a markdown page with the `.markdown` extension', async () => {
|
||||||
|
const html = await fixture.readFile('/dot-markdown-page/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
expect($('h1').html()).to.equal('Page with alternative .markdown extension');
|
||||||
|
expect($('p').html()).to.equal('Hope this loads fine 🤞');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can load a markdown page with the `.mdwn` extension', async () => {
|
||||||
|
const html = await fixture.readFile('/dot-mdwn-page/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
expect($('h1').html()).to.equal('Page with alternative .mdwn extension');
|
||||||
|
expect($('p').html()).to.equal('Hope this loads fine 🤞');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can load a markdown page with the `.mkdn` extension', async () => {
|
||||||
|
const html = await fixture.readFile('/dot-mkdn-page/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
expect($('h1').html()).to.equal('Page with alternative .mkdn extension');
|
||||||
|
expect($('p').html()).to.equal('Hope this loads fine 🤞');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can load a markdown page with the `.mdown` extension', async () => {
|
||||||
|
const html = await fixture.readFile('/dot-mdown-page/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
expect($('h1').html()).to.equal('Page with alternative .mdown extension');
|
||||||
|
expect($('p').html()).to.equal('Hope this loads fine 🤞');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can load a markdown page with the `.mkd` extension', async () => {
|
||||||
|
const html = await fixture.readFile('/dot-mkd-page/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
expect($('h1').html()).to.equal('Page with alternative .mkd extension');
|
||||||
|
expect($('p').html()).to.equal('Hope this loads fine 🤞');
|
||||||
|
});
|
||||||
|
|
||||||
it('Can load a simple markdown page with Astro', async () => {
|
it('Can load a simple markdown page with Astro', async () => {
|
||||||
const html = await fixture.readFile('/post/index.html');
|
const html = await fixture.readFile('/post/index.html');
|
||||||
const $ = cheerio.load(html);
|
const $ = cheerio.load(html);
|
||||||
|
|
|
@ -68,7 +68,7 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
||||||
recmaPlugins: mdxOptions.recmaPlugins,
|
recmaPlugins: mdxOptions.recmaPlugins,
|
||||||
jsx: true,
|
jsx: true,
|
||||||
jsxImportSource: 'astro',
|
jsxImportSource: 'astro',
|
||||||
// Note: disable `.md` support
|
// Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
|
||||||
format: 'mdx',
|
format: 'mdx',
|
||||||
mdExtensions: [],
|
mdExtensions: [],
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue