Installation (webpack, Rspack, Rsbuild)
@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
alphaTabCoresplit 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 tosoundfont/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.usedExportsis set to'global'in production builds unless you set it. Withtrue, 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
splitChunkscache groupalphaTabCoremoves the core into its own chunk. Your other cache groups and thesplitChunksdefaults 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
});
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 devturns 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โ
- Next.js with webpack: React and Next.js
- Angular with
@angular-builders/custom-webpack: Angular