npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vite-plugin-json-partial-merge

v0.4.0

Published

Vite plugin for JSON partial/merge system - ideal for Shopify theme development

Readme

vite-plugin-json-partial-merge

A Vite plugin for JSON partial/merge system - ideal for Shopify theme development. This plugin allows you to create reusable JSON configuration blocks and merge multiple JSON files during the build process.

npm version Test Coverage License: MIT

Features

  • Partial Imports: Import reusable JSON configuration blocks
  • ID Transformations: Prepend prefixes or replace IDs to avoid conflicts
  • Selective Inclusion: Exclude specific settings using the except option (filters by both id and type fields)
  • Add Settings: Append settings to Shopify blocks with support for nested partials
  • Directory Merging: Combine multiple JSON files into a single array
  • Nested Partials: Partials can reference other partials (up to 5 levels deep)
  • Type-Safe: Full TypeScript support with strict type checking
  • Well-Tested: 92.79% code coverage with comprehensive test suite

Installation

npm install -D vite-plugin-json-partial-merge
pnpm add -D vite-plugin-json-partial-merge
yarn add -D vite-plugin-json-partial-merge

Quick Start

1. Configure Vite

// vite.config.ts
import { defineConfig } from 'vite';
import jsonPartialMerge from 'vite-plugin-json-partial-merge';

export default defineConfig({
  plugins: [
    jsonPartialMerge({
      partialsDir: 'src/partials', // Default: 'src/partials'
    }),
  ],
});

2. Create a Partial

Create a reusable JSON partial in src/partials/buttonSettings.json:

[
  {
    "type": "text",
    "id": "button_text",
    "label": "Button Text",
    "default": "Click me"
  },
  {
    "type": "url",
    "id": "button_url",
    "label": "Button URL",
    "default": "#"
  }
]

3. Use the Partial

Reference the partial in your JSON file:

{
  "name": "Hero Section",
  "settings": [
    {
      "type": "text",
      "id": "title",
      "label": "Title"
    },
    {
      "type": "partial",
      "with": "buttonSettings"
    }
  ]
}

4. Build

During the Vite build, the partial will be expanded inline:

{
  "name": "Hero Section",
  "settings": [
    {
      "type": "text",
      "id": "title",
      "label": "Title"
    },
    {
      "type": "text",
      "id": "button_text",
      "label": "Button Text",
      "default": "Click me"
    },
    {
      "type": "url",
      "id": "button_url",
      "label": "Button URL",
      "default": "#"
    }
  ]
}

Plugin Options

partialsDir

Directory containing partial JSON files.

  • Type: string
  • Default: 'src/partials'
jsonPartialMerge({
  partialsDir: 'config/partials',
});

include

File patterns to include for processing.

  • Type: string | string[]
  • Default: '**/*.json' (all JSON files)
jsonPartialMerge({
  include: ['src/**/*.json', 'config/**/*.json'],
});

exclude

File patterns to exclude from processing.

  • Type: string | string[]
  • Default: undefined
jsonPartialMerge({
  exclude: ['node_modules/**', 'dist/**'],
});

Directive Syntax

Partial Import

Import a reusable partial:

{
  "type": "partial",
  "with": "partialName"
}

Partial with ID Prefix

Add a prefix to all IDs to avoid conflicts:

{
  "type": "partial",
  "with": "buttonSettings",
  "prepend": "hero"
}

Result: button_texthero_button_text

Partial with ID Replacement

Map specific IDs to new values:

{
  "type": "partial",
  "with": "buttonSettings",
  "replace": {
    "button_text": "cta_text",
    "button_url": "cta_url"
  }
}

Result: button_textcta_text, button_urlcta_url

Partial with Exclusions

Omit specific settings from the partial by ID or type:

{
  "type": "partial",
  "with": "sectionSettings",
  "except": ["background_image", "anchor_id", "header", "paragraph"]
}

Note: The except array can filter objects by either their id field or type field.

Add Settings to Blocks

Append settings to each block's settings array (for Shopify blocks):

{
  "type": "partial",
  "with": "shopifyBlocks",
  "addSettings": [
    { "type": "checkbox", "id": "visible", "label": "Visible", "default": true },
    { "type": "text", "id": "custom_class", "label": "Custom CSS Class" }
  ]
}

How it works: If the loaded partial is an array of objects with a settings property, the addSettings array will be appended to each object's settings.

Use case: Add common settings (like visibility toggles or CSS classes) to multiple block types at once.

Nested partials: You can use partials inside addSettings:

{
  "type": "partial",
  "with": "shopifyBlocks",
  "addSettings": [
    { "type": "partial", "with": "commonBlockSettings" }
  ]
}

Note: The addSettings feature works with both partial and merge directives.

Combining Options

You can use multiple options together:

{
  "type": "partial",
  "with": "sectionSettings",
  "prepend": "hero",
  "except": ["hero_background_image"],
  "replace": {
    "padding_top": "custom_padding_top"
  }
}

Processing order: replaceprependfilteraddSettings

Directory Merge

Merge multiple JSON files from a directory:

{
  "type": "merge",
  "directory": ".",
  "except": ["settings_data.json", "settings_schema.json"]
}

Use case: Consolidate modular configuration files into a single array (e.g., Shopify theme settings).

Use Cases

Shopify Theme Development

This plugin was designed for Shopify theme development, where you often need to:

  1. Share common settings across multiple sections
  2. Build a consolidated settings_schema.json from modular config files
  3. Avoid ID conflicts when reusing settings

Example: Building Theme Settings

Directory structure:

src/config/
  settings_schema.json → {"type": "merge", "directory": ".", "except": [...]}
  0_theme_info.json    → {"name": "theme_info", ...}
  1_colors.json        → {"name": "Colors", "settings": [...]}
  2_buttons.json       → {"name": "Buttons", "settings": [...]}
  settings_data.json   → (excluded from merge)

Build output (dist/config/settings_schema.json):

[
  {"name": "theme_info", ...},
  {"name": "Colors", "settings": [...]},
  {"name": "Buttons", "settings": [...]}
]

Best Practices

  1. Keep partials focused: One concern per partial (e.g., visibility, buttons, colors)
  2. Use descriptive names: buttonSettings instead of buttons
  3. Avoid deep nesting: Max 2-3 levels of partial-in-partial
  4. Minimize replace: Prefer prepend or inline settings for clarity
  5. Test builds: Ensure partials expand correctly with npm run build
  6. Alphabetical ordering: Name config files with numeric prefixes (0_, 1_, 2_) to control merge order

Error Handling

Partial must have "with"

Error: Partials must have a "with" property

Fix: Ensure the "with" property is present and points to a valid partial name.

{
  "type": "partial",
  "with": "partialName"  // ← Required
}

Partial must be array

Error: All partials must be arrays!

Fix: Ensure partial files export an array [...], not an object {...}.

// ✓ Correct
[
  {"type": "text", "id": "heading"}
]

// ✗ Incorrect
{
  "setting": {"type": "text", "id": "heading"}
}

Could not load partial

Error: Could not load partial: partialName.json not found

Fix: Check that src/partials/partialName.json exists and has valid JSON syntax.

Circular reference

Error: Circular partial reference detected: partialName

Fix: Check for circular partial references (A includes B, B includes A).

Could not read directory

Error: Could not read directory: directoryPath

Fix: Ensure the directory path in merge directive is correct and accessible.

TypeScript

The plugin is written in TypeScript and provides full type definitions out of the box.

import jsonPartialMerge, { 
  type PluginOptions,
  type PartialOptions,
  type MergeOptions,
} from 'vite-plugin-json-partial-merge';

const options: PluginOptions = {
  partialsDir: 'src/partials',
  include: '**/*.json',
};

API Reference

jsonPartialMerge(options?: PluginOptions): Plugin

Creates a Vite plugin instance.

Parameters:

  • options (optional): Plugin configuration

Returns: Vite plugin object

Types

PluginOptions

interface PluginOptions {
  partialsDir?: string;           // Default: 'src/partials'
  include?: string | string[];     // Default: '**/*.json'
  exclude?: string | string[];     // Default: undefined
}

PartialOptions

interface PartialOptions {
  type: 'partial';
  with: string;                   // Partial file name (without .json)
  replace?: Record<string, string>; // ID remapping
  prepend?: string;               // ID prefix
  except?: string[];              // IDs or types to exclude
  addSettings?: JsonValue[];      // Settings to add to each block's settings array
}

MergeOptions

interface MergeOptions {
  type: 'merge';
  directory: string;              // Relative path to directory
  except?: string[];              // Filenames to exclude
  addSettings?: JsonValue[];      // Settings to add to each block's settings array
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT © Evan Ford

Related