Skip to content

The last MSFS instrument bundler you'll ever need.

License

Notifications You must be signed in to change notification settings

synapticsim/mach

Repository files navigation

Mach

Mach is an ultra-fast transpiler and bundler for use with MSFS (Microsoft Flight Simulator 2020) instruments. Unlike other bundling tools such as rollup or webpack, Mach has been built from the ground up with the sole purpose of serving the MSFS development community's needs.

Features

Mach currently supports bundling both JavaScript and TypeScript React instruments, along with any CSS or SCSS stylesheets and images that are included. Instruments built with the MSFS Avionics Framework are also supported, but require additional steps to ensure compatibility as described here.

Mach also allows you to create nested instruments, enabling you to bundle MSFS Avionics instruments separately and import them into your React instrument.

Usage

CLI

Options

  • -c, --config <filename> specify path to configuration file (default: ./mach.config.js)
  • -d, --work-in-config-dir use config directory as working directory
  • -b, --bundles <dirname> bundles output directory (default: ./bundles)
  • -e, --werror makes all warnings into errors
  • -f, --filter <regex> regex filter of included instrument names
  • -m, --minify minify bundle code
  • -s, --skip-simulator-package skips writing simulator package templates
  • -t, --output-metafile output build_meta.json file to bundles directory
  • -u, --output-sourcemaps append sourcemaps to the end of bundle files
  • -v, --verbose output additional build information

mach build [options]

The build command will simply go through each instrument defined in your configuration, then output the bundles and package source files to the configured directories.

mach watch [options]

The watch command will first build each instrument in the configuration, and then watch the source files for changes in order to re-bundle the instrument. If there was an error while bundling the instrument in the beginning, the watcher will not run.

JavaScript

async function machBuild(conf: MachConfig, filter?: RegExp)

This function has the same behavior as the mach build [options] CLI command.

async function machWatch(conf: MachConfig, filter?: RegExp)

This function has the same behavior as the mach watch [options] CLI command.

Configuration

Whether you supply the configuration with the mach.config.js file to the CLI or with a JavaScript object to the API, the structure is identical.

interface PackageSettings {
    /**
     * Specifies type of instrument.
     * - `React` instruments will be created with a `BaseInstrument` harness that exposes an `MSFS_REACT_MOUNT` element for mounting.
     * - `BaseInstrument` instruments must specify the `instrumentId` and `mountElementId` to match the instrument configuration.
     */
    type: string;
    /** Final template filename. Defaults to `template` */
    fileName?: string;
    /** Simulator packages to import in the HTML template. */
    imports?: string[];
}

interface ReactInstrumentPackageSettings extends PackageSettings {
    type: 'react';
    /** Optional parameter to specify template ID. Defaults to `Instrument.name`. */
    templateId?: string;
    /** Whether the instrument is interactive or not. Defaults to `true`. */
    isInteractive?: boolean;
}

interface BaseInstrumentPackageSettings extends PackageSettings {
    type: 'baseInstrument';
    /**
     * Required for `BaseInstrument` instruments.
     * This value must match the return value from the `BaseInstrument.templateID()` function.
     * */
    templateId: string;
    /**
     * Required for `BaseInstrument` instruments.
     * This value must match the ID in your call to `FSComponent.render()`..
     */
    mountElementId: string;
}

interface Instrument {
    /** Instrument name, used as directory name for bundles and packages. */
    name: string;
    /** Entrypoint filename for instrument. */
    index: string;

    /** When passed a configuration object, enables a simulator package export. */
    simulatorPackage?: ReactInstrumentPackageSettings | BaseInstrumentPackageSettings;

    /** Instruments to import as ESM modules. */
    modules?: Instrument[];
    /** (Required for instruments included as `modules`) Import name to resolve to the bundled module. */
    resolve?: string;

    /** esbuild plugins to include for only this instrument (<https://github.com/esbuild/community-plugins>) */
    plugins?: Plugin[];
}

interface MachConfig {
    /** Name of package, used for bundling simulator packages. */
    packageName: string;
    /** Path to directory containing `html_ui`. */
    packageDir: string;
    /** esbuild plugins to include for all instruments (<https://github.com/esbuild/community-plugins>) */
    plugins?: Plugin[];
    /** All instruments to be bundled by Mach. */
    instruments: Instrument[];
}

Example

const imageInline = require('esbuild-plugin-inline-image');

/** @type { import('@synaptic-simulations/mach').MachConfig } */
module.exports = {
    packageName: 'a22x',
    packageDir: 'PackageSources',
    plugins: [imageInline({ limit: -1 })],
    instruments: [
        {
            name: 'DisplayUnits',
            index: 'src/instruments/src/DisplayUnits/index.tsx',
            simulatorPackage: {
                type: 'react',
                imports: ['/JS/dataStorage.js'],
            },
            modules: [{
                name: 'PFD',
                resolve: '@instruments/PFD',
                index: 'src/instruments/src/PFD/index.tsx',
            }],
        },
        {
            name: 'CTP',
            index: 'src/instruments/src/CTP/index.tsx',
            simulatorPackage: {
                type: 'react',
                imports: ['/JS/dataStorage.js'],
            },
        },
        {
            name: 'ISI',
            index: 'src/instruments/src/ISI/index.tsx',
            simulatorPackage: {
                type: 'react',
                imports: ['/JS/dataStorage.js'],
            },
        },
    ],
};

MSFS Avionics Framework Compatibility

For compatibility with Mach, a modification must be made to the msfs-avionics source code:

# src/sdk/components/FSComponent.ts
- [357]   if (typeof type === 'function' && type.name === 'Fragment') {
+ [357]   if (typeof type === 'function' && type.name === Fragment.name) {

These changes are also available through the @synaptic-simulations/msfssdk npm package.