add typescript and react

This commit is contained in:
Nils Ramstöck
2023-10-05 15:48:37 +02:00
parent 02c5c003a6
commit 2ff28fbd8f
7 changed files with 140 additions and 1 deletions

3
.gitignore vendored
View File

@@ -128,3 +128,6 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# Netscript Type Definitions. These are pulled from the game
NetscriptDefinitions.d.ts

View File

@@ -8,11 +8,15 @@ const ctx = await context({
outbase: "./servers",
outdir: "./dist",
plugins: [BitburnerPlugin({
port: 12525
port: 12525,
servers: ['home'],
types: 'NetscriptDefinitions.d.ts'
})],
bundle: true,
format: 'esm',
platform: 'browser',
logLevel: 'info'
});
ctx.watch();

38
package-lock.json generated
View File

@@ -9,6 +9,8 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@types/react": "^18.2.25",
"@types/react-dom": "^18.2.10",
"esbuild": "^0.19.4",
"esbuild-bitburner-plugin": "file:../esbuild-bitburner-plugin",
"glob": "^10.3.10"
@@ -17,6 +19,9 @@
"../esbuild-bitburner-plugin": {
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"websocket": "^1.0.34"
},
"devDependencies": {
"esbuild": "^0.19.4"
}
@@ -376,6 +381,34 @@
"node": ">=14"
}
},
"node_modules/@types/prop-types": {
"version": "15.7.8",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz",
"integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ=="
},
"node_modules/@types/react": {
"version": "18.2.25",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.25.tgz",
"integrity": "sha512-24xqse6+VByVLIr+xWaQ9muX1B4bXJKXBbjszbld/UEDslGLY53+ZucF44HCmLbMPejTzGG9XgR+3m2/Wqu1kw==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
"version": "18.2.10",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.10.tgz",
"integrity": "sha512-5VEC5RgXIk1HHdyN1pHlg0cOqnxHzvPGpMMyGAP5qSaDRmyZNDaQ0kkVAkK6NYlDhP6YBID3llaXlmAS/mdgCA==",
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/scheduler": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz",
"integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ=="
},
"node_modules/ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
@@ -440,6 +473,11 @@
"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=="
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",

View File

@@ -17,6 +17,8 @@
},
"homepage": "https://github.com/NilsRamstoeck/bb-external-editor#readme",
"dependencies": {
"@types/react": "^18.2.25",
"@types/react-dom": "^18.2.10",
"esbuild": "^0.19.4",
"esbuild-bitburner-plugin": "file:../esbuild-bitburner-plugin",
"glob": "^10.3.10"

View File

@@ -1,3 +1,4 @@
export async function main(ns){
const a = 1;
ns.tprint('hello world');
}

66
servers/home/react.tsx Normal file
View File

@@ -0,0 +1,66 @@
import { NS } from "NetscriptDefinitions";
import {render, unmountComponentAtNode} from 'react-dom';
import React, {useState} from "react";
export async function main(ns: NS) {
//i dont know a better way to open a window in bb, so feel free to use yours
//print a string we can search for
const ID = `SCRIPT_ID:${ns.pid}`;
ns.tail(ns.pid, 'home');
ns.print(ID);
//wait for a bit to make sure the change took affect
await new Promise<void>(resolve => setTimeout(() => resolve(), 100));
//grab the actual html element
const tailWindows = [...document.querySelectorAll('.react-resizable')];
const spans = tailWindows.map(win => [...win.querySelectorAll('span')]).flat();
const idSpan = spans.filter((cur) => cur.innerHTML == ID)[0];
const windowEl = findRoot(idSpan);
//now we can render our react stuff
render(<div></div>, windowEl);
if(false)useState();
//make sure to unmount our react stuff on exit
ns.atExit(() => {
unmountComponentAtNode(windowEl);
});
//return a promise that resolves when the tail window gets closed so our script terminates properly
return new Promise<void>(resolve => watchElForDeletion(windowEl, () => resolve()));
}
//find root of tail window
function findRoot(span: Element) {
let el = span;
while (!el.parentElement.classList.contains('react-resizable'))
el = el.parentElement;
return el;
}
function watchElForDeletion(elToWatch: Element, callback: () => void) {
const parent = document.body;
const observer = new MutationObserver(function (mutations) {
// loop through all mutations
mutations.forEach(function (mutation) {
// check for changes to the child list
if (mutation.type === 'childList') {
mutation.removedNodes.forEach(node => !containsRecursive(node, elToWatch) || callback());
}
});
});
// start observing the parent - defaults to document body
observer.observe(parent, { childList: true, subtree: true });
};
//check if an element is part of another elements subtree
function containsRecursive(container: Node | Element, child: Element) {
if (!('children' in container)) return;
return [...container.children].reduce((prev, cur) => prev || cur == child || containsRecursive(cur, child), false);
}

25
tsconfig.json Normal file
View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"lib": [
"esnext",
"dom",
"dom.iterable"
],
"baseUrl": "./",
"jsx": "react",
"paths": {
"@/*": [
"src/*"
],
"NetscriptDefinitions" : ["NetscriptDefinitions.d.ts"]
}
},
"include": [
"servers/**/*.ts*"
]
}