1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-09 16:21:51 +00:00

Add support for JSX

Allows usage of JSX across the codebase, JSX is turned into regular HTML elements.
This commit is contained in:
Bagel03 2023-10-24 09:58:53 -04:00 committed by GitHub
parent 6deee07a80
commit 81df743334
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 7 deletions

View File

@ -31,7 +31,7 @@ const moduleRules = [
type: "javascript/auto",
},
{
test: /\.js$/,
test: /\.jsx?$/,
enforce: "pre",
exclude: /node_modules/,
use: [
@ -45,7 +45,7 @@ const moduleRules = [
],
},
{
test: /\.[jt]s$/,
test: /\.[jt]sx?$/,
use: [
{
loader: "ts-loader",
@ -89,12 +89,14 @@ export default {
fallback: { fs: false },
alias: {
"global-compression": resolve("../src/js/core/lzstring.js"),
"root": resolve("../src/js/"),
},
fullySpecified: false,
extensions: [".ts", ".js"],
extensions: [".ts", ".js", ".tsx", ".jsx"],
},
devtool: "cheap-source-map",
watch: true,
cache: false,
plugins: [
new webpack.DefinePlugin(globalDefs),
new webpack.IgnorePlugin({ resourceRegExp: /\.(png|jpe?g|svg)$/ }),

View File

@ -34,7 +34,7 @@ const moduleRules = [
type: "javascript/auto",
},
{
test: /\.js$/,
test: /\.jsx?$/,
enforce: "pre",
exclude: /node_modules/,
use: [
@ -56,7 +56,7 @@ const moduleRules = [
],
},
{
test: /\.[jt]s$/,
test: /\.[jt]sx?$/,
use: [
{
loader: "ts-loader",
@ -100,9 +100,10 @@ export default {
fallback: { fs: false },
alias: {
"global-compression": resolve("../src/js/core/lzstring.js"),
"root": resolve("../src/js/"),
},
fullySpecified: false,
extensions: [".ts", ".js"],
extensions: [".ts", ".js", ".tsx", ".jsx"],
},
stats: { optimizationBailout: true },
devtool: false,

43
src/js/globals.d.ts vendored
View File

@ -208,3 +208,46 @@ declare module "worker-loader?inline=true&fallback=false!*" {
export default WebpackWorker;
}
// JSX type support - https://www.typescriptlang.org/docs/handbook/jsx.html
// modified from https://stackoverflow.com/a/68238924
declare namespace JSX {
/**
* The return type of a JSX expression.
*
* In reality, Fragments can return arbitrary values, but we ignore this for convenience.
*/
type Element = HTMLElement;
/**
* Key-value list of intrinsic element names and their allowed properties.
*
* Because children are treated as a property, the Node type cannot be excluded from the index signature.
*/
type IntrinsicElements = {
[K in keyof HTMLElementTagNameMap]: {
children?: Node | Node[];
[k: string]: Node | Node[] | string | number | boolean;
};
};
/**
* The property of the attributes object storing the children.
*/
type ElementChildrenAttribute = { children: unknown };
// The following do not have special meaning to TypeScript.
/**
* An attributes object.
*/
type Props = { [k: string]: unknown };
/**
* A functional component requiring attributes to match `T`.
*/
type Component<T extends Props> = {
(props: T): Element;
};
/**
* A child of a JSX element.
*/
type Node = Element | string | boolean | null | undefined;
}

41
src/js/jsx-runtime.ts Normal file
View File

@ -0,0 +1,41 @@
function isDisplayed(node: JSX.Node): node is Exclude<JSX.Node, boolean | null | undefined> {
return typeof node !== "boolean" && node != null;
}
/**
* JSX factory.
*/
function jsx<T extends keyof JSX.IntrinsicElements>(tag: T, props: JSX.IntrinsicElements[T]): HTMLElement;
function jsx<U extends JSX.Props>(tag: JSX.Component<U>, props: U): Element;
function jsx<U extends JSX.Props>(
tag: keyof JSX.IntrinsicElements | JSX.Component<U>,
props: U
): JSX.Element {
if (typeof tag === "function") return tag(props);
const { children, ...attrs } = props as JSX.IntrinsicElements[keyof JSX.IntrinsicElements];
const element = document.createElement(tag);
Object.entries(attrs).forEach(([key, value]) => {
switch (typeof value) {
case "boolean":
if (!value) return;
return element.setAttribute(key, "");
case "number":
case "string":
return element.setAttribute(key, `${value}`);
}
throw new TypeError("JSX element attribute assigned invalid type");
});
element.append(...([children].flat(Infinity) as JSX.Node[]).filter(isDisplayed));
return element;
}
// functional component, called indirectly as `jsx(Fragment, props)`
/**
* Groups elements without introducing a parent element.
*/
const Fragment = (props: JSX.Props) => props.children as JSX.Element;
// jsxs is used when there are multiple children
export { jsx, jsx as jsxs, Fragment };

View File

@ -31,12 +31,19 @@
/* Module Resolution Options */
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"paths": {
"root/*": ["./*"]
},
/* JSX Compilation */
"jsx": "react-jsx",
"jsxImportSource": "root",
/* Experimental Options */
"resolveJsonModule": true,
"skipLibCheck": true,
"skipDefaultLibCheck": true
},
"include": ["./**/*.js", "./**/*.ts"],
"include": ["./**/*.js", "./**/*.ts", "./**/*.jsx", "./**/*.tsx"],
"exclude": ["webworkers", "node_modules"]
}