寻找自定义JSX babel插件,只需将jsx转换为标记字符串

时间:2017-10-02 09:47:00

标签: javascript jsx

这不是反应项目,也不是V-DOM相关。 我只需要一个jsx运行时编译器到(HTML / XML)字符串,稍后将用作element.innerHTML = result

它应该用作babel-plugin来支持自定义库

一些信息: babel-cli@6.26 babel-loader@7.1.2

3 个答案:

答案 0 :(得分:1)

我设法解决了我的问题。

babel配置: ```

{
    "presets": ["env"],
    "plugins": ["transform-decorators-legacy", "transform-class-properties",
        [
            "transform-jsx", {
                "function": "jsx"
            }
        ]
    ]
}

```

我必须编写自己的jsx解析器,因为任何其他解析器都不会提供我的自定义功能。

答案 1 :(得分:0)

这可能是您正在寻找的内容:

https://www.npmjs.com/package/jsx-to-html

答案 2 :(得分:0)

这会将jsx转换为带标签的模板文字(或可选的空字符串以省略标签),并且可以用作起点或直接使用。

(<a href={url} {...o}>#</a>)变为jsx'<a href=${url} ${{...o}}>#</a>',其中单引号是反引号

https://astexplorer.net/#/gist/fdaed19a884dc75fe4a92092826bd635/9bc3c34e276eaf74cc318da9b87bbe0cfd37ff6d

'use strict';
/*
node --inspect-brk ./node_modules/.bin/babel ./samplein/ --out-dir ./sampleout --config-file ./babelrc.json
Note this plugin is the last in the list (ie processed first, right-to-left)
{ "plugins":["./otherplugins", "./path/to/babel-jsx-templates.js"] }
{ "plugins":[["./path/to/babel-jsx-templates.js", {tagname:'xyz'}]] }

 * translate JSX attribute values and children to either quasis or expressions for a TemplateLiteral
 * NOTE expressions 1 item less than quasis, and quasis always 1 more than expressions
    @usage .reduce or call directly
    @param {object} config - eg {expressions: [expressions], quasis: ['strings', 'later translated to TemplateElement']}
    @param {any} item - value
    @param {number} index - array index key
 */
function itemize(config, item, index){
    if(!item){
        return config;
    };

    if(item.expression){
        config.expressions.push(item.expression);
    }else if(item.extra){
        config.quasis[ config.quasis.length - 1 ] += item.extra.raw;
    };

    return config;
}
/*
 * translate JSX attributes to either quasis or expressions for a TemplateLiteral
 * NOTE expressions 1 item less than quasis, and quasis always 1 more than expressions
    @usage .reduce or call directly
    @param {object} config - eg {expressions: [expressions], quasis: ['strings', 'later translated to TemplateElement']}
    @param {any} attr - node
    @param {number} index - array index key
 */
function jsxAttributes(config, attr, index){
    let value = attr.value;
    let name = attr.name;
    //console.log(attr.type);
    let last = config.expressions.length;
    if(name){
        // must align with expressions 1-1
        // "<Tag" => "<Tag attr" add to existing string
        config.quasis[ last ] = (config.quasis[ last ] || '') + (' ' +name.name + (value ? '=':''));
    }else if(attr.argument){
        // {...it} => JSXSpreadAttribute => Identifier.argument.name = "it"
        let types = config.types;
        config.quasis[ last ] = ' ';
        config.expressions.push( types.objectExpression([types.spreadElement(types.identifier(attr.argument.name))]) );
    }

    return itemize(config, value);
}
/* transform JSX to tagged template literals
    <Any attribute={ 4 }></Any>
    @param {object} options - {tagname:'theTagName'}
    @param {string} options.tagname - optional tag-name theTagName`for template literal` default 'jsx'
    @returns jsx`<Any attribute=${ 4 }></Any>`
 * */
function jsxTransform(babel, options={}, dir) {
    const types = babel.types;
    //babel.assertVersion(7);

    const tagname = typeof options.tagname === 'string' ? options.tagname : 'jsx';

    return {
        // enable JSX parsing, adjust to fit your runtime
        inherits: require("@babel/plugin-syntax-jsx").default,
        visitor: {
            JSXElement(path, state){
                let node = path.node.openingElement;
                const tagName = node.name.name;
                const config = node.attributes.reduce(jsxAttributes, {
                    quasis: [`<${tagName}`]
                    ,expressions: []
                    ,types
                });

                let last = config.expressions.length;
                // close tag
                config.quasis[last] = `${ config.quasis[ last ] || '' }>`;
                path.node.children.reduce(itemize, config);
                last = config.expressions.length;
                // closing tag
                config.quasis[last] = `${ config.quasis[ last ] || '' }</${ tagName }>`;
                // convert
                config.quasis = config.quasis.map(function templateElement(str){
                    return types.templateElement({raw:str})
                });

                var templateLiteral;
                templateLiteral = types.templateLiteral(config.quasis, config.expressions);

                if(path.parent.type === "TaggedTemplateExpression"){
                    path.replaceWith(templateLiteral);
                }else{
                    path.replaceWith(
                        types.taggedTemplateExpression(
                            types.identifier( tagname )
                            ,templateLiteral
                        )
                    );
                };
            }
            ,JSXFragment(path, state){
                console.warn('TODO JSXFragment ie <></>',path.type);
            }
        }
    };
};
/* adjust to fit your runtime:
    export default jsxTransform;
    module.exports = require('@babel/helper-plugin-utils').declare(jsxTransform);
 */
module.exports = require('@babel/helper-plugin-utils').declare(jsxTransform);