简体   繁体   中英

Looking for custom JSX babel plugin that simply converts jsx to a markup string

It is NOT a react project nor V-DOM related. I just need a jsx runtime compiler to (HTML/XML) string that will be used later as element.innerHTML = result

It should be used as a babel-plugin to support a custom library

some info: babel-cli@6.26 babel-loader@7.1.2

I have managed to solve my problem.

babel config: ```

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

```

And i had to write my own jsx parser as any other parser would not provide my custom features.

This might be what you're looking for:

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

This converts jsx to tagged template literals (or optional empty string to omit the tag) and can be used as a starting point or directly.

(<a href={url} {...o}>#</a>) becomes jsx'<a href=${url} ${{...o}}>#</a>' where the single-quotes are backticks

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

transformer js with sample input+output also at (git clonable with the embed-selector) https://gist.github.com/jimmont/63b3a0506d0c5da9a9831e30be22a758

'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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM