vite babel 获取组件的 children 代码, 填写到 jsxCode 属性中

最终效果

<DocsModule title="类型">
  <Button>默认按钮</Button>
  <Button type="primary">主要按钮</Button>
  <Button type="success">成功按钮</Button>
  <Button type="danger">危险按钮</Button>
</DocsModule>

转换为 ↓↓↓↓ ( 自动生成 , 再也不用手动写这些重复的代码了)

<DocsModule 
	title="类型" 
	jsxCode={`
		
  		
  		
  		
  		`}
>
  <Button>默认按钮</Button>
  <Button type="primary">主要按钮</Button>
  <Button type="success">成功按钮</Button>
  <Button type="danger">危险按钮</Button>
</DocsModule>

jsxCode 中格式比较乱, 无所谓,
组件内部会使用 prettier 格式化代码,
还有 highlight.js 给代码高亮

组件中还可以封装 代码前内容代码后内容 属性
用来自定义前后的内容
vite babel 获取组件的 children 代码, 填写到 jsxCode 属性中_第1张图片

测试 行高亮

<DocsModule
  title="类型"
  codeLineHighLight={[
    { line: 1, type: "info" },
    { line: 2, type: "info" },
    { line: 5, type: "error" },
    { line: 6, type: "error" },
  ]}
>
  <Button>默认按钮</Button>
  <Button type="primary">主要按钮</Button>
  <Button type="success">成功按钮</Button>
  <Button type="info">信息按钮</Button>
  <Button type="warning">警告按钮</Button>
  <Button type="danger">危险按钮</Button>
</DocsModule>

vite babel 获取组件的 children 代码, 填写到 jsxCode 属性中_第2张图片

安装依赖

"devDependencies": {
  "@babel/core": "^7.22.9",
  "@babel/generator": "^7.22.9",
  "@babel/parser": "^7.22.7",
  "@babel/plugin-syntax-jsx": "^7.22.5",
  "@babel/preset-env": "^7.22.9",
  "@babel/preset-typescript": "^7.22.5",
  "@babel/traverse": "^7.22.8",
  "@babel/types": "^7.22.5",
  
  "@types/babel__generator": "^7.6.4",
  "@types/babel__traverse": "^7.20.1",  
},

vite.config.ts

// 导入
import * as babelParser from '@babel/parser';
import babelTraverse from '@babel/traverse';
import * as babelTypes from '@babel/types';
import babelGenerator from '@babel/generator';

//插件
plugins: [
  {
    name: '自动获取 jsx 内容,填写到 jsxCode',
    enforce: 'pre',
    transform(code, id) {
      // 只处理自己的 pages 目录代码
      if (!id.includes("node_modules") && id.includes("/examples/src/pages/")) {
        const ast = babelParser.parse(code, {
          plugins: ["jsx", "typescript"],
          sourceType: "module",
        });
        babelTraverse(ast, {
          JSXOpeningElement(path) {
            // DocsModule 是自己封装的 组件
            if (path.node.name.type == "JSXIdentifier" && path.node.name.name === "DocsModule") {
            
              const attributes = path.node.attributes;
              
              const hasJsxCodeAttr = attributes.find(
                item =>
                  item.type === 'JSXAttribute' &&
                  babelTypes.isJSXIdentifier(item.name, { name: 'jsxCode' }) // 忘了判断 code,用的很少,就懒得搞了.
              );
              
              // 如果已经自定义了 jsxCode 属性, 则跳过本次处理
              if (hasJsxCodeAttr) {
                return;
              }
              
              // 开始开始拼装 属性, 并赋值给 组件
              if (path.parent.type == "JSXElement") {
                const children = path.parent.children.filter((node) => node.type === "JSXElement");                
                const childrenStr = children.map((child) => babelGenerator(child).code).join("");
				
                const jsxCodeAttribute = babelTypes.jsxAttribute(
                  // 组件中会给 jsxCode 在前后 加上 <>  , 因为 jsx 不允许一级结构存在多个组件 (组件中用了 prettier 格式化代码,所以会报错)
                  // 多个组件就赋值给 jsxCode
                  babelTypes.jsxIdentifier(children.length > 1 ? "jsxCode" : "code"),
                  babelTypes.jsxExpressionContainer(
                  	// 定义模版字符串
                    babelTypes.templateLiteral([babelTypes.templateElement({ raw: childrenStr }, true)], [])
                  )
                );
                // 向原始属性列表中添加新的 jsxCode 属性
                attributes.push(jsxCodeAttribute);
              }
            }
          },
        });
        
        // 生成转换后的代码
        let transformedCode: string = babelGenerator(ast).code;
        
        // fix: ast处理后末尾出现了分号  
        // 莫名其妙的多了分号, 感觉是 babel 的 bug, 或者是 边缘情况, babel 给误判了. (不是标准的js代码, 是纯jsx)
        transformedCode = transformedCode.replaceAll(">;", ">")
        
        return {
          code: transformedCode,
          map: null
        };
      }
      
      // 不是 pages 目录的代码 就直接返回原code
      return {
        code: code,
        map: null
      };
    },
  },
  // 其他插件↓
],

你可能感兴趣的:(JavaScript,vite,babel,solidjs,代码展示,组件源码展示,storybook)