vite-plugin-shopify-easel
v0.2.2
Published
Vite plugin for Shopify Liquid themes with HMR, safe asset builds, named bundles, and generated Liquid loaders
Maintainers
Readme
Easel
Easel is an independent Vite plugin and theme generator for Shopify Liquid themes.
It builds JavaScript, TypeScript, and CSS into Shopify theme assets, generates the Liquid that loads them, and safely replaces only output it owns. Shopify CLI remains responsible for authentication, previews, synchronization, and deployment.
Create a theme · Add Easel to a theme · Choosing Easel · Documentation · Examples
Create a new theme
npm create easel-theme@latest my-themecreate-easel-theme scaffolds TypeScript or JavaScript, optional Alpine, React or Vue, and plain CSS or Tailwind CSS. It includes generic Online Store 2.0 JSON templates for the standard storefront page types while leaving current customer accounts to Shopify.
Use . instead of my-theme to scaffold into an empty current directory. Use --yes --no-install for non-interactive automation. Existing files are never overwritten. Generated projects include npm run check:theme for Shopify Theme Check and npm run check:all for source, build, and Liquid validation.
Why Easel
- Vite-native: use normal Vite plugins, configuration, dynamic imports, HMR, and production builds.
- Shopify-native: keep the standard Liquid theme structure and use Shopify CLI directly for store operations.
- Safe publication: stage output, track ownership, reject unsafe overwrites, and roll back interrupted commits.
- Selective loading: start with one shared entry and add named script, style, or CSS-only bundles when needed.
- Framework optional: use vanilla TypeScript, Alpine, React, Vue, Tailwind CSS, Sass, or PostCSS through their standard Vite integrations.
Add Easel to an existing theme
pnpm add -D vite-plugin-shopify-easel viteEasel requires Node.js 22.12 or newer and supports Vite 7 and 8.
From a checkout of this repository, run pnpm install and pnpm create:theme ../my-theme to exercise the local generator. Shopify CLI is installed and authenticated separately.
Start
Keep the Shopify theme at the project root and place source files in src.
assets/
config/
layout/
sections/
snippets/
templates/
src/
main.ts
style.css
vite.config.tssrc/main.js also works.
import {defineConfig} from 'vite';
import easel from 'vite-plugin-shopify-easel';
export default defineConfig({
plugins: [easel()],
});Render the generated loader inside <head> in layout/theme.liquid.
{% render 'easel-assets' %}Ignore generated output.
.easel/
assets/easel-*
snippets/easel-assets.liquidRun Vite and Shopify CLI in separate terminals.
npm run devshopify theme dev --notify .easel/shopify-readyThe notification is optional. Vite HMR and Shopify CLI live reload still work without it.
Build before pushing or packaging.
npm run build
shopify theme pushShopify automatically preloads render-blocking stylesheets in <head> through Link headers, so the generated stylesheet tags don't need preload: true.
Because generated output is ignored by Git, anything that deploys straight from the repository, such as the Shopify GitHub integration, gets no loader or assets. Build in CI and deploy with Shopify CLI, or commit the generated output on the branch Shopify deploys. Run Theme Check after the build, since layouts that render easel-assets report MissingTemplate until it exists.
Named bundles
Load only the code each Liquid surface needs.
import {defineConfig} from 'vite';
import easel from 'vite-plugin-shopify-easel';
export default defineConfig({
plugins: [
easel({
bundles: {
theme: {script: 'main.ts', style: 'style.css'},
product: {script: 'product.ts', style: 'product.css'},
typography: {style: 'typography.css'},
},
}),
],
});{% render 'easel-assets', entry: 'product' %}Bundle paths resolve from src by default. The first bundle is used when entry is omitted.
Configuration
easel({
// Shopify theme directory relative to the Vite root. Defaults to the Vite root.
theme: '.',
// Source directory relative to the Vite root. Defaults to src.
source: 'src',
// Named entries relative to source. Defaults to main.ts or main.js with style.css.
bundles: {
theme: {script: 'main.ts', style: 'style.css'},
},
// Namespace used by generated assets and the Liquid snippet. Defaults to easel.
namespace: 'easel',
// Shopify CLI reload coordination. Use false to disable it.
refresh: {
// Notification file relative to the Vite root.
signal: '.easel/shopify-ready',
// Reload debounce in milliseconds. Defaults to 100.
delay: 100,
},
});Use Tailwind CSS, Alpine.js, React, Vue, Sass, PostCSS, and other tools through their normal Vite setup. React Fast Refresh requires @vitejs/plugin-react/preamble because Easel does not use an HTML entry.
Safe by default
Easel never empties Shopify's shared assets directory. It tracks only its own files, refuses unsafe overwrites, stages builds in isolation, serializes publication, and rolls back interrupted commits.
Production entries keep stable names. Shared chunks, dynamic chunks, imported CSS, images, fonts, and source maps retain Vite's cache safe output behavior.
Shopify CLI remains responsible for authentication, previews, synchronization, pushes, and packaging.
Examples
• examples/vanilla for TypeScript and CSS
• examples/named-bundles for separate product and collection entries
• examples/alpine-tailwind for Alpine.js and Tailwind CSS
• examples/react for React inside Liquid sections
• examples/vue for Vue single file components inside Liquid sections
Each example includes Shopify Theme Editor lifecycle handling and automated build checks.
Support and security
Use the documentation for setup and troubleshooting, open an issue for reproducible bugs and focused feature requests, and use private vulnerability reporting for security concerns. See CONTRIBUTING.md before opening a pull request.
License
MIT
