├── package.json ├── index.js └── README.md /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-glsl-loader", 3 | "version": "1.0.1", 4 | "description": "A webpack loader for glsl shaders - includes support for nested imports.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/grieve/webpack-glsl-loader.git" 12 | }, 13 | "keywords": [ 14 | "glsl", 15 | "shader", 16 | "webgl", 17 | "webpack", 18 | "loader", 19 | "import", 20 | "include" 21 | ], 22 | "author": "Ryan Grieve (http://ryangrieve.com)", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/grieve/webpack-glsl-loader/issues" 26 | }, 27 | "homepage": "https://github.com/grieve/webpack-glsl-loader#readme" 28 | } 29 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | 7 | function parse(loader, source, context, cb) { 8 | var imports = []; 9 | var importPattern = /#include "([.\/\w_-]+)"/gi; 10 | var match = importPattern.exec(source); 11 | 12 | while (match != null) { 13 | imports.push({ 14 | key: match[1], 15 | target: match[0], 16 | content: '' 17 | }); 18 | match = importPattern.exec(source); 19 | } 20 | 21 | processImports(loader, source, context, imports, cb); 22 | } 23 | 24 | function processImports(loader, source, context, imports, cb) { 25 | if (imports.length === 0) { 26 | return cb(null, source); 27 | } 28 | 29 | var imp = imports.pop(); 30 | 31 | loader.resolve(context, imp.key, function(err, resolved) { 32 | if (err) { 33 | return cb(err); 34 | } 35 | 36 | loader.addDependency(resolved); 37 | fs.readFile(resolved, 'utf-8', function(err, src) { 38 | if (err) { 39 | return cb(err); 40 | } 41 | 42 | parse(loader, src, path.dirname(resolved), function(err, bld) { 43 | if (err) { 44 | return cb(err); 45 | } 46 | 47 | source = source.replace(imp.target, bld); 48 | processImports(loader, source, context, imports, cb); 49 | }); 50 | }); 51 | }); 52 | } 53 | 54 | module.exports = function(source) { 55 | this.cacheable(); 56 | var cb = this.async(); 57 | parse(this, source, this.context, function(err, bld) { 58 | if (err) { 59 | return cb(err); 60 | } 61 | 62 | cb(null, 'module.exports = ' + JSON.stringify(bld)); 63 | }); 64 | }; 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Webpack loader for GLSL shaders 2 | 3 | A glsl shader loader for webpack, includes support for nested imports, 4 | allowing for smart code reuse among more complex shader implementations. 5 | The shader is returned as a string. 6 | 7 | ## Install 8 | 9 | ```shell 10 | npm install --save-dev webpack-glsl-loader 11 | ``` 12 | 13 | ## Usage 14 | 15 | ### With `require` 16 | 17 | > **N.B.** As noted in the [webpack documentation]( 18 | http://webpack.github.io/docs/using-loaders.html#loaders-in-require), you 19 | should avoid using this and use the configuration method in the next section. 20 | 21 | ```javascript 22 | require('webpack-glsl!./my-lovely-shader.glsl'); 23 | ``` 24 | 25 | ### In configuration 26 | 27 | ```javascript 28 | { 29 | module: { 30 | loaders: [ 31 | { 32 | test: /\.glsl$/, 33 | loader: 'webpack-glsl' 34 | } 35 | ] 36 | } 37 | } 38 | ``` 39 | 40 | and then 41 | 42 | ```javascript 43 | require('./my-lovely-shader.glsl'); 44 | ``` 45 | 46 | ### On command line 47 | 48 | You can also define the module extension bind on the command line if you are 49 | not using a configuration file (you probably should be though). 50 | 51 | ```shell 52 | webpack --module-bind 'glsl=webpack-glsl' 53 | ``` 54 | 55 | ## Imports 56 | 57 | This loader supports an import syntax to allow you to maximise your code reuse 58 | and keep those shaders 59 | [DRY](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself). This syntax is 60 | very similar to that of SASS. 61 | 62 | ### Example 63 | 64 | Example project structure: 65 | ``` 66 | src/ 67 | ---- js/ 68 | ---- ---- main.js 69 | ---- glsl/ 70 | ---- ---- includes/ 71 | ---- ---- ---- perlin-noise.glsl 72 | ---- ---- fragment.glsl 73 | ``` 74 | 75 | If I require my fragment shader inside `main.js`: 76 | 77 | ```javascript 78 | var shader = require('../glsl/fragment.glsl'); 79 | ``` 80 | 81 | I can have that shader include other `.glsl` files inline, like so: 82 | 83 | ```sass 84 | #include "./includes/perlin-noise.glsl"; 85 | ``` 86 | 87 | > **N.B.** all imports within `.glsl` files exclude the file extension and 88 | are relative to the file doing the importing. 89 | 90 | Imported files are parsed for `#include` statements as well, so you can nest 91 | imports as deep as you'd like (although, you should probably rethink your 92 | shader if you require any more than 2 levels). 93 | 94 | Imported files are inserted directly into the source file in place of the 95 | `#include` statement and no special handling or error checking is provided. So, 96 | if you get syntax errors, please first check that shader works as one 97 | contiguous file before raising an issue. 98 | 99 | ## TODO 100 | 101 | + Deduplicate imports, to prevent code clobbering and conflicts at runtime 102 | --------------------------------------------------------------------------------