Skip to main content
HLS Downloader uses pnpm workspaces and Vite for fast, efficient builds. This guide covers all build commands, variants, and workflows.

Quick reference

Full build

pnpm run build
Builds all packages and creates extension archives

Development mode

pnpm dev
Watches for changes and rebuilds automatically

Clean artifacts

pnpm run clean
Removes all build outputs

Component preview

pnpm storybook
Opens Storybook on port 6006

Build commands

Production build

Build all packages and create extension archives:
pnpm run build
This command:
  1. Cleans previous build artifacts (pnpm run clean)
  2. Copies assets to dist/ (pnpm run copy-assets)
  3. Builds packages in order (pnpm run build:packages):
    • core → TypeScript compilation to lib/
    • design-system → Vite bundle to dist/
    • background and popup in parallel → Vite bundles to dist/
  4. Creates archives (pnpm run build:zip):
    • extension-chrome.zip for Chromium browsers
    • extension-firefox.xpi for Firefox
After building, you’ll have:
hls-downloader/
├── dist/                      # Extension files
│   ├── manifest.json          # Generated manifest
│   ├── background.js          # Background script bundle
│   ├── popup.html             # Popup HTML
│   ├── popup.js               # Popup bundle
│   ├── assets/                # Copied assets
│   │   ├── icons/
│   │   └── ffmpeg/
│   └── ...                    # Other generated files
├── extension-chrome.zip       # Chromium installation package
└── extension-firefox.xpi      # Firefox installation package
Never commit build artifacts. The following are listed in .gitignore:
  • dist/
  • dist-mv2/
  • dist-mv3/
  • extension-*.zip
  • extension-*.xpi

Individual package builds

Build specific packages:
pnpm run build:core
Packages must build in dependency order. The build:packages script handles this automatically.

Clean build artifacts

Remove all generated files:
pnpm run clean
This removes:
  • dist/ directory
  • dist-mv2/ and dist-mv3/ directories (variant builds)
  • All extension-*.zip and extension-*.xpi files

Manifest variants

HLS Downloader supports both Manifest V2 and V3 to accommodate different browser requirements.

Default build (MV2)

The standard build targets Manifest V2:
pnpm run build
Manifest V2 is used for:
  • Firefox (full MV3 support pending)
  • Legacy Chromium workflows
  • Browsers that support background pages

MV3 build

Build for modern Chromium browsers:
MV_TARGET=mv3 pnpm run build
This generates:
  • manifest.json with version 3 schema
  • Service worker background script
  • Offscreen document for FFmpeg
Manifest V3 is required for:
  • Google Chrome (MV2 deprecated)
  • Microsoft Edge
  • Brave, Arc, Opera, and other Chromium browsers

Variant build scripts

Build specific variants with pre-configured names:
pnpm run build:mv2
The build:all command creates:
  • dist/mv2/ → MV2 extension files
  • dist/mv3/ → MV3 extension files
  • extension-mv2-chrome.zip
  • extension-mv2-firefox.xpi
  • extension-mv3-chrome.zip
The build:all script:
  1. Runs pnpm run clean
  2. Executes pnpm run build:mv2 → builds to dist/mv2/
  3. Executes pnpm run build:mv3 → builds to dist/mv3/
  4. Creates separate archives with mv2 and mv3 in filenames
Each variant is built from scratch to avoid file conflicts.

Blocklist variants

For distribution outside official stores, you can build without the domain blocklist:
pnpm run build:mv2:no-blocklist
Non-blocklist builds are named “experimental unstable nightly beta alpha hls-downloader” and are intended for personal use only. Do not redistribute them on official browser stores.
Official store releases include a domain blocklist that:
  • Respects copyright holder opt-out requests
  • Complies with distribution platform policies
  • Honors content owner preferences
Independent builds without the blocklist allow unrestricted operation for advanced users who prefer complete local control.

Development workflows

Watch mode

Automatic rebuild on file changes:
pnpm dev
This runs all package builds in watch mode:
  • core → TypeScript watch compilation
  • design-system → Vite watch
  • background → Vite watch
  • popup → Vite watch
By default, pnpm dev builds for MV3. The output goes to dist/mv3/.
The dev script uses npm-run-all to run parallel tasks:
{
  "dev": "DIST_DIR=dist/mv3 MV_TARGET=mv3 run-p dev:*"
}
Each dev:* script watches its package:
  • dev:coretsc -w
  • dev:design-systemvite build -w
  • dev:backgroundvite build -w
  • dev:popupvite build -w
1

Start watch mode

pnpm dev
2

Load extension in browser

Chrome/Edge/Brave/Arc:
  1. Open chrome://extensions/ (or equivalent)
  2. Enable “Developer mode”
  3. Click “Load unpacked”
  4. Select dist/mv3/ directory
Firefox:
  1. Open about:debugging#/runtime/this-firefox
  2. Click “Load Temporary Add-on”
  3. Select any file in dist/ directory
3

Make changes

Edit files in src/. Changes are automatically rebuilt.
4

Reload extension

Click the reload button on the extension card in the browser’s extensions page.
Some changes (like manifest updates) require a full reload. Others (like popup UI changes) may only need a popup refresh.

Component development

Develop UI components in isolation with Storybook:
pnpm storybook
Storybook runs on http://localhost:6006 and hot-reloads on changes.
Create a .stories.tsx file next to your component:
// src/popup/src/components/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'Components/Button',
  component: Button,
};

export default meta;
type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: {
    variant: 'primary',
    children: 'Click me',
  },
};
The story appears automatically in Storybook.
Use Storybook to:
  • Develop components without running the full extension
  • Test different props and states
  • Document component APIs
  • Catch visual regressions

Build troubleshooting

Enable Corepack and install the pinned pnpm version:
corepack enable
corepack prepare pnpm@10.11.0 --activate
Verify installation:
pnpm --version  # should output 10.11.0
The core package may not be built. Run:
pnpm run build:core
Or rebuild everything:
pnpm run clean && pnpm run build
The zip command is not found. Install it:macOS: Pre-installed, or use brew install zip
Linux: sudo apt install zip or equivalent
Windows: Install via Git for Windows or use WSL
Try restarting the dev server:
# Stop current process (Ctrl+C)
pnpm run clean
pnpm dev
If issues persist, check that you’re editing source files in src/, not generated files in dist/ or lib/.
Ensure you’re loading the correct directory:
  • MV3 builds: Load dist/mv3/ or dist/
  • MV2 builds: Load dist/mv2/ or dist/
Check that manifest.json exists in the directory you’re loading.For Firefox, try loading the .xpi file instead of the directory.

CI/CD considerations

When setting up continuous integration:
  1. Use pnpm install --frozen-lockfile to ensure reproducible builds
  2. Run pnpm test before building
  3. Use pnpm run build:all-variants to create all distribution packages
  4. Upload extension-*.zip and extension-*.xpi as artifacts
Example GitHub Actions workflow snippet:
- name: Setup Node.js
  uses: actions/setup-node@v3
  with:
    node-version: '20'

- name: Enable Corepack
  run: corepack enable

- name: Install dependencies
  run: pnpm install --frozen-lockfile

- name: Run tests
  run: pnpm test

- name: Build all variants
  run: pnpm run build:all-variants

- name: Upload artifacts
  uses: actions/upload-artifact@v3
  with:
    name: extension-packages
    path: |
      extension-*.zip
      extension-*.xpi

Next steps

Testing

Run tests and generate coverage reports

Contributing

Submit changes following project guidelines

Build docs developers (and LLMs) love