mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-12 02:10:30 +00:00
Use Preact for static rendering of components
We already use preact for the copy-cat integration, so it makes sense to use it during the static pass too. This allows us to drop a dependency on react.
This commit is contained in:
parent
6c8b391dab
commit
3188197447
112
package-lock.json
generated
112
package-lock.json
generated
@ -17,10 +17,8 @@
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@rollup/plugin-url": "^8.0.1",
|
||||
"@types/glob": "^8.1.0",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"glob": "^10.3.4",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"preact-render-to-string": "^6.2.1",
|
||||
"rehype": "^13.0.0",
|
||||
"rehype-highlight": "^7.0.0",
|
||||
"rehype-react": "^8.0.0",
|
||||
@ -635,38 +633,6 @@
|
||||
"integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.2.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz",
|
||||
"integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "18.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz",
|
||||
"integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/scheduler": {
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz",
|
||||
@ -824,12 +790,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
@ -1288,24 +1248,6 @@
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lowlight": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.0.0.tgz",
|
||||
@ -1554,6 +1496,24 @@
|
||||
"url": "https://opencollective.com/preact"
|
||||
}
|
||||
},
|
||||
"node_modules/preact-render-to-string": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.2.1.tgz",
|
||||
"integrity": "sha512-5t7nFeMUextd53igL3GAakAAMaUD+dVWDHaRYaeh1tbPIjQIBtgJnMw6vf8VS/lviV0ggFtkgebatPxvtJsXyQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"pretty-format": "^3.8.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"preact": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
|
||||
"integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/property-information": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.3.0.tgz",
|
||||
@ -1573,31 +1533,6 @@
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rehype": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.1.tgz",
|
||||
@ -1751,15 +1686,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
|
@ -14,13 +14,11 @@
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@rollup/plugin-url": "^8.0.1",
|
||||
"@types/glob": "^8.1.0",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"glob": "^10.3.4",
|
||||
"react-dom": "^18.1.0",
|
||||
"react": "^18.1.0",
|
||||
"preact-render-to-string": "^6.2.1",
|
||||
"rehype": "^13.0.0",
|
||||
"rehype-highlight": "^7.0.0",
|
||||
"rehype-react": "^8.0.0",
|
||||
"rehype": "^13.0.0",
|
||||
"requirejs": "^2.3.6",
|
||||
"rollup": "^3.19.1",
|
||||
"tsx": "^3.12.10",
|
||||
|
@ -687,7 +687,7 @@ settings.define("paint.default_extension", {
|
||||
|
||||
settings.define("list.show_hidden", {
|
||||
default = false,
|
||||
description = [[Show hidden files (those starting with "." in the Lua REPL).]],
|
||||
description = [[Whether the list program show hidden files (those starting with ".").]],
|
||||
type = "boolean",
|
||||
})
|
||||
|
||||
|
@ -5,13 +5,14 @@
|
||||
import { readFileSync } from "fs";
|
||||
import path from "path";
|
||||
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
import url from '@rollup/plugin-url';
|
||||
import terser from "@rollup/plugin-terser";
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
import url from "@rollup/plugin-url";
|
||||
|
||||
const input = "src";
|
||||
const requirejs = readFileSync("../../node_modules/requirejs/require.js");
|
||||
|
||||
/** @type import("rollup").RollupOptions */
|
||||
export default {
|
||||
input: [`${input}/index.tsx`],
|
||||
output: {
|
||||
@ -54,7 +55,7 @@ export default {
|
||||
async transform(code, file) {
|
||||
// Allow loading files in /mount.
|
||||
const ext = path.extname(file);
|
||||
return ext != '.dfpwm' && path.dirname(file) === path.resolve(`${input}/mount`)
|
||||
return ext != ".dfpwm" && path.dirname(file) === path.resolve(`${input}/mount`)
|
||||
? `export default ${JSON.stringify(code)};\n`
|
||||
: null;
|
||||
},
|
||||
|
@ -2,8 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import type { FunctionComponent } from "react";
|
||||
import { createElement as h } from "react";
|
||||
import { h, type FunctionComponent, type JSX } from "preact";
|
||||
import useExport from "./WithExport";
|
||||
|
||||
const Item: FunctionComponent<{ item: string }> = ({ item }) => {
|
||||
|
@ -2,7 +2,8 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import { createElement as h, useContext, createContext, type FunctionComponent, type ReactNode } from "react";
|
||||
import { h, createContext, type FunctionComponent, type VNode } from "preact";
|
||||
import { useContext } from "preact/hooks";
|
||||
|
||||
export type DataExport = {
|
||||
readonly itemNames: Record<string, string>,
|
||||
@ -23,5 +24,5 @@ const DataExport = createContext<DataExport>({
|
||||
export const useExport = () => useContext(DataExport);
|
||||
export default useExport;
|
||||
|
||||
export const WithExport: FunctionComponent<{ data: DataExport, children: ReactNode }> =
|
||||
({ data, children }) => <DataExport.Provider value={data}> {children}</DataExport.Provider >;
|
||||
export const WithExport: FunctionComponent<{ data: DataExport, children: VNode }> =
|
||||
({ data, children }) => <DataExport.Provider value={data}> {children}</DataExport.Provider>;
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import type { FunctionComponent } from "react";
|
||||
import { type FunctionComponent } from "preact";
|
||||
|
||||
/**
|
||||
* Wrap a component and ensure that no children are passed to it.
|
||||
@ -20,7 +20,7 @@ export const noChildren = function <T>(component: FunctionComponent<T>): Functio
|
||||
|
||||
const name = component.displayName ?? component.name;
|
||||
const wrapped: FunctionComponent<T> = props => {
|
||||
if ((props as any).children) throw Error("Unexpected children in " + name);
|
||||
if (props.children) throw Error("Unexpected children in " + name);
|
||||
|
||||
return component(props);
|
||||
};
|
||||
|
@ -2,18 +2,18 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import { render, h, Component, Computer, type PeripheralKind } from "copycat/embed";
|
||||
import type { ComponentChild } from "preact";
|
||||
import { Component, Computer, h, render, type PeripheralKind } from "copycat/embed";
|
||||
import type { ComponentChild, FunctionalComponent } from "preact";
|
||||
|
||||
import settingsFile from "./mount/.settings";
|
||||
import startupFile from "./mount/startup.lua";
|
||||
import exprTemplate from "./mount/expr_template.lua";
|
||||
import exampleAudioUrl from "./mount/example.dfpwm";
|
||||
import exampleAudioLicense from "./mount/example.dfpwm.license";
|
||||
import exampleNfp from "./mount/example.nfp";
|
||||
import exampleNft from "./mount/example.nft";
|
||||
import exampleAudioLicense from "./mount/example.dfpwm.license";
|
||||
import exampleAudioUrl from "./mount/example.dfpwm";
|
||||
import exprTemplate from "./mount/expr_template.lua";
|
||||
import startupFile from "./mount/startup.lua";
|
||||
|
||||
const defaultFiles: { [filename: string]: string } = {
|
||||
const defaultFiles: Record<string, string> = {
|
||||
".settings": settingsFile,
|
||||
"startup.lua": startupFile,
|
||||
|
||||
@ -36,13 +36,13 @@ const download = async (url: string): Promise<Uint8Array> => {
|
||||
|
||||
let dfpwmAudio: Promise<Uint8Array> | null = null;
|
||||
|
||||
const Click = (options: { run: () => void }) =>
|
||||
<button type="button" class="example-run" onClick={options.run}>Run ᐅ</button>
|
||||
const Click: FunctionalComponent<{ run: () => void }> = ({ run }) =>
|
||||
<button type="button" class="example-run" onClick={run}>Run ᐅ</button>
|
||||
|
||||
type WindowProps = {};
|
||||
|
||||
type Example = {
|
||||
files: { [file: string]: string | Uint8Array },
|
||||
files: Record<string, string | Uint8Array>,
|
||||
peripheral: PeripheralKind | null,
|
||||
}
|
||||
|
||||
@ -105,8 +105,8 @@ class Window extends Component<WindowProps, WindowState> {
|
||||
</div>
|
||||
<div class="computer-container">
|
||||
<Computer key={exampleIdx} files={{
|
||||
...defaultFiles, ...example!.files,
|
||||
}} peripherals={{ back: example!.peripheral }} />
|
||||
...defaultFiles, ...example.files,
|
||||
}} peripherals={{ back: example.peripheral }} />
|
||||
</div>
|
||||
</div>
|
||||
</div> : <div class="example-window example-window-hidden" />;
|
||||
@ -120,7 +120,7 @@ class Window extends Component<WindowProps, WindowState> {
|
||||
this.top = 20;
|
||||
}
|
||||
|
||||
const files: { [file: string]: string | Uint8Array } = { "example.lua": example };
|
||||
const files: Record<string, string | Uint8Array> = { "example.lua": example };
|
||||
if (mount !== null) {
|
||||
for (const toMount of mount.split(",")) {
|
||||
const [name, path] = toMount.split(":", 2);
|
||||
|
@ -10,20 +10,20 @@
|
||||
*
|
||||
* Yes, this would be so much nicer with next.js.
|
||||
*/
|
||||
import * as fs from "fs/promises";
|
||||
import fs from "fs/promises";
|
||||
import { glob } from "glob";
|
||||
import * as path from "path";
|
||||
import { createElement as h } from 'react';
|
||||
import runtime from 'react/jsx-runtime';
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import rehypeHighlight from "rehype-highlight";
|
||||
import rehypeParse from 'rehype-parse';
|
||||
import rehypeReact, { type Options as ReactOptions } from 'rehype-react';
|
||||
import { unified } from 'unified';
|
||||
import path from "path";
|
||||
import { h, type JSX } from "preact";
|
||||
import renderToStaticMarkup from "preact-render-to-string";
|
||||
import * as runtime from "preact/jsx-runtime";
|
||||
import rehypeHighlight, { type Options as HighlightOptions } from "rehype-highlight";
|
||||
import rehypeParse from "rehype-parse";
|
||||
import rehypeReact, { type Options as ReactOptions } from "rehype-react";
|
||||
import { unified, type Plugin } from "unified";
|
||||
// Our components
|
||||
import Recipe from "./components/Recipe";
|
||||
import { noChildren } from "./components/support";
|
||||
import { type DataExport, WithExport } from "./components/WithExport";
|
||||
import { WithExport, type DataExport } from "./components/WithExport";
|
||||
|
||||
(async () => {
|
||||
const base = "build/illuaminate";
|
||||
@ -31,19 +31,19 @@ import { type DataExport, WithExport } from "./components/WithExport";
|
||||
const reactOptions: ReactOptions = {
|
||||
...(runtime as ReactOptions),
|
||||
components: {
|
||||
['mc-recipe']: noChildren(Recipe),
|
||||
['mcrecipe']: noChildren(Recipe),
|
||||
["mc-recipe"]: noChildren(Recipe),
|
||||
["mcrecipe"]: noChildren(Recipe),
|
||||
// Wrap example snippets in a <div class="lua-example">...</div>, so we can inject a
|
||||
// Run button into them.
|
||||
['pre']: (args: JSX.IntrinsicElements["pre"] & { "data-lua-kind"?: undefined }) => {
|
||||
["pre"]: (args: JSX.IntrinsicElements["pre"] & { "data-lua-kind"?: undefined }) => {
|
||||
const element = <pre {...args} />;
|
||||
return args["data-lua-kind"] ? <div className="lua-example">{element}</div> : element
|
||||
}
|
||||
} as any
|
||||
}
|
||||
};
|
||||
const processor = unified()
|
||||
.use(rehypeParse, { emitParseErrors: true })
|
||||
.use(rehypeHighlight, { prefix: "" })
|
||||
.use(rehypeHighlight as unknown as Plugin<[HighlightOptions], import("hast").Root>, { prefix: "" })
|
||||
.use(rehypeReact, reactOptions);
|
||||
|
||||
const dataExport = JSON.parse(await fs.readFile("src/export/index.json", "utf-8")) as DataExport;
|
||||
|
Loading…
Reference in New Issue
Block a user