- Million.js automatically optimizes React, making it run way
- faster. It's one of the top performers in the{' '}
-
- JS Framework Benchmark
-
- .
-
-
-
-
-
-
-
-
- Up to 70% faster* than React.
-
-
- * - Benchmarks may not represent real-world performance.
-
-
-
-
-
-
-
-
-
- Integrate and ship in minutes.
-
-
- No need to learn a new framework. Works with your existing
- React components.
-
-
-
-
-
- Note: It's important to note that benchmarks (via JS Framework
- Benchmark) do not represent real-life performance. Million.js
- does include some limitations. You may see more performance
- improvement if you have more data / UI heavy apps.
-
-
-
-
-
What's in Million.js?
- All the tools to make React faster, automatically.
+ The tools to make React faster, automatically.
+
+
+
+
+
+
+
+
+ React at the speed of raw JS
+
+
+ Million.js optimizes React, improving its performance. It stands
+ out as one of the top performers in the{' '}
+
+ JS Framework Benchmark
+
+ .
+
+
+
+
+
+
+
+
+ Up to 70% faster* than React.
+
+
+ * - Benchmarks may not represent real-world performance.
+
+
+
+
+
+
+
+
+
+ Integrate and ship in minutes.
+
+
+ No need to learn a new framework. Works with your existing
+ React components.
+
+
+
+
+
+ Note: Benchmarks (via JS Framework Benchmark) do not represent
+ real-life performance. Million.js does have some limitations.
+ Performance improvements may be more noticeable with apps that
+ include more data / UI components.
+
+
+
+
+
>
);
}
diff --git a/website/components/home/community.tsx b/website/components/home/community.tsx
new file mode 100644
index 0000000000..86ff31916f
--- /dev/null
+++ b/website/components/home/community.tsx
@@ -0,0 +1,113 @@
+import React from 'react';
+import Image from 'next/image';
+import Link from 'next/link';
+import Wyze from '../../pages/showcase/wyze.png';
+import HackClub from '../../pages/showcase/hackclub.jpeg';
+import DonaAI from '../../pages/showcase/dona-ai.jpeg';
+import LLMReport from '../../pages/showcase/llm-report.png';
+import Texts from '../../pages/showcase/texts.png';
+import { Container } from './container';
+
+
+export function Community() {
+ return (
+ <>
+
+
+
+
+ Join our community
+
+
+ Connect with 5000+ React developers committed to better performing
+ applications. Connect, participate, and seek support โ all on
+ Discord.
+
+ );
+};
diff --git a/website/components/home/faq.tsx b/website/components/home/faq.tsx
index c69b805f61..2afaa9782a 100644
--- a/website/components/home/faq.tsx
+++ b/website/components/home/faq.tsx
@@ -8,7 +8,7 @@ const faq = [
question: <>How is it fast?>,
answer: (
<>
- We use a novel approach to the virtual DOM called the block virtual DOM.
+ It uses a novel approach to the virtual DOM called the block virtual DOM.
You can read more on what the block virtual DOM is with{' '}
import('react-countup'), {
loading: () => 70,
@@ -29,15 +30,27 @@ export function Hero() {
The{' '}
- Virtual DOM Replacement
+
+ Virtual DOM
+ {' '}
+ Replacement
{' '}
- for React. Gain big performance wins for UI and data heavy React
- apps. Dead simple to use โ try it out with{' '}
+ for React. Experience improved performance for UI and data-heavy
+ React apps. Minimal effort required - all it takes is {' '}
- just one plugin
+ a single plugin
.
+
-
-
+ {/* */}
+
);
diff --git a/website/components/home/showcase.tsx b/website/components/home/showcase.tsx
index 723a2f1901..02e61ffc6b 100644
--- a/website/components/home/showcase.tsx
+++ b/website/components/home/showcase.tsx
@@ -8,6 +8,35 @@ import Texts from '../../pages/showcase/texts.png';
import { Container } from './container';
export function Showcase() {
+ return (
+
+
+
+
+ Faster than the rest
+
+
+ Witness MillionJS in production where it creates a better user
+ experiences.
+
);
-}
+};
diff --git a/website/package.json b/website/package.json
index 7d9a02da2a..57dacd481d 100644
--- a/website/package.json
+++ b/website/package.json
@@ -34,6 +34,7 @@
"react-dom": "^18.2.0",
"react-lag-radar": "^1.0.0",
"react-parallax-tilt": "^1.7.110",
+ "react-tooltip": "^5.24.0",
"react-tweet": "^3.1.1",
"react-youtube": "^10.1.0",
"tailwindcss": "^3.2.7"
diff --git a/website/pages/_meta.json b/website/pages/_meta.json
index 6fd482ba55..5465c7c808 100644
--- a/website/pages/_meta.json
+++ b/website/pages/_meta.json
@@ -31,6 +31,13 @@
"typesetting": "article"
}
},
+ "faq": {
+ "type": "page",
+ "title": "FAQ",
+ "theme": {
+ "layout": "raw"
+ }
+ },
"ai": {
"type": "page",
"title": "AI",
diff --git a/website/pages/docs/_meta.json b/website/pages/docs/_meta.json
index 58f652cf8d..fab5b82cf0 100644
--- a/website/pages/docs/_meta.json
+++ b/website/pages/docs/_meta.json
@@ -1,25 +1,7 @@
{
- "-- Getting Started": {
- "type": "separator",
- "title": "Getting Started"
- },
"index": "Introduction",
- "install": "Installation",
- "automatic": "Automatic Mode",
- "-- API Reference": {
- "type": "separator",
- "title": "API Reference"
- },
- "block": "block()",
- "for": "",
- "-- Guide": {
- "type": "separator",
- "title": "Guide"
- },
- "quickstart": "Tutorial",
- "rules": "Rules of Blocks",
- "typescript": "Usage with TypeScript",
- "virtualization": "Virtualization",
- "common-errors": "Common Errors",
+ "getting-started": "Getting Started",
+ "automatic-mode": "Automatic Mode",
+ "manual-mode": "Manual Mode",
"internals": "Internals"
}
diff --git a/website/pages/docs/automatic-mode/_meta.json b/website/pages/docs/automatic-mode/_meta.json
new file mode 100644
index 0000000000..d3d2f16ea9
--- /dev/null
+++ b/website/pages/docs/automatic-mode/_meta.json
@@ -0,0 +1,4 @@
+{
+ "introduction": "Introduction",
+ "advanced-customization": "Advanced Customization"
+}
diff --git a/website/pages/docs/automatic-mode/advanced-customization.mdx b/website/pages/docs/automatic-mode/advanced-customization.mdx
new file mode 100644
index 0000000000..e3972f0ae7
--- /dev/null
+++ b/website/pages/docs/automatic-mode/advanced-customization.mdx
@@ -0,0 +1,194 @@
+---
+title: 'Advanced Customization'
+description: 'Advanced Customization configurations for automatic mode'
+---
+
+import { Callout, Tabs, Tab, Steps } from 'nextra-theme-docs';
+
+### Advanced customization
+
+Automatic mode provides customization options:
+
+- `threshold`: What is used to determine whether a component should be converted to Million.js.
+ When the threshold increases, fewer components will be optimized, and vice versa.
+- `skip`: An array of identifiers to indicate if a component should be skipped. You can add hook or variable names, function names, etc.
+
+The `auto` object lets you configure options beyond the default ones set during installation:
+
+```js
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+ }
+```
+
+
+
+
+```js filename="next.config.mjs"
+import million from 'million/compiler';
+
+/\*_ @type {import('next').NextConfig} _/
+const nextConfig = {
+reactStrictMode: true,
+};
+
+const millionConfig = {
+{
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+},
+}
+// if you're using RSC:
+// auto: { rsc: true },
+}
+
+export default million.next(nextConfig, millionConfig);
+```
+
+
+
+ ```js filename="astro.config.mjs"
+ import { defineConfig } from 'astro/config';
+ import million from 'million/compiler';
+
+export default defineConfig({
+ vite: {
+ plugins: [
+ million.vite({
+ mode: 'react',
+ server: true,
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+ },
+ }),
+ ],
+ },
+});
+
+````
+
+
+```js filename="gatsby-node.js"
+const million = require('million/compiler');
+
+exports.onCreateWebpackConfig = ({ actions }) => {
+ actions.setWebpackConfig({
+ plugins: [million.webpack({
+ mode: 'react',
+ server: true,
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+ },
+ })],
+ })
+}
+````
+
+
+
+ ```js filename="vite.config.js"
+ import million from 'million/compiler';
+ import react from "@vitejs/plugin-react";
+ import { defineConfig } from 'vite';
+
+export default defineConfig({
+ plugins: [
+ million.vite({
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+ },
+ }),
+ react(),
+ ],
+});
+
+// With Remix:
+
+import { unstable_vitePlugin as remix } from "@remix-run/dev";
+import million from 'million/compiler';
+import { defineConfig } from "vite";
+
+export default defineConfig({
+plugins: [million.vite({
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+ }
+ }),
+ remix()
+ ],
+})๏ผ
+
+````
+
+
+
+ If you are using a [Create React App (CRA)](https://create-react-app.dev/) Setup, you will need to [configure Craco](https://craco.js.org/docs/getting-started/) before proceeding.
+
+
+```js filename="craco.config.js"
+const million = require('million/compiler');
+module.exports = {
+ webpack: {
+ plugins: { add: [million.webpack({
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+ }})] }
+ }
+};
+````
+
+
+
+ ```js filename="webpack.config.js"
+ const million = require('million/compiler');
+ module.exports = {
+ plugins: [
+ million.webpack({
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+ }}),
+ ],
+ }
+ ```
+
+
+ ```js filename="rollup.config.js"
+ import million from 'million/compiler';
+
+export default {
+ plugins: [
+ million.rollup({
+ auto: {
+ threshold: 0.05, // default: 0.1,
+ skip: ['useBadHook', /badVariable/g], // default []
+ },
+ }),
+ ],
+};
+
+````
+
+
+
+### Ignoring components
+
+If you encounter an error with a component during the Million.js runtime, it can be skipped using the `// million-ignore` comment.
+
+```js
+// million-ignore
+function App() {
+return ...
+}
+````
+
+### Muting help messages
+
+To avoid seeing help messages, you can pass the `mute: true{:js}` option to the compiler inside the `auto` object.
diff --git a/website/pages/docs/automatic-mode/introduction.mdx b/website/pages/docs/automatic-mode/introduction.mdx
new file mode 100644
index 0000000000..ae3c0a013d
--- /dev/null
+++ b/website/pages/docs/automatic-mode/introduction.mdx
@@ -0,0 +1,16 @@
+---
+title: 'Automatic Mode'
+description: 'How to use Automatic Mode'
+---
+
+# Automatic Mode
+
+Million.js comes with Automatic Mode as its default setting. This transforms your React components into Million.js components, improving speed without any major code changes.
+
+When [installing Million into your project](/docs/install), automatic mode is recommended for most users and this is because it packs in it all the necessary optimizations that your application needs. The `auto` option of the compiler toggles it.
+
+### `auto`
+
+The `auto` option is a boolean that enables automatic mode. By default it is unset, because Million offers [a way to manually set your configuration](/docs/install#configure-it-yourself).
+
+
Checkout{' '} Advanced Customization to see how to add custom options to your automatic mode setup
diff --git a/website/pages/docs/automatic.mdx b/website/pages/docs/automatic.mdx
deleted file mode 100644
index f77398f7a6..0000000000
--- a/website/pages/docs/automatic.mdx
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: 'Automatic Mode'
-description: 'The default mode of Million.js'
----
-
-import { Callout, Tabs, Tab, Steps } from 'nextra-theme-docs';
-
-# Automatic Mode
-
-Automatic mode is the default mode of Million.js. It automatically converts React components to Million.js components.
-
-### Ignoring components
-
-If a certain component conflicts with the Million.js runtime, it's possible to skip over them via the `// million-ignore` comment.
-
-```js
-// million-ignore
-function App() {
- return ...
-}
-```
-
-### Advanced customization
-
-Automatic mode provides options to tune automatic mode:
-
-- `threshold`: The threshold for the heuristic to determine whether a component should be converted to Million.js. The greater the threshold, fewer components will be optimized, and vice versa. The default is `0.1`.
-- `skip`: An array of identifiers that indicate a component should be skipped. You can put hook names, variable names, etc. The default is `[]`.
-
-
-```js
-const options = {
- auto: {
- threshold: 0.25, // default: 0.1,
- skip: ['useBadHook', /badVariable/g] // default []
- }
-}
-```
-
-### Muting help messages
-
-If you don't want to see the help messages, you can pass the `{ mute: true }{:js}` option to the compiler.
diff --git a/website/pages/docs/block.mdx b/website/pages/docs/block.mdx
deleted file mode 100644
index 2113983a95..0000000000
--- a/website/pages/docs/block.mdx
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: 'block()'
-description: 'Million.js introduces the concept of a Block. Blocks are a way for React components to be rendered using the Million.js virtual DOM.'
----
-
-import { Callout } from 'nextra-theme-docs';
-import { AutomaticModeWarning } from '../../components/automatic-mode-warning';
-
-# `block(){:jsx}`
-
-
-
-**Syntax:** `block((props) => vnode){:jsx}`\
-**Example:** `block((props) =>
{props.foo}
){:jsx}`
-
-Million.js is a library that enables you to create _blocks_. A block is a special [Higher Order Component (HOC)](https://legacy.reactjs.org/docs/higher-order-components.html) that can be used as a React component but is hyper-optimized for rendering speed.
-
-Blocks are essentially components wrapped by `block(){:jsx}`.
-
-```jsx
-import { block } from 'million/react';
-
-const LionBlock = block(function Lion() {
- return ;
-});
-
-export default LionBlock;
-```
-
-
- There are some limitations to using blocks. Please reference the [Rules of
- Blocks](/docs/rules) for more information.
-
-
-## `as` prop
-
-The `as` prop can be used to specify the tag name of the For. By default, it is `slot`.
-
-```jsx
-import { block } from 'million/react';
-
-const LionBlock = block(
- function Lion() {
- return ;
- },
- { as: 'div' },
-);
-```
-
-## Hydration mismatch
-
-If you are using Million.js on the server, you may encounter a hydration mismatch error. This is because Million.js uses a different algorithm for rendering on the server than it does on the client. To fix this, you can disable SSR.
-
-```jsx
-const NoSSRBlock = block(
- function NoSSR() {
- return
{Math.random()}
;
- },
- { ssr: false },
-);
-```
diff --git a/website/pages/docs/common-errors.mdx b/website/pages/docs/common-errors.mdx
deleted file mode 100644
index 479c91c137..0000000000
--- a/website/pages/docs/common-errors.mdx
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: 'Common Errors With Million.js Integration'
-description: 'How to overcome common errors when using Million.js with other technologies'
----
-
-import { Callout } from 'nextra-theme-docs';
-
-This page is a stub
-
-# Common Errors
-
-You are probably here because you are having issues integrating your existing project with Million.js.
-
-## MobX Integration
-
-- Upgrade to MobX v6
-- Remove decorators
-
-## twin.macro
-
-Million.js does not work with `twin.macro` due to their JSX transform override.
diff --git a/website/pages/docs/getting-started/_meta.json b/website/pages/docs/getting-started/_meta.json
new file mode 100644
index 0000000000..2713adb886
--- /dev/null
+++ b/website/pages/docs/getting-started/_meta.json
@@ -0,0 +1,4 @@
+{
+ "install": "Installation"
+ }
+
\ No newline at end of file
diff --git a/website/pages/docs/install.mdx b/website/pages/docs/getting-started/install.mdx
similarity index 76%
rename from website/pages/docs/install.mdx
rename to website/pages/docs/getting-started/install.mdx
index 6bcb1c7b33..cf61f47799 100644
--- a/website/pages/docs/install.mdx
+++ b/website/pages/docs/getting-started/install.mdx
@@ -5,50 +5,15 @@ description: 'How to install Million.js into your React project'
import { Callout, Tabs, Tab, Steps } from 'nextra-theme-docs';
-# Installation
-
-Million.js assumes that you've already initialized a React project. If you haven't, we recommend checking out [react.dev](https://react.dev) first.
-
-## Setup in seconds
-The Million.js CLI will automatically install the package and configure your project for you.
-
-
- {/* prettier-ignore */}
-
- ```bash copy
- npx million@latest
- ```
-
- {/* prettier-ignore */}
-
- ```bash copy
- pnpx million@latest
- ```
-
- {/* prettier-ignore */}
-
- ```bash copy
- yarn add million@latest
- ```
-
- {/* prettier-ignore */}
-
- ```bash copy
- bunx million@latest
- ```
-
-
+# Installation
-That's it! **Your project is now running on Million.js ๐**
+Million.js assumes that you have an existing React project. To learn about how to create a React app, please see [React's documentation](https://react.dev).
-
- Million.js is compatible with React 16 and above. If you're using an older version of React, you'll need to upgrade first.
-
-## Manual configuration
+## Configure It Yourself
-In the case you want more granular control over the installation process, you can follow the steps below.
+For more control, Million offers customizable options.
@@ -56,9 +21,10 @@ In the case you want more granular control over the installation process, you ca
-### Install package
-First things first, you'll need to install Million.js. You can do this with your favorite package manager:
+
+### Install Million.js
+
{/* prettier-ignore */}
@@ -87,9 +53,8 @@ First things first, you'll need to install Million.js. You can do this with your
-### Use the compiler
+### Add the compiler to your application
-Then, add the compiler to your build tool of choice:
@@ -161,6 +126,10 @@ Then, add the compiler to your build tool of choice:
```
+
+ If you are using a [Create React App (CRA)](https://create-react-app.dev/) Setup, you will need to [configure Craco](https://craco.js.org/docs/getting-started/) before proceeding.
+
+
```js filename="craco.config.js"
const million = require('million/compiler');
module.exports = {
@@ -192,16 +161,17 @@ Then, add the compiler to your build tool of choice:
-
+
Checkout Automatic Mode to learn about the mechanisms behind Automatic mode.
+
+
-### Install package
+### Install Million.js
-First things first, you'll need to install Million.js. You can do this with your favorite package manager:
{/* prettier-ignore */}
@@ -230,9 +200,8 @@ First things first, you'll need to install Million.js. You can do this with your
-### Use the compiler
+### Add the compiler to your application
-Then, add the compiler to your build tool of choice:
React Instructions
@@ -283,9 +252,26 @@ Then, add the compiler to your build tool of choice:
export default defineConfig({
plugins: [million.vite(), react()],
});
+
+
+
+ // With Remix:
+
+ import { unstable_vitePlugin as remix } from "@remix-run/dev";
+ import million from 'million/compiler';
+ import { defineConfig } from "vite";
+
+
+ export default defineConfig({
+ plugins: [million.vite(), remix()],
+ }๏ผ
```
+
+ If you are using a [Create React App (CRA)](https://create-react-app.dev/) Setup, you will need to [configure Craco](https://craco.js.org/docs/getting-started/) before proceeding.
+
+
```js filename="craco.config.js"
const million = require('million/compiler');
module.exports = {
@@ -293,6 +279,7 @@ Then, add the compiler to your build tool of choice:
plugins: { add: [million.webpack()] }
}
};
+
```
@@ -369,21 +356,6 @@ Then, add the compiler to your build tool of choice:
-### Using the experimental Optimizer
-
-
- This is a _**highly experimental**_ feature. It's not recommended to use this in production.
-
-
-You can enable the experimental optimizer by passing `optimize: true{:js}` to the compiler options. This will allow the server to attempt to statically analyze blocks beforehand for a zero initialization cost.
-
-You can also add a leading comment of `/* @optimize */` to any block to opt-in to optimization on a component-by-component basis.
-
-```js {3}
-import { block } from "million/react";
-
-const AppBlock = /* @optimize */ block(App);
-```
diff --git a/website/pages/docs/index.mdx b/website/pages/docs/index.mdx
index 422c14f3a6..130e6d3764 100644
--- a/website/pages/docs/index.mdx
+++ b/website/pages/docs/index.mdx
@@ -1,12 +1,69 @@
import { Disclosures } from '../../components/home/faq';
-import { Tab, Tabs } from 'nextra-theme-docs';
+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),
+);
# Introduction
-**Million.js** is an extremely fast and lightweight `<4kb` virtual DOM that makes React up to [70% faster](https://krausest.github.io/js-framework-benchmark/current.html). By using a fine-tuned, optimized virtual DOM, Million.js reduces the overhead of React.
+**Million.js** is a fast and lightweight (`<4kb`) virtual DOM that can improve [React's speed by up to 70%](https://krausest.github.io/js-framework-benchmark/current.html).
+With a fine-tuned, optimized virtual DOM, Million.js can have your React components running at the speed of raw JavaScript.
+
+## Setup in seconds
+
+The Million.js CLI will automatically install the package and configure your project for you.
+
+
+ {/* prettier-ignore */}
+
+ ```bash copy
+ npx million@latest
+ ```
+
+ {/* prettier-ignore */}
+
+ ```bash copy
+ pnpx million@latest
+ ```
+
+ {/* prettier-ignore */}
+
+ ```bash copy
+ yarn add million@latest
+ ```
+
+ {/* prettier-ignore */}
+
+ ```bash copy
+ bunx million@latest
+ ```
+
+
+
+That's it! **Your project is now running on Million.js.**
+
+
+ Million.js is compatible with React 16 and above. If you're using an older
+ version of React, you'll need to upgrade first.
+
+
+The [Installation Guide](/docs/getting-started/install) can help you get started right away.
+
+## 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.
+
+
+
-Imagine React components running at the speed of raw JavaScript.
+
-## FAQ
+## Any questions?
-
+If you have any questions or need support, please feel free to ask them in the `questions` channel on the [Discord](https://discord.gg/7ZAGgTQVTE) or check out Million Beyond "Speed"
diff --git a/website/pages/docs/internals/_meta.json b/website/pages/docs/internals/_meta.json
index 5d5ef703e1..6b7ba58786 100644
--- a/website/pages/docs/internals/_meta.json
+++ b/website/pages/docs/internals/_meta.json
@@ -1,5 +1,4 @@
{
- "block": "block()",
"mount": "mount()",
"patch": "patch()",
"map-array": "mapArray()",
diff --git a/website/pages/docs/internals/block.mdx b/website/pages/docs/internals/block.mdx
deleted file mode 100644
index bb3844fc68..0000000000
--- a/website/pages/docs/internals/block.mdx
+++ /dev/null
@@ -1,74 +0,0 @@
----
-title: 'block()'
-description: 'The internal virtual DOM block() function instantiates a Block. It accepts a function with a props object parameter and returns a VNode.'
----
-
-import { Callout } from 'nextra-theme-docs';
-
-
- **This function is part of the internal API.** You should only be using this
- if you are making your own framework.
-
-
-
-
-# `block(){:jsx}`
-
-**Syntax:** `block((props) => vnode){:jsx}`\
-**Example:** `block((props) =>
{props.foo}
){:jsx}`
-
-The `block` function instantiates a `Block` (_a stateless "component"_). It accepts a function with a props object parameter that returns a `VNode`.
-
-## Rules of usage
-
-##### `props` is an immutable object with primitive or `Block` values.
-
-```jsx
-someBlock({
- one: '1', // โ
- two: 1 + 1, // โ
- three: true, // โ
- four: Date.now(), // โ
- five: anotherBlock({ crewmate: true }), // โ
- six: { imposter: true }, // โ
- seven: new Date(), // โ
-});
-```
-
-##### Top level values of `props` may not be interpolated with other values.
-
-The props are filled with `Hole` values. These `Hole` values are replaced with the actual values when the `block(){:jsx}` is called. The `Hole` values are immutable and cannot be derived with other values.
-
-```jsx
-// Anatomy of a `Hole`
-{
- $: 'prop';
-}
-
-// Example:
-block((props) => {
- console.log(props.foo); // { $: 'foo' } โ
- console.log(props.foo + ' bar'); // { $: 'foo' } + ' bar' โ
- return
{props.foo}
;
-});
-```
-
-The following are examples of this rule:
-
-```jsx
-block((props) => {
- const { favorite } = props.favorite; // โ
-
;
-});
-```
diff --git a/website/pages/docs/internals/map-array.mdx b/website/pages/docs/internals/map-array.mdx
index 6facdb8017..d0afdb6695 100644
--- a/website/pages/docs/internals/map-array.mdx
+++ b/website/pages/docs/internals/map-array.mdx
@@ -6,8 +6,8 @@ description: "The mapArray function is used to create a Block list. It's the bes
import { Callout } from 'nextra-theme-docs';
- **This function is part of the internal API.** You should only be using this if
- you are making your own framework.
+ **This function is part of the internal API.** It is intended for developers
+ creating their own frameworks. It is not recommended for general use.
diff --git a/website/pages/docs/internals/mount.mdx b/website/pages/docs/internals/mount.mdx
index a4aa593e53..cdda7678f7 100644
--- a/website/pages/docs/internals/mount.mdx
+++ b/website/pages/docs/internals/mount.mdx
@@ -6,8 +6,8 @@ description: 'Mount a block to a DOM element.'
import { Callout } from 'nextra-theme-docs';
- **This function is part of the internal API.** You should only be using this if
- you are making your own framework.
+ **This function is part of the internal API.** It is intended for developers
+ creating their own frameworks. It is not recommended for general use.
diff --git a/website/pages/docs/internals/patch.mdx b/website/pages/docs/internals/patch.mdx
index 95551cd4b5..fbf1e18334 100644
--- a/website/pages/docs/internals/patch.mdx
+++ b/website/pages/docs/internals/patch.mdx
@@ -6,8 +6,8 @@ description: 'The patch function is used to rerender a block with another block.
import { Callout } from 'nextra-theme-docs';
- **This function is part of the internal API.** You should only be using this if
- you are making your own framework.
+ **This function is part of the internal API.** It is intended for developers
+ creating their own frameworks. It is not recommended for general use.
@@ -20,8 +20,8 @@ import { Callout } from 'nextra-theme-docs';
The `patch` function is used to rerender a block with another block. The `oldBlock` is the block that will be rerendered, and the `newBlock` represents the new version of the DOM.
- Always try to keep Blocks of the same shape (derived from the same function)
- when using patch in order to maintain good performance.
+ Blocks must be derived from the same function when using `patch()`. This
+ ensures performance is not negatively impacted.
```jsx
diff --git a/website/pages/docs/internals/render-to-template.mdx b/website/pages/docs/internals/render-to-template.mdx
index 8675489be1..994f4559f3 100644
--- a/website/pages/docs/internals/render-to-template.mdx
+++ b/website/pages/docs/internals/render-to-template.mdx
@@ -6,8 +6,8 @@ description: 'The renderToTemplate function is used to render a virtual DOM node
import { Callout } from 'nextra-theme-docs';
- **This function is part of the internal API.** You should only be using this if
- you are making your own framework.
+ **This function is part of the internal API.** It is intended for developers
+ creating their own frameworks. It is not recommended for general use.
diff --git a/website/pages/docs/internals/string-to-dom.mdx b/website/pages/docs/internals/string-to-dom.mdx
index e356da7ca7..6e49cdaa71 100644
--- a/website/pages/docs/internals/string-to-dom.mdx
+++ b/website/pages/docs/internals/string-to-dom.mdx
@@ -6,8 +6,8 @@ description: 'Convert a string to a virtual DOM node.'
import { Callout } from 'nextra-theme-docs';
- **This function is part of the internal API.** You should only be using this
- if you are making your own framework.
+ **This function is part of the internal API.** It is intended for developers
+ creating their own frameworks. It is not recommended for general use.
diff --git a/website/pages/docs/manual-mode/_meta.json b/website/pages/docs/manual-mode/_meta.json
new file mode 100644
index 0000000000..c1b2a86d5a
--- /dev/null
+++ b/website/pages/docs/manual-mode/_meta.json
@@ -0,0 +1,7 @@
+{
+ "block": "block()",
+ "usage-guide": "Usage Guide",
+ "for": "",
+ "virtualization": "Virtualization"
+ }
+
\ No newline at end of file
diff --git a/website/pages/docs/manual-mode/block.mdx b/website/pages/docs/manual-mode/block.mdx
new file mode 100644
index 0000000000..2e56317434
--- /dev/null
+++ b/website/pages/docs/manual-mode/block.mdx
@@ -0,0 +1,403 @@
+---
+title: 'block()'
+description: 'Million.js introduces the concept of a Block. Blocks are a way for React components to be rendered using the Million.js virtual DOM.'
+---
+
+import { Callout, Tabs, Tab, Steps } from 'nextra-theme-docs';
+import { AutomaticModeWarning } from '../../../components/automatic-mode-warning';
+
+# `block(){:jsx}`
+
+**Syntax:** `block((props) => vnode){:jsx}`\
+**Example:** `block((props) =>
{props.foo}
){:jsx}`
+
+Million.js is a library that enables you to create _blocks_. A block is a special [Higher Order Component (HOC)](https://legacy.reactjs.org/docs/higher-order-components.html) that can be used as a React component but is hyper-optimized for rendering speed.
+
+Blocks are essentially components wrapped by `block(){:jsx}`.
+
+
+
+ ```jsx
+ import { block } from 'million/react';
+
+ const LionBlock = block(function Lion() {
+ return ;
+ });
+
+ export default LionBlock;
+ ```
+
+
+
+
+
+ You must make your Props use `type` instead of `interface`, as this is the [officially recognized
+ behavior](https://github.com/microsoft/TypeScript/issues/15300#issuecomment-332366024)
+ by the TypeScript team. Alternatively, if you want to use interfaces you can
+ add `[key: string]: any` as per [this Stack Overflow
+ comment](https://stackoverflow.com/questions/37006008/typescript-index-signature-is-missing-in-type/65473225#65473225).
+
+
+
+ ```jsx
+ type Props = {
+ name: string,
+ };
+
+ const Lion: React.FC = ({ name }) => {
+ return (
+
Hello {name}
+ ;
+ )
+ };
+ const LionBlock = block(Lion);
+
+ export default LionBlock;
+
+ ```
+
+
+
+
+
+## Custom Tags
+
+The `as` prop can be used to specify the tag name of the For. By default, it is `slot`.
+
+```jsx
+import { block } from 'million/react';
+
+const LionBlock = block(
+ function Lion() {
+ return ;
+ },
+ { as: 'div' },
+);
+```
+
+## Using Block With SSR
+
+If you are using Million.js on the server, you may encounter a hydration mismatch error. This is because Million.js uses a different algorithm for rendering on the server than it does on the client. To fix this, you can disable SSR.
+
+```jsx
+const NoSSRBlock = block(
+ function NoSSR() {
+ return
+ ```
+
+
+
+There are three common reasons you might be seeing it:
+
+1. Breaking [rules of blocks](/docs/manual-mode/block#breaking-rules-of-blocks)
+2. Not [adding the compiler](/docs/manual-mode/block#using-the-compiler)
+3. Encountering [unsupported behavior](/docs/manual-mode/block#unsupported-behavior)
+
+## Breaking Rules of Blocks
+
+You may have heard of ["progressive enhancement,"](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement) which is the idea that tools progressively use features based on what is supported. Similarly, Million.js has "progressive degradation," or the concept that if you use features that are not supported, it will degrade to default React rendering gracefully.
+
+This section highlights some of the possible warnings you might encounter using blocks. Note that this is not an exhaustive list.
+
+{' '}
+
+ This section presents idiomatic patterns to use blocks. It is not a list of
+ errors, your application will still work if you don't follow these patterns.
+
+
+### Declaring blocks
+
+{' '}
+
+
+ [Million.js] Block needs to be defined as a variable
+ declaration.
+
+
+
+The above usually occurs when you have a block that is not declared as a variable. This prevents the compiler from analyzing the block correctly.
+
+```jsx
+console.log(block(() => )) // โ Wrong
+export default block(() => ) // โ Wrong
+
+// ๐๐๐
+
+const Block = block(() => ) // โ Correct
+console.log(Block);
+export default Block;
+```
+
+### Calling `block()`
+
+{' '}
+
+
+ [Million.js] Found unsupported argument for block. Make
+ sure blocks consume a reference to a component function or the direct
+ declaration.
+
+
+
+The above usually occurs when you have an actual JSX component like `{:jsx}` passed into the `block(){:jsx}` function instead of a reference to the Component itself.
+
+```jsx
+const BadBlock = block(); // โ Wrong
+
+const GoodBlock = block(App); // โ Correct
+```
+
+### Using `` instead of `map()`
+
+{' '}
+
+
+ [Million.js]
+ Array.map() will degrade performance. We recommend removing the block on the
+ current component and using a `` component instead
+
+
+
+The above will occur when you use `.map` within a block. This is not ideal, especially if the component that holds the list is a block. The right pattern is to remove the block on the current component and use a `` component instead for the children.
+
+```jsx
+
+ {items.map((item) => (
+
{item}
+ ))}
+
+
+// ๐๐๐
+
+
+ {(item) =>
{item}
}
+
+```
+
+### Deterministic returns
+
+
+
+
+ [Million.js]
+ Conditional expressions will degrade performance. We recommend using
+ deterministic returns instead.
+
+
+
+
+
+ Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
+
+
+
+
+Returns must be "deterministic," meaning there can only be one return statement at the end of the block that returns a stable tree.
+
+Some examples of non-deterministic returns:
+
+```jsx
+function Component() {
+ const [count, setCount] = useState(initial.count);
+
+ if (count > 10) {
+ return
;
+}
+
+const ComponentBlock = block(Component);
+```
+
+### UI Component libraries ๐ โโ๏ธ
+
+{' '}
+
+
+ [Million.js]
+ Components will cause degraded performance. Ideally, you should use DOM elements
+ instead.
+
+
+
+Many React applications use UI component libraries like Material UI, Chakra UI, or Tailwind UI. These libraries are great, but they are not optimized for Million.js.
+
+Million.js requires that you use DOM elements instead of components. This is because components can introduce non-deterministic returns, which can cause degraded performance.
+
+```jsx
+// โ Bad
+
+ What's up my fellow components
+
+
+// ๐คจ Maybe
+
+ What's up my fellow components
+
+
+// โ Good
+
+
What's up my fellow components
+
+```
+
+### Spread attributes/children
+
+{' '}
+
+
+ [Million.js]
+ Spread attributes/children are not fully supported
+
+
+
+You can't use spread attributes/children that change safely or reference a binding within the component inside Million.js, as they can introduce non-deterministic returns.
+
+```jsx
+const arr = ['Hello'];
+
+
{...arr}
; // Ok if arr never changes
+
+// โ Bad
+arr.push('World');
+```
+
+### Unsupported import
+
+{' '}
+
+
+ [Million.js]
+ Found unsupported import for block. Make sure blocks are imported from million/react.
+
+
+
+This may be caused by importing the block from the wrong place. Make sure you import the block from `million/react` instead of `million`.
+
+```jsx
+import { block } from 'million'; // โ Wrong
+
+import { block } from 'million/react'; // โ Correct
+```
+
+### Using the compiler
+
+{' '}
+
+
+ Warning:
+ Invalid Hook Call. Hooks can only be called inside of the body of a function
+ component.
+
+
+
+You may have forgot to use the compiler, a necessary part in ensuring that your JSX is compiled to Million.js compatible code. You can view the instructions at [the installation guide](/docs/getting-started/install).
+
+On a side note, Million.js is technically usable without the compiler, but it's significantly more limited in scope, and there is a more limited set of features available. This is not recommended.
+
+### Unsupported behavior
+
+{' '}
+
+ Uncaught Error: ??? :(
+
+
+If none of this worked, please [create an issue](https://github.com/aidenybai/million/issues/new?assignees=aidenybai&labels=bug&projects=&template=bug_report.md&title=bug%3A+) and we'll try to help. Try to create a small reproducing example โ you might discover the problem as you're doing it.
+
+
+
+
+ Advanced Information
+
+{' '}
+
+ **This function is part of the internal API.** You should only be using this
+ if you are making your own framework.
+
+
+{' '}
+
+
+# `block(){:jsx}`
+
+**Syntax:** `block((props) => vnode){:jsx}`\
+ **Example:** `block((props) =>
{props.foo}
){:jsx}`
+
+The `block` function instantiates a `Block` (_a stateless "component"_). It accepts a function with a `props` object parameter that returns a `VNode`.
+
+### Rules of usage
+
+##### `props` is an immutable object with primitive or `Block` values.
+
+```jsx
+someBlock({
+ one: '1', // โ
+ two: 1 + 1, // โ
+ three: true, // โ
+ four: Date.now(), // โ
+ five: anotherBlock({ crewmate: true }), // โ
+ six: { imposter: true }, // โ
+ seven: new Date(), // โ
+});
+```
+
+##### Top level values of `props` may not be interpolated with other values.
+
+The `props` are filled with immutable `Hole` values. These values are replaced with the actual values when the `block(){:jsx}` is called.
+
+```jsx
+// Anatomy of a `Hole`
+{
+ $: 'prop';
+}
+
+// Example:
+block((props) => {
+ console.log(props.foo); // { $: 'foo' } โ
+ console.log(props.foo + ' bar'); // { $: 'foo' } + ' bar' โ
+ return
{props.foo}
;
+});
+```
+
+The following are examples of this rule:
+
+```jsx
+block((props) => {
+ const { favorite } = props.favorite; // โ
+
;
+});
+```
+
+
diff --git a/website/pages/docs/for.mdx b/website/pages/docs/manual-mode/for.mdx
similarity index 92%
rename from website/pages/docs/for.mdx
rename to website/pages/docs/manual-mode/for.mdx
index 4d952cdcb2..5cb165b5a1 100644
--- a/website/pages/docs/for.mdx
+++ b/website/pages/docs/manual-mode/for.mdx
@@ -3,7 +3,7 @@ title: ''
description: 'Learn how to render lists of blocks in Million.'
---
-import { AutomaticModeWarning } from '../../components/automatic-mode-warning';
+import { AutomaticModeWarning } from '../../../components/automatic-mode-warning';
# `{:jsx}`
@@ -37,7 +37,7 @@ function App() {
export default App;
```
-## `as` prop
+## Custom Tags
The `as` prop can be used to specify the tag name of the For. By default, it is `slot`.
@@ -47,7 +47,7 @@ The `as` prop can be used to specify the tag name of the For. By default, it is
```
-## Optimizing ``
+## Optimizing `` With `memo`
Internally, `` will not reuse blocks in order to avoid unknown behavior. This means that if you have a `` with 1000 items, it will recreate 1000 blocks.
@@ -59,7 +59,9 @@ However, if you know that your items aren't dependent on any values except the `
```
-## Hydration mismatch
+
+
+## Using For With SSR
If you are using Million.js on the server, you may encounter a hydration mismatch error. This is because Million.js uses a different algorithm for rendering on the server than it does on the client. To fix this, you can disable SSR.
diff --git a/website/pages/docs/quickstart.mdx b/website/pages/docs/manual-mode/usage-guide.mdx
similarity index 60%
rename from website/pages/docs/quickstart.mdx
rename to website/pages/docs/manual-mode/usage-guide.mdx
index bd81b6c6cb..a1d5b15153 100644
--- a/website/pages/docs/quickstart.mdx
+++ b/website/pages/docs/manual-mode/usage-guide.mdx
@@ -1,59 +1,40 @@
---
-title: 'Tutorial'
+title: 'How To Integrate Million In A Project'
description: 'Learn how to use Million.js'
---
-import dynamic from 'next/dynamic';
import { Callout, Tabs, Tab, Cards, Card } from 'nextra-theme-docs';
-import { Box } from '../../components/box';
-import { AutomaticModeWarning } from '../../components/automatic-mode-warning';
+import { Box } from '../../../components/box';
+import { AutomaticModeWarning } from '../../../components/automatic-mode-warning';
import { BrowserView, MobileView } from 'react-device-detect';
-import { VDomExample } from '../../components/back-in-block/vdom';
-import { CombinedBlockExample } from '../../components/back-in-block/combined-block';
-export const Demo = dynamic(() =>
- import('../../components/demo').then((mod) => mod.Demo),
-);
+import { VDomExample } from '../../../components/back-in-block/vdom';
+import { CombinedBlockExample } from '../../../components/back-in-block/combined-block';
- We highly recommend viewing this documentation on a desktop browser to get access to interactive code examples.
+ It is highly recommended you view this documentation on a desktop browser to
+ get access to interactive code examples.
-# Tutorial
+# How To Integrate Million In A Project
-Welcome to the Million.js documentation (_woop woop ๐๐ค_). Let's learn how we can integrate Million.js into our React applications.
+Let's learn how you can integrate Million.js into your React applications.
-Million.js assumes that you're already familiar with and you're using React. If you're not, we recommend checking out [react.dev](https://react.dev/) first.
+Million.js assumes that you're already familiar with and you're using React. If you're not, is is recommended you check out [react.dev](https://react.dev/) first.
**You will learn:**
-- How to use `block(){:jsx}` to convert React components into blocks
+- How to use [`block(){:jsx}`](/docs/manual-mode/block) to convert React components into blocks
- How to use `{:jsx}` for efficiently rendering lists
- When to use `block(){:jsx}` and `{:jsx}`
- The limitations of blocks
-## What's a block?
-
-Million.js is a library that enables you to create _blocks_. A block is a special [Higher Order Component (HOC)](https://legacy.reactjs.org/docs/higher-order-components.html) that can be used as a React component but is hyper-optimized for rendering speed.
-
-Blocks are essentially components wrapped by `block(){:jsx}`.
-
-```jsx {3, 7}
-import { block } from "million/react";
-
-const LionBlock = block(function Lion() {
- return (
-
- );
-})
-```
-
Blocks can be used just like a normal React component:
```jsx {5}
@@ -74,22 +55,22 @@ Have a look at the result:
- );
- }
+function Lion() {
+return (
+
+);
+}
- const LionBlock = block(Lion);
+const LionBlock = block(Lion);
- export default function App() {
- return (
-
+);
+}
`} />
@@ -100,7 +81,7 @@ With that in hand, let's build an app.
One use case of blocks is rendering lists of data efficiently. In this example, let's build a data grid in React.
-We have access to the prebuilt components `
{:jsx}` and `{:jsx}` from our fake user interface (UI) library. We can then store the number of rows we want to display in a `useState(){:jsx}` hook.
+You have access to the prebuilt components `
{:jsx}` and `{:jsx}` from your fake user interface (UI) library. You can then store the number of rows you want to display in a `useState(){:jsx}` hook.
```jsx
function App() {
@@ -109,22 +90,20 @@ function App() {
return (
-
- // ...
-
+
// ...
);
}
```
-But wait! We made a grid but we have no data. Let's say we can grab some array of arbitrary data from a function called `buildData(rows){:jsx}`:
+But wait! You made a grid but you have no data. Let's say you can grab some array of arbitrary data from a function called `buildData(rows){:jsx}`:
```jsx
const data = buildData(100);
// returns [{ adjective: '...', color: '...', noun: '...' }, ... x100]
```
-Now, we can render the data in our table using `Array.map(){:jsx}`:
+Now, you can render the data in our table using `Array.map(){:jsx}`:
```jsx {3, 9-15}
function App() {
@@ -155,9 +134,9 @@ function App() {
import { Table, Input } from './ui';
import { buildData } from './data';
- function App() {
- const [rows, setRows] = useState(1);
- const data = buildData(rows);
+function App() {
+const [rows, setRows] = useState(1);
+const data = buildData(rows);
return (
@@ -173,18 +152,19 @@ function App() {
);
+
}
export default App;
`} />
-We can see that it performs pretty well. From 0-100, there's virtually no lag, but once you get higher than 500 or so, there's a noticable delay in rendering.
+You can see that it performs pretty well. From 0-100, there's virtually no lag, but once you get higher than 500 or so, there's a noticable delay in rendering.
-Cool right? React is great because we can declaratively write great UI and get pretty good performance. But the data grid we just made is a rudimentary example, and is not necessarily representative of most React applications.
+React is great because you can declaratively write great UI and get pretty good performance. But the data grid you just made is a rudimentary example, and is not necessarily representative of most React applications.
### More realistic rendering
-So, let's introduce some spice. In the following example, we add `lotsOfElements` (an array of a lot of blank elements) to each row. We also add a lag radar to monitor page performance.
+In the following example, you add `lotsOfElements` (an array of a lot of blank elements) to each row. you can also add a lag radar to monitor page performance.
Try changing the input value up and down from 0 to 1000. Notice how React _really struggles_ when rendering a lot of elements.
@@ -193,9 +173,9 @@ Try changing the input value up and down from 0 to 1000. Notice how React _reall
import { Table, Input, lotsOfElements } from './ui';
import { buildData } from './data';
- function App() {
- const [rows, setRows] = useState(1);
- const data = buildData(rows);
+function App() {
+const [rows, setRows] = useState(1);
+const data = buildData(rows);
return (
@@ -212,6 +192,7 @@ Try changing the input value up and down from 0 to 1000. Notice how React _reall
);
+
}
export default App;
@@ -221,9 +202,9 @@ export default App;
### Just `block` it
-In the following example, we use `block(){:jsx}` and `{:jsx}` in order to optimize rendering.
+In the following example, you can use `block(){:jsx}` and `{:jsx}` in order to optimize rendering.
-First, we need to abstract the `
{:jsx}` into its own component.
+First, you need to abstract the `
{:jsx}` into its own component.
```jsx
data.map(({ adjective, color, noun }) => (
@@ -233,7 +214,7 @@ data.map(({ adjective, color, noun }) => (
{noun}
{...lotsOfElements}
-))
+));
// ๐๐๐
@@ -249,26 +230,24 @@ function Row({ adjective, color, noun }) {
}
```
-Then, we can wrap it with `block(){:jsx}` in order to optimize the `{:jsx}` component.
+Then, you can wrap it with `block(){:jsx}` in order to optimize the `{:jsx}` component.
```jsx {3, 14}
-import { block } from "million/react";
+import { block } from 'million/react';
-const RowBlock = block(
- function Row({ adjective, color, noun }) {
- return (
-
+ );
+});
```
-Once, we've optimized a row, we need to render it as a list:
+Once, you've optimized a row, you will need to render it as a list:
```jsx
data.map(({ adjective, color, noun }) => (
@@ -276,7 +255,7 @@ data.map(({ adjective, color, noun }) => (
));
```
-**BUT WAIT!** We can actually use Million.js' built-in rendering solution.
+**BUT WAIT!** You can actually use Million.js' built-in rendering solution.
### Optimized List Rendering
@@ -287,20 +266,21 @@ The `{:jsx}` component is used to render a list of blocks. It takes an ar
Syntax: `{(item, index) => Block}{:jsx}`\
Example: `{(item, index) => myBlock({ item, index })}{:jsx}`
+
It's the best way to loop over an array (uses [`mapArray(){:jsx}`](/docs/internals/map-array) under the hood). As the array changes, `{:jsx}` updates or moves items in the DOM rather than recreating them. Let's look at an example:
-With this in mind, we can rewrite our table to use `{:jsx}`:
+With this in mind, you can rewrite your table to use `{:jsx}`:
```jsx {3, 4, 5, 6, 7}
-import { For } from "million/react";
+import { For } from 'million/react';
{({ adjective, color, noun }) => (
)}
-
+;
```
@@ -315,22 +295,22 @@ Notice when you change the input value, the lag radar shows significantly less l
import { buildData } from './data';
import { block, For } from 'million/react';
- const RowBlock = block(
- function Row({ adjective, color, noun }) {
- return (
-
@@ -344,6 +324,7 @@ Notice when you change the input value, the lag radar shows significantly less l
);
+
}
export default App;
@@ -351,20 +332,12 @@ export default App;
-### Million.js vs. React
-
-
- The following is a more 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.
-
-
-
-
-
-
## Hitting the limit
- This section is a bit more advanced. If you want a list of limitations, check out the [Rules of Blocks](/docs/rules). Or, if you just want to start integrating Million.js, check out the [installation guide](/docs/install).
+ This section is a bit more advanced. If you want a list of limitations, check
+ out the [Rules of Blocks](/docs/rules). Or, if you just want to start
+ integrating Million.js, check out the [installation guide](/docs/install).
Blocks are great for rendering large lists, data grids, and many other use cases. Under the hood, they render with the Million.js virtual DOM instead of React.
diff --git a/website/pages/docs/virtualization.mdx b/website/pages/docs/manual-mode/virtualization.mdx
similarity index 86%
rename from website/pages/docs/virtualization.mdx
rename to website/pages/docs/manual-mode/virtualization.mdx
index c888368c96..247fd8fabb 100644
--- a/website/pages/docs/virtualization.mdx
+++ b/website/pages/docs/manual-mode/virtualization.mdx
@@ -4,13 +4,13 @@ description: 'List virtualization allows you to render large lists without perfo
---
import { Callout, Tabs, Tab, Steps } from 'nextra-theme-docs';
-import { AutomaticModeWarning } from '../../components/automatic-mode-warning';
+import { AutomaticModeWarning } from '../../../components/automatic-mode-warning';
# Virtualization
-Million.js plays very well with [TanStack Virtual](https://tanstack.com/virtual/v3/docs/guide/introduction). TanStack Virtual is a headless UI utility for virtualizing long lists of elements in React. Together, you can automatically use blocks within virtualized lists.
+Million.js works with [TanStack Virtual](https://tanstack.com/virtual/v3/docs/guide/introduction). TanStack Virtual is a headless UI utility for virtualizing long lists of elements in React. Together, you can automatically use blocks within virtualized lists.
## Why Virtualize?
@@ -56,7 +56,7 @@ You can easily install it via this command:
## Example
-Here is just a quick example of what it looks like to virtualize a long list within a div using TanStack Virtual with Million.js:
+Here is just a quick example of what it looks like to virtualize a long list within a `div` using TanStack Virtual with Million.js:
```jsx
import { useRef } from 'react';
diff --git a/website/pages/docs/rules.mdx b/website/pages/docs/rules.mdx
deleted file mode 100644
index 2eed08934b..0000000000
--- a/website/pages/docs/rules.mdx
+++ /dev/null
@@ -1,237 +0,0 @@
----
-title: 'Rules Of Blocks'
-description: 'How to use blocks in your projects the right way'
----
-
-import { Callout } from 'nextra-theme-docs';
-import { AutomaticModeWarning } from '../../components/automatic-mode-warning';
-
-# Rules of Blocks
-
-
-
-You are probably here because you got a warning message in your console.
-
-
- \[Million.js\] You did something wrong!
-
- ```jsx showLineNumbers filename="App.jsx" {2}
-
- Uh oh...
- ^
-
- ```
-
-
-There are three common reasons you might be seeing it:
-
-1. You might be **breaking Rules of Blocks.**
-2. You might have **forgot to use the compiler.**
-3. You've entered **unsupported behavior.**
-
-## Breaking Rules of Blocks
-
-You may have heard of ["progressive enhancement,"](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement) which is the idea that tools progressively use features based on what is supported. Similarly, Million.js has "progressive degradation," or the concept that if you use features that are not supported, it will degrade to default React rendering gracefully.
-
-This section highlights some of the possible warnings you might encounter using blocks. Note that this is not an exhaustive list.
-
-
- This section presents idiomatic patterns to use blocks. It is not a list of errors, your application will still work if you don't follow these patterns.
-
-
-### Declaring blocks
-
-
-
- [Million.js] Block needs to be defined as a variable declaration.
-
-
-
-The above usually occurs when you have a block that is not declared as a variable. This prevents the compiler from analyzing the block correctly.
-
-```jsx
-console.log(block(() => )) // โ Wrong
-export default block(() => ) // โ Wrong
-
-// ๐๐๐
-
-const Block = block(() => ) // โ Correct
-console.log(Block);
-export default Block;
-```
-
-### Calling `block()`
-
-
-
- [Million.js] Found unsupported argument for block. Make sure blocks consume a reference
- to a component function or the direct declaration.
-
-
-
-The above usually occurs when you have an actual JSX component like `{:jsx}` passed into the `block(){:jsx}` function instead of a reference to the Component itself.
-
-```jsx
-const BadBlock = block() // โ Wrong
-
-const GoodBlock = block(App) // โ Correct
-```
-
-### Using `` instead of `map()`
-
-
-
- [Million.js]
- Array.map() will degrade performance. We recommend removing the block on the
- current component and using a `` component instead
-
-
-
-The above will occur when you use `.map` within a block. This is not ideal, especially if the component that holds the list is a block. The right pattern is to remove the block on the current component and use a `` component instead for the children.
-
-```jsx
-
- {items.map((item) => (
-
{item}
- ))}
-
-
-// ๐๐๐
-
-
- {(item) =>
{item}
}
-
-```
-
-### Deterministic returns
-
-
-
-
- [Million.js]
- Conditional expressions will degrade performance. We recommend using
- deterministic returns instead.
-
-
-
-
-
- Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
-
-
-
-
-
-
-Returns must be "deterministic," meaning there can only be one return statement at the end of the block that returns a stable tree.
-
-Some examples of non-deterministic returns:
-
-```jsx
-function Component() {
- const [count, setCount] = useState(initial.count);
-
- if (count > 10) {
- return
- );
-}
-
-const ComponentBlock = block(Component);
-```
-
-### UI Component libraries ๐ โโ๏ธ
-
-
-
- [Million.js]
- Components will cause degraded performance. Ideally, you should use DOM elements instead.
-
-
-
-Many React applications use UI component libraries like Material UI, Chakra UI, or Tailwind UI. These libraries are great, but they are not optimized for Million.js.
-
-Million.js requires that you use DOM elements instead of components. This is because components can introduce non-deterministic returns, which can cause degraded performance.
-
-```jsx
-// โ Bad
-
- What's up my fellow components
-
-
-// ๐คจ Maybe
-
- What's up my fellow components
-
-
-// โ Good
-
-
What's up my fellow components
-
-```
-
-### Spread attributes/children
-
-
-
- [Million.js]
- Spread attributes/children are not fully supported
-
-
-
-You can't use spread attributes/children that change safely or reference a binding within the component inside Million.js, as they can introduce non-deterministic returns.
-
-```jsx
-const arr = ['Hello'];
-
-
{...arr}
// Ok if arr never changes
-
-// โ Bad
-arr.push('World');
-```
-
-### Unsupported import
-
-
-
- [Million.js]
- Found unsupported import for block. Make sure blocks are imported from million/react.
-
-
-
-This may be caused by importing the block from the wrong place. Make sure you import the block from `million/react` instead of `million`.
-
-```jsx
-import { block } from 'million'; // โ Wrong
-
-import { block } from 'million/react'; // โ Correct
-```
-
-## Using the compiler
-
-
-
- Warning:
- Invalid Hook Call. Hooks can only be called inside of the body of a function component.
-
-
-
-You may have forgot to use the compiler, a necessary part in ensuring that your JSX is compiled to Million.js compatible code. You can view the instructions at [the installation guide](/docs/install).
-
-On a side note, Million.js is technically usable without the compiler, but it's significantly more limited in scope, and there is a [more limited set of features available](/docs/block#rules-of-usage). This is not recommended.
-
-## Unsupported behavior
-
-
-
- Uncaught Error: ??? :(
-
-
-
-If none of this worked, please [create an issue](https://github.com/aidenybai/million/issues/new?assignees=aidenybai&labels=bug&projects=&template=bug_report.md&title=bug%3A+) and we'll try to help. Try to create a small reproducing example โ you might discover the problem as you're doing it.
diff --git a/website/pages/docs/typescript.mdx b/website/pages/docs/typescript.mdx
deleted file mode 100644
index 0a4642c361..0000000000
--- a/website/pages/docs/typescript.mdx
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: 'Usage with TypeScript'
-description: 'Learn how to use TypeScript with Million.js'
----
-
-import { Callout } from 'nextra-theme-docs';
-import { AutomaticModeWarning } from '../../components/automatic-mode-warning';
-
-# Usage with TypeScript
-
-
-
-If your project uses TypeScript, you may want to make your components type-safe.
-
-
-You must make your Props use `type` instead of `interface`, as this is the [officially recognized
-behavior](https://github.com/microsoft/TypeScript/issues/15300#issuecomment-332366024)
-by the TypeScript team. Alternatively, if you want to use interfaces you can
-add `[key: string]: any` as per [this Stack Overflow
-comment](https://stackoverflow.com/questions/37006008/typescript-index-signature-is-missing-in-type/65473225#65473225).
-
-
-
-```jsx
-type Props = {
- name: string,
-};
-
-const MyComponent: React.FC = ({ name }) => {
- return