kjelsrud.dev/node_modules/astro/dist/vite-plugin-jsx/index.js
2023-07-19 21:31:30 +02:00

208 lines
6.3 KiB
JavaScript

import {
transformWithEsbuild
} from "vite";
import babel from "@babel/core";
import * as colors from "kleur/colors";
import path from "node:path";
import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from "../content/index.js";
import { astroEntryPrefix } from "../core/build/plugins/plugin-component-entry.js";
import { error } from "../core/logger/core.js";
import { removeQueryString } from "../core/path.js";
import { detectImportSource } from "./import-source.js";
import tagExportsPlugin from "./tag.js";
const JSX_EXTENSIONS = /* @__PURE__ */ new Set([".jsx", ".tsx", ".mdx"]);
const IMPORT_STATEMENTS = {
react: "import React from 'react'",
preact: "import { h } from 'preact'",
"solid-js": "import 'solid-js'",
astro: "import 'astro/jsx-runtime'"
};
function getEsbuildLoader(filePath) {
const fileExt = path.extname(filePath);
if (fileExt === ".mdx")
return "jsx";
return fileExt.slice(1);
}
function collectJSXRenderers(renderers) {
const renderersWithJSXSupport = renderers.filter((r) => r.jsxImportSource);
return new Map(
renderersWithJSXSupport.map((r) => [r.jsxImportSource, r])
);
}
async function transformJSX({
code,
mode,
id,
ssr,
renderer,
root
}) {
const { jsxTransformOptions } = renderer;
const options = await jsxTransformOptions({ mode, ssr });
const plugins = [...options.plugins || []];
if (ssr) {
plugins.push(await tagExportsPlugin({ rendererName: renderer.name, root }));
}
const result = await babel.transformAsync(code, {
presets: options.presets,
plugins,
cwd: process.cwd(),
filename: id,
ast: false,
compact: false,
sourceMaps: true,
configFile: false,
babelrc: false,
inputSourceMap: options.inputSourceMap
});
if (!result)
return null;
if (renderer.name === "astro:jsx") {
const { astro } = result.metadata;
return {
code: result.code || "",
map: result.map,
meta: {
astro,
vite: {
// Setting this vite metadata to `ts` causes Vite to resolve .js
// extensions to .ts files.
lang: "ts"
}
}
};
}
return {
code: result.code || "",
map: result.map
};
}
const SPECIAL_QUERY_REGEX = new RegExp(
`[?&](?:worker|sharedworker|raw|url|${CONTENT_FLAG}|${PROPAGATED_ASSET_FLAG})\\b`
);
function jsx({ settings, logging }) {
let viteConfig;
const jsxRenderers = /* @__PURE__ */ new Map();
const jsxRenderersIntegrationOnly = /* @__PURE__ */ new Map();
let astroJSXRenderer;
let defaultJSXRendererEntry;
return {
name: "astro:jsx",
enforce: "pre",
// run transforms before other plugins
async configResolved(resolvedConfig) {
viteConfig = resolvedConfig;
const possibleRenderers = collectJSXRenderers(settings.renderers);
for (const [importSource, renderer] of possibleRenderers) {
jsxRenderers.set(importSource, renderer);
if (importSource === "astro") {
astroJSXRenderer = renderer;
} else {
jsxRenderersIntegrationOnly.set(importSource, renderer);
}
}
defaultJSXRendererEntry = [...jsxRenderersIntegrationOnly.entries()][0];
},
async transform(code, id, opts) {
const ssr = Boolean(opts == null ? void 0 : opts.ssr);
if (SPECIAL_QUERY_REGEX.test(id) || id.startsWith(astroEntryPrefix)) {
return null;
}
id = removeQueryString(id);
if (!JSX_EXTENSIONS.has(path.extname(id))) {
return null;
}
const { mode } = viteConfig;
if (id.endsWith(".mdx")) {
const { code: jsxCode2 } = await transformWithEsbuild(code, id, {
loader: getEsbuildLoader(id),
jsx: "preserve",
sourcemap: "inline",
tsconfigRaw: {
compilerOptions: {
// Ensure client:only imports are treeshaken
// @ts-expect-error anticipate esbuild 0.18 feature
verbatimModuleSyntax: false,
importsNotUsedAsValues: "remove"
}
}
});
return transformJSX({
code: jsxCode2,
id,
renderer: astroJSXRenderer,
mode,
ssr,
root: settings.config.root
});
}
if (defaultJSXRendererEntry && jsxRenderersIntegrationOnly.size === 1) {
const { code: jsxCode2 } = await transformWithEsbuild(code, id, {
loader: getEsbuildLoader(id),
jsx: "preserve",
sourcemap: "inline"
});
return transformJSX({
code: jsxCode2,
id,
renderer: defaultJSXRendererEntry[1],
mode,
ssr,
root: settings.config.root
});
}
const importSource = await detectImportSource(code, jsxRenderers, settings.tsConfig);
if (!importSource && defaultJSXRendererEntry) {
const [defaultRendererName] = defaultJSXRendererEntry;
error(
logging,
"renderer",
`${colors.yellow(id)}
Unable to resolve a renderer that handles this file! With more than one renderer enabled, you should include an import or use a pragma comment.
Add ${colors.cyan(
IMPORT_STATEMENTS[defaultRendererName] || `import '${defaultRendererName}';`
)} or ${colors.cyan(`/** @jsxImportSource: ${defaultRendererName} */`)} to this file.
`
);
return null;
} else if (!importSource) {
error(
logging,
"renderer",
`${colors.yellow(id)}
Unable to find a renderer for JSX. Do you have one configured in your Astro config? See this page to learn how:
https://docs.astro.build/en/core-concepts/framework-components/#installing-integrations
`
);
return null;
}
const selectedJsxRenderer = jsxRenderers.get(importSource);
if (!selectedJsxRenderer) {
error(
logging,
"renderer",
`${colors.yellow(
id
)} No renderer installed for ${importSource}. Try adding \`@astrojs/${importSource}\` to your project.`
);
return null;
}
const { code: jsxCode } = await transformWithEsbuild(code, id, {
loader: getEsbuildLoader(id),
jsx: "preserve",
sourcemap: "inline"
});
return await transformJSX({
code: jsxCode,
id,
renderer: selectedJsxRenderer,
mode,
ssr,
root: settings.config.root
});
}
};
}
export {
jsx as default
};