Loading external tileset files using Webpack

Hey guys!

I wrote a small Webpack hack to automatically load Tilesets into Tiled maps, and I think this could be useful for some of you, so I decided to share it here.

const CopyWebpackPlugin = require('copy-webpack-plugin');
const { promises: fs } = require('fs');
const stageFiles = await fs.readdir(STAGES_PATH);
// get only the JSON files
const stageJsons = stageFiles
    .filter((stage) => stage.split('.')[1] === 'json');

const copyWebpackPluginPatterns = [];
stageJsons.forEach((stage) => {
    copyWebpackPluginPatterns.push({
        from: `${STAGES_PATH}/${stage}`,
        to: '../assets/stages',
        transform: (fileBuffer, elPath) => {
            const manifestString = fileBuffer.toString();
            const stageData = JSON.parse(manifestString);
            const newTilesets = stageData.tilesets.map((tileset) => {
                // firstgid is an important id reference for Tiled
                const { firstgid } = tileset;
                if (!tileset.source) {
                    // if there's no source, it means the Tileset
                    // is already embeded
                    return tileset;
                }

                // on my setup, stages are in root/stages/
                // and the tilesets are in root/tilesets/
                // so we need to remove "../tilesets/" from the path
                // and load it based on the root dir of the tilesets
                const filePath = tileset.source.replace('../tilesets/', '');
                // eslint-disable-next-line import/no-dynamic-require
                const tilesetData = require(`${TILESETS_PATH}/${filePath}`);
                if (!tilesetData) {
                    console.error('Could not find file', `${TILESETS_PATH}/${filePath}`);
                    return tileset;
                }

                return {
                    ...tilesetData,
                    firstgid,
                };
            });
            stageData.tilesets = newTilesets;

            return Buffer.from(JSON.stringify(stageData));
        },
    });
});

module.exports = {
    plugins: [
        new CopyWebpackPlugin({
            patterns: [
                ...copyWebpackPluginPatterns,
            ],
        }),
    ],
};

I wrote a detailed explanation about why and how this was done here: https://pablo.gg/en/blog/games/loading-external-tileset-file-on-phaser-js-using-webpack-skate-platformer-game-devlog-7/