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

@smartimpact-it/shopify-disable-features

v0.3.0

Published

Disabled-features engine, analyzer, config helpers, and schema tools for Shopify themes.

Downloads

869

Readme

@smartimpact-it/shopify-disable-features

Shared disabled-features engine, unused-features analyzer, config helpers, derived-state helpers, schema generator, and webpack plugins for Shopify themes.

Installation

Install from the public npm registry:

npm install @smartimpact-it/shopify-disable-features

Consumer usage

Example in a theme repo:

{
  "dependencies": {
    "@smartimpact-it/shopify-disable-features": "^0.1.0"
  }
}

Example type usage in theme-disabled-features.mts:

import type { ThemeSchema } from "./available-schema-fields";
import type {
  FeatureSetup,
  FeatureGroups,
  AlwaysEnabledFeatures,
} from "@smartimpact-it/shopify-disable-features";

export const featureGroups = {} as const satisfies FeatureGroups<ThemeSchema>;
export type FeatureGroupNames = keyof typeof featureGroups;

export const featureSetup: FeatureSetup<ThemeSchema, FeatureGroupNames> = {};
export const alwaysEnabledFeatures: AlwaysEnabledFeatures<ThemeSchema> = {};

Naming the baked-in settings

Removing a setting that Liquid still reads does not leave a hole: the setting's live value is baked into a variable and every reference is rewritten to it. By default those variables are named after what happened to them:

{% comment %} START ADDED DISABLED FEATURES {% endcomment %}
{%- assign removed_settings_schema_predictive_search_enabled = true -%}
{% comment %} END ADDED BY DISABLED FEATURES {% endcomment %}

That is useful in a theme the team maintains and unhelpful in one handed to someone else. bakedSettingNaming: "neutral" writes the same values under names that read as theme code, with no marker comments:

{%- assign theme_setting_predictive_search_enabled = true -%}

| Flavour | legacy (default) | neutral | | --- | --- | --- | | Theme setting | removed_settings_schema_<id> | theme_setting_<id> | | Section setting | removed_section_settings_<id> | section_setting_<id> | | Block setting | removed_block_settings_<id> | block_setting_<id> | | Inline block setting | removed_inline_block_<id> | inline_block_setting_<id> | | Parent section setting | removed_parent_section_<id> | parent_section_setting_<id> |

Pass an object instead of a preset name to set prefixes individually. A neutral prefix can collide with a variable the theme already defines, which removed_* never could; when the name is already in use in that file the legacy name is used for that one variable rather than shadowing it.

What the collision guard cannot see

The check reads the file being rewritten, and names are reserved across that one file. It cannot see a variable that arrives from somewhere else: the deprecated {% include %} shares its caller's scope, so a snippet reached that way could have an injected theme_setting_x overwrite a caller variable of the same name. {% render %} has its own scope and is not affected. If a theme still uses include, prefer bakedSettingNaming: 'legacy' there — the removed_* prefix is deliberately one no theme would write by hand.

Orphan removal (assets and snippets)

Disabling a section or block deletes its .liquid file, but in the si-shopify-base-theme layout the entity's styles and scripts live in a parallel source tree that webpack discovers by glob — so they survive the removal and keep being compiled into assets/. orphanRemoval cleans those up.

export const featureSetup: FeatureSetup<ThemeSchema, FeatureGroupNames> = {
  sectionsToRemove: ["editorial__parallax-hero"],
  orphanRemoval: {
    sourceAssets: true,      // src/scss/**, src/sjs/** (default true)
    compiledAssets: true,    // assets/<prefix>-<name>.{css,js} (default true)
    snippets: "zero-reference", // default "off"
  },
};

For each disabled section and block this removes, when the files exist:

| What | Example for sectionsToRemove: ["hero"] | | --- | --- | | Styles | src/scss/sections/hero.scss, src/scss/sections/hero-editor.scss | | Scripts | src/sjs/sections/hero.ts | | Compiled chunks | assets/section-hero.css, assets/section-hero.js | | Sidecars | assets/section-hero.js.map, assets/section-hero.js.LICENSE.txt |

Names map to files the same way wildcards-entry-webpack-plugin builds chunk names: the path relative to the kind's base directory, without extension, with separators replaced by __. Nested sources therefore resolve too — src/scss/components/product/quick-add.scss belongs to component-product__quick-add. Override assetConventions if a theme lays its sources out differently.

Snippet removal

orphanRemoval.snippets: "zero-reference" deletes every snippet that no surviving Liquid file renders, iterating to a fixed point so a snippet orphaned by another snippet's removal is caught too. Component styles and scripts belonging to a removed snippet go with it.

Three safeguards apply:

  • Protected names. assets, script-tags, style-tags, breakpoints, image-size, responsive-image*, responsive-aspect-ratios-css and svg.* are build artefacts or the asset-loading facade and are never removed, whatever their reference count.
  • Unsound-graph bail-out. A {% render some_variable %} means a snippet could be reached by a name the scan cannot see. When any such tag exists the sweep reports candidates and deletes nothing; list them in snippetsToRemove to remove them anyway. Shopify's {% render block %} app-block idiom is recognised and does not trip this.
  • Validation. If a surviving file still renders a removed snippet, the run fails.

Renders are found by walking the whole Liquid AST, not just element children — the base theme puts renders in HTML attribute position (<div {% render "section__layout" %}>) and inside {% liquid %} blocks. Renders inside {% comment %} are correctly not references.

Nothing is removed in --comment-out mode, which is non-destructive by contract, and dry-run reports the same set it would delete.

Protecting specific files

export const alwaysEnabledFeatures: AlwaysEnabledFeatures<ThemeSchema> = {
  snippetsToKeepUnchanged: ["legacy-*"],
  assetsToKeep: ["src/sjs/sections/*"],
};

snippetsToRemove deletes named snippets outright, independently of the sweep.

Build process

This package is published from generated dist/ output.

  • source files stay committed in the repo
  • dist/ is generated by npm run build
  • dist/ is gitignored and should not be committed
  • the published package includes dist/ because package.json -> files points to it

That means:

  • local repo checkout: run npm run build if you want to exercise the built package locally
  • publish workflow: runs npm run build before npm publish
  • consuming repos: install the package tarball from npm, which already contains dist/

npm run verify checks that the built export surface can be imported successfully.

Publishing

Release flow:

npm version patch
git push --follow-tags

Pushing a vX.Y.Z tag triggers .github/workflows/publish-package.yml, which:

  • installs dependencies
  • builds dist/
  • verifies the tag matches package.json version
  • creates a GitHub release
  • publishes to the public npm registry

The workflow uses:

  • GITHUB_TOKEN for the GitHub release
  • NPM_TOKEN for npm publishing

NPM_TOKEN should be an npm automation token with publish access to the @smartimpact-it organization.

Exports

Main exports:

  • @smartimpact-it/shopify-disable-features
  • @smartimpact-it/shopify-disable-features/config
  • @smartimpact-it/shopify-disable-features/mutations
  • @smartimpact-it/shopify-disable-features/state
  • @smartimpact-it/shopify-disable-features/analyzer
  • @smartimpact-it/shopify-disable-features/feature-disabler
  • @smartimpact-it/shopify-disable-features/schema
  • @smartimpact-it/shopify-disable-features/webpack/schema-definitions-plugin
  • @smartimpact-it/shopify-disable-features/webpack/extension-data-plugin

CLI binaries

Published bins:

  • shopify-disable-features
  • shopify-lint-disabled-features
  • shopify-disable-unused-features
  • shopify-optimize-disabled-features
  • shopify-generate-schema-definitions
  • shopify-generate-extension-data
  • shopify-generate-theme-features-inventory