ReactJS ist das Javascript-Framework von Facebook. Es ist Open Source.

Webpack#

Webpack ist ein sogenannter Transpiler, der Javascript Code parsed und für das Web, dem Browser oder zum Debugging packt.

ReactJS kommt mit einer internen Konfiguration von Webpack. Sobald man etwas ändern möchte, braucht man eine "webpack.config.js" im Projekt.

	module: {
		rules: [{
			test: /\.jsx$/i,
			include: path.resolve(__dirname, "src"),
			use: {
				loader: "babel-loader",
				options: {
					presets: [
						"@babel/preset-env",
						["@babel/preset-react", {"runtime": "automatic"}]
					]
				}
			}
		}, {
			test: /\.ts$/i,
			include: path.resolve(__dirname, "src"),
			use: {
				loader: "babel-loader",
				options: {
					presets: [
						"@babel/preset-env",
						"@babel/typescript"
					]
				}
			}
		}, {
			test: /\.js$/i,
			include: path.resolve(__dirname, "src"),
			use: {
				loader: "babel-loader",
				options: {
					presets: [
						"@babel/preset-env"
					]
				}
			}
		}, {
			test: /\.css$/i,
			include: [
				path.resolve(__dirname, "src"),
				path.resolve(__dirname, "node_modules")
			],
			use: ["style-loader", "css-loader", "postcss-loader"]
		}, {
			test: /\.(png|svg|jpe?g|gif|woff2?|ttf|eot)$/,
			use: "file-loader"
		}]
	},
	resolve: {
		extensions: [".js", ".jsx", ".css", ".ts"]
	}

Typescript Komponenten .tsx#

ReactJS kann auch mit Typescript kombiniert werden. Dazu muss in der webpack.config.js folgende Regel für den Babel-Loader konfiguriert werden:
        {
            test: /\.(jsx|tsx)$/,
            exclude: /node_modules/,
			use: {
				loader: "babel-loader",
				options: {
					presets: [
						"@babel/preset-env",
						["@babel/preset-react", {"runtime": "automatic"}],
                        "@babel/preset-typescript"
					]
				}
			}
        }

Zusätzlich muss in der TS-Config angegeben werden, dass es sich um Extended Javascript handelt:

{
	"compilerOptions": {
		"jsx": "react-jsx"
	}
}

Typescript nur Typen generieren#

Der Typescript-Compiler hat eine eigene Konfiguration:
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve"
  },
  "include": [
    "src"
  ]
}

Tailwind-Config#

Tailwind ist ein Style-Framework, welches versucht ohne Stylesheets auszukommen. Für ReactJS wird meist eine Konfiguration benötigt:
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"],
  theme: {
    extend: {},
  },
  plugins: [],
}

Typescript mit Decorators#

Von Typescript sind sehr viele Varianten mit sogenannten Decorators (Annotationen etc.) im Umlauf. Folgende Konfiguration unterstützt einige davon.

webpack.config.js:

            use: {
                loader: "babel-loader",
                options: {
                    presets: [
                        "@babel/preset-env",
                        "@babel/preset-typescript",
                        ["@babel/preset-react", {runtime: "automatic"}]
                    ],
                    plugins: [
                        "@babel/syntax-dynamic-import",
                        ["@babel/plugin-proposal-decorators", {version: "2023-05", decoratorAutoAccessors: true}],
                        "@babel/plugin-proposal-object-rest-spread",
                        ["@babel/plugin-transform-class-properties"]
                    ]
                }

tsconfig.json:

{
	"compilerOptions": {
		"jsx": "react-jsx",
		"experimentalDecorators": true,
		"emitDecoratorMetadata": true,
		"target": "ESNext",
		"moduleResolution": "node"
	}
}

Hinweis: Viele Konfigurationen sind inkonsistent. Es ist schwierig herauszufinden, welche Kombinationen dieser Plugins mit welchen Parametern zusammen arbeiten.

LitJS Adapter#

Folgender Adapter vereinfacht das Einbinden von LitJS-Komponenten:
import {createComponent} from "@lit/react";
import React from "react";

export function lit(tag) {
	return createComponent({
		tagName: customElements.getName(tag),
		elementClass: tag,
		react: React
	});
}
export default function Lit({tag, children, ...props}) {
	const Element = lit(tag);
	return <Element {...props}>{children}</Element>;
}

Oder in Typescript:

import {ReactWebComponent, createComponent} from "@lit/react";
import React from "react";

declare var customElements: any;

type Constructor<T> = {
    new (): T;
};

type LitProps<I> = {
	tag: Constructor<I>,
	children: React.ReactNode,
	rest: any[]
};

type AnyComponent = (props: any) => React.ReactElement;

export function lit<I extends HTMLElement>(tag: Constructor<I>): ReactWebComponent<I> {
	return createComponent({
		tagName: customElements.getName(tag),
		elementClass: tag,
		react: React
	});
}
export default function Lit<I extends HTMLElement>({tag, children, ...rest}: LitProps<I>): React.ReactElement {
	const Element: AnyComponent = lit(tag) as AnyComponent;
	return <Element {...rest}>{children}</Element>;
}