Migration Guide
Prerequisites
This guide assumes you are using Alokai Ecosystem version 0.1.0. For details about this version, please refer to the changelog.
Project Structure After Migration to Multistore
Before we begin, here's what your project structure will look like after completing this migration:
apps/
├── playwright/
├── storefront-unified-nextjs/
├── storefront-unified-middleware/
└── stores/
├── default/
│ └── playwright/
│ └── storefront-unified-nextjs/
│ └── storefront-middleware/
packages/
eslint-config/
lint-staged-config/
prettier-config/
tailwind-config/
File-based Inheritance
The structure above enables Alokai's powerful file-based inheritance system, allowing you to share code efficiently across multiple stores while maintaining the ability to customize specific parts for each brand. Learn more about file-based inheritance.
Migration Steps
1
Set Up Shared Configuration Packages
The first step in migrating to Alokai Multistore is setting up shared configuration packages. These packages help maintain consistency across multiple stores by:
- Centralizing common configuration like ESLint, Prettier, and Tailwind settings
- Reducing duplication of configuration files
- Making it easier to update configurations across all stores
- Enforcing consistent code style and quality standards
This approach follows the DRY (Don't Repeat Yourself) principle and makes maintenance more manageable as your multistore setup grows.
- Create the following directory structure:
mkdir -p packages/{eslint-config,prettier-config,lint-staged-config,tailwind-config}
- Set up ESLint configuration:
Create packages/eslint-config/middleware.mjs
:
import { concat, ecma, style, typescript } from "@vue-storefront/eslint-config";
import gitignore from "eslint-config-flat-gitignore";
export default concat(
gitignore(),
ecma(),
typescript(
{},
{
files: ["**/*.{ts,tsx}"],
rules: {
"@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/no-magic-numbers": "off",
"import/no-unresolved": "off",
},
},
),
style(),
);
Create packages/eslint-config/playwright.mjs
:
import { concat, ecma, playwright, style, typescript } from '@vue-storefront/eslint-config';
import gitignore from 'eslint-config-flat-gitignore';
export default concat(
gitignore(),
ecma(),
typescript(
{
files: '**/*.ts',
},
{
files: ['setup/**/*.ts'],
rules: {
'@typescript-eslint/no-unused-expressions': 'off',
},
},
{
files: ['**/*.ts'],
rules: {
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-magic-numbers': 'off',
},
},
),
style(),
playwright({
files: ['**/*.test.ts', 'sf-modules/**/*.test.ts'],
}),
);
Create packages/eslint-config/nextjs.mjs
:
import { concat, ecma, nextjs, style, typescript } from '@vue-storefront/eslint-config';
import gitignore from 'eslint-config-flat-gitignore';
export default concat(
gitignore(),
ecma(),
typescript(
{
files: '**/*.{ts,tsx}',
},
{
files: ['**/*.{ts,tsx}'],
rules: {
'@typescript-eslint/consistent-type-imports': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-magic-numbers': 'off',
'import/no-unresolved': 'off',
},
},
),
nextjs({
files: {
components: ['components/**/*.{js,jsx,ts,tsx}', 'app/**/components/*.{js,jsx,ts,tsx}'],
general: '**/*.{js,jsx,ts,tsx}',
hooks: '{hooks,helpers}/**/*.{js,jsx,ts,tsx}',
},
}),
style(),
);
Create packages/eslint-config/index.mjs
:
export * from './middleware.mjs';
export * from './nextjs.mjs';
export * from './playwright.mjs';
Create packages/eslint-config/package.json
:
{
"name": "eslint-config",
"version": "0.0.1",
"private": true,
"exports": {
".": {
"import": "./index.mjs"
},
"./middleware": {
"import": "./middleware.mjs"
},
"./nextjs": {
"import": "./nextjs.mjs"
},
"./playwright": {
"import": "./playwright.mjs"
}
},
"devDependencies": {
"@vue-storefront/eslint-config": "4.1.0",
"eslint-config-flat-gitignore": "0.3.0"
}
}
- Set up Prettier configuration:
Create packages/prettier-config/middleware.mjs
:
export default {
arrowParens: "always",
endOfLine: "lf",
printWidth: 100,
singleQuote: true,
semi: true,
tabWidth: 2,
trailingComma: "all",
};
Create packages/prettier-config/playwright.mjs
:
export default {
arrowParens: "always",
endOfLine: "lf",
printWidth: 100,
singleQuote: true,
semi: true,
tabWidth: 2,
trailingComma: "all",
};
Create packages/prettier-config/nextjs.mjs
:
export default {
plugins: ['prettier-plugin-tailwindcss'],
printWidth: 120,
singleQuote: true,
};
Create packages/prettier-config/index.mjs
:
export * from './middleware.mjs';
export * from './nextjs.mjs';
export * from './playwright.mjs';
Create packages/prettier-config/package.json
:
{
"name": "prettier-config",
"version": "0.0.1",
"private": true,
"exports": {
".": {
"import": "./index.mjs"
},
"./middleware": {
"import": "./middleware.mjs"
},
"./nextjs": {
"import": "./nextjs.mjs"
},
"./playwright": {
"import": "./playwright.mjs"
}
},
"dependencies": {
"prettier-plugin-tailwindcss": "0.6.11"
}
}
- Set up lint-staged configuration:
Create packages/lint-staged-config/middleware.mjs
:
export default {
"*.{js,cjs,mjs,ts,tsx}": ["eslint --fix", "prettier --write"],
};
Create packages/lint-staged-config/playwright.mjs
:
export default {
'*.{js,cjs,mjs,ts,tsx}': ['eslint --fix', 'prettier --write'],
};
Create packages/lint-staged-config/nextjs.mjs
:
export default {
'*.{js,cjs,mjs,ts,tsx}': ['eslint --fix'],
};
Create packages/lint-staged-config/index.mjs
:
export * from './middleware.mjs';
export * from './nextjs.mjs';
export * from './playwright.mjs';
Create packages/lint-staged-config/package.json
:
{
"name": "lint-staged-config",
"version": "0.0.1",
"private": true,
"exports": {
".": {
"import": "./index.mjs"
},
"./middleware": {
"import": "./middleware.mjs"
},
"./nextjs": {
"import": "./nextjs.mjs"
},
"./playwright": {
"import": "./playwright.mjs"
}
}
}
- Set up Tailwind configuration:
Create packages/tailwind-config/tsconfig.json
:
{
"compilerOptions": {
"module": "preserve",
"target": "ESNext",
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"esModuleInterop": true,
"isolatedModules": true,
"moduleDetection": "auto",
"moduleResolution": "bundler",
"skipLibCheck": true,
"lib": [
"DOM",
"DOM.Iterable",
"ES2019"
]
},
"include": ["src/**/*.ts"],
"exclude": ["./dist/**/*"]
}
Create packages/tailwind-config/src/nextjs.ts
:
import { tailwindConfig } from '@storefront-ui/react/tailwind-config';
import sfTypography from '@storefront-ui/typography';
import type { Config } from 'tailwindcss';
const config: Config = {
content: [],
corePlugins: {
preflight: true,
},
plugins: [sfTypography],
presets: [tailwindConfig],
theme: {
extend: {
colors: {
// Uncomment to customize your primary color
// primary: {
// 50: '#f5f9ff',
// 100: '#e9f3ff',
// 200: '#c8e0ff',
// 300: '#a6ccff',
// 400: '#6ea1ff',
// 500: '#3375ff',
// 600: '#2e6ae6',
// 700: '#264ebf',
// 800: '#1d3f99',
// 900: '#132f72',
// },
},
fontFamily: {
body: 'var(--font-body)',
headings: 'var(--font-headings)',
},
screens: {
'2-extra-large': '1366px',
'2-extra-small': '360px',
'3-extra-large': '1536px',
'4-extra-large': '1920px',
'extra-large': '1280px',
'extra-small': '376px',
large: '1024px',
medium: '768px',
small: '640px',
},
},
},
};
export default config;
Create packages/tailwind-config/src/index.ts
:
export * from './nextjs';
Create packages/tailwind-config/package.json
:
{
"name": "tailwind-config",
"version": "0.0.1",
"private": true,
"main": "dist/index.cjs",
"exports": {
".": {
"import": {
"default": "./dist/index.mjs",
"types": "./dist/index.d.mts"
},
"require": {
"default": "./dist/index.cjs",
"types": "./dist/index.d.cts"
},
"types": "./dist/index.d.ts"
},
"./nextjs": {
"import": {
"default": "./dist/nextjs.mjs",
"types": "./dist/nextjs.d.mts"
},
"require": {
"default": "./dist/nextjs.cjs",
"types": "./dist/nextjs.d.cts"
},
"types": "./dist/nextjs.d.ts"
},
},
"scripts": {
"build": "unbuild",
"prepare": "yarn build"
},
"dependencies": {
"@storefront-ui/react": "2.7.1",
"@storefront-ui/typography": "2.6.1",
"tailwindcss": "3.4.4"
},
"devDependencies": {
"typescript": "5.4.5",
"unbuild": "2.0.0"
},
"files": [
"dist"
]
}
- Update app configurations to use shared packages:
First, rename the Prettier configuration files to use the .mjs
extension:
mv apps/playwright/.prettierrc apps/playwright/.prettierrc.mjs
mv apps/storefront-middleware/.prettierrc apps/storefront-middleware/.prettierrc.mjs
mv apps/storefront-unified-nextjs/.prettierrc apps/storefront-unified-nextjs/.prettierrc.mjs
Then update the configuration files:
Update apps/storefront-unified-nextjs/eslint.config.mjs
:
export { default } from 'eslint-config/nextjs';
Update apps/storefront-unified-nextjs/.prettierrc.mjs
:
export { default } from 'prettier-config/nextjs';
Update apps/storefront-unified-nextjs/lint-staged.config.mjs
:
export { default } from 'lint-staged-config/nextjs';
Update apps/storefront-unified-nextjs/tailwind.config.ts
:
import tailwindConfig from 'tailwind-config/nextjs';
import type { Config } from 'tailwindcss';
const config: Config = {
content: [
'./app/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./sf-modules/**/*.{js,ts,jsx,tsx}',
'../../node_modules/@storefront-ui/react/**/*.js',
// For multistore `.out` folder
'../../../node_modules/@storefront-ui/react/**/*.js',
],
presets: [tailwindConfig],
};
export default config;
Update apps/playwright/eslint.config.mjs
:
export { default } from 'eslint-config/playwright';
Update apps/playwright/.prettierrc.mjs
:
export { default } from 'prettier-config/playwright';
Update apps/playwright/lint-staged.config.mjs
:
export { default } from 'lint-staged-config/playwright';
Update apps/storefront-middleware/eslint.config.mjs
:
export { default } from 'eslint-config/middleware';
Update apps/storefront-middleware/.prettierrc.mjs
:
export { default } from 'prettier-config/middleware';
Update apps/storefront-middleware/lint-staged.config.mjs
:
export { default } from 'lint-staged-config/middleware';
After setting up the shared configuration packages, run:
yarn install
yarn lint:fix
This will install all the new dependencies and ensure all files matches ESLint rules.
If yarn lint:fix
finds any issues that it cannot automatically fix, we recommend addressing these issues before proceeding with the migration. This ensures your codebase is in a consistent state and helps prevent potential problems later in the migration process.
2
Update Turbo
- Update the Turbo version in your root
package.json
:
{
"dependencies": {
- "turbo": "1.10.5",
+ "turbo": "2.4.4",
}
}
- Add package manager specification to your root
package.json
:
{
+ "packageManager": "yarn@1.22.22"
}
- Update your
turbo.json
configuration to use the new tasks format:
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"storefront-middleware#build": {
"dependsOn": ["^build"],
"outputs": ["lib/**"]
},
"storefront-unified-nextjs#build": {
"dependsOn": [
"^build",
"storefront-middleware#build",
"tailwind-config#build"
],
"outputs": [".next/**", "!.next/cache/**"]
},
"test:unit": {
"dependsOn": ["^build"]
},
"test:integration": {
"dependsOn": ["^build"],
"inputs": ["tests/**/*.ts", "mocks/**/*.ts", "setup/**/*.ts"],
"outputs": ["test-results/**", "playwright-report/**"]
},
"playwright#test:integration": {
"dependsOn": ["^build"],
"inputs": ["tests/**/*.ts", "mocks/**/*.ts", "setup/**/*.ts"],
"outputs": ["test-results/**", "playwright-report/**"]
},
"playwright#test:integration:ui": {
"dependsOn": [],
"cache": false
},
"start": {
"outputs": []
},
"start:standalone": {
"outputs": []
},
"lint": {
"dependsOn": []
},
"format": {
"outputs": []
},
"dev": {
"cache": false
},
"prepare": {
"dependsOn": [],
"cache": false
},
"playwright-default#test:integration": {
"dependsOn": ["^build"],
"inputs": ["**"],
"outputs": ["test-results/**", "playwright-report/**"]
},
"playwright-default#test:integration:ui": {
"dependsOn": [],
"cache": false,
"inputs": ["**"]
},
"storefront-middleware-default#build": {
"dependsOn": ["^build"],
"outputs": ["lib/**"],
"inputs": ["**"]
},
"storefront-unified-nextjs-default#build": {
"dependsOn": [
"^build",
"storefront-middleware-default#build",
"tailwind-config#build"
],
"outputs": [".next/**", "!.next/cache/**"],
"inputs": ["**"]
}
}
}
After updating Turbo, run:
yarn install
Test if the Turbo update works correctly:
yarn dev
If you encounter any issues with the yarn dev
command, make sure all dependencies are properly installed and the Turbo configuration is correct. Fix any reported errors before proceeding to the next step.
3
Update Apps
- Update Frontend Configuration:
Update apps/storefront-unified-nextjs/next.config.mjs
:
experimental: {
- outputFileTracingRoot: join(fileURLToPath(import.meta.url), '..', '..'),
+ outputFileTracingRoot: join(fileURLToPath(import.meta.url), '..', '..', '..', '..'),
typedRoutes: true,
},
Update apps/storefront-unified-nextjs/tsconfig.json
:
{
"compilerOptions": {
"paths": {
"@/*": ["./*"],
"@sf-modules-middleware/*": ["../storefront-middleware/sf-modules/*"],
"@sf-modules/*": ["./sf-modules/*"],
+ "storefront-middleware/*": ["../storefront-middleware/*"]
}
}
}
- Update Middleware Configuration:
Update apps/storefront-middleware/tsconfig.json
:
{
"compilerOptions": {
"esModuleInterop": true,
"skipLibCheck": true,
"target": "es2022",
"allowJs": true,
"resolveJsonModule": true,
"moduleDetection": "force",
"isolatedModules": true,
"verbatimModuleSyntax": false,
"strict": true,
"noImplicitOverride": true,
"lib": ["es2022"],
"forceConsistentCasingInFileNames": true,
"module": "Node16",
"moduleResolution": "Node16",
"rootDir": ".",
"outDir": "lib",
"paths": {
"@sf-modules-middleware/*": ["./sf-modules/*"]
},
"plugins": [
{ "transform": "typescript-transform-paths" },
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
]
},
"include": ["**/*.ts"],
"exclude": ["dist", "lib", "node_modules", ".turbo"]
}
- Update Playwright Configuration:
Update apps/playwright/package.json
:
{
"scripts": {
"lint:fix": "eslint --fix .",
"format": "prettier --write .",
"test:integration:dev": "PW_DEV=true playwright test --ui",
"test:integration": "playwright test",
+ "test:integration:ui": "playwright test --ui"
}
}
Update server configurations in apps/playwright/setup/framework/nextjs/server-dev.ts
and server.ts
to include envs and error handling:
const server = exec(
'yarn dev',
{
cwd: nextRootDir,
env: {
...process.env,
NEXT_PUBLIC_ALOKAI_MIDDLEWARE_API_URL: `http://localhost:${middlewarePort}`,
NEXT_PUBLIC_ALOKAI_MIDDLEWARE_SSR_API_URL: `http://localhost:${middlewarePort}`,
PORT: String(port),
TEST_BUILD_DIR: join('.next', 'test', `${workerInfo.workerIndex}`),
},
},
(error) => {
if (error !== null) {
debug && console.log(`[WORKER ${workerInfo.workerIndex}] Next.js server encountered an error: ${error}`);
}
}
);
4
Add Alokai CLI
- Update your
.npmrc
file:
+@alokai:registry=https://registrynpm.storefrontcloud.io/
@vsf-enterprise:registry=https://registrynpm.storefrontcloud.io/
auto-install-peers=true
- Update your root
package.json
workspaces. Include.out/*/*
directory which will include the output directories for all stores.
{
"workspaces": [
"apps/*",
"packages/*",
+ ".out/*/*"
]
}
- Install
@alokai/cli
. It requirescross-env
to be present in the dependencies.
yarn add @alokai/cli@0.2.0 cross-env -W
5
Set Up Alokai Configuration
- Create
alokai.config.json
:
{
"$schema": "node_modules/@alokai/cli/dist/static/alokaiConfigSchema.json",
"stores": {}
}
- Update
.gitignore
:
// ... existing code ...
+.out/
After setting up the Alokai configuration, create your first store:
yarn exec alokai-cli store add
Store Name
When creating your first store, you can use any name you prefer. If you plan to have just one store, using the name default
is recommended.
6
Update Scripts
- Add
scripts/clean-out-dir.mjs
which will be make sure that.out
directory doesn't contain outdated files:
import { existsSync, rm } from "node:fs";
import { join } from "node:path";
// This script is intended to be run before installing packages, as the .out directory is now part of the workspace.
// To avoid installing outdated packages, the script removes the .out directory, which may contain outdated packages.
const outPath = join(process.cwd(), ".out");
if (existsSync(outPath)) {
console.log("Removing temporary .out directory...");
rm(outPath, { recursive: true }, (error) => {
if (error) {
console.error(`Error removing temporary .out directory: ${error}`);
} else {
console.log("Done!");
}
});
}
- Update the root
package.json
scripts:
{
"scripts": {
"build": "turbo run build --filter=!\"./apps/**\" --filter=!\"./.out/**\" && alokai-cli store build --all",
"postinstall": "yarn build:packages",
"build:packages": "turbo run build --filter='./packages/*'",
"dev": "alokai-cli store dev --all --verbose",
"format": "alokai-cli store build --all --compose-only && turbo run format",
"init": "yarn install && node init.mjs && mkdir -p .out",
"lint": "alokai-cli store build --all --compose-only && turbo run lint --filter=!\"./apps/**\"",
"lint:fix": "alokai-cli store build --all --compose-only && turbo run lint:fix --filter=!\"./apps/**\"",
"preinstall": "node scripts/clean-out-dir.mjs",
"prepare": "husky install && turbo run prepare",
"start": "alokai-cli store start --all --verbose",
"store": "alokai-cli store",
"test:integration:pw": "alokai-cli store test --all",
"typecheck": "alokai-cli store build --all --compose-only && turbo run typecheck --filter=!\"./apps/**\""
}
}
After updating the build scripts, test your setup:
yarn dev
Once the development server is running and everything looks good, you can check also if the build succeeds:
yarn build
7
Set Up CI/CD Pipeline
- Create
.github/actions/affected-stores/action.yml
:
name: Affected Stores
description: Determines which stores are affected based on the GitHub event type and commits.
inputs:
since:
description: Optional base commit SHA for determining changes.
required: false
to:
description: Optional head commit SHA for determining changes.
required: false
cli_bin_path:
description: Path to Alokai CLI bin
default: ./node_modules/.bin/alokai-cli
required: false
outputs:
storeIds:
description: A JSON array of store ids that are affected.
value: ${{ steps.affectedStores.outputs.storeIds }}
storeIdsFlag:
description: A CLI-ready flag for the Alokai CLI. This will be empty when all or no stores are affected.
value: ${{ steps.affectedStores.outputs.storeIdsFlag }}
runs:
using: composite
steps:
- name: Determine affected stores
id: affectedStores
shell: bash
run: |
if [ ${{ github.event_name }} == "workflow_dispatch" ]; then
echo "Triggered by workflow dispatch. All stores are affected."
echo "storeIds=$(jq -c '.stores | keys' alokai.config.json)" >> "$GITHUB_OUTPUT"
echo "storeIdsFlag=--all" >> "$GITHUB_OUTPUT"
exit 0
fi
OPTIONAL_SINCE_FLAG=""
OPTIONAL_TO_FLAG=""
if [ -n "${{ inputs.since }}" ]; then
OPTIONAL_SINCE_FLAG="--since=${{ inputs.since }}"
fi
if [ -n "${{ inputs.to }}" ]; then
OPTIONAL_TO_FLAG="--to=${{ inputs.to }}"
fi
${{ inputs.cli_bin_path }} store changed $OPTIONAL_SINCE_FLAG $OPTIONAL_TO_FLAG > changed_stores.json
echo "Changed stores report:"
cat changed_stores.json
STORES=$(jq -r '.[].storeId' changed_stores.json | tr '\n' ' ' | sed 's/ $//')
if [ -z "$STORES" ]; then
echo "No stores affected."
echo "storeIds=[]" >> "$GITHUB_OUTPUT"
echo "storeIdsFlag=" >> "$GITHUB_OUTPUT"
else
echo "Stores that have changed: $STORES"
echo "storeIds=$(jq -c '[.[].storeId]' changed_stores.json)" >> "$GITHUB_OUTPUT"
echo "storeIdsFlag=--store-id $STORES" >> "$GITHUB_OUTPUT"
fi
- Create
.github/actions/setup/action.yml
:
name: Setup repository
description: Installs all the packages and initializes environment variables
inputs:
npm_user:
description: Enterprise NPM registry user
type: string
required: true
npm_password:
description: Enterprise NPM registry password
type: string
required: true
npm_email:
description: Enterprise NPM registry email
type: string
required: true
runs:
using: composite
steps:
- name: Use Node.js based on .nvmrc file
uses: actions/setup-node@v4
with:
node-version-file: ./.nvmrc
- name: Yarn cache
uses: actions/cache@v4
with:
path: .yarn
key: storefront-demo-yarn-cache
- name: Cache turbo build setup
uses: actions/cache@v4
with:
path: .turbo
key: starter-turbo-${{ github.sha }}
restore-keys: |
starter-turbo-
- name: Configure NPM registry
shell: bash
run: |
npm install -g npm-cli-login;
npm-cli-login -u ${{ inputs.npm_user }} -p ${{ inputs.npm_password }} -e ${{ inputs.npm_email }} -r https://registrynpm.storefrontcloud.io || exit 1;
- name: Install dependencies
shell: bash
run: yarn install --frozen-lockfile --cache-folder .yarn && node init.mjs
- Create
.github/workflows/continuous-integration.yml
:
name: CI
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
node_version: [18]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
uses: ./.github/actions/setup
with:
npm_user: ${{ vars.NPM_USER }}
npm_password: ${{ secrets.NPM_PASS }}
npm_email: ${{ vars.NPM_EMAIL }}
- name: Find affected stores
id: affectedStores
uses: ./.github/actions/affected-stores
with:
since: ${{ github.event.pull_request.base.sha }}
to: ${{ github.event.pull_request.head.sha }}
- name: Build affected stores
if: ${{ steps.affectedStores.outputs.storeIds != '[]' }}
run: |
yarn store build ${{ steps.affectedStores.outputs.storeIdsFlag }} --cache-dir=.turbo
- name: Lint project
run: yarn lint
- name: Install Playwright Browsers
run: yarn playwright install --with-deps chromium
- name: Run integration tests in Playwright
if: ${{ steps.affectedStores.outputs.storeIds != '[]' }}
run: yarn store test ${{ steps.affectedStores.outputs.storeIdsFlag }}
- Create
.github/workflows/continuous-delivery.yml
:
name: Deployment
on:
push:
branches:
- main
workflow_dispatch:
inputs:
store_ids:
description: "Space separated list of store IDs to deploy (optional). Example: store1 store2"
required: false
default: ""
verbose:
description: "Enable verbose output (true/false)."
required: false
default: "false"
jobs:
chooseStoresToDeploy:
name: Choose stores to deploy
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
outputs:
storeIds: ${{ steps.outputStoresToDeploy.outputs.storeIds }}
storeIdsFlag: ${{ steps.outputStoresToDeploy.outputs.storeIdsFlag }}
verbose: ${{ github.event.inputs.verbose == 'true' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure NPM registry
run: |
npm install -g npm-cli-login;
npm-cli-login -u ${{ vars.NPM_USER }} -p ${{ secrets.NPM_PASS }} -e ${{ vars.NPM_EMAIL }} -r https://registrynpm.storefrontcloud.io/
- name: Choose CLI version
id: cli_version
run: |
echo CLI_VERSION=$(jq -r '.dependencies["@alokai/cli"]' package.json) >> $GITHUB_OUTPUT
- name: Find affected stores
if: ${{ github.event.inputs.store_ids == '' }}
id: affectedStores
uses: ./.github/actions/affected-stores
with:
cli_bin_path: npx @alokai/cli@${{ steps.cli_version.outputs.cli_version }}
- name: Output stores to deploy
id: outputStoresToDeploy
run: |
if [ -n "${{ github.event.inputs.store_ids }}" ]; then
echo "storeIds=$(echo ${{ github.event.inputs.store_ids }} | jq -R 'split(" ")' -c)" >> "$GITHUB_OUTPUT"
echo "storeIdsFlag=--store-id ${{ github.event.inputs.store_ids }}" >> "$GITHUB_OUTPUT"
else
echo 'storeIds=${{ steps.affectedStores.outputs.storeIds }}' >> "$GITHUB_OUTPUT"
echo "storeIdsFlag=${{ steps.affectedStores.outputs.storeIdsFlag }}" >> "$GITHUB_OUTPUT"
fi
deploy:
name: Deploy ${{ matrix.store_id }} store
needs: chooseStoresToDeploy
if: needs.chooseStoresToDeploy.outputs.storeIds != '[]'
runs-on: ubuntu-latest
strategy:
matrix:
store_id: ${{ fromJson(needs.chooseStoresToDeploy.outputs.storeIds) }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.store_id }}
cancel-in-progress: true
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
uses: ./.github/actions/setup
with:
npm_user: ${{ vars.NPM_USER }}
npm_password: ${{ secrets.NPM_PASS }}
npm_email: ${{ vars.NPM_EMAIL }}
- name: 🚀 Deploy store
run: |
echo "Deploying store: ${{ matrix.store_id }}"
yarn store deploy \
--cloud-username ${{ vars.CLOUD_USERNAME }} \
--cloud-password ${{ secrets.CLOUD_PASSWORD }} \
--docker-registry-url ${{ vars.DOCKER_REGISTRY_URL }} \
--store-id ${{ matrix.store_id }} \
--verbose ${{ needs.chooseStoresToDeploy.outputs.verbose }}
Learn More About Deployment
For more details about how deployment works in Alokai Multistore, check out our Deployment guide.