Vite plugin to generate a Shopify Liquid snippet with all Vite build entries.
- Generates a Liquid snippet (default:
vite.liquid
) in your theme'ssnippets
directory - Cleans up old asset files in the output directory if they no longer exist in the new build (optional)
- Supports dynamic imports in Shopify themes via a helper function
Add the plugin to your project:
npm install @alexander.k/vite-plugin-for-shopify --save-dev
All options are optional:
import shopifyVitePlugin from '@alexander.k/vite-plugin-for-shopify'
export default {
plugins: [
shopifyVitePlugin({
// Root path to your Shopify theme (default: './')
themeRoot: './',
// Name of the snippet file to generate (default: 'vite.liquid')
snippetFilename: 'vite.liquid',
cleanup: {
// Regex to match files in the assets folder generated by Vite.
// Old files matching this pattern will be removed after each build.
// If not set, old files will not be deleted.
fileNameRegex: /.*\.min\.(js|css)$/m
}
})
]
}
Note: The
fileNameRegex
option can also be provided at the root level for backward compatibility, but it is recommended to use thecleanup
object.
This will add the helper function for dynamic imports to your code. For example, add to your theme.liquid
file:
<html>
<head>
...
{% render 'vite' %}
</head>
<body>
...
</body>
</html>
Example Vite config:
export default defineConfig({
plugins: [
shopifyVitePlugin()
],
build: {
rollupOptions: {
input: {
theme: './some-path/theme.js',
coolSection: './some-path/coolSection.js',
utils: './some-path/utils.js',
pageStyles: './some-path/pageStyles.css'
}
}
}
})
{% liquid
# You can also preload styles
render 'vite', entry: 'theme', preload_stylesheet: true
render 'vite', entry: 'pageStyles'
render 'vite', entry: 'coolSection'
%}
{% liquid
# Only styles
render 'vite', entry: 'theme', only_css: true
# Only JS
render 'vite', entry: 'coolSection', only_js: true
%}
<template class="component-template">
<style>
{% render 'vite', entry: 'theme', only_css: true, import_mode: true %}
:root {
display: block;
}
.wrapper {
padding: 10px;
}
</style>
<div class="wrapper">
<button class="global-class-from-theme">Button</button>
</div>
</template>
==> result:
<template class="component-template">
<style>
@import url("//www.your-store.com/cdn/shop/t/111/assets/theme.C0CJB5x1.min.css");
:root {
display: block;
}
.wrapper {
padding: 10px;
}
</style>
<div class="wrapper">
<button class="global-class-from-theme">Button</button>
</div>
</template>
<script type="module">
{% render 'vite', entry: 'utils', only_js: true, import_mode: true %}
</script>
==> result:
<script type="module">
import "//www.your-store.com/cdn/shop/t/111/assets/utils.C0CJB5x1.min.js";
</script>
Or named import:
<script type="module">
{% render 'vite', entry: 'utils', only_js: true, import_mode: true, import_name: '{ getCart }' %}
const cart = getCart()
</script>
==> result:
<script type="module">
import { getCart } from "//www.your-store.com/cdn/shop/t/111/assets/utils.C0CJB5x1.min.js";
const cart = getCart()
</script>
Or dynamic way:
<script type="module">
const addClickHandler = async (items) => {
{% render 'vite', entry: 'utils', only_js: true, import_mode: true, dynamic_import: true, import_name: '{ addToCart }' %}
return await addToCart(items)
}
</script>
==> result:
<script type="module">
const addClickHandler = async (items) => {
const { addToCart } = await import("//www.your-store.com/cdn/shop/t/111/assets/utils.C0CJB5x1.min.js");
return await addToCart(items)
}
</script>
- The plugin generates a snippet file (default:
vite.liquid
) in your theme'ssnippets
directory after each build. - The snippet contains all entry points from your Vite config and supports various usage modes (see above).
- If the
cleanup.fileNameRegex
option is set, the plugin will remove old files in the output directory that do not exist in the new build. - The plugin automatically removes the manifest file after build (except in development mode).
- For dynamic imports, a helper function is injected into the global scope to resolve asset URLs correctly.
- The snippet is auto-generated. Do not edit it manually.
- Make sure to commit the snippet file if you want to keep it in version control.
- For more details, see the comments in the generated snippet or the plugin source code.