fix: bundle client-side code for components used in .md pages (#78)
This commit is contained in:
parent
b588581396
commit
ac22d94e11
7 changed files with 50 additions and 26 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@ lib/
|
||||||
dist/
|
dist/
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
test/fixtures/*/_site/
|
||||||
|
|
|
@ -8,6 +8,7 @@ import esbuild from 'esbuild';
|
||||||
import { promises as fsPromises } from 'fs';
|
import { promises as fsPromises } from 'fs';
|
||||||
import { parse } from '../parser/index.js';
|
import { parse } from '../parser/index.js';
|
||||||
import { transform } from '../compiler/transform/index.js';
|
import { transform } from '../compiler/transform/index.js';
|
||||||
|
import { convertMdToAstroSource } from '../compiler/index.js';
|
||||||
import { getAttrValue } from '../ast.js';
|
import { getAttrValue } from '../ast.js';
|
||||||
import { walk } from 'estree-walker';
|
import { walk } from 'estree-walker';
|
||||||
import babelParser from '@babel/parser';
|
import babelParser from '@babel/parser';
|
||||||
|
@ -72,12 +73,17 @@ export async function collectDynamicImports(filename: URL, { astroConfig, loggin
|
||||||
const imports = new Set<string>();
|
const imports = new Set<string>();
|
||||||
|
|
||||||
// Only astro files
|
// Only astro files
|
||||||
if (!filename.pathname.endsWith('astro')) {
|
if (!filename.pathname.endsWith('.astro') && !filename.pathname.endsWith('.md')) {
|
||||||
return imports;
|
return imports;
|
||||||
}
|
}
|
||||||
|
|
||||||
const extensions = astroConfig.extensions || defaultExtensions;
|
const extensions = astroConfig.extensions || defaultExtensions;
|
||||||
const source = await readFile(filename, 'utf-8');
|
|
||||||
|
let source = await readFile(filename, 'utf-8');
|
||||||
|
if (filename.pathname.endsWith('.md')) {
|
||||||
|
source = await convertMdToAstroSource(source);
|
||||||
|
}
|
||||||
|
|
||||||
const ast = parse(source, {
|
const ast = parse(source, {
|
||||||
filename,
|
filename,
|
||||||
});
|
});
|
||||||
|
|
|
@ -48,13 +48,9 @@ async function convertAstroToJsx(template: string, opts: ConvertAstroOptions): P
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* .md -> .jsx
|
* .md -> .astro source
|
||||||
* Core function processing Markdown, but along the way also calls convertAstroToJsx().
|
|
||||||
*/
|
*/
|
||||||
async function convertMdToJsx(
|
export async function convertMdToAstroSource(contents: string): Promise<string> {
|
||||||
contents: string,
|
|
||||||
{ compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string }
|
|
||||||
): Promise<TransformResult> {
|
|
||||||
const { data: frontmatterData, content } = matter(contents);
|
const { data: frontmatterData, content } = matter(contents);
|
||||||
const { headers, headersExtension } = createMarkdownHeadersCollector();
|
const { headers, headersExtension } = createMarkdownHeadersCollector();
|
||||||
const { htmlAstro, mdAstro } = encodeAstroMdx();
|
const { htmlAstro, mdAstro } = encodeAstroMdx();
|
||||||
|
@ -80,15 +76,24 @@ async function convertMdToJsx(
|
||||||
// Break it up here so that the HTML parser won't detect it.
|
// Break it up here so that the HTML parser won't detect it.
|
||||||
const stringifiedSetupContext = JSON.stringify(contentData).replace(/\<\/script\>/g, `</scrip" + "t>`);
|
const stringifiedSetupContext = JSON.stringify(contentData).replace(/\<\/script\>/g, `</scrip" + "t>`);
|
||||||
|
|
||||||
const raw = `---
|
return `---
|
||||||
${imports}
|
${imports}
|
||||||
${frontmatterData.layout ? `import {__renderPage as __layout} from '${frontmatterData.layout}';` : 'const __layout = undefined;'}
|
${frontmatterData.layout ? `import {__renderPage as __layout} from '${frontmatterData.layout}';` : 'const __layout = undefined;'}
|
||||||
export const __content = ${stringifiedSetupContext};
|
export const __content = ${stringifiedSetupContext};
|
||||||
---
|
---
|
||||||
<section>${mdHtml}</section>`;
|
<section>${mdHtml}</section>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* .md -> .jsx
|
||||||
|
* Core function processing Markdown, but along the way also calls convertAstroToJsx().
|
||||||
|
*/
|
||||||
|
async function convertMdToJsx(
|
||||||
|
contents: string,
|
||||||
|
{ compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string }
|
||||||
|
): Promise<TransformResult> {
|
||||||
|
const raw = await convertMdToAstroSource(contents);
|
||||||
const convertOptions = { compileOptions, filename, fileID };
|
const convertOptions = { compileOptions, filename, fileID };
|
||||||
|
|
||||||
return await convertAstroToJsx(raw, convertOptions);
|
return await convertAstroToJsx(raw, convertOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
|
import { existsSync, promises as fsPromises } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
import { suite } from 'uvu';
|
import { suite } from 'uvu';
|
||||||
import * as assert from 'uvu/assert';
|
import * as assert from 'uvu/assert';
|
||||||
import { createRuntime } from '../lib/runtime.js';
|
import { createRuntime } from '../lib/runtime.js';
|
||||||
|
import { build } from '../lib/build.js';
|
||||||
import { loadConfig } from '../lib/config.js';
|
import { loadConfig } from '../lib/config.js';
|
||||||
import { doc } from './test-utils.js';
|
import { doc } from './test-utils.js';
|
||||||
|
|
||||||
|
const { rmdir, readFile } = fsPromises;
|
||||||
|
|
||||||
const Markdown = suite('Astro Markdown');
|
const Markdown = suite('Astro Markdown');
|
||||||
|
|
||||||
let runtime, setupError;
|
let runtime, setupError, fixturePath, astroConfig;
|
||||||
|
|
||||||
Markdown.before(async () => {
|
Markdown.before(async () => {
|
||||||
const astroConfig = await loadConfig(new URL('./fixtures/astro-markdown', import.meta.url).pathname);
|
fixturePath = new URL('./fixtures/astro-markdown', import.meta.url).pathname;
|
||||||
|
|
||||||
|
astroConfig = await loadConfig(fixturePath);
|
||||||
|
|
||||||
const logging = {
|
const logging = {
|
||||||
level: 'error',
|
level: 'error',
|
||||||
|
@ -26,6 +33,7 @@ Markdown.before(async () => {
|
||||||
|
|
||||||
Markdown.after(async () => {
|
Markdown.after(async () => {
|
||||||
(await runtime) && runtime.shutdown();
|
(await runtime) && runtime.shutdown();
|
||||||
|
rmdir(join(fixturePath, '_site'), { recursive: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
Markdown('No errors creating a runtime', () => {
|
Markdown('No errors creating a runtime', () => {
|
||||||
|
@ -50,4 +58,13 @@ Markdown('Can load more complex jsxy stuff', async () => {
|
||||||
assert.equal($el.text(), 'Hello world');
|
assert.equal($el.text(), 'Hello world');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Markdown('Bundles client-side JS for prod', async () => {
|
||||||
|
await build(astroConfig);
|
||||||
|
|
||||||
|
const complexHtml = await readFile(join(fixturePath, './_site/complex/index.html'), 'utf-8');
|
||||||
|
|
||||||
|
assert.match(complexHtml, `import("/_astro/components/Counter.js"`);
|
||||||
|
assert.ok(existsSync(join(fixturePath, `./_site/_astro/components/Counter.js`)), 'Counter.jsx is bundled for prod');
|
||||||
|
});
|
||||||
|
|
||||||
Markdown.run();
|
Markdown.run();
|
||||||
|
|
7
test/fixtures/astro-markdown/astro/components/Counter.jsx
vendored
Normal file
7
test/fixtures/astro-markdown/astro/components/Counter.jsx
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { h } from 'preact';
|
||||||
|
import { useState } from 'preact/hooks';
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
return <button onClick={() => setCount(count + 1)}>{count}</button>;
|
||||||
|
}
|
|
@ -4,8 +4,10 @@ title: My Blog Post
|
||||||
description: This is a post about some stuff.
|
description: This is a post about some stuff.
|
||||||
import:
|
import:
|
||||||
Hello: '../components/Hello.jsx'
|
Hello: '../components/Hello.jsx'
|
||||||
|
Counter: '../components/Counter.jsx'
|
||||||
---
|
---
|
||||||
|
|
||||||
## Interesting Topic
|
## Interesting Topic
|
||||||
|
|
||||||
<Hello name={`world`} />
|
<Hello name={`world`} />
|
||||||
|
<Counter:load />
|
|
@ -1,14 +0,0 @@
|
||||||
---
|
|
||||||
export function setup() {
|
|
||||||
return {props: {}}
|
|
||||||
}
|
|
||||||
---
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Head Stuff -->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Hello world!</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in a new issue