From f411544fe979241b91a8933cf3c83cb5db70ab67 Mon Sep 17 00:00:00 2001 From: aleidk Date: Tue, 25 Jun 2024 13:02:10 -0400 Subject: [PATCH] First commit Create basic render engine that only allows to add elements --- .gitignore | 24 ++++++ README.md | 13 +++ bun.lockb | Bin 0 -> 67365 bytes eslint.config.js | 10 +++ index.html | 13 +++ package.json | 22 +++++ public/vite.svg | 1 + src/lib/YarJS.ts | 164 ++++++++++++++++++++++++++++++++++++ src/lib/YarJs.interfaces.ts | 18 ++++ src/main.tsx | 13 +++ src/style.css | 96 +++++++++++++++++++++ src/vite-env.d.ts | 1 + tsconfig.json | 29 +++++++ vite.config.ts | 10 +++ 14 files changed, 414 insertions(+) create mode 100644 .gitignore create mode 100755 bun.lockb create mode 100644 eslint.config.js create mode 100644 index.html create mode 100644 package.json create mode 100644 public/vite.svg create mode 100644 src/lib/YarJS.ts create mode 100644 src/lib/YarJs.interfaces.ts create mode 100644 src/main.tsx create mode 100644 src/style.css create mode 100644 src/vite-env.d.ts create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/README.md b/README.md index 255eec0..cf677db 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,15 @@ # yarjs +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.1.16. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..e02b481400bbbc66fc46aa54065ec4bd792270a9 GIT binary patch literal 67365 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 z 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 literal 0 HcmV?d00001 diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..9e38baa --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,10 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import tseslint from "typescript-eslint"; + +export default [ + { files: ["**/*.{js,mjs,cjs,ts}"] }, + { languageOptions: { globals: globals.browser } }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, +]; diff --git a/index.html b/index.html new file mode 100644 index 0000000..e6025da --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + TS + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..6da01ea --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "yarjs", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@eslint/js": "^9.5.0", + "@types/bun": "latest", + "@types/react": "^18.3.3", + "eslint": "9.x", + "globals": "^15.6.0", + "typescript": "^5.2.2", + "typescript-eslint": "^7.13.1", + "vite": "^5.3.1" + }, + "module": "index.ts" +} diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/lib/YarJS.ts b/src/lib/YarJS.ts new file mode 100644 index 0000000..93ae5cc --- /dev/null +++ b/src/lib/YarJS.ts @@ -0,0 +1,164 @@ +import { + YarElement, + YarFiber, + YarHTMLTagName, + YarProps, +} from "./YarJs.interfaces"; + +export function createTextElement(text: string) { + return { + type: "TEXT", + props: { + nodeValue: text, + children: [], + }, + }; +} + +export function createElement( + type: YarHTMLTagName, + props: YarProps, + ...children: YarElement[] +) { + return { + type, + props: { + ...props, + children: children.map((child) => + typeof child === "object" ? child : createTextElement(child), + ), + }, + }; +} + +function createDom(fiber: YarFiber) { + const dom = + fiber.type === "TEXT" + ? document.createTextNode("") + : document.createElement(fiber.type); + + Object.keys(fiber.props) + .filter((key) => key !== "children") + .forEach((key) => { + // @ts-expect-error: I cannot figure it out how to properly type the dom props + dom[key] = fiber.props[key]; + }); + + return dom; +} + +let nextUnitOfWork: YarFiber | null | undefined = null; +let wipRoot: YarFiber | null | undefined = null; + +function commitWork(fiber: YarFiber | null) { + if (!fiber) return; + + const domParent = fiber.parent!.dom!; + domParent.appendChild(fiber.dom!); + commitWork(fiber.child); + commitWork(fiber.sibling); +} + +function commitRoot() { + if (!wipRoot) return; + + commitWork(wipRoot.child); + wipRoot = null; +} + +function workLoop(deadline: IdleDeadline) { + let shouldYield = false; + while (nextUnitOfWork && !shouldYield) { + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + shouldYield = deadline.timeRemaining() < 1; + } + + if (!nextUnitOfWork && wipRoot) { + commitRoot(); + } + + requestIdleCallback(workLoop); +} + +requestIdleCallback(workLoop); + +function performUnitOfWork(fiber: YarFiber) { + // Process the Fiber Tree, this is a representation of the DOM + // Since this this process could be interrupted before the whole + // tree is processed, we just do the representation and computation here, + // then in "commitWork" we add the representation to the actual DOM + + if (!fiber.dom) { + // Create the actual dom element + fiber.dom = createDom(fiber); + } + + // Create a new fiber for each child + const elements = fiber.props.children; + let index = 0; + let prevSibling: YarFiber | null = null; + + while (index < elements.length) { + const element = elements[index]; + + const newFiber = { + parent: fiber, + type: element.type, + props: element.props, + child: null, + sibling: null, + dom: null, + }; + + // Each Fiber only holds a reference to it's first child (in the Fiber Tree representation), + // so if is the first new Fiber we add it as a child to the parent, + // if is not, we add as a sibling of the last child + // Nonetheless, each fiber has a reference to it's parent + if (index === 0) { + fiber.child = newFiber; + } else if (prevSibling !== null) { + prevSibling.sibling = newFiber; + } + + prevSibling = newFiber; + index++; + } + + // Search for the new fiber that needs to be processed + if (fiber.child) { + // return the first child of the current fiber + return fiber.child; + } + + let nextFiber = fiber; + + while (nextFiber) { + if (nextFiber.sibling) { + // return the next sibling of the current fiber + return nextFiber.sibling; + } + + // Reference the parent so we look at the "uncle" (parent sibling) + // in the next itereation + nextFiber = nextFiber.parent!; + } +} + +export function render(element: React.JSX.Element, container: HTMLElement) { + wipRoot = { + type: "", + dom: container, + parent: null, + child: null, + sibling: null, + props: { + children: [element], + }, + }; + + nextUnitOfWork = wipRoot; +} + +export function Fragment() {} + +export default { render, createElement, Fragment }; diff --git a/src/lib/YarJs.interfaces.ts b/src/lib/YarJs.interfaces.ts new file mode 100644 index 0000000..974c502 --- /dev/null +++ b/src/lib/YarJs.interfaces.ts @@ -0,0 +1,18 @@ +export type YarHTMLTagName = keyof React.JSX.IntrinsicElements | string; + +export type YarProps = { + children: YarElement[]; + [key: string]: unknown; +}; + +export interface YarElement { + type: YarHTMLTagName; + props: YarProps; +} + +export interface YarFiber extends YarElement { + parent: null | YarFiber; + dom: null | HTMLElement | Text; + child: null | YarFiber; + sibling: null | YarFiber; +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..0a7e63d --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,13 @@ +import "./style.css"; +import { render } from "./lib/YarJS"; + +const root = document.querySelector("#app")!; + +const element = ( +
+ bar + +
+); + +render(element, root); diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..f9c7350 --- /dev/null +++ b/src/style.css @@ -0,0 +1,96 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.vanilla:hover { + filter: drop-shadow(0 0 2em #3178c6aa); +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b084023 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "jsx": "preserve", + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + "paths": { + "@/*": ["./*"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..eab331a --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,10 @@ +// vite.config.js +import { defineConfig } from "vite"; + +export default defineConfig({ + esbuild: { + jsxFactory: "createElement", + jsxFragment: "Fragment", + jsxInject: `import {createElement, Fragment} from './lib/YarJS'`, + }, +});