/react-three-babel

A Babel plugin that automatically builds the extend catalogue of known native Three.js elements

Primary LanguageTypeScriptMIT LicenseMIT

react-three-babel

Version

A Babel plugin that automatically builds the extend catalogue of known native Three.js elements which enables granular usage of Three.js and therefore tree shaking.

Install

npm install --save-dev @react-three/babel

Usage

Default

module.exports = {
  plugins: ["module:@react-three/babel"],
};

In

import { createRoot } from "@react-three/fiber";

createRoot(canvasNode).render(
  <mesh>
    <boxGeometry />
    <meshStandardMaterial />
  </mesh>
);

Out

import { createRoot, extend } from "@react-three/fiber";
import {
  Mesh as _Mesh,
  BoxGeometry as _BoxGeometry,
  MeshStandardMaterial as _MeshStandardMaterial,
} from "three";

extend({
  Mesh: _Mesh,
  BoxGeometry: _BoxGeometry,
  MeshStandardMaterial: _MeshStandardMaterial,
});

createRoot(canvasNode).render(
  <mesh>
    <boxGeometry />
    <meshStandardMaterial />
  </mesh>
);

Custom import sources

module.exports = {
  plugins: [
    [
      "module:@react-three/babel",
      {
        importSources: ["three", "three-stdlib"], // default: ["three"]
      },
    ],
  ],
};

In

import { createRoot } from "@react-three/fiber";

createRoot(canvasNode).render(<orbitControls />);

Out

import { createRoot, extend } from "@react-three/fiber";
import { OrbitControls as _OrbitControls } from "three-stdlib";

extend({ OrbitControls: _OrbitControls });

createRoot(canvasNode).render(<orbitControls />);

How it Works

The plugin starts by looking at all the JSX elements that you include in your source code files (ex. <h1/>, <p/>, <ambientLight/>, etc.). If any of them match an import from the three namespace (or importSources, as shown in example above), then it is added to a set.

Once all the JSX elements in a file are examined, the plugin adds the following imports to that file:

  • Import extend function from @react-three/fiber
  • For each name in the set, a named import from the three namespace (ex. import { Mesh } from 'three')

Finally, it adds a call to extend with the named imports.

Limitations

This plugin relies on static analysis of JSX identifiers, which means that if you wrap any elements or generate elements dynamically, they will not be picked up by this plugin.

However, the animated elements from @react-spring/three, like <animated.mesh />, WILL be picked up by this plugin.

But something like this will not:

const StyledMesh = styled('mesh')

<StyledMesh />