+ 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?
- The tools to make React faster, automatically.
+ All 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
deleted file mode 100644
index 86ff31916f..0000000000
--- a/website/components/home/community.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-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 2afaa9782a..c69b805f61 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: (
<>
- It uses a novel approach to the virtual DOM called the block virtual DOM.
+ We use 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,
@@ -30,27 +29,15 @@ export function Hero() {
The{' '}
-
- Virtual DOM
- {' '}
- Replacement
+ Virtual DOM Replacement
{' '}
- for React. Experience improved performance for UI and data-heavy
- React apps. Minimal effort required - all it takes is {' '}
+ for React. Gain big performance wins for UI and data heavy React
+ apps. Dead simple to use โ try it out with{' '}
- a single plugin
+ just one plugin
.
-
- {/* */}
-
+
+
);
diff --git a/website/components/home/showcase.tsx b/website/components/home/showcase.tsx
index 02e61ffc6b..723a2f1901 100644
--- a/website/components/home/showcase.tsx
+++ b/website/components/home/showcase.tsx
@@ -8,35 +8,6 @@ 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 57dacd481d..7d9a02da2a 100644
--- a/website/package.json
+++ b/website/package.json
@@ -34,7 +34,6 @@
"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 5465c7c808..6fd482ba55 100644
--- a/website/pages/_meta.json
+++ b/website/pages/_meta.json
@@ -31,13 +31,6 @@
"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 fab5b82cf0..58f652cf8d 100644
--- a/website/pages/docs/_meta.json
+++ b/website/pages/docs/_meta.json
@@ -1,7 +1,25 @@
{
+ "-- Getting Started": {
+ "type": "separator",
+ "title": "Getting Started"
+ },
"index": "Introduction",
- "getting-started": "Getting Started",
- "automatic-mode": "Automatic Mode",
- "manual-mode": "Manual Mode",
+ "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",
"internals": "Internals"
}
diff --git a/website/pages/docs/automatic-mode/_meta.json b/website/pages/docs/automatic-mode/_meta.json
deleted file mode 100644
index d3d2f16ea9..0000000000
--- a/website/pages/docs/automatic-mode/_meta.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "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
deleted file mode 100644
index e3972f0ae7..0000000000
--- a/website/pages/docs/automatic-mode/advanced-customization.mdx
+++ /dev/null
@@ -1,194 +0,0 @@
----
-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
deleted file mode 100644
index ae3c0a013d..0000000000
--- a/website/pages/docs/automatic-mode/introduction.mdx
+++ /dev/null
@@ -1,16 +0,0 @@
----
-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
new file mode 100644
index 0000000000..f77398f7a6
--- /dev/null
+++ b/website/pages/docs/automatic.mdx
@@ -0,0 +1,42 @@
+---
+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
new file mode 100644
index 0000000000..2113983a95
--- /dev/null
+++ b/website/pages/docs/block.mdx
@@ -0,0 +1,61 @@
+---
+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
new file mode 100644
index 0000000000..479c91c137
--- /dev/null
+++ b/website/pages/docs/common-errors.mdx
@@ -0,0 +1,21 @@
+---
+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/manual-mode/for.mdx b/website/pages/docs/for.mdx
similarity index 92%
rename from website/pages/docs/manual-mode/for.mdx
rename to website/pages/docs/for.mdx
index 5cb165b5a1..4d952cdcb2 100644
--- a/website/pages/docs/manual-mode/for.mdx
+++ b/website/pages/docs/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;
```
-## Custom Tags
+## `as` prop
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 `` With `memo`
+## Optimizing ``
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,9 +59,7 @@ However, if you know that your items aren't dependent on any values except the `
```
-
-
-## Using For With SSR
+## 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.
diff --git a/website/pages/docs/getting-started/_meta.json b/website/pages/docs/getting-started/_meta.json
deleted file mode 100644
index 2713adb886..0000000000
--- a/website/pages/docs/getting-started/_meta.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "install": "Installation"
- }
-
\ No newline at end of file
diff --git a/website/pages/docs/index.mdx b/website/pages/docs/index.mdx
index 130e6d3764..422c14f3a6 100644
--- a/website/pages/docs/index.mdx
+++ b/website/pages/docs/index.mdx
@@ -1,69 +1,12 @@
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),
-);
+import { Tab, Tabs } from 'nextra-theme-docs';
# Introduction
-**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.
-
-
-
+**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.
-
+Imagine React components running at the speed of raw JavaScript.
-## Any questions?
+## FAQ
-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/getting-started/install.mdx b/website/pages/docs/install.mdx
similarity index 76%
rename from website/pages/docs/getting-started/install.mdx
rename to website/pages/docs/install.mdx
index cf61f47799..6bcb1c7b33 100644
--- a/website/pages/docs/getting-started/install.mdx
+++ b/website/pages/docs/install.mdx
@@ -5,15 +5,50 @@ 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 have an existing React project. To learn about how to create a React app, please see [React's documentation](https://react.dev).
+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
+ ```
+
+
+
+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.
+
-## Configure It Yourself
+## Manual configuration
-For more control, Million offers customizable options.
+In the case you want more granular control over the installation process, you can follow the steps below.
@@ -21,10 +56,9 @@ For more control, Million offers customizable options.
+### 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 */}
@@ -53,8 +87,9 @@ For more control, Million offers customizable options.
-### Add the compiler to your application
+### Use the compiler
+Then, add the compiler to your build tool of choice:
@@ -126,10 +161,6 @@ For more control, Million offers customizable options.
```
-
- 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 = {
@@ -161,17 +192,16 @@ For more control, Million offers customizable options.
-
Checkout Automatic Mode to learn about the mechanisms behind Automatic mode.
-
-
+
-### Install Million.js
+### Install package
+First things first, you'll need to install Million.js. You can do this with your favorite package manager:
{/* prettier-ignore */}
@@ -200,8 +230,9 @@ For more control, Million offers customizable options.
-### Add the compiler to your application
+### Use the compiler
+Then, add the compiler to your build tool of choice:
React Instructions
@@ -252,26 +283,9 @@ For more control, Million offers customizable options.
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 = {
@@ -279,7 +293,6 @@ For more control, Million offers customizable options.
plugins: { add: [million.webpack()] }
}
};
-
```
@@ -356,6 +369,21 @@ For more control, Million offers customizable options.
+### 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/internals/_meta.json b/website/pages/docs/internals/_meta.json
index 6b7ba58786..5d5ef703e1 100644
--- a/website/pages/docs/internals/_meta.json
+++ b/website/pages/docs/internals/_meta.json
@@ -1,4 +1,5 @@
{
+ "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
new file mode 100644
index 0000000000..bb3844fc68
--- /dev/null
+++ b/website/pages/docs/internals/block.mdx
@@ -0,0 +1,74 @@
+---
+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 d0afdb6695..6facdb8017 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.** It is intended for developers
- creating their own frameworks. It is not recommended for general use.
+ **This function is part of the internal API.** You should only be using this if
+ you are making your own framework.
diff --git a/website/pages/docs/internals/mount.mdx b/website/pages/docs/internals/mount.mdx
index cdda7678f7..a4aa593e53 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.** It is intended for developers
- creating their own frameworks. It is not recommended for general use.
+ **This function is part of the internal API.** You should only be using this if
+ you are making your own framework.
diff --git a/website/pages/docs/internals/patch.mdx b/website/pages/docs/internals/patch.mdx
index fbf1e18334..95551cd4b5 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.** It is intended for developers
- creating their own frameworks. It is not recommended for general use.
+ **This function is part of the internal API.** You should only be using this if
+ you are making your own framework.
@@ -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.
- Blocks must be derived from the same function when using `patch()`. This
- ensures performance is not negatively impacted.
+ Always try to keep Blocks of the same shape (derived from the same function)
+ when using patch in order to maintain good performance.
```jsx
diff --git a/website/pages/docs/internals/render-to-template.mdx b/website/pages/docs/internals/render-to-template.mdx
index 994f4559f3..8675489be1 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.** It is intended for developers
- creating their own frameworks. It is not recommended for general use.
+ **This function is part of the internal API.** You should only be using this if
+ you are making your own framework.
diff --git a/website/pages/docs/internals/string-to-dom.mdx b/website/pages/docs/internals/string-to-dom.mdx
index 6e49cdaa71..e356da7ca7 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.** It is intended for developers
- creating their own frameworks. It is not recommended for general use.
+ **This function is part of the internal API.** You should only be using this
+ if you are making your own framework.
diff --git a/website/pages/docs/manual-mode/_meta.json b/website/pages/docs/manual-mode/_meta.json
deleted file mode 100644
index c1b2a86d5a..0000000000
--- a/website/pages/docs/manual-mode/_meta.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "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
deleted file mode 100644
index 2e56317434..0000000000
--- a/website/pages/docs/manual-mode/block.mdx
+++ /dev/null
@@ -1,403 +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, 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/manual-mode/usage-guide.mdx b/website/pages/docs/quickstart.mdx
similarity index 60%
rename from website/pages/docs/manual-mode/usage-guide.mdx
rename to website/pages/docs/quickstart.mdx
index a1d5b15153..bd81b6c6cb 100644
--- a/website/pages/docs/manual-mode/usage-guide.mdx
+++ b/website/pages/docs/quickstart.mdx
@@ -1,40 +1,59 @@
---
-title: 'How To Integrate Million In A Project'
+title: 'Tutorial'
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';
+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),
+);
- It is highly recommended you view this documentation on a desktop browser to
- get access to interactive code examples.
+ We highly recommend viewing this documentation on a desktop browser to get access to interactive code examples.
-# How To Integrate Million In A Project
+# Tutorial
-Let's learn how you can integrate Million.js into your React applications.
+Welcome to the Million.js documentation (_woop woop ๐๐ค_). Let's learn how we can integrate Million.js into our React applications.
-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.
+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.
**You will learn:**
-- How to use [`block(){:jsx}`](/docs/manual-mode/block) to convert React components into blocks
+- How to use `block(){:jsx}` 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}
@@ -55,22 +74,22 @@ Have a look at the result:
-);
-}
+ function Lion() {
+ return (
+
+ );
+ }
-const LionBlock = block(Lion);
+ const LionBlock = block(Lion);
-export default function App() {
-return (
-
+ );
+ }
`} />
@@ -81,7 +100,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.
-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.
+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.
```jsx
function App() {
@@ -90,20 +109,22 @@ function App() {
return (
-
// ...
+
+ // ...
+
);
}
```
-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}`:
+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}`:
```jsx
const data = buildData(100);
// returns [{ adjective: '...', color: '...', noun: '...' }, ... x100]
```
-Now, you can render the data in our table using `Array.map(){:jsx}`:
+Now, we can render the data in our table using `Array.map(){:jsx}`:
```jsx {3, 9-15}
function App() {
@@ -134,9 +155,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 (
@@ -152,19 +173,18 @@ const data = buildData(rows);
);
-
}
export default App;
`} />
-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.
+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.
-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.
+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.
### More realistic rendering
-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.
+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.
Try changing the input value up and down from 0 to 1000. Notice how React _really struggles_ when rendering a lot of elements.
@@ -173,9 +193,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 (
@@ -192,7 +212,6 @@ const data = buildData(rows);
);
-
}
export default App;
@@ -202,9 +221,9 @@ export default App;
### Just `block` it
-In the following example, you can use `block(){:jsx}` and `{:jsx}` in order to optimize rendering.
+In the following example, we use `block(){:jsx}` and `{:jsx}` in order to optimize rendering.
-First, you need to abstract the `
{:jsx}` into its own component.
+First, we need to abstract the `
{:jsx}` into its own component.
```jsx
data.map(({ adjective, color, noun }) => (
@@ -214,7 +233,7 @@ data.map(({ adjective, color, noun }) => (
{noun}
{...lotsOfElements}
-));
+))
// ๐๐๐
@@ -230,24 +249,26 @@ function Row({ adjective, color, noun }) {
}
```
-Then, you can wrap it with `block(){:jsx}` in order to optimize the `{:jsx}` component.
+Then, we 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, you've optimized a row, you will need to render it as a list:
+Once, we've optimized a row, we need to render it as a list:
```jsx
data.map(({ adjective, color, noun }) => (
@@ -255,7 +276,7 @@ data.map(({ adjective, color, noun }) => (
));
```
-**BUT WAIT!** You can actually use Million.js' built-in rendering solution.
+**BUT WAIT!** We can actually use Million.js' built-in rendering solution.
### Optimized List Rendering
@@ -266,21 +287,20 @@ 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, you can rewrite your table to use `{:jsx}`:
+With this in mind, we can rewrite our table to use `{:jsx}`:
```jsx {3, 4, 5, 6, 7}
-import { For } from 'million/react';
+import { For } from "million/react";
{({ adjective, color, noun }) => (
)}
-;
+
```
@@ -295,22 +315,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 (
-
);
-
}
export default App;
@@ -332,12 +351,20 @@ 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/rules.mdx b/website/pages/docs/rules.mdx
new file mode 100644
index 0000000000..2eed08934b
--- /dev/null
+++ b/website/pages/docs/rules.mdx
@@ -0,0 +1,237 @@
+---
+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
new file mode 100644
index 0000000000..0a4642c361
--- /dev/null
+++ b/website/pages/docs/typescript.mdx
@@ -0,0 +1,33 @@
+---
+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
Hello {name}
;
+};
+const MyBlock = block(MyComponent);
+```
diff --git a/website/pages/docs/manual-mode/virtualization.mdx b/website/pages/docs/virtualization.mdx
similarity index 86%
rename from website/pages/docs/manual-mode/virtualization.mdx
rename to website/pages/docs/virtualization.mdx
index 247fd8fabb..c888368c96 100644
--- a/website/pages/docs/manual-mode/virtualization.mdx
+++ b/website/pages/docs/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 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.
+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.
## 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/faq.mdx b/website/pages/faq.mdx
deleted file mode 100644
index 9db96f87c6..0000000000
--- a/website/pages/faq.mdx
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: 'FAQ'
-description: 'Frequently asked questions about Million.js'
----
-
-import { FAQ } from '../components/home/faq';
-
-
-
-
diff --git a/website/styles/global.css b/website/styles/global.css
index 91515e20a0..dc416af068 100644
--- a/website/styles/global.css
+++ b/website/styles/global.css
@@ -235,14 +235,13 @@ li > a {
}
.dark .slider::before,
.dark .slider::after {
- background: linear-gradient(to right, #111 0%, #11111100 50%);
+ background: linear-gradient(to right, #111 0%, #11111100 100%);
content: '';
z-index: 2;
position: absolute;
height: 100%;
width: 10rem;
pointer-events: none;
- /* background:transparent; */
}
.slider::after {
right: 0;
diff --git a/website/tailwind.config.js b/website/tailwind.config.js
index 8df2b35030..8e432a67bc 100644
--- a/website/tailwind.config.js
+++ b/website/tailwind.config.js
@@ -11,10 +11,6 @@ module.exports = {
spin: 'spin calc(var(--speed) * 2) infinite linear',
slide: 'slide var(--speed) ease-in-out infinite alternate',
},
- backgroundImage: {
- 'blue-purple-gradient':
- 'linear-gradient(83.21deg,#3245FF 0%,#B845ED 100%)',
- },
},
keyframes: {
spin: {
diff --git a/website/theme.config.tsx b/website/theme.config.tsx
index 4d4b6ffaed..333c2b0f92 100644
--- a/website/theme.config.tsx
+++ b/website/theme.config.tsx
@@ -112,84 +112,9 @@ const config: DocsThemeConfig = {
docsRepositoryBase: 'https://github.com/aidenybai/million/tree/main/website/',
footer: {
text: (
-
+
ยฉ 2021-{new Date().getFullYear()} Million Software, Inc.