-
-
Notifications
You must be signed in to change notification settings - Fork 580
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: add projects to showcase * chore: checkout to new branch * feat/add-i18n-to-docs * fix: docs link
- Loading branch information
1 parent
36d1913
commit 8f856c0
Showing
3 changed files
with
163 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,11 @@ | ||
{ | ||
<<<<<<< HEAD | ||
"index": "介绍" | ||
======= | ||
"introduction": "Introduction", | ||
"install": "Installation", | ||
"automatic": "Automatic", | ||
"manual-mode": "Manual Mode", | ||
"internals": "Internals" | ||
>>>>>>> 36d1913569efff3399cde30dbda145ffd761115e | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import { Disclosures } from '../../components/home/faq'; | ||
import { Callout, Tab, Tabs } from 'nextra-theme-docs'; | ||
import Link from 'next/link'; | ||
import dynamic from 'next/dynamic'; | ||
|
||
export const Demo = dynamic(() => | ||
import('../../components/demo').then((mod) => mod.Demo), | ||
); | ||
|
||
# Chinese We | ||
|
||
Million.js is an extremely fast and lightweight optimizing compiler that make [components](https://react.dev) up to [_**70% faster**_](https://krausest.github.io/js-framework-benchmark/current.html). | ||
|
||
**TL;DR:** Imagine [React](https://react.dev) components running at the speed of raw JavaScript. | ||
|
||
## Why Million.js? | ||
|
||
To understand why to use Million.js, we need to understand how React updates interfaces. When an application's state or props change, React undergoes an update in two parts: rendering and reconciliation. | ||
|
||
To show this, let's say this is our `App`: | ||
|
||
```jsx | ||
function App() { | ||
const [count, setCount] = useState(0); | ||
const increment = () => setCount(count + 1); | ||
return ( | ||
<div> | ||
<p>Count: {count}</p> | ||
<button onClick={increment}>Increment</button> | ||
</div> | ||
); | ||
} | ||
``` | ||
|
||
In this `App`, when I click on the button, the `count` state will update and the `<p>` tag will update to reflect the new value. Let's break this down. | ||
|
||
### Rendering | ||
|
||
The first step is rendering. Rendering is the process of generating a snapshot of the current component. You can imagine it as simply "calling" the `App` function and storing the output in a variable. This is what the `App` snapshot would look like: | ||
|
||
```jsx | ||
const snapshot = App(); | ||
|
||
// snapshot = | ||
<div> | ||
<p>Count: 1</p> | ||
<button onClick={increment}>Increment</button> | ||
</div>; | ||
``` | ||
|
||
### Reconciliation | ||
|
||
In order to update the interface to reflect the new state, React needs to compare the previous snapshot to the new snapshot (_called "diffing"_). React's reconciler will go to each element in the previous snapshot and compare it to the new snapshot. If the element is the same, it will skip it. If the element is different, it will update it. | ||
|
||
- The `<div>` tag is the same, so it doesn't need to be updated. ✅ | ||
- The `<p>` tag is the same, so it doesn't needs to be updated. ✅ | ||
- The text inside the `<p>` tag is different, so it needs to be updated. ⚠ ️ | ||
- The `<button>` tag is the same, so it doesn't need to be updated. ✅ | ||
- The `onClick` prop is the same, so it doesn't need to be updated. ✅ | ||
- The text inside the `<button>` tag is the same, so it doesn't need to be updated. ✅ | ||
|
||
_(total: 6 diff checks)_ | ||
|
||
```diff | ||
<div> | ||
- <p>Count: 0</p> | ||
+ <p>Count: 1</p> | ||
<button onClick={increment}>Increment</button> | ||
</div> | ||
``` | ||
|
||
From here, we can see that the `<p>` tag needs to be updated. React will then update the `<p>` DOM node to reflect the new value. | ||
|
||
```jsx | ||
<p>.innerHTML = `Count: ${count}`; | ||
``` | ||
|
||
### How Million.js makes this faster | ||
|
||
React is slow. | ||
|
||
The issue with React's reconciliation it becomes **exponentially slower** the more JSX elements you have. With this simple `App`, it only needs to diff a few elements. In a real world React app, you can easily have hundreds of elements, slowing down interface updates. | ||
|
||
Million.js solves this by **skipping the diffing step entirely** and directly updating the DOM node. | ||
|
||
Here is a conceptual example of how Million.js reconciler works: | ||
|
||
```jsx | ||
function App() { | ||
const [count, setCount] = useState(0); | ||
const increment = () => setCount(count + 1); | ||
|
||
// generated by compiler | ||
if (count !== prevCount) { | ||
<p>.innerHTML = `Count: ${count}`; | ||
} | ||
|
||
<button>.onclick = increment; | ||
|
||
// ... | ||
} | ||
``` | ||
|
||
Notice how when the `count` is updated, Million.js will directly update the DOM node. Million.js turns React reconciliation from `O(n^3)` (cubic time) to `O(1)` (constant time). | ||
|
||
> How fast is it? [**→ View the benchmarks**](https://krausest.github.io/js-framework-benchmark/current.html) | ||
## Setup in seconds | ||
|
||
The Million.js CLI will automatically install the package and configure your project for you. | ||
|
||
<Tabs items={['npm', 'pnpm', 'yarn', 'bun']} storageKey="selected-manager"> | ||
{/* prettier-ignore */} | ||
<Tab> | ||
```bash copy | ||
npx million@latest | ||
``` | ||
</Tab> | ||
{/* prettier-ignore */} | ||
<Tab> | ||
```bash copy | ||
pnpx million@latest | ||
``` | ||
</Tab> | ||
{/* prettier-ignore */} | ||
<Tab> | ||
```bash copy | ||
yarn add million@latest | ||
``` | ||
</Tab> | ||
{/* prettier-ignore */} | ||
<Tab> | ||
```bash copy | ||
bunx million@latest | ||
``` | ||
</Tab> | ||
</Tabs> | ||
|
||
<Callout type="info"> | ||
Million.js is compatible with React 16 and above. If you're using an older | ||
version of React, you'll need to upgrade first. | ||
</Callout> | ||
|
||
That's it! Your project is now running on Million.js 🎉 | ||
|
||
## Million.js vs. React | ||
|
||
The following is a comprehensive demo using [key-based | ||
rendering](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) | ||
to show how Million.js performance compares to React. | ||
|
||
<br /> | ||
|
||
<Demo /> | ||
|
||
## Any questions? | ||
|
||
If you have any questions or need support, please feel free to ask them in [Discord](https://million.dev/chat) or submit an issue on [GitHub](/~https://github.com/aidenybai/million). |