Read this on Medium. The code in this repo is based on the course Create 3D Graphics in JavaScript using WebGL on Egghead.io.
I start learning about WebGL recently from WebGL Tutorials on the internet. The editor I use is VSCode which an is awesome editor for frontend development, but still I found some issues and I think I should take a note.
Most tutorials I have seen start like this
- Create a
<canvas>
element inindex.html
<canvas id="canvas"></canvas>
- In
main.js
, use the canvas element as a WebGL rendering context
const canvas = document.getElementById('canvas'); // or document.querySelector('#canvas')
const gl = canvas.getContext('webgl');
Then use gl
object for .. basically almost everything.
// methods
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.attachShader();
gl.vertexAttrib1f();
gl.getAttribLocation();
// constants
gl.COLOR_BUFFER_BIT;
gl.VERTEX_SHADER;
gl.COMPILE_STATUS;
The problem I had was that VSCode was unable to display code IntelliSense
for gl
object because VSCode finds it has the type of any
-
VSCode does not know what type of the object is, thus it cannot help with its awesome IntelliSense, which is unfortunate.
First I thought it would be fine. Maybe I can get along with this.
In fact, the gl
object has type of WebGLRenderingContext
. And if we check the specs of this interface,
there are over 200 properties (constants) and methods in this object type.
There is 0% chance that I could remember them all, and there are more than 87.525% chance that I will make a typo in the code when typing those property and method names manually by hand.
The actual problem is that VSCode cannot guess the type of returned canvas
element.
By using document.getElementById()
, we got HTMLElement
type returned.
By using document.querySelector()
, we got Element
type returned.
I could think of 2 workarounds.
Instead of pre-create <canvas>
element in the HTML, we can alo create it in JavaScript code and put it in the page via appendChild()
.
const canvas = document.createElement('canvas');
document.querySelector('body').appendChild(canvas);
const gl = canvas.getContext('webgl');
Creating a canvas with document.createElement('canvas')
,
VSCode knows that it has type of HTMLCanvasElement
which gives a better sense with calling .getContext()
on it.
Passing in webgl
as a parameter, VSCode knows the return type of the method that should be WebGLRenderingContext
type.
(built-in lib.dom.d.ts
type definitions file in VSCode)
Now we can get code autocompletion our gl
object working.
If the project is using TypeScript, we can use Type Assertion to tell VSCode about the canvas object type.
const canvas = <HTMLCanvasElement>document.getElementById('canvas');
This tells the TypeScript compiler to treat canvas
object as HTMLCanvasElement
type, instead of the default HTMLElement
type. (It is not the same with type casting though.)
When VSCode knows the type, it shows the code IntelliSense like so.
I started the learning project with vanilla JavaScript because I wanted to avoid setting up build tools if I don't need them. With TypeScript, this is unavoidable. At least we have to set up some build steps to transpile TypeScript to JavaScript.
Here is how I set up webpack (with my very limited knowledge about webpack) to use TypeScript.
- Install TypeScript
$ npm install --save-dev typescript
- Install webpack
$ npm install --save-dev webpack webpack-dev-server
- Install TypeScript loader with sourcemaps support
$ npm install --save-dev awesome-typescript-loader source-map-loader
or you can install everything above in a single command.
- Create
webpack.config.js
configuration file for webpack.
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.ts',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
devServer: {
contentBase: './dist'
},
resolve: {
extensions: ['.ts', '.tsx']
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'awesome-typescript-loader'
}
]
}
};
- Start the webpack dev server
$ npx webpack-dev-server
And now I can use TypeScript in my learning project.