UNPKG

react-live-unplugin

Version:

Turn React components into live code blocks with ease.

75 lines (74 loc) 2.49 kB
import { parse } from "@babel/parser"; import defu from "defu"; import { createUnplugin } from "unplugin"; import { interopDefault } from "./utils.js"; const randomSeed = Math.random().toString(36).slice(2); const defaults = { id: /\.live\.(j|t)sx$/, exclude: /node_modules/, reactLiveModulePath: "react-live-unplugin/default/ReactLive", reactLiveExportName: "ReactLive" }; const reactLiveUnpluginFactory = (options) => { const mergedOptions = defu(options, defaults); return { name: "unplugin-react-live", enforce: mergedOptions.enforce, transform: { filter: { id: mergedOptions.id, exclude: mergedOptions.exclude }, async handler(code) { const ast = parse(code, { // parse in strict mode and allow module declarations sourceType: "module", plugins: ["jsx", "typescript"] }); const imports = []; const importsCode = []; const traverse = await interopDefault( interopDefault(import("@babel/traverse")) ); traverse(ast, { ImportDeclaration(path) { importsCode.push( code.substring( path.node.start ?? 0, path.node.end ?? code.length ) ); path.node.specifiers.forEach((specifier) => { imports.push(specifier.local.name); }); } }); const codeVarName = `code_${randomSeed}`; const scopeVarName = `scope_${randomSeed}`; const componentVarName = `Component_${randomSeed}`; const codeCode = `const ${codeVarName} = ${JSON.stringify(code)};`; const scopeCode = `const ${scopeVarName} = ${imports.length === 0 ? "{}" : `{ ${imports.join(", ")} }`};`; const exportDemo = `export default function Demo() { return ( <${componentVarName} scope={${scopeVarName}} code={${codeVarName}} /> ); }`; const compiled = `import { ${mergedOptions.reactLiveExportName} as ${componentVarName} } from "${mergedOptions.reactLiveModulePath.replace( /"/g, '\\"' )}"; ${importsCode.join("\n")} ${codeCode} ${scopeCode} ${exportDemo} `; return compiled; } } }; }; const reactLiveUnpluginInternal = createUnplugin(reactLiveUnpluginFactory); const reactLiveUnplugin = Object.assign(reactLiveUnpluginInternal, { defaults }); export { reactLiveUnplugin };