Vite Plugin GLSL
April 7, 2026 · View on GitHub
Import, inline (and minify) GLSL/WGSL/Slang shader files
Inspired by threejs-glsl-loader and vite-plugin-string, compatible with Babylon.js, three.js and lygia.
Installation
npm i vite-plugin-glsl --save-dev
# or
yarn add vite-plugin-glsl --dev
# or
pnpm add -D vite-plugin-glsl
# or
bun add vite-plugin-glsl --dev
Usage
// vite.config.js
import { defineConfig } from 'vite';
import glsl from 'vite-plugin-glsl';
export default defineConfig({
plugins: [glsl()]
});
With TypeScript
Add extension declarations to your types in tsconfig.json:
{
"compilerOptions": {
"types": [
"vite-plugin-glsl/ext"
]
}
}
or as a package dependency directive to your global types:
/// <reference types="vite-plugin-glsl/ext" />
With Slang Shaders
Slang shaders are not supported out of the box; however, starting from version 1.6.0, it's quite easy to use them with this plugin. You'll need some minimal setup you can find here to copy-paste in your vite.config file. The idea is to use multiple importKeywords to include Slang shader chunks and convert the output shader to a web-friendly format (like WGSL) by using the onComplete option and the Slang compiler.
Default Options
glsl({
include: [ // Glob pattern, or array of glob patterns to import
'**/*.glsl', '**/*.wgsl',
'**/*.vert', '**/*.frag',
'**/*.vs', '**/*.fs'
],
exclude: undefined, // Glob pattern, or array of glob patterns to ignore
defaultExtension: 'glsl', // Shader suffix to use when no extension is specified
warnDuplicatedImports: true, // Warn if the same chunk was imported multiple times
removeDuplicatedImports: false, // Automatically remove an already imported chunk
importKeywords: ['#include'], // Keywords used to import shader chunks
onComplete: undefined, // Function to call with output shader
minify: false, // Minify/optimize output shader code
watch: true, // Recompile shader on change
root: '/' // Directory for root imports
})
Example
root
├── src/
│ ├── glsl/
│ │ ├── chunk0.frag
│ │ ├── chunk3.frag
│ │ ├── main.frag
│ │ ├── main.vert
│ │ └── utils/
│ │ ├── chunk1.glsl
│ │ └── chunk2.frag
│ └── main.js
├── vite.config.js
└── package.json
// main.js
import fragment from './glsl/main.frag';
// main.frag
#version 300 es
#ifndef GL_FRAGMENT_PRECISION_HIGH
precision mediump float;
#else
precision highp float;
#endif
out vec4 fragColor;
#include chunk0.frag;
void main (void) {
fragColor = chunkFn();
}
// chunk0.frag
// ".glsl" extension will be added automatically:
#include utils/chunk1;
vec4 chunkFn () {
return vec4(chunkRGB(), 1.0);
}
// utils/chunk1.glsl
#include chunk2.frag;
#include ../chunk3.frag;
vec3 chunkRGB () {
return vec3(chunkRed(), chunkGreen(), 0.0);
}
// utils/chunk2.frag
float chunkRed () {
return 0.0;
}
// chunk3.frag
float chunkGreen () {
return 0.8;
}
Will result in:
// main.frag
#version 300 es
#ifndef GL_FRAGMENT_PRECISION_HIGH
precision mediump float;
#else
precision highp float;
#endif
out vec4 fragColor;
float chunkRed () {
return 0.0;
}
float chunkGreen () {
return 0.8;
}
vec3 chunkRGB () {
return vec3(chunkRed(), chunkGreen(), 0.0);
}
vec4 chunkFn () {
return vec4(chunkRGB(), 1.0);
}
void main (void) {
fragColor = chunkFn();
}
Change Log
-
Starting from
v1.6.0this plugin supportsonCompletecallback function to customize output shaders. -
Starting from
v1.5.2this plugin usesvite.transformWithOxcfunction when available. -
Starting from
v1.5.1this plugin is fully compatible withvite^7.0.0. -
Starting from
v1.5.0this plugin supports a customimportKeywordto include shader chunks. -
Starting from
v1.4.0compressoption was renamed tominifyand now it allows a promise callback. -
Starting from
v1.3.2this plugin allows to automatically remove already imported chunks with theremoveDuplicatedImportsoption set totrue. -
Starting from
v1.3.1this plugin is fully compatible withvite^6.0.0. -
Starting from
v1.3.0this plugin will not remove comments starting with///, unlesscompressoption is set totrue. -
Starting from
v1.2.0this plugin is fully compatible withvite^5.0.0. -
Starting from
v1.1.1this plugin has a complete TypeScript support. Check "Usage" > "With TypeScript" for more info. -
Starting from
v1.0.0this plugin is fully compatible withvite^4.0.0. -
Starting from
v0.5.4this plugin supports customcompresscallback function to optimize output shader length after all shader chunks have been included. -
Starting from
v0.5.0this plugin supports shaders hot reloading whenwatchoption is set totrue. -
Starting from
v0.4.0this plugin supports chunk imports from project root androotoption to override the default root directory. -
Starting from
v0.3.0this plugin is pure ESM. Consider updating your project to an ESM module by adding"type": "module"in yourpackage.jsonor consult this issue for possible workarounds. -
Starting from
v0.2.2this plugin supportscompressoption to optimize output shader length. You might consider setting this totruein production environment. -
Starting from
v0.2.0this plugin uses a config object as a single argument toglslfunction and allows to disable import warnings with thewarnDuplicatedImportsparam set tofalse. -
Starting from
v0.1.5this plugin warns about duplicated chunks imports and throws an error when a recursive loop occurres. -
Starting from
v0.1.2this plugin generates sourcemaps using vite esbuild when thesourcemapoption is set totrue. -
Starting from
v0.1.0this plugin supports WebGPU shaders with.wgslextension. -
Starting from
v0.0.9this plugin supports optional semicolons at the end of#includestatements. -
Starting from
v0.0.7this plugin supports optional single and double quotation marks around file names.
Note:
When used with three.js r0.99 and higher, it's possible to include shader chunks as specified in the documentation, those imports will be ignored by vite-plugin-glsl since they are handled internally by the library itself:
#include <common>
vec3 randVec3 (const in vec2 uv) {
return vec3(
rand(uv * 0.1), rand(uv * 2.5), rand(uv)
);
}