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-shopify-liquid-imports

v0.2.6

Published

Post-build companion to vite-plugin-shopify that enables native-ESM code splitting on Shopify themes via a classic bootstrap and Blob module graph — no import maps or .js.liquid chunk rewriting.

Readme

vite-plugin-shopify-liquid-imports

Post-build companion to vite-plugin-shopify that enables native-ESM code splitting on Shopify themes without import maps or .js.liquid chunk rewriting.

It emits a Liquid JSON manifest of Shopify asset_urls, a tiny classic bootstrap (*loader.min.js), and rewrites chunk graphs so modules load through Blob URLs with stable marker substitution.

Why

Shopify themes can't ship a normal hashed-filename ESM chunk graph — chunk URLs must go through asset_url. Import maps are the usual workaround, but they have weak browser support and conflict when multiple maps exist in one theme.

This plugin takes a different path:

  1. Liquid emits a JSON manifest of CDN URLs (Shopify's own ?v=), then a classic bootstrap script.
  2. The bootstrap fetches module sources, rewrites controlled static-import markers to Blob URLs, and import()s the entry Blob.
  3. Dynamic import() calls become namespaced loader imports, so lazy chunks stay lazy.

Browser floor: dynamic import() + Blob/createObjectURL (~Chrome 63 / Safari 11.1 / Firefox 67). Storefront CSP must allow script-src blob: and CDN connect-src.

Install

npm i -D vite-plugin-shopify-liquid-imports

Peers: vite >= 8, vite-plugin-shopify >= 4.

Usage

Register after vite-plugin-shopify:

import { defineConfig } from 'vite'
import shopify from 'vite-plugin-shopify'
import liquidImports from 'vite-plugin-shopify-liquid-imports'

export default defineConfig({
  plugins: [
    shopify({
      themeRoot: '../',
      snippetFile: 'vite-tag.liquid',
      versionNumbers: true,
    }),
    liquidImports({
      namespace: 'my-app',
      assetPrefix: 'MA_',
      snippetFile: 'vite-tag.liquid', // must match shopify()
      versionNumbers: true, // must match shopify()
      entrypointsDir: './entries', // must match shopify() when non-default
      prefetchSnippetFile: 'vite-tag-preload.liquid', // optional
    }),
  ],
})

The plugin forces production modulePreload: false, sourcemap: false, and stable [name].min.js / [name].min.css entry filenames under assetPrefix (non-CSS assets like fonts/images keep a content hash).

In production it regenerates the shared snippetFile from the Vite manifest: JS entries become Blob-loader branches (JSON manifest + classic bootstrap); CSS and other non-JS entries keep stylesheet_tag / shopify-style tags. No consumer-side CSS patch plugin is required.

Options

| Option | Required | Description | |--------|----------|-------------| | namespace | yes | Isolates runtime Symbol.for key, markers, and reload storage. Must match /^[a-z][a-z0-9-]*$/. | | assetPrefix | yes | Filename prefix for all emitted JS/CSS assets (e.g. HC_). Must match /^[A-Za-z][A-Za-z0-9_-]*$/. | | snippetFile | yes | Shared Liquid snippet with vite-plugin-shopify. Must match shopify({ snippetFile }). | | versionNumbers | no | Match shopify({ versionNumbers }). Default true. | | entrypointsDir | no | Match shopify({ entrypointsDir }) for CSS path aliases. Default entries. | | prefetchSnippetFile | no | Section-gated prefetch helper snippet. |

Bootstrap loading (JS entries)

Per-render params control how the classic *loader.min.js bootstrap is requested. They apply only to JS entry branches (CSS branches ignore them).

| Param | Values | Default | |-------|--------|---------| | script_loading | defer | async | blocking | defer | | fetchpriority | high | low | auto | omit attribute |

{% comment %} Secondary UI (cart drawers, widgets) — default {% endcomment %}
{% render 'vite-tag' with 'ns-hybrid-cart.tsx' %}

{% comment %} Main-page / LCP content — start the bootstrap earlier {% endcomment %}
{% render 'vite-tag',
  entry: 'naked-quiz-v2.tsx',
  script_loading: 'async',
  fetchpriority: 'high'
%}

Legacy {% render 'vite-tag' with 'entry.tsx' %} still works and defaults to defer with no fetchpriority. Unknown script_loading values are coerced to defer (storefront-safe).

Guidance

  • Secondary widgets / cart: defer (default).
  • LCP / main content apps: prefer async + fetchpriority: 'high'. Use blocking only when the tag is intentionally early in the parse and you want the bootstrap file itself parser-blocking.
  • These params only affect the tiny classic bootstrap. The module graph still loads asynchronously via fetch + import(blob). blocking does not make the full app render-blocking.

Section-gated prefetch

When prefetchSnippetFile is set, sections can warm a lazy chunk's source fetch without evaluating it:

{% render 'vite-tag-preload', chunk: 'PreCartUpsells' %}

chunk is the Vite [name] (e.g. PreCartUpsells). Prefetch shares the loader's source-fetch map so a later import does not download twice.

What it does

| Hook | Action | |------|--------| | config | Forces modulePreload: false, sourcemap: false, and prefixed stable chunk names. | | generateBundle | Rewrites static/dynamic imports to loader markers/calls, stamps modules, emits *loader.min.js. | | closeBundle | Regenerates the shared vite-tag from the Vite manifest (JS → Blob loader, CSS → stylesheet_tag) and optional prefetch helper. |

Stable module identity

Shopify assigns a volatile ?v= to assets. The Liquid manifest embeds each module's asset_url once per page render, and every module source is stamped with /* shopify-module-loader:<namespace>:<buildId> */. A mismatch triggers one guarded reload to heal mixed deployments.

Caveats

  • Place after shopify() — production closeBundle regenerates the shared vite-tag; register this plugin after so it wins the final write.
  • Shared vite-tag — only the JS entry loading path is replaced (no type=module / modulepreload for managed chunks). CSS entries and other non-JS tags from the manifest are preserved. Do not append CSS with a local post-plugin.
  • No production source maps — Blob marker substitution invalidates them.
  • Chunk-scoped CSS is unsupported — use a CSS entry, cssCodeSplit: false, or ?inline. The build fails clearly if a JS chunk imports CSS.
  • CSP: allow script-src blob: and CDN connect-src.
  • Stable asset names are not atomic across Shopify uploads; build stamps + one guarded reload mitigate mixed deployments.

Breaking change (0.2)

0.1.x rewrote chunks to .js.liquid with inline asset_url imports. 0.2.0 replaces that approach entirely with the bootstrap + Blob loader. Options and output format are incompatible — migrate call sites to the options above.

License

MIT