The above snippet will allow webpack to read the following file extensions and pack them into your bundled file:
jpg/jpeg
png
gif
svg
mp3
If you wish to include more extensions, simply just add onto the test regex.
Referencing Packed Assets
First, in any file that you are referencing packed assets, you need to supply a type declaration file so TypeScript knows what to do with these asset extensions as modules. The engine provides this for you. This is a part of TypeScript preprocessing, so we use the triple slash directive as shown below.
This line must come before any other code on top of your TS file.
Then you can proceed to use the asset like so:
import * as background from "./resources/background.png";
...
var background: Asset = AssetFactory.getSingleton().build(AssetType.IMAGE, background);
// Everything else is works the same as before!
Code-Splitting
Now packing assets into your bundle file may make your file cumbersome. The problem with the examples shown above is, all your assets are packed into one giant bundled JS file. Which needs to be downloaded & parsed by the client. This includes all asset data that is also packed.
This means that before the game can even start, you need to wait until the game in entirely is downloaded and parsed/loaded into memory. You can quickly see how this is not very good.
So what's the solution? Code-splitting. With some additional configuration and some adaption to code, you can split out assets as appropriate from your core game files. Ideally you would want to load your game with just your minimal but core assets, and load the rest later, or on-demand, or however way suits you're specific needs. Let's see an example.
Webpack Config for Code-Splitting Support
First, we need to make a couple of changes to our webpack.config.js file.
Second, we need to add another declaration to give the TypeScript compiler information of a require.ensure method, that is provided. Just the the WebpackAssetSupport.d.ts reference we need to add a triple-slash directive at the top of the file. It doesn't matter the order of the triple-slash directives if you are using multiple of the,
Using require.ensure, webpack will automatically detect and split out code into independent packages, and will load them on-demand. This will enforce your usage to be asynchronous.
require.ensure(["./path/to/resources.ts"], (require) => {
var resources: AssetGroupDefinition = require("./path/to/resources.ts");
var assetGroup: AssetGroup = assetGroupLoader.loadFromMemory(resources);
assetGroup.load().then(() => {
//You can use your assets!
});
});
Note that require.ensure is not just limited to splitting out assets. It can be used for all sorts of code-splitting, which is why ensure accepts an array of module paths.
The resources.ts file
Note the usage of require above, and not the typical import/export module syntax. These are not actual TypeScript modules, and TypeScript offers a way to differentiate that by using a special export = syntax.
Here is the typical resources.ts boilerplate.
/// <reference path="./src/assets/WebpackAssetSupprt.d.ts" />
import {AssetType} from "./src/assets/AssetType";
import {AssetGroupDefinition} from "./src/assets/AssetGroupLoader";
// Import your packed assets here
var resources: AssetGroupDefinition = {
assets : [
]
};
export = resources;
This is a barebones resources.ts file that contains no assets, but could be used to create an AssetGroup (with no assets) Note the special use of export = resources and not export { resources }; or export default resources; But we still use import {Module} from "engine/modules"; because they are still actual typescript modules that we can use for both typings and logic.
Here is a full example:
/// <reference path="./src/assets/WebpackAssetSupprt.d.ts" />
import {AssetType} from "./src/assets/AssetType";
import {AssetGroupDefinition} from "./src/assets/AssetGroupLoader";
import * as background from "./background.png";
import * as character from "./character.png";
import * as bgMusic from "./bgMusic.mp3";
var resources: AssetGroupDefinition = {
assets : [
{
name : "background",
type : AssetType.IMAGE,
source : background
},
{
name : "character",
type : AssetType.IMAGE,
source : character
},
{
name : "bgMusic",
type : AssetType.AUDIO,
source : bgMusic
},
]
};
export = resources;
Overview
This pull request introduces the utilities required to use webpack url-loader to not only pack assets, but code-split them as well.
To pack assets in webpack, you must install the
url-loader
and add the following to your webpack config insidemodule.rules
:Then referencing your assets is as simple as:
For more details on how to use, read on!
Packing assets
The full config
The above snippet will allow webpack to read the following file extensions and pack them into your bundled file:
If you wish to include more extensions, simply just add onto the test regex.
Referencing Packed Assets
First, in any file that you are referencing packed assets, you need to supply a type declaration file so TypeScript knows what to do with these asset extensions as modules. The engine provides this for you. This is a part of TypeScript preprocessing, so we use the triple slash directive as shown below.
This line must come before any other code on top of your TS file.
Then you can proceed to use the asset like so:
Code-Splitting
Now packing assets into your bundle file may make your file cumbersome. The problem with the examples shown above is, all your assets are packed into one giant bundled JS file. Which needs to be downloaded & parsed by the client. This includes all asset data that is also packed.
This means that before the game can even start, you need to wait until the game in entirely is downloaded and parsed/loaded into memory. You can quickly see how this is not very good.
So what's the solution? Code-splitting. With some additional configuration and some adaption to code, you can split out assets as appropriate from your core game files. Ideally you would want to load your game with just your minimal but core assets, and load the rest later, or on-demand, or however way suits you're specific needs. Let's see an example.
Webpack Config for Code-Splitting Support
First, we need to make a couple of changes to our
webpack.config.js
file.Your config may look something like this:
We need to make
filename
dynamic, and provide achunkFilename
option.TypeScript Declaration for Code-Split Support
Second, we need to add another declaration to give the TypeScript compiler information of a
require.ensure
method, that is provided. Just the theWebpackAssetSupport.d.ts
reference we need to add a triple-slash directive at the top of the file. It doesn't matter the order of the triple-slash directives if you are using multiple of the,This provides the TypeScript
require.ensure
definition, which has a interface:Using
require.ensure
, webpack will automatically detect and split out code into independent packages, and will load them on-demand. This will enforce your usage to be asynchronous.Note that
require.ensure
is not just limited to splitting out assets. It can be used for all sorts of code-splitting, which is whyensure
accepts an array of module paths.The resources.ts file
Note the usage of
require
above, and not the typical import/export module syntax. These are not actual TypeScript modules, and TypeScript offers a way to differentiate that by using a specialexport =
syntax.Here is the typical
resources.ts
boilerplate.This is a barebones
resources.ts
file that contains no assets, but could be used to create an AssetGroup (with no assets) Note the special use ofexport = resources
and notexport { resources };
orexport default resources;
But we still useimport {Module} from "engine/modules";
because they are still actual typescript modules that we can use for both typings and logic.Here is a full example: