With the release of new Apple silicon chips, this new architecture has lead to some issues with Slate failing on M1 Macs. However, since Slate is no longer supported by Shopify, it is unlikely we'll see an official fix. Follow this guide to fix the issue:
Open your terminal app using Rosetta
You may need to set your terminal app to open using Rosetta. More info on why can be found here:
Update Themekit Version
This solution is based on a discussion here regarding a crash when trying to install/run Slate on M1 Macs due to the dependency on @shopify/themekit
v0.6 in slate-tools
and slate-sync
.
Adding a resolutions
block to update to the latest themekit version in package.json
appears to fix the issue.
Add the following to your project's package.json
, below the dependencies
block:
"resolutions": {
"**/@shopify/themekit": "^1.1.9"
}
An issue may still remain: It looks like the themekit api changed when compared to v0.6.x
. We will also need to manually update one of the node_modules found in @shopify/slate-sync
.
This change effects how configs are send to themekit. Replace the entirety of `node_modules/@shopify/slate-sync/index.js` with the following snippet so it looks like this: (The changes were based on this PR):
const chalk = require('chalk');
const figures = require('figures');
const https = require('https');
const themekit = require('@shopify/themekit');
const slateEnv = require('@shopify/slate-env');
const SlateConfig = require('@shopify/slate-config');
const config = new SlateConfig(require('./slate-sync.schema'));
let deploying = false;
let filesToDeploy = [];
function maybeDeploy() {
if (deploying) {
return Promise.reject(new Error('Deploy already in progress.'));
}
if (filesToDeploy.length) {
const files = [...filesToDeploy];
filesToDeploy = [];
return deploy('upload', files);
}
return Promise.resolve();
}
function _validateEnvValues() {
const result = slateEnv.validate();
if (!result.isValid) {
console.log(
chalk.red(
`Some values in environment '${slateEnv.getEnvNameValue()}' are invalid:`,
),
);
result.errors.forEach((error) => {
console.log(chalk.red(`- ${error}`));
});
process.exit(1);
}
}
function _generateConfigFlags(cmd) {
_validateEnvValues();
const flags = {
password: slateEnv.getPasswordValue(),
themeid: slateEnv.getThemeIdValue(),
store: slateEnv.getStoreValue(),
env: slateEnv.getEnvNameValue(),
};
if (cmd === 'upload') {
flags.nodelete = true;
}
if (slateEnv.getTimeoutValue()) {
flags.timeout = slateEnv.getTimeoutValue();
}
if (slateEnv.getIgnoreFilesValue()) {
flags.ignoredFiles = slateEnv.getIgnoreFilesValue().split(':');
}
// Convert object to key value pairs and flatten the array
return flags;
}
/**
* Deploy to Shopify using themekit.
*
* @param cmd String The command to run
* @param files Array An array of files to deploy
* @return Promise
*/
async function deploy(cmd = '', files = []) {
if (!['upload', 'replace'].includes(cmd)) {
throw new Error(
'shopify-deploy.deploy() first argument must be either "upload", "replace"',
);
}
deploying = true;
console.log(chalk.magenta(`\n${figures.arrowUp} Uploading to Shopify...\n`));
try {
await themekit.command('configure', _generateConfigFlags(), {
cwd: config.get('paths.theme.dist'),
});
await themekit.command(
'deploy',
{
..._generateConfigFlags(cmd),
files,
},
{
cwd: config.get('paths.theme.dist'),
},
);
} catch (error) {
console.error('My Error', error);
}
deploying = false;
return maybeDeploy;
}
/**
* Fetch the main theme ID from Shopify
*
* @param env String The environment to check against
* @return Promise Reason for abort or the main theme ID
*/
function fetchMainThemeId() {
_validateEnvValues();
return new Promise((resolve, reject) => {
https.get(
{
hostname: slateEnv.getStoreValue(),
path: '/admin/themes.json',
auth: `:${slateEnv.getPasswordValue}`,
agent: false,
headers: {
X-Shopify-Access-Token': slateEnv.getPasswordValue(),
},
},
(res) => {
let body = '';
res.on('data', (datum) => (body += datum));
res.on('end', () => {
const parsed = JSON.parse(body);
if (parsed.errors) {
reject(
new Error(
`API request to fetch main theme ID failed: \n${JSON.stringify(
parsed.errors,
null,
'\t',
)}`,
),
);
return;
}
if (!Array.isArray(parsed.themes)) {
reject(
new Error(
`Shopify response for /admin/themes.json is not an array. ${JSON.stringify(
parsed,
null,
'\t',
)}`,
),
);
return;
}
const mainTheme = parsed.themes.find((t) => t.role === 'main');
if (!mainTheme) {
reject(
new Error(
`No main theme in response. ${JSON.stringify(
parsed.themes,
null,
'\t',
)}`,
),
);
return;
}
resolve(mainTheme.id);
});
},
);
});
}
module.exports = {
sync(files = []) {
if (!files.length) {
return Promise.reject(new Error('No files to deploy.'));
}
filesToDeploy = [...new Set([...filesToDeploy, ...files])];
return maybeDeploy();
},
replace() {
return deploy('replace');
},
upload() {
return deploy('upload');
},
fetchMainThemeId,
};
Source: ARM64 (Apple M1) support ยท Issue #1107 ยท Shopify/slate ยท GitHub
Optional: Fixing ssl issues (ie. styles/scripts not loading in localhost)
If the above changes have worked, you should find that Slate spins up a development server as expected. However, your styles and scripts may not be working. This is due to an issue with mkcert
used to create a self-signed SSL certificate. If you are on a new Mac, you will need to install this.
- Install mkcert with homebrew:
brew install mkcert
- Install a new CA into the key store:
mkcert -install
- Run
brew install nss
- If using FireFox, you may need to run
arch -arm64 brew install nss
and then re -runmkcert -install
li> - Copy and paste this bash function into your terminal (or into your
.bashrc
file if you want to have it available in the future):function ssl-check() { f=~/.localhost_ssl; ssl_crt=$f/server.crt ssl_key=$f/server.key b=$(tput bold) c=$(tput sgr0) # local_ip=$(ip route get 8.8.4.4 | head -1 | awk '{print $7}') # Linux Version local_ip=$(ipconfig getifaddr $(route get default | grep interface | awk '{print $2}')) # Mac Version # local_ip=999.999.999 # (uncomment for testing) domains=( "localhost" "$local_ip" ) if [[ ! -f $ssl_crt ]]; then echo -e "\n๐ ${b}Couldn't find a Slate SSL certificate:${c}" make_key=true elif [[ ! $(openssl x509 -noout -text -in $ssl_crt | grep $local_ip) ]]; then echo -e "\n๐ ${b}Your IP Address has changed:${c}" make_key=true else echo -e "\nโ ${b}Your IP address is still the same.${c}" fi if [[ $make_key == true ]]; then echo -e "Generating a new Slate SSL certificate...\n" count=$(( ${#domains[@]} - 1)) mkcert ${domains[@]} # Create Slate's default certificate directory, if it doesn't exist test ! -d $f && mkdir $f # It appears mkcert bases its filenames off the number of domains passed after the first one. # This script predicts that filename, so it can copy it to Slate's default location. if [[ $count = 0 ]]; then mv ./localhost.pem $ssl_crt mv ./localhost-key.pem $ssl_key else mv ./localhost+$count.pem $ssl_crt mv ./localhost+$count-key.pem $ssl_key fi fi }
- Run
ssl-check
in the terminal.
โ ๏ธ Note: macOS Monterey now uses ZSH as the default shell, so if you are used to using bash, you will need to typebash
in the console to access the function in your.bashrc
file, and then typeexit
to get back out.