Skip to content

Commit b2ce805

Browse files
Adding support for Sandbox Storefront "Remote Control"
This featured, when configured with `rvw_devtools` cartridge, allows you to post messages to your Sandbox Storefront via an injected JS Script Tag.
1 parent 0d7c525 commit b2ce805

23 files changed

+476
-167
lines changed

.browser-refresh

Lines changed: 0 additions & 5 deletions
This file was deleted.

.eslintrc.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module.exports = {
77
env: {
88
es6: true,
99
node: true,
10-
browser: false
10+
browser: true
1111
},
1212
plugins: [
1313
'prettier'
@@ -35,5 +35,8 @@ module.exports = {
3535
}
3636
],
3737
'no-console': 0
38+
},
39+
globals: {
40+
'io': true
3841
}
3942
}

.gitignore

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
.DS_Store
22
node_modules
33
npm-debug.log
4-
5-
# Generated SSL Files
6-
localhost.crt
7-
localhost.key
4+
remote/ssl/sfcc-cli-localhost.*

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ Introduction
1313

1414
Make developing for Salesforce Commerce Cloud work with any IDE on MacOS, Windows, and Linux.
1515

16-
- [X] Easily Manage Multiple Clients & Instances
17-
- [X] Watch for code changes and upload in background ( without being prompted for passwords )
18-
- [X] Log Viewing with Advanced Search & Filter Capabilities
16+
![checkmark](https://sfcc-cli.s3.amazonaws.com/checkmark.png) Easily Manage Multiple Clients & Instances
17+
![checkmark](https://sfcc-cli.s3.amazonaws.com/checkmark.png) Watch for code changes and upload in background ( without being prompted for passwords )
18+
![checkmark](https://sfcc-cli.s3.amazonaws.com/checkmark.png) Support for Eclipse Build Processes
19+
![checkmark](https://sfcc-cli.s3.amazonaws.com/checkmark.png) Log Viewing with Advanced Search & Filter Capabilities
20+
![checkmark](https://sfcc-cli.s3.amazonaws.com/checkmark.png) Sandbox Storefront "Remote Control"
1921

2022
Developer Overview
2123
---
@@ -27,6 +29,7 @@ Developer Overview
2729
* [`sfcc delete`](docs/cmd-delete.md) - Delete Config for Client
2830
* [`sfcc watch`](docs/cmd-watch.md) - Watch for Changes and Push Updates
2931
* [`sfcc log`](docs/cmd-log.md) - View Logs with Advanced Search & Filter Capabilities
32+
* [`sfcc remote`](docs/cmd-remote.md) - Remote Control for your Sandbox
3033
* [`sfcc help`](docs/cmd-help.md) - Get Help when you need it
3134

3235
#### Additional Information

bin/cli.js

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const argv = yargs
4747
})
4848
.command('list', 'List Configured SFCC Clients')
4949
.command('delete <client> [instance]', 'Delete Config for Client')
50-
.command('watch [client] [instance]', 'Watch for Code Changes and Push Updates', {
50+
.command('watch [client] [instance]', 'Watch for Changes and Push Updates', {
5151
log: {
5252
describe: 'Pipe Output to ~/.sffc-cli.log',
5353
type: 'boolean',
@@ -112,29 +112,17 @@ const argv = yargs
112112
default: false
113113
}
114114
})
115-
.command('live-reload [client] [instance]', 'Reload Sandbox Browser after file change', {
116-
delay: {
117-
alias: 'd',
118-
describe: 'Timeout Delay after Upload (seconds)',
119-
type: 'number',
120-
default: 2
121-
},
122-
include: {
123-
alias: 'i',
124-
describe: 'File Extensions to Include',
125-
type: 'array',
126-
default: []
127-
},
128-
exclude: {
129-
alias: 'e',
130-
describe: 'File Extensions to Exclude',
131-
type: 'array',
132-
default: []
115+
.command('remote [client] [instance]', 'Remote Control your Sandbox', {
116+
'live-reload': {
117+
describe: 'Enable Live Reload on Code Change',
118+
type: 'boolean',
119+
default: false
133120
}
134121
})
135122
.example('sfcc delete my-client sandbox', 'Delete my-client sandbox config')
136123
.example('sfcc watch my-client sandbox', 'Watch for my-client sandbox changes')
137124
.example('sfcc log -i customerror --latest', 'Watch Latest Custom Error Logs')
125+
.example('sfcc remote --use=live-reload', 'Live Reload Sandbox on Changes')
138126
.demand(1)
139127
.help()
140128
.version().argv

commands/live-reload.js

Lines changed: 0 additions & 94 deletions
This file was deleted.

commands/remote.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
const argv = require('minimist')(process.argv.slice(2))
2+
const chalk = require('chalk')
3+
const express = require('express')
4+
const fs = require('fs')
5+
const https = require('https')
6+
const ipc = require('node-ipc')
7+
const ora = require('ora')
8+
const path = require('path')
9+
10+
const config = require('../lib/config')()
11+
const notify = require('../lib/notify')()
12+
13+
const port = 8443
14+
15+
module.exports = async options => {
16+
let client = argv['_'][1] || null
17+
let instance = argv['_'][2] || null
18+
let selected = null
19+
let remote
20+
let reloadTimeout
21+
22+
// Get Client & Instance, or check for Default
23+
if (client && instance) {
24+
selected = config.get(client, instance)
25+
} else {
26+
const defaultConfig = config.get(client, instance, true)
27+
28+
if (defaultConfig) {
29+
client = defaultConfig.client
30+
instance = defaultConfig.instance
31+
selected = defaultConfig.config
32+
}
33+
}
34+
35+
if (selected) {
36+
const sslKey = path.resolve(__dirname, '../remote/ssl/sfcc-cli-ca.pvk')
37+
const sslCrt = path.resolve(__dirname, '../remote/ssl/sfcc-cli-ca.cer')
38+
const jsFile = path.resolve(__dirname, '../remote/sfcc-cli-remote.js')
39+
40+
// Start Message Bus
41+
ipc.config.id = 'remote'
42+
ipc.config.retry = 1500
43+
ipc.config.silent = true
44+
ipc.serve(() => {
45+
ipc.server.on('message', cmd => {
46+
// Check if `remote` exists from socket.io and listen for commands
47+
if (remote && typeof remote.emit !== 'undefined') {
48+
// Handle Live Reload if enabled
49+
if (cmd === 'live-reload' && options.liveReload) {
50+
clearTimeout(reloadTimeout)
51+
reloadTimeout = setTimeout(() => {
52+
notify({
53+
title: `${client} ${instance}`,
54+
icon: path.join(__dirname, '../icons/', 'sfcc-reload.png'),
55+
subtitle: 'LIVE RELOAD',
56+
message: `Sending Reload Request to Sandbox`
57+
})
58+
59+
remote.emit('refresh', true)
60+
}, 3000)
61+
}
62+
}
63+
})
64+
})
65+
66+
ipc.server.start()
67+
68+
// Check that SSL files exist
69+
if (!fs.existsSync(sslKey)) {
70+
console.log(chalk.red.bold(`✖ Missing ${sslKey}`))
71+
console.log('See ./docs/cmd-remote.md for setup instructions.')
72+
process.exit()
73+
}
74+
75+
if (!fs.existsSync(sslCrt)) {
76+
console.log(chalk.red.bold(`✖ Missing ${sslCrt}`))
77+
console.log('See ./docs/cmd-remote.md for setup instructions.')
78+
process.exit()
79+
}
80+
81+
// Start Socket Server
82+
const app = express()
83+
const server = https.createServer(
84+
{
85+
key: fs.readFileSync(sslKey),
86+
cert: fs.readFileSync(sslCrt)
87+
},
88+
app
89+
)
90+
91+
const io = require('socket.io')(server)
92+
93+
// https://localhost:8443/sfcc-cli-remote.js
94+
app.get('/sfcc-cli-remote.js', (req, res) => {
95+
res.set('Content-Type', 'application/javascript')
96+
res.send(fs.readFileSync(jsFile))
97+
})
98+
99+
// Handle connections from remote script
100+
io.on('connection', socket => {
101+
remote = socket
102+
// Check if Live Reload flag was enabled
103+
if (options.liveReload) {
104+
remote.emit('message', 'Live Reload Enabled')
105+
}
106+
})
107+
108+
server.listen(port, function() {
109+
console.log(`\n${chalk.bold('IMPORTANT')}: Make sure your sandbox has the following script tag:`)
110+
console.log('<script src="https://localhost:8443/sfcc-cli-remote.js" id="sfcc-cli-remote"></script>\n')
111+
112+
ora(
113+
`${chalk.bold('REMOTE')} ${chalk.cyan.bold(client)} ${chalk.magenta.bold(instance)} [Ctrl-C to Cancel]\n`
114+
).start()
115+
})
116+
}
117+
}

commands/watch.js

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const argv = require('minimist')(process.argv.slice(2))
22
const chalk = require('chalk')
33
const chokidar = require('chokidar')
4+
const ipc = require('node-ipc')
45
const ora = require('ora')
56
const path = require('path')
67
const {exec} = require('child_process')
@@ -15,7 +16,6 @@ module.exports = options => {
1516
let instance = argv['_'][2] || null
1617
let selected = null
1718
let errorMessage
18-
let logMessage
1919

2020
const useLog = options.log
2121
const errorsOnly = options.errorsOnly
@@ -35,13 +35,30 @@ module.exports = options => {
3535

3636
if (selected) {
3737
let spinner
38+
3839
const watcher = chokidar.watch(selected.d, {
3940
ignored: [/[/\\]\./, '**/node_modules/**'],
4041
ignoreInitial: true,
4142
persistent: true,
4243
awaitWriteFinish: true
4344
})
4445

46+
// Connect to Remote Message Bus
47+
let remote = null
48+
49+
ipc.config.id = 'upload'
50+
ipc.config.retry = 1500
51+
ipc.config.silent = true
52+
53+
ipc.connectTo('remote', () => {
54+
ipc.of.remote.on('connect', () => {
55+
remote = ipc.of.remote
56+
})
57+
ipc.of.remote.on('disconnect', () => {
58+
remote = null
59+
})
60+
})
61+
4562
const buildCheck = file => {
4663
if (Object.keys(selected.b).length > 0) {
4764
const checkPath = path.dirname(file).replace(path.normalize(selected.d), '')
@@ -71,13 +88,20 @@ module.exports = options => {
7188
}
7289
}
7390

91+
const callback = () => {
92+
if (typeof remote.emit !== 'undefined') {
93+
remote.emit('message', 'live-reload')
94+
}
95+
}
96+
7497
// Watch for File Changes
7598
watcher.on('change', file => {
76-
upload({file, spinner, selected, client, instance, options})
99+
upload({file, spinner, selected, client, instance, options, callback})
77100
buildCheck(file)
78101
})
102+
79103
watcher.on('add', file => {
80-
upload({file, spinner, selected, client, instance, options})
104+
upload({file, spinner, selected, client, instance, options, callback})
81105
buildCheck(file)
82106
})
83107

@@ -115,11 +139,12 @@ module.exports = options => {
115139
})
116140
}
117141

118-
logMessage = `Watching ${client} ${instance}`
119142
if (useLog) {
120-
logger.log(logMessage, true)
143+
logger.log(`Watching ${client} ${instance}`, true)
121144
} else {
122-
spinner = ora(`${chalk.bold(logMessage)} [Ctrl-C to Cancel]\n`).start()
145+
spinner = ora(
146+
`${chalk.bold('WATCHING')} ${chalk.cyan.bold(client)} ${chalk.magenta.bold(instance)} [Ctrl-C to Cancel]\n`
147+
).start()
123148
}
124149
})
125150
} else if (client && instance) {

0 commit comments

Comments
 (0)