Skip to main content

Installation (webpack, Rspack, Rsbuild)

since 1.3.0

@coderline/alphatab-webpack is one plugin for webpack 5 (5.90 or later), Rspack 1.7 and 2, and Rsbuild, which runs on Rspack.

npm install @coderline/alphatab
npm install --save-dev @coderline/alphatab-webpack

Register the plugin in webpack.config.js:

import path from 'node:path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import { AlphaTabWebPackPlugin } from '@coderline/alphatab-webpack';

export default {
entry: './src/index.js',
output: {
path: path.resolve(import.meta.dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' }),
new AlphaTabWebPackPlugin()
]
};

Then use alphaTab with the normal import:

import * as alphaTab from '@coderline/alphatab';

const element = document.getElementById('alphaTab');
const api = new alphaTab.AlphaTabApi(element, {
core: {
file: '/song.gp'
},
player: {
enablePlayer: true,
soundFont: '/soundfont/sonivox.sf2'
}
});

The font is found without a setting here, because webpack writes the scripts to the root of the output, next to the font/ folder the plugin copies. Sample: bundler-webpack-5.

What the plugin doesโ€‹

  • Bundles alphaTab's Web Worker (new Worker(new URL(...))) and Audio Worklet (alphaTabWorklet.addModule(new URL(...))) as entries. The worker syntax applies to alphaTab's modules only, also when your project turns worker parsing off (Angular does).
  • Moves alphaTab's core into one alphaTabCore split chunk that the page, the workers and the worklet load. An Audio Worklet cannot load chunks on its own, so alphaTab adds the chunks the plugin lists to the worklet before its entry.
  • Copies the Bravura font to font/ and the SoundFonts to soundfont/ in the output, and serves them from the dev server.

See How alphaTab loads its code for the structure the plugin reproduces.

Optimization settingsโ€‹

Sharing the core needs two optimization settings, which the plugin configures:

  • optimization.usedExports is set to 'global' in production builds unless you set it. With true, used exports are optimized per runtime and the core is bundled once for the page and once more for the workers; the plugin warns in that case.
  • The splitChunks cache group alphaTabCore moves the core into its own chunk. Your other cache groups and the splitChunks defaults stay as configured.

Because the core is a chunk of the entrypoint, the HTML must load every file of the entrypoint. HtmlWebpackPlugin, HtmlRspackPlugin, Rsbuild and Next.js do. If you write the <script> tags yourself, include every file webpack lists for the entrypoint in its stats or manifest.

Opt out of the shared chunk if your host only injects chunks it knows by name, like Angular's webpack builder:

import { AlphaTabWebPackPlugin } from '@coderline/alphatab-webpack';

export default {
plugins: [new AlphaTabWebPackPlugin()],
optimization: {
splitChunks: {
cacheGroups: {
alphaTabCore: false
}
}
}
};

The page then contains one copy of the core and the workers and worklet share another. optimization.splitChunks: false has the same effect.

alphaTab's core is about 1.2 MiB minified, above webpack's default performance budget of 244 KiB. Raise performance.maxEntrypointSize and performance.maxAssetSize to about 1.5 MiB to silence the warning, and limit performance.assetFilter to JavaScript files; the font and the SoundFonts load on demand.

Rspackโ€‹

Rspack runs the same plugin. Register it next to HtmlRspackPlugin in rspack.config.mjs:

import { defineConfig } from '@rspack/cli';
import { rspack } from '@rspack/core';
import { AlphaTabWebPackPlugin } from '@coderline/alphatab-webpack';

export default defineConfig({
entry: { main: './src/index.js' },
plugins: [
new rspack.HtmlRspackPlugin({ template: './index.html' }),
new AlphaTabWebPackPlugin()
]
});

The plugin declares webpack and @rspack/core as optional peer dependencies, so an Rspack project does not need webpack installed. If npm install reports an ERESOLVE conflict for @rspack/core, the installed plugin predates Rspack 2 support; update it.

Samples: bundler-rspack-1, bundler-rspack-2.

Rsbuildโ€‹

Rsbuild exposes the Rspack configuration through tools.rspack. Append the plugin there in rsbuild.config.ts:

import { defineConfig } from '@rsbuild/core';
import { AlphaTabWebPackPlugin } from '@coderline/alphatab-webpack';

export default defineConfig({
html: { template: './index.html' },
tools: {
rspack: (_config, { appendPlugins }) => {
appendPlugins(new AlphaTabWebPackPlugin());
}
}
});

Rsbuild writes its scripts to static/js/, while the plugin copies the font to font/. Set core.fontDirectory, or the font requests go to /static/js/font/ and nothing renders:

import * as alphaTab from '@coderline/alphatab';

const element = document.getElementById('alphaTab')!;
const api = new alphaTab.AlphaTabApi(element, {
core: {
file: '/song.gp',
fontDirectory: '/font/'
},
player: {
enablePlayer: true,
soundFont: '/soundfont/sonivox.sf2'
}
});

The same configuration works with Rsbuild 1.7 and 2. Sample: bundler-rsbuild-2.

Plugin optionsโ€‹

Pass options to the plugin constructor. All of them are optional.

alphaTabSourceDirโ€‹

The folder the plugin copies the font and the SoundFonts from. Defaults to the dist folder of the installed @coderline/alphatab.

import path from 'node:path';
import { AlphaTabWebPackPlugin } from '@coderline/alphatab-webpack';

new AlphaTabWebPackPlugin({
alphaTabSourceDir: path.resolve('../../node_modules/@coderline/alphatab/dist')
});

assetOutputDirโ€‹

Where the plugin copies font/ and soundfont/ to. Defaults to output.path. Set it to false to skip the copy.

import { AlphaTabWebPackPlugin } from '@coderline/alphatab-webpack';

// Next.js serves static files from public/ only, also in development.
new AlphaTabWebPackPlugin({
assetOutputDir: 'public/alphatab'
});

audioWorklets and webWorkersโ€‹

Both default to true. Set one to false if another plugin bundles alphaTab's worklet or worker.

import { AlphaTabWebPackPlugin } from '@coderline/alphatab-webpack';

new AlphaTabWebPackPlugin({
audioWorklets: false,
webWorkers: false
});
warning

Without a worklet, set player.outputMode to the ScriptProcessor output. Without a worker, alphaTab renders and synthesizes on the main thread; set core.useWorkers to false.

Known limitationsโ€‹

  • webpack's own Audio Worklet support (webpack 5.112, module.parser.javascript.worklet) requests chunks that do not exist when file names contain [contenthash]. Do not combine it with alphaTab; the plugin bundles the worklet.
  • next dev turns chunk splitting off, so the page, the worker and the worklet each contain a copy of the core during development. Production builds load one. See React and Next.js.

Frameworks on webpackโ€‹