Configuration

The configuration file can be one of these files

  • jampack.config.js (in ESM or CJS format)
  • jampack.config.mjs
  • jampack.config.cjs
  • config/jampack.config.js (in ESM or CJS format)
  • config/jampack.config.mjs
  • config/jampack.config.cjs

Or in a top-level jampack property in your package.json.

Example

// jampack.config.js

export default {
  image: {
    compress: false,
  },
};

Options

Available in config-types.js.

import type { UrlTransformer } from 'unpic';

export type WebpOptions = {
  effort: number;
  mode: 'lossless' | 'lossly';
  quality: number;
};

export type Options = {
  general: {
    browserslist: string; // browserslist query string
  };
  html: {
    add_css_reset_as: 'inline' | 'off'; // 'inline': adds "<style>:where(img){height:auto}</style>" on top of the <head>
    sort_attributes: boolean;
  };
  js: {
    compressor: 'esbuild' | 'swc'; // swc have smaller result but can break code (seen with SvelteKit code)
  };
  css: {
    inline_critical_css: boolean;
    browserslist?: string; // If present, overrides general.browserslist just for CSS
  };
  image: {
    embed_size: number; // Embed above the fold images if size < embed_size
    srcset_min_width: number; // Minimum width of generate image in srcset
    srcset_max_width: number; // Maximum width of generate image in srcset
    srcset_step: number; // Number of pixels between sizes in srcset
    max_width: number; // Maximum width of original images - if bigger => resized output
    src_include: RegExp;
    src_exclude: RegExp | null;
    external: {
      process:
        | 'off' // Default
        | 'download' // Experimental
        | ((attrib_src: string) => Promise<string>); // Experimental
      src_include: RegExp;
      src_exclude: RegExp | null;
    };
    cdn: {
      process:
        | 'off' //default
        | 'optimize';
      src_include: RegExp | null;
      src_exclude: RegExp | null;
      transformer?: UrlTransformer; // Custom 'unpic' cdn url transformer, if not present it will be determined by 'unpic' based on original url
    };
    compress: boolean;
    jpeg: {
      options: {
        quality: number;
        mozjpeg: boolean;
      };
    };
    png: {
      options: {
        compressionLevel: number;
      };
    };
    webp: {
      options_lossless: WebpOptions;
      options_lossly: WebpOptions;
    };
    svg: {
      optimization: boolean;
      add_width_and_height: boolean;
    };
  };
  iframe: {
    lazyload: {
      when: // Default: 'below-the-fold'
      | 'never' // All iframes are loaded eagerly
        | 'below-the-fold' // Iframe are lazy loaded only if they are below the fold
        | 'always'; // Not recommended, but if you want to lazy load all iframes
      how: // Default: 'native'
      | 'native' // Using `loading="lazy" attribue on iframe tag
        | 'js'; // Using IntersectionObserver. Requires ~1Ko of JS but is more precise than native lazyload
    };
  };
  video: {
    autoplay_lazyload: {
      // Only for videos with autoplay
      when: // Default: 'below-the-fold'
      | 'never' // All video are loaded eagerly
        | 'below-the-fold' // videos are lazy loaded only if they are below the fold
        | 'always'; // Not recommended
      how: 'js'; // Using IntersectionObserver. Requires ~1Ko of JS
    };
  };
  misc: {
    prefetch_links: 'in-viewport' | 'off';
  };
};

Default values

Available in config-default.js.

import { Options } from './config-types.js';

const default_options: Options = {
  general: {
    browserslist: 'defaults', // defaults = '> 0.5%, last 2 versions, Firefox ESR, not dead'
  },
  html: {
    add_css_reset_as: 'off',
    sort_attributes: false,
  },
  css: {
    inline_critical_css: false,
  },
  js: {
    compressor: 'esbuild',
  },
  image: {
    embed_size: 1500,
    srcset_min_width: 390 * 2, // HiDPI phone
    srcset_max_width: 1920 * 2, // 4K
    srcset_step: 300,
    max_width: 99999,
    src_include: /^.*$/,
    src_exclude: /^\/vercel\/image\?/, // Ignore /vervel/image? URLs because not local and most likely already optimized,
    external: {
      process: 'off',
      src_include: /^.*$/,
      src_exclude: null,
    },
    cdn: {
      process: 'off',
      src_include: null,
      src_exclude: null,
    },
    compress: true,
    jpeg: {
      options: {
        quality: 75,
        mozjpeg: true,
      },
    },
    png: {
      options: {
        compressionLevel: 9,
      },
    },
    webp: {
      options_lossless: {
        effort: 4,
        quality: 77,
        mode: 'lossless',
      },
      options_lossly: {
        effort: 4,
        quality: 77,
        mode: 'lossly',
      },
    },
    svg: {
      optimization: true,
      add_width_and_height: false,
    },
  },
  iframe: {
    lazyload: {
      when: 'below-the-fold',
      how: 'native',
    },
  },
  video: {
    autoplay_lazyload: {
      when: 'below-the-fold',
      how: 'js',
    },
  },
  misc: {
    prefetch_links: 'off',
  },
};

export default default_options;

Technical notes

Jampack is using Nate Moore’s proload package to load configuration.