@alexander.k/vite-plugin-for-shopify
v1.2.0
Published
Vite plugin to generate a Shopify Liquid snippet with all Vite build entries.
Maintainers
Readme
vite-plugin-for-shopify
Vite plugin to generate a Shopify Liquid snippet with all Vite build entries.
Features
- Generates a Liquid snippet (default:
vite.liquid) in your theme'ssnippetsdirectory - 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
Installation
Add the plugin to your project:
npm install @alexander.k/vite-plugin-for-shopify --save-devUsage
Add the plugin to your vite.config.js
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
fileNameRegexoption can also be provided at the root level for backward compatibility, but it is recommended to use thecleanupobject.
Add the snippet to <head></head> once (no params)
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>Use the snippet with entry name as in your Vite inputs
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'
}
}
}
})Default usage
{% liquid
# You can also preload styles
render 'vite', entry: 'theme', preload_stylesheet: true
render 'vite', entry: 'pageStyles'
render 'vite', entry: 'coolSection'
%}Only styles or only JS
{% liquid
# Only styles
render 'vite', entry: 'theme', only_css: true
# Only JS
render 'vite', entry: 'coolSection', only_js: true
%}Import mode for styles
<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>Import mode for JS
<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>How it works
- The plugin generates a snippet file (default:
vite.liquid) in your theme'ssnippetsdirectory after each build. - The snippet contains all entry points from your Vite config and supports various usage modes (see above).
- If the
cleanup.fileNameRegexoption 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.
Notes
- 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.
