uicrooks / Shopify Theme Lab
Programming Languages
Projects that are alternatives of or similar to Shopify Theme Lab
Shopify Theme Lab
Shopify Theme Lab is a customizable modular development environment for blazing-fast Shopify theme creation. By default, it's bundled with Vue.js and Tailwind CSS, but you can swap them for pretty much anything. Build a custom Shopify theme from scratch with a modern stack!
Disclaimer: This project is not affiliated with Shopify Inc., Tailwind Labs Inc. or Vue.org
TL;DR Go to Installing, then go to Getting started. Now you're ready to start π₯
Table of contents
- Ecosystem
- Features
- System requirements
- Installing
- Getting started
- Deploying
- CSS preprocessors
- Swapping CSS framework
- Swapping JavaScript framework
- Project structure
- Tasks
- Development environment concepts
- Common pitfalls
- Limitations
- Contributing
Ecosystem
Project | Status | Description |
---|---|---|
Shopify Theme Lab | Modular development environment for blazing-fast Shopify theming | |
Shopify Theme Lab CLI | Command Line Interface for Shopify Theme Lab | |
Shopify Settings Control | Automatic Git version control for Shopify settings_data.json
|
|
Shopify Foundation Theme | A modern Shopify starter theme built with Vue and Tailwind CSS |
Features
- Shopify
- Self-contained, no need to install external tools
- Shopify Theme Kit npm package included
- Quick Shopify theme setup on a remote store with
npm run shopify:init
- CI/CD integration with Shopify Theme Lab CLI
- Default Shopify theme directory structure with unstyled
.liquid
files - A batch of
npm scripts
to run common tasks
- JavaScript
- Vue
- Vuex
- Swap Vue with any other framework e.g. Alpine.js
- Axios
- Extend with npm packages π¦
- CSS
- Tailwind CSS
- Swap Tailwind CSS with any other framework e.g. Bulma
- PostCSS with postcss-preset-env
- Preprocessor support: SASS / SCSS, LESS and Stylus
- Workflow
- Webpack
- Babel
- ESLint
- stylelint
- Browserslist
- Autoprefixer
- PurgeCSS integrated in Tailwind CSS
- Shopify remote theme auto-reloading with shopify-reloadr
- Auto-loading of Vue
components
,mixins
,directives
andfilters
as well as Vuexmodules
with require.context - Clean config structure
- Easily adjustable/extendable configurations
System requirements
- Node.js >=
12.0.0
- npm or yarn
Installing
- Clone this repo or simply run the following command in your terminal:
$ npx themelab create <directory-name>
- Run the following command(s) with your preferred package manager:
npm
$ npm install
yarn
$ yarn import # migrate package-lock.json to yarn.lock
$ rm package-lock.json # or delete manually
$ yarn install --force
If you migrated to yarn, you can replace
npm run
withyarn
when executing upcoming commands.
Getting started
-
Get Shopify API access: Instructions at Theme Kit Docs
-
Initialize theme on Shopify store with credentials from the first step. Either for dev or live environment:
npm
requires the extra--
before any arguments! When usingyarn
you can omit them.
$ npm run shopify:init -- --password [your-api-password] --store [your-store.myshopify.com] --env [dev or live] --name [theme-name]
-
Publish the new theme through the Shopify panel: your-store.myshopify.com/admin/themes
-
Start developing:
$ npm run start
$ npm run open:dev # open/preview theme in default browser
Deploying
first, make sure the configuration for the
live
environment is initialized.
$ npm run build # bundle js, css and other assets like images/fonts with webpack
$ npm run deploy:live # deploy shopify/ directory
There is a safety mechanism in place, which won't allow you to deploy to an already published theme on the live store. If you want to deploy regardless use the
--allow-live
flag.
$ npm run deploy:live -- --allow-live
Teams
The shopify:init
task always creates a new theme with a unique ID for the provided store. Sometimes it can be useful to connect to an existing initialized theme (e.g. when multiple people deploy to the same live environment).
- Run the following command to list all themes from the provided store and write down the ID for the theme in question:
$ npm run shopify:themes -- --password [your-api-password] --store [your-store.myshopify.com]
- Copy and rename the Shopify sample config file:
$ cp .config/shopify/shopify.sample.yml .config/shopify/shopify.live.yml # or copy and rename manually
- Adjust the contents of the newly created
shopify.live.yml
file.
CI/CD
GitHub actions
- Add the following four secrets to your Shopify Theme Lab repo in
settings
βsecrets
:
SHOPIFY_API_PASSWORD # your-api-password
SHOPIFY_STORE_URL # your-store.myshopify.com
SHOPIFY_ENV # dev or live
SHOPIFY_THEME_ID # theme-id (without quotation marks) - find the id either in shopify.[env].config.yml or with shopify:themes task
- Copy and paste into a GitHub action (adjust contents if necessary):
# Shopify Theme Lab CI/CD integration for GitHub actions
name: Shopify Theme Lab CI/CD
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch: # allows to manually run from GitHub actions panel
jobs:
build-and-deploy:
name: Build and Deploy
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 14.x ]
steps:
- name: Checkout master branch
uses: actions/[email protected]
- name: Use Node.js
uses: actions/[email protected]
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies and build dist files
run: |
npm install
npm run build
# first, make sure the theme is already initialized on the Shopify store in question
#
# Below "run" commands explained:
# 1. creates a Shopify credential config
# 2. downloads settings_data.json from the remote store
# 3. deploys the shopify/ directory to the remote store
- name: Deploy to Shopify store
run: |
npx themelab shopify:init -p ${{ secrets.SHOPIFY_API_PASSWORD }} -s ${{ secrets.SHOPIFY_STORE_URL }} -e ${{ secrets.SHOPIFY_ENV }} -i ${{ secrets.SHOPIFY_THEME_ID }}
npm run settings:${{ secrets.SHOPIFY_ENV }}
npm run deploy:${{ secrets.SHOPIFY_ENV }} -- --allow-live
CSS preprocessors
For the most cohesive development experience, it's recommended that you use PostCSS exclusively when working with Tailwind CSS.
By default, only PostCSS with postcss-preset-env
is installed. postcss-preset-env lets you use tomorrowβs CSS today. If you want to use a preprocessor it's recommended to use SASS/SCSS
since it's the most compatible with a variety of CSS frameworks.
SASS/SCSS
- Run the following command:
npm
$ npm install sass sass-loader --save-dev
yarn
$ yarn add sass sass-loader --dev
-
Rename
src/css/main.css
tosrc/css/main.scss
-
Change
import './css/main.css'
toimport './css/main.scss'
in src/main.js
LESS
- Run the following command:
npm
$ npm install less less-loader --save-dev
yarn
$ yarn add less less-loader --dev
-
Rename
src/css/main.css
tosrc/css/main.less
-
Change
import './css/main.css'
toimport './css/main.less'
in src/main.js
Stylus
- Run the following command:
npm
$ npm install stylus stylus-loader --save-dev
yarn
$ yarn add stylus stylus-loader --dev
-
Rename
src/css/main.css
tosrc/css/main.styl
-
Change
import './css/main.css'
toimport './css/main.styl'
in src/main.js
Swapping CSS framework
Removing Tailwind CSS
- Remove package:
npm
$ npm uninstall tailwindcss
yarn
$ yarn remove tailwindcss
- Remove tailwind config:
$ rm src/tailwind.config.js # or delete manually
-
Inside postcss.config.js remove
require('tailwindcss')(path.resolve(__dirname, '../src/tailwind.config.js'))
. -
Remove all
@import "tailwindcss/..";
imports from main.css
Bulma
-
Install SASS/SCSS and update files accordingly
-
Install package:
npm
$ npm install bulma
yarn
$ yarn add bulma
- import bulma in
main.scss
with@import "~bulma/bulma";
Swapping JavaScript framework
Removing Vue
- Remove packages:
npm
$ npm uninstall vue vuex vue-loader vue-template-compiler
yarn
$ yarn remove vue vuex vue-loader vue-template-compiler
- Remove vue directory:
$ rm -r src/vue # or delete manually
-
Remove everything from main.js except
import './css/main.css'
-
Inside .eslintrc.js:
{
...
extends: [
...
'plugin:vue/recommended' // remove 'plugin:vue/recommended'
...
],
plugins: [
'vue' // remove 'vue'
]
...
}
- Inside webpack.common.js:
...
const VueLoaderPlugin = require('vue-loader/lib/plugin') // remove VueLoaderPlugin require
...
module: {
rules: [
...
// remove vue-loader
{
test: /\.vue$/,
loader: 'vue-loader'
}
...
]
}
{
plugins: [
...
new VueLoaderPlugin() // remove VueLoaderPlugin
...
]
}
Alpine.js
If you want to use something lighter than Vue, a good alternative is Alpine.js.
- Install package:
npm
$ npm install alpinejs
yarn
$ yarn add alpinejs
- Import
alpinejs
in main.js:
import 'alpinejs'
Project structure
shopify-theme-lab/ π root of your Shopify Theme Lab project
βββ .config/ π development environment files and configs
β βββ shopify/ π Shopify credential-configs
β β βββ .shopifyignore π files and directories that won't be uploaded to Shopify
β β βββ ...
β βββ webpack/ π webpack configs
β β βββ webpack.common.js π webpack shared config used in development and production
β β βββ webpack.dev.js π webpack development config
β β βββ webpack.prod.js π webpack production config
β βββ .browserslistrc π Browserslist config
β βββ .eslintrc.js π ESLint config
β βββ .stylelintrc.js π stylelint config
β βββ postcss.config.js π PostCSS config
βββ .github/ π files related to GitHub and images for READMEs
βββ shopify/ π default Shopify theme structure
β βββ assets/ π files outputted by webpack will be placed here
β βββ ...
βββ src/ π source files processed by webpack
β βββ css/ π css directory
β β βββ main.css π main stylesheet
β βββ vue/ π Vue, Vuex files and directories
β β βββ ...
β βββ main.js π webpack's main entry point
β βββ tailwind.config.js π Tailwind CSS config
βββ .gitignore π files and directories ignored by git
βββ package.json π dependencies and tasks
βββ ...
Tasks
Task | Description |
---|---|
start | run dev , reloadr and shopify:watch tasks simultaneously in parallel |
dev | bundle and watch for changes in src/ files with webpack |
build | create minified production files for Shopify in shopify/assets/ directory |
reloadr | run an HTTP server and WebSocket server for remote auto-reloading |
lint | run lint:js and lint:css tasks in sequence |
lint:js | lint .js and .vue files inside the src/ directory |
lint:css | lint the <style></style> section of .vue files, .css , .sass and .scss files inside the src/ directory |
shopify:watch | watch for changes in the shopify/ directory and upload to the dev store |
shopify:init | initialize a theme on remote Shopify store and create a Shopify config file for the specified environment (Run in the root directory of your project) |
shopify:themes | list all themes with IDs from the provided store. Takes two arguments --password and --store
|
deploy:dev | upload the shopify/ directory to the dev store |
deploy:live | upload the shopify/ directory to the live store |
settings:dev | download settings_data.json from the dev store |
settings:live | download settings_data.json from the live store |
open:dev | open/preview theme on the dev store |
open:live | open/preview theme on the live store |
Development environment concepts
CLI
Under the hood Shopify Theme Lab uses the Shopify Theme Lab CLI for some tasks. You can also use the CLI independantly from included tasks.
Configs
Inside .configs/
are multiple pre-configured config files. You should be able to work from start to finish, without ever going into this directory. But if you feel the need to adjust some configs to your liking, go for it!
Shopify & environment initialization
By running shopify:init
and entering credentials, the task initializes a new theme from shopify/
directory to the provided Shopify store. It also saves a configuration file for the specified environment inside .config/shopify/
directory. This file will be ignored by git and shouldn't be tracked for security reasons. All tasks regarding Shopify will use the credentials from the saved configuration file.
Shopify + webpack
- All webpack configs are inside
.config/webpack/
directory - main.js is webpack's main entry point
- All Vue related files are auto-loaded by webpack with require.context - Vue components, Vuex modules, as well as mixins, directives and filters with
global
in their filename. Everything is defined insrc/main.js
- Vue components can be either used as regular single-file-components or as renderless components without
<template></template>
tags (You can use Liquid templating while hooking in Vue functionality). - The webpack bundle and all other assets are outputted to
shopify/assets/
directory. This directory is cleaned on every build. If you want to keep certain files like favicons addstatic
to their filenames:myfile.static.png
Shopify remote auto-reloading
While npm run start
task is running: The shopify/
directory is being watched for changes and all changed files are uploaded to the Shopify remote server. After the upload is finished, a request is sent to a localhost:port
address (specified in package.json
) and the shopify-reloadr package reloads all connected Shopify store sites. Open the web console to check if a site is connected.
Common pitfalls
-
<style></style>
and<script></script>
will be removed on mount inside Vue components (basically everything inside<div id="app">...</div>
), use<component is="style"><componet>
and<component is="script"></componet>
instead - If you want to pass an entire Shopify Drop (Object) as a prop, you have to first convert the Drop to
json
and replace all double quotes with single quotes:<component :shopify-data="{{ product | json | replace: '"', "'" }}"></component>
. Not all Drops can be converted tojson
, if you get an{"error":"json not allowed for this object"}
it's a Shopify limitation and you have to pass the values in question individually
Limitations
- When the development task is running, the browser console throws a
bundle.css
missing error - Already running Shopify tasks only upload files which are changed, a simple re-save of a file, without editing it, won't upload the file to the remote store
- Vue components inside
.liquid
files can only be used in a non-self-closing<kebab-case></kebap-case>
manner
Contributing
Everyone is welcome to make Shopify theme development better! Please read the Contributing guide before creating issues or submitting pull requests.