メインコンテンツまでスキップ

Bundle Size and Tree Shaking

The PlayCanvas Engine is published on npm as ES modules, one module per source file, and its package.json declares "sideEffects": false. When you bundle your application with a build tool such as Vite, Rollup, esbuild or webpack, the build tool follows the imports in your code and leaves out every module that nothing uses. This is called tree shaking.

Most of what ends up in your bundle is decided by how you set up AppBase. This page explains how to set it up so that your application includes only what it uses.

How It Works​

Your code refers to components and assets by name: entity.addComponent('render') or new Asset('logo', 'texture', { url }). A build tool can't tell from these strings which parts of the engine your application needs.

Instead, AppBase registers only the component systems and resource handlers that you list in an AppOptions object:

  • A component system runs one type of component. For example, RenderComponentSystem runs the render component.
  • A resource handler loads one type of asset. For example, TextureHandler loads texture assets.

Each class you list is imported by your code, so it is included in your bundle. Each class you don't list is left out, together with the code that only it uses.

Setting Up AppBase​

This example registers what an application with meshes, a camera, lights, scripts, textures and glTF models needs:

main.js
import {
AppBase,
AppOptions,
CameraComponentSystem,
ContainerHandler,
createGraphicsDevice,
DEVICETYPE_WEBGPU,
Keyboard,
LightComponentSystem,
Mouse,
RenderComponentSystem,
ScriptComponentSystem,
ScriptHandler,
TextureHandler,
TouchDevice
} from 'playcanvas';

const canvas = document.getElementById('application');
const device = await createGraphicsDevice(canvas, {
deviceTypes: [DEVICETYPE_WEBGPU]
});

const createOptions = new AppOptions();
createOptions.graphicsDevice = device;

// input devices the application reads
createOptions.mouse = new Mouse(canvas);
createOptions.touch = new TouchDevice(canvas);
createOptions.keyboard = new Keyboard(window);

// component systems and resource handlers the application uses
createOptions.componentSystems = [
RenderComponentSystem,
CameraComponentSystem,
LightComponentSystem,
ScriptComponentSystem
];
createOptions.resourceHandlers = [TextureHandler, ContainerHandler, ScriptHandler];

const app = new AppBase(canvas);
app.init(createOptions);
app.start();

If you use a component without registering its system, addComponent returns null, and the debug build of the Engine logs addComponent: System 'sound' doesn't exist. If you load an asset without registering its handler, the load fails with No resource handler for asset type.

ヒント

During development, Vite and other build tools that set the development export condition use the debug build of the Engine, which logs these errors. Production builds use the release build.

Component Systems​

Register a component system for each type of component your application adds. The Also needs column lists what else the component uses.

Component systemComponentUsed forAlso needs
RenderComponentSystemrenderMeshes, primitive shapes and the entities of glTF models
CameraComponentSystemcameraCameras
LightComponentSystemlightDirectional, omni, spot and area lights
ScriptComponentSystemscriptScriptsScriptHandler to load scripts as script assets
GSplatComponentSystemgsplatGaussian splatsGSplatHandler
ParticleSystemComponentSystemparticlesystemParticle systemsTextureHandler for particle textures
AnimComponentSystemanimAnimation state graphs and animation layersAnimClipHandler and AnimStateGraphHandler to load animclip and animstategraph assets
AnimationComponentSystemanimationLegacy animation playback, superseded by animAnimationHandler
ModelComponentSystemmodelLegacy meshes, superseded by renderModelHandler
SoundComponentSystemsoundPlaying soundsAudioHandler, and soundManager in AppOptions
AudioListenerComponentSystemaudiolistenerThe listener for positional soundsoundManager in AppOptions
CollisionComponentSystemcollisionCollision shapes and triggersammo.js
RigidBodyComponentSystemrigidbodyRigid body physicsCollisionComponentSystem, ammo.js
JointComponentSystemjointPhysics jointsRigidBodyComponentSystem, CollisionComponentSystem, ammo.js
ScreenComponentSystemscreenThe root of a user interface
ElementComponentSystemelementText, image and group elementsScreenComponentSystem, FontHandler for text, and elementInput in AppOptions for input
ButtonComponentSystembuttonButtonsElementComponentSystem, elementInput in AppOptions
ScrollViewComponentSystemscrollviewScrolling contentElementComponentSystem, ScrollbarComponentSystem for its scrollbars
ScrollbarComponentSystemscrollbarScrollbarsElementComponentSystem
LayoutGroupComponentSystemlayoutgroupLaying out child elementsElementComponentSystem
LayoutChildComponentSystemlayoutchildLayout settings of an element in a layout groupElementComponentSystem, LayoutGroupComponentSystem
SpriteComponentSystemsprite2D sprites and sprite animationsSpriteHandler, TextureAtlasHandler and TextureHandler to load sprites

Resource Handlers​

Register a resource handler for each type of asset your application loads.

Resource handlerAsset typeLoads
TextureHandlertextureImages, HDR images and compressed textures
ContainerHandlercontainerglTF and GLB models, with their meshes, materials, textures and animations
ScriptHandlerscriptJavaScript files that define scripts
GSplatHandlergsplatGaussian splat files
CubemapHandlercubemapCubemaps
MaterialHandlermaterialMaterials stored as JSON
RenderHandlerrenderMeshes that refer to a container asset, as exported by the Editor
FontHandlerfontFonts for text elements
AudioHandleraudioSound files
AnimClipHandleranimclipAnimation clips for the anim component
AnimStateGraphHandleranimstategraphAnimation state graphs for the anim component
AnimationHandleranimationAnimations for the legacy animation component
ModelHandlermodelModels for the legacy model component
SpriteHandlerspriteSprites
TextureAtlasHandlertextureatlasTexture atlases for sprites
SceneHandlersceneScenes exported by the Editor
JsonHandlerjsonJSON data
TextHandlertextText files
BinaryHandlerbinaryBinary data, as an ArrayBuffer

Other Options​

The other properties of AppOptions add features in the same way: what you don't set is not included.

OptionValueUsed for
graphicsDeviceA GraphicsDevice, from createGraphicsDeviceRendering. Required.
mousenew Mouse(canvas)Reading mouse input through app.mouse
touchnew TouchDevice(canvas)Reading touch input through app.touch
keyboardnew Keyboard(window)Reading keyboard input through app.keyboard
gamepadsnew GamePads()Reading gamepad input through app.gamepads
elementInputnew ElementInput(canvas)Mouse and touch input on user interface elements
soundManagernew SoundManager()Playing sounds with the sound and audiolistener components
lightmapperThe Lightmapper classBaking lightmaps at runtime
batchManagerThe BatchManager classCombining mesh instances into batches
xrThe XrManager classWebXR, through app.xr
assetPrefixA stringA prefix added to the URL of every asset
scriptPrefixA stringA prefix added to the URL of every script
scriptsOrderAn array of script URLsThe order in which scripts are loaded
devtoolstrue or falseWhether the application announces itself to developer tools such as the PlayCanvas Inspector. Defaults to true.

Each input device stays null on the application unless you set it here.

Keeping the Bundle Small​

  • Import from playcanvas. The package name resolves to the per-module build that build tools can tree shake. The single-file builds in playcanvas/build/ are meant for use without a build tool, such as from an import map.
  • Use the engine's exports directly. Named imports (import { Entity } from 'playcanvas') and members of a namespace import (pc.Entity) both tree shake. Passing the whole namespace to a function as a value, as in setup(pc), makes some build tools, such as esbuild, keep the entire engine.
  • Check what your bundle contains. esbuild prints the size of each module with --analyze, and rollup-plugin-visualizer draws a map of a Vite or Rollup bundle.