Skip to content

Latest commit

 

History

History
254 lines (174 loc) · 5.47 KB

README.md

File metadata and controls

254 lines (174 loc) · 5.47 KB

jsx-xml

Generate xml string from jsx

codecov Build Status

Install

npm install jsx-xml
# or
yarn add jsx-xml
# or
pnpm add jsx-xml

Usage

import { render } from 'jsx-xml';
import { expect } from 'vitest';

let xml = render(<test />).end({ headless: true });

expect(xml).toBe(`<test/>`);

API

render(jsx, options): XMLBuilder

The render function returns an instance of XMLBuilder. You can call the end to get the XML string.

Components

You can define your own components by defining a function that returns a JSX.Element. Component name should start with a capital letter.

import { render } from 'jsx-xml';

function MyComponent(props) {
  return <test>{props.children}</test>;
}

let xml = render(<MyComponent />).end({ headless: true });

Built-in Components

CData

import { CData } from 'jsx-xml';

const value = 1;

let xml = render(
  <test>
    <CData>some text and {value}</CData>
  </test>,
).end({ headless: true });

expect(xml).toBe(`<test><![CDATA[some text and 1]]></test>`);

Comment

import { Comment } from 'jsx-xml';

let xml = render(
  <test>
    <Comment>some comment</Comment>
  </test>,
).end({ headless: true });

expect(xml).toBe(`<test><!--some comment--></test>`);

Ins

import { Ins } from 'jsx-xml';

let xml = render(
  <test>
    <Ins target="target"></Ins>
    <Ins target="other" content="value"></Ins>
  </test>,
).end({ headless: true });

expect(xml).toBe(`<test><?target?><?other value?></test>`);

Fragment

import { Fragment } from 'jsx-xml';

let xml = render(
  <root>
    <Fragment>
      <test />
      <test />
    </Fragment>
  </root>,
).end({ headless: true });

expect(xml).toBe(`<root><test/><test/></root>`);

JSX Transformations

The jsx-xml supports multiple jsx transformations:

  • React element
  • automatic jsx transformation
  • classic jsx transformation

React Element

jsx-xml render function accepts any React element as jsx argument. It helps you to use the jsx-xml in React projects without extra config.

Pros:

  • No extra config is required
  • it can be used jsx-xml and React in the same file

Cons:

  • Order of the key and ref attrs is not preserved
let xml = render(<test before="1" ref="2" key="3" after="4" />).end({
  headless: true,
});

console.log(xml); // <test key="3" ref="2" before="1" after="4"/>
  • It is not possible to have the children attribute
let xml2 = render(<test children="attr">child</test>).end({ headless: true });

console.log(xml2); // <test>child</test>
  • It logs some warnings in the console that do not apply to jsx-xml
const props = { key: '1', other: 'value' };
const xml = render(<test {...props} />).end({ headless: true });

// Warning: A props object containing a "key" prop is being spread into JSX:

Automatic JSX Transformation

jsx-xml provides automatic jsx transformation. It can be configured in the vite or esbuild config.

To config the whole files in the project:

export default defineConfig({
  esbuild: {
    jsxImportSource: 'jsx-xml',
  },
});

Or to config a specific file:

// @jsxImportSource jsx-xml

Pros:

  • No unrelated warnings in the console

Cons:

  • it can not be used jsx-xml and React in the same file
  • it needs per file config
  • it is not possible to have the children attribute
  • order of the key attr is not preserved
let xml = render(<test before="1" ref="2" key="3" after="4" />).end({
  headless: true,
});

console.log(xml); // <test key="3" before="1" ref="2" after="4"/>

Classic JSX Transformation

jsx-xml provides classic jsx transformation. It can be configured in the vite or esbuild config.

To config the whole files in the project:

export default defineConfig({
  esbuild: {
    jsx: 'transform',
    jsxFactory: 'h',
    jsxFragment: 'Fragment',
  },
});

Or to config a specific file:

// @jsxRuntime classic
// @jsxFrag Fragment
// @jsx h

import { h, Fragment } from 'jsx-xml';

Pros:

  • Preserve the order of the key and ref attrs
let xml = render(<test before="1" ref="2" key="3" after="4" />).end({
  headless: true,
});
console.log(xml); // <test before="1" ref="2" key="3" after="4"/>
  • It is possible to have the children attribute
let xml = render(<test children="attr">child</test>).end({ headless: true });
console.log(xml); // <test children="attr">child</test>

Cons:

  • It can not be used jsx-xml and React in the same file
  • It needs per file config

How to choose the transformation

  • If your project is not a React project, it is better to use the classic jsx transformation.
  • If your project is a React project, it is better to split the jsx-xml and React code into different files and use the classic jsx transformation for jsx-xml files.
  • If your project is a React project, you can use the React element transformation. if you need key, ref or children attribute, you can use the classic jsx transformation per file.