Skip to content

Commit

Permalink
feat: init react-dom
Browse files Browse the repository at this point in the history
  • Loading branch information
saitoChen committed Nov 8, 2023
1 parent e8508f1 commit 06f81de
Show file tree
Hide file tree
Showing 23 changed files with 1,262 additions and 28 deletions.
466 changes: 466 additions & 0 deletions dist/node_modules/react-dom/client.js

Large diffs are not rendered by default.

466 changes: 466 additions & 0 deletions dist/node_modules/react-dom/index.js

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions dist/node_modules/react-dom/package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "eslint --ext .jsx,.ts,.js,.tsx --fix --quiet ./packages",
"build:dev": "rimraf dist && rollup --bundleConfigAsCjs --config scripts/rollup/react.config.js"
"build:dev": "rimraf dist && rollup --bundleConfigAsCjs --config scripts/rollup/dev.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@commitlint/cli": "^18.2.0",
"@commitlint/config-conventional": "^18.1.0",
"@rollup/plugin-alias": "^5.0.1",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-replace": "^5.0.5",
"@types/node": "^20.8.10",
Expand Down
8 changes: 8 additions & 0 deletions packages/react-dom/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* @Author: chenjianfeng chenjianfeng93@163.com
* @Date: 2023-11-07 23:33:32
* @Description:
*/
import * as ReactDOM from './src/root'

export default ReactDOM
1 change: 1 addition & 0 deletions packages/react-dom/node_modules/react

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/react-dom/node_modules/react-reconciler

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/react-dom/node_modules/shared

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions packages/react-dom/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "react-dom",
"version": "1.0.0",
"description": "",
"module": "index.ts",
"dependencies": {
"shared": "workspace:*",
"react-reconciler": "workspace:*"
},
"peerDependencies": {
"react": "workspace:*"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
26 changes: 26 additions & 0 deletions packages/react-dom/src/hostConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* @Author: chenjianfeng chenjianfeng93@163.com
* @Date: 2023-11-03 14:58:51
* @Description:
*/
export type Container = Element
export type Instance = Element

// export const createInstance = (type: string, props: any): Instance => {
export const createInstance = (type: string): Instance => {
const element = document.createElement(type)
return element
}

export const appendInitialChild = (
parent: Instance | Container,
child: Instance
) => {
parent.appendChild(child)
}

export const createTextInstance = (content: string) => {
return document.createTextNode(content)
}

export const appendChildToContainer = appendInitialChild
21 changes: 21 additions & 0 deletions packages/react-dom/src/root.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* @Author: chenjianfeng chenjianfeng93@163.com
* @Date: 2023-11-07 22:25:43
* @Description:
*/
import {
createContainer,
updateContainer
} from 'react-reconciler/src/fiberReconciler'
import { Container } from './hostConfig'
import { ReactElementType } from 'shared/ReactTypes'

export const createRoot = (container: Container) => {
const root = createContainer(container)

return {
render(element: ReactElementType) {
updateContainer(element, root)
}
}
}
1 change: 1 addition & 0 deletions packages/react-reconciler/src/beginWork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const beginWork = (wip: FiberNode) => {
console.warn('unknown type by beginWork')
}
}
return null
}

const updateHostRoot = (wip: FiberNode) => {
Expand Down
96 changes: 96 additions & 0 deletions packages/react-reconciler/src/commitWork.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* @Author: chenjianfeng chenjianfeng93@163.com
* @Date: 2023-11-07 16:04:55
* @Description:
*/
import { Container, appendChildToContainer } from 'hostConfig'
import { FiberNode, FiberRootNode } from './fiber'
import { MutationMask, NoFlags, Placement } from './fiberFlags'
import { HostComponent, HostRoot, HostText } from './workTags'

export const commitMutationEffects = (finishedWork: FiberNode) => {
let nextEffect = finishedWork

while (nextEffect !== null) {
const child = nextEffect.child
if (
(nextEffect.subtreeFlags & MutationMask) !== NoFlags &&
child !== null
) {
nextEffect = child
} else {
up: while (nextEffect !== null) {
commitMutationEffectsOnFiber(nextEffect)
const sibling = nextEffect.sibling
if (sibling !== null) {
nextEffect = sibling
break up
}
nextEffect = nextEffect.return!
}
}
}
}

const commitMutationEffectsOnFiber = (finishedWork: FiberNode) => {
const flags = finishedWork.flags
if ((flags & Placement) !== NoFlags) {
commitPlacement(finishedWork)
// remove Placement from flags
finishedWork.flags &= ~Placement
}

// update

// childDelection
}

const commitPlacement = (finishedWork: FiberNode) => {
// insert dom to parent's dom
if (__DEV__) {
console.warn('execute Placement operation')
}

const hostParent = getHostParent(finishedWork)
if (hostParent) {
appendPlacementNodeIntoContainer(finishedWork, hostParent)
}
}

const getHostParent = (fiber: FiberNode): Container | null => {
let parent = fiber.return
while (parent) {
const parentTag = parent.tag
if (parentTag === HostComponent) {
return parent.stateNode
}
if (parentTag === HostRoot) {
return (parent.stateNode as FiberRootNode).container
}
parent = parent.return
}
if (__DEV__) {
console.warn('can not find host parent')
}

return null
}

const appendPlacementNodeIntoContainer = (
finishedWork: FiberNode,
hostParent: Container
) => {
if (finishedWork.tag === HostComponent || finishedWork.tag === HostText) {
appendChildToContainer(hostParent, finishedWork.stateNode)
return
}
const child = finishedWork.child
if (child !== null) {
appendPlacementNodeIntoContainer(child, hostParent)
let sibling = child.sibling
while (sibling !== null) {
appendPlacementNodeIntoContainer(sibling, hostParent)
sibling = sibling.sibling
}
}
}
8 changes: 5 additions & 3 deletions packages/react-reconciler/src/completeWork.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
createInstance,
appendInitialChild,
createTextInstance
createTextInstance,
Container
} from 'hostConfig'
import { FiberNode } from './fiber'
import { HostComponent, HostRoot, HostText } from './workTags'
Expand All @@ -20,7 +21,8 @@ export const completeWork = (wip: FiberNode) => {
// update
} else {
// 1. create Dom 2. insert dom
const instance = createInstance(wip.type, newProps)
// const instance = createInstance(wip.type, newProps)
const instance = createInstance(wip.type)
appendAllChildren(instance, wip)
wip.stateNode = instance
}
Expand All @@ -39,7 +41,7 @@ export const completeWork = (wip: FiberNode) => {
}
}

const appendAllChildren = (parent: FiberNode, wip: FiberNode) => {
const appendAllChildren = (parent: Container, wip: FiberNode) => {
let node = wip.child
while (node !== null) {
if (node.tag === HostComponent || node.tag === HostText) {
Expand Down
2 changes: 2 additions & 0 deletions packages/react-reconciler/src/fiberFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export const NoFlags = 0b0000001
export const Placement = 0b0000010
export const Update = 0b0000100
export const ChildDeletion = 0b0010000

export const MutationMask = Placement | Update | ChildDeletion
3 changes: 2 additions & 1 deletion packages/react-reconciler/src/fiberReconciler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import {
} from './updateQueue'
import { ReactElementType } from 'shared/ReactTypes'
import { scheduleUpdateOnFiber } from './workLoop'
import { HostRoot } from './workTags'

// ReactDom.createRoot
export const createContainer = (container: Container) => {
const hostRootFiber = new FiberNode(container, {}, null)
const hostRootFiber = new FiberNode(HostRoot, {}, null)
const root = new FiberRootNode(container, hostRootFiber)
hostRootFiber.updateQueue = createUpdateQueue()

Expand Down
18 changes: 0 additions & 18 deletions packages/react-reconciler/src/hostConfig.ts

This file was deleted.

29 changes: 29 additions & 0 deletions packages/react-reconciler/src/workLoop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { FiberNode, FiberRootNode, crateWorkInProgress } from './fiber'
import { beginWork } from './beginWork'
import { completeWork } from './completeWork'
import { HostRoot } from './workTags'
import { MutationMask, NoFlags } from './fiberFlags'

let workInProgress: FiberNode | null = null

Expand Down Expand Up @@ -49,11 +50,39 @@ export const renderRoot = (root: FiberRootNode) => {
} while (true)

const finishedWork = root.current.alternate
// finishedWork is wip
root.finishedWork = finishedWork

commitRoot(root)
}

const commitRoot = (root: FiberRootNode) => {
// 1. switch fiber tree
// 2. execute Placement operation
const finishedWork = root.finishedWork
if (finishedWork === null) return
if (__DEV__) console.warn('commit start', finishedWork)

// reset
root.finishedWork = null

const subtreeHasEffect =
(finishedWork.subtreeFlags & MutationMask) !== NoFlags
const rootHasEffect = (finishedWork.flags & MutationMask) !== NoFlags

if (subtreeHasEffect || rootHasEffect) {
// beforeMutation
// mutation

// switch fiber tree
// hostRootNode
root.current = finishedWork
// layout
} else {
root.current = finishedWork
}
}

const workLoop = () => {
while (workInProgress !== null) {
performUnitOfWork(workInProgress)
Expand Down
33 changes: 33 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 06f81de

Please sign in to comment.