Skip to content
This repository was archived by the owner on Sep 12, 2019. It is now read-only.

Commit f6ab1c8

Browse files
author
sw-yx
committed
add open browser
1 parent ecb0208 commit f6ab1c8

File tree

2 files changed

+157
-51
lines changed

2 files changed

+157
-51
lines changed

src/commands/dev/index.js

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
const {flags} = require('@oclif/command')
2-
const {spawn} = require('child_process')
1+
const { flags } = require('@oclif/command')
2+
const { spawn } = require('child_process')
33
const http = require('http')
44
const httpProxy = require('http-proxy')
55
const waitPort = require('wait-port')
66
const getPort = require('get-port')
7-
const {serveFunctions} = require('@netlify/zip-it-and-ship-it')
8-
const {serverSettings} = require('../../detect-server')
7+
const { serveFunctions } = require('@netlify/zip-it-and-ship-it')
8+
const { serverSettings } = require('../../detect-server')
9+
const openBrowser = require('./openBrowser')
910
const Command = require('@netlify/cli-utils')
10-
const {getAddons} = require('netlify/src/addons')
11+
const { getAddons } = require('netlify/src/addons')
1112

1213
function cleanExit() {
1314
process.exit()
@@ -26,47 +27,45 @@ function addonUrl(addonUrls, req) {
2627
async function startProxy(settings, addonUrls) {
2728
const rulesProxy = require('netlify-rules-proxy')
2829

29-
await waitPort({port: settings.proxyPort})
30+
await waitPort({ port: settings.proxyPort })
3031
if (settings.functionsPort) {
31-
await waitPort({port: settings.functionsPort})
32+
await waitPort({ port: settings.functionsPort })
3233
}
33-
const port = await getPort({port: settings.port})
34-
const functionsServer = settings.functionsPort ?
35-
`http://localhost:${settings.functionsPort}` :
36-
null
34+
const port = await getPort({ port: settings.port })
35+
const functionsServer = settings.functionsPort ? `http://localhost:${settings.functionsPort}` : null
3736

3837
const proxy = httpProxy.createProxyServer({
3938
target: {
4039
host: 'localhost',
41-
port: settings.proxyPort,
42-
},
40+
port: settings.proxyPort
41+
}
4342
})
4443

45-
const rewriter = rulesProxy({publicFolder: settings.dist})
44+
const rewriter = rulesProxy({ publicFolder: settings.dist })
4645

47-
const server = http.createServer(function (req, res) {
46+
const server = http.createServer(function(req, res) {
4847
if (isFunction(settings, req)) {
49-
return proxy.web(req, res, {target: functionsServer})
48+
return proxy.web(req, res, { target: functionsServer })
5049
}
5150
let url = addonUrl(addonUrls, req)
5251
if (url) {
53-
return proxy.web(req, res, {target: url})
52+
return proxy.web(req, res, { target: url })
5453
}
5554

5655
rewriter(req, res, () => {
5756
if (isFunction(settings, req)) {
58-
return proxy.web(req, res, {target: functionsServer})
57+
return proxy.web(req, res, { target: functionsServer })
5958
}
6059
url = addonUrl(addonUrls, req)
6160
if (url) {
62-
return proxy.web(req, res, {target: url})
61+
return proxy.web(req, res, { target: url })
6362
}
6463

65-
proxy.web(req, res, {target: `http://localhost:${settings.proxyPort}`})
64+
proxy.web(req, res, { target: `http://localhost:${settings.proxyPort}` })
6665
})
6766
})
6867

69-
server.on('upgrade', function (req, socket, head) {
68+
server.on('upgrade', function(req, socket, head) {
7069
proxy.ws(req, socket, head)
7170
})
7271

@@ -89,17 +88,17 @@ function startDevServer(settings, log, error) {
8988
name: 'netlify-dev',
9089
port: settings.proxyPort,
9190
templates: {
92-
notFound: '404.html',
93-
},
91+
notFound: '404.html'
92+
}
9493
})
9594

96-
server.start(function () {
95+
server.start(function() {
9796
log('Server listening to', settings.proxyPort)
9897
})
9998
return
10099
}
101100

102-
const ps = spawn(settings.cmd, settings.args, {env: settings.env})
101+
const ps = spawn(settings.cmd, settings.args, { env: settings.env })
103102

104103
ps.stdout.on('data', data => {
105104
log(`${data}`.replace(settings.urlRegexp, `$1$2${settings.port}$3`))
@@ -119,28 +118,24 @@ function startDevServer(settings, log, error) {
119118

120119
class DevCommand extends Command {
121120
async run() {
122-
const {flags, args} = this.parse(DevCommand)
123-
const {api, site, config} = this.netlify
121+
const { flags, args } = this.parse(DevCommand)
122+
const { api, site, config } = this.netlify
124123
const functionsDir =
125-
flags.functions ||
126-
(config.dev && config.dev.functions) ||
127-
(config.build && config.build.functions)
124+
flags.functions || (config.dev && config.dev.functions) || (config.build && config.build.functions)
128125
const addonUrls = {}
129126
if (site.id && !flags.offline) {
130127
const accessToken = await this.authenticate()
131128
const addons = await getAddons(site.id, accessToken)
132129
if (Array.isArray(addons)) {
133130
addons.forEach(addon => {
134-
addonUrls[addon.slug] = `${addon.config.site_url}/.netlify/${
135-
addon.slug
136-
}`
131+
addonUrls[addon.slug] = `${addon.config.site_url}/.netlify/${addon.slug}`
137132
for (const key in addon.env) {
138133
process.env[key] = process.env[key] || addon.env[key]
139134
}
140135
})
141136
}
142137
const api = this.netlify.api
143-
const apiSite = await api.getSite({site_id: site.id})
138+
const apiSite = await api.getSite({ site_id: site.id })
144139
// TODO: We should move the environment outside of build settings and possibly have a
145140
// `/api/v1/sites/:site_id/environment` endpoint for it that we can also gate access to
146141
// In the future and that we could make context dependend
@@ -154,55 +149,50 @@ class DevCommand extends Command {
154149
let settings = serverSettings(config.dev)
155150
if (!(settings && settings.cmd)) {
156151
this.log('No dev server detected, using simple static server')
157-
const dist =
158-
(config.dev && config.dev.publish) ||
159-
(config.build && config.build.publish)
152+
const dist = (config.dev && config.dev.publish) || (config.build && config.build.publish)
160153
settings = {
161154
noCmd: true,
162155
port: 8888,
163156
proxyPort: 3999,
164-
dist,
157+
dist
165158
}
166159
}
167160
startDevServer(settings, this.log, this.error)
168161
if (functionsDir) {
169-
const fnSettings = await serveFunctions({functionsDir})
162+
const fnSettings = await serveFunctions({ functionsDir })
170163
settings.functionsPort = fnSettings.port
171164
}
172165

173166
const url = await startProxy(settings, addonUrls)
174167
this.log(`Netlify dev server is now ready on ${url}`)
168+
openBrowser(url)
175169
}
176170
}
177171

178172
DevCommand.description = `Local dev server
179173
The dev command will run a local dev server with Netlify's proxy and redirect rules
180174
`
181175

182-
DevCommand.examples = [
183-
'$ netlify dev',
184-
'$ netlify dev -c "yarn start"',
185-
'$ netlify dev -c hugo',
186-
]
176+
DevCommand.examples = ['$ netlify dev', '$ netlify dev -c "yarn start"', '$ netlify dev -c hugo']
187177

188178
DevCommand.strict = false
189179

190180
DevCommand.flags = {
191-
cmd: flags.string({char: 'c', description: 'command to run'}),
181+
cmd: flags.string({ char: 'c', description: 'command to run' }),
192182
devport: flags.integer({
193183
char: 'd',
194-
description: 'port of the dev server started by command',
184+
description: 'port of the dev server started by command'
195185
}),
196-
port: flags.integer({char: 'p', description: 'port of netlify dev'}),
197-
dir: flags.integer({char: 'd', description: 'dir with static files'}),
186+
port: flags.integer({ char: 'p', description: 'port of netlify dev' }),
187+
dir: flags.integer({ char: 'd', description: 'dir with static files' }),
198188
functions: flags.string({
199189
char: 'f',
200-
description: 'Specify a functions folder to serve',
190+
description: 'Specify a functions folder to serve'
201191
}),
202192
offline: flags.boolean({
203193
char: 'o',
204-
description: 'disables any features that require network access',
205-
}),
194+
description: 'disables any features that require network access'
195+
})
206196
}
207197

208198
module.exports = DevCommand

src/commands/dev/openBrowser.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// from https://github.com/facebook/create-react-app/blob/7864ba3ce70892ebe43d56487b45d3267890df14/packages/react-dev-utils/openBrowser.js
2+
3+
'use strict'
4+
5+
var chalk = require('chalk')
6+
var execSync = require('child_process').execSync
7+
var spawn = require('cross-spawn')
8+
var opn = require('opn')
9+
10+
// https://github.com/sindresorhus/opn#app
11+
var OSX_CHROME = 'google chrome'
12+
13+
const Actions = Object.freeze({
14+
NONE: 0,
15+
BROWSER: 1,
16+
SCRIPT: 2
17+
})
18+
19+
function getBrowserEnv() {
20+
// Attempt to honor this environment variable.
21+
// It is specific to the operating system.
22+
// See https://github.com/sindresorhus/opn#app for documentation.
23+
const value = process.env.BROWSER
24+
let action
25+
if (!value) {
26+
// Default.
27+
action = Actions.BROWSER
28+
} else if (value.toLowerCase().endsWith('.js')) {
29+
action = Actions.SCRIPT
30+
} else if (value.toLowerCase() === 'none') {
31+
action = Actions.NONE
32+
} else {
33+
action = Actions.BROWSER
34+
}
35+
return { action, value }
36+
}
37+
38+
function executeNodeScript(scriptPath, url) {
39+
const extraArgs = process.argv.slice(2)
40+
const child = spawn('node', [scriptPath, ...extraArgs, url], {
41+
stdio: 'inherit'
42+
})
43+
child.on('close', code => {
44+
if (code !== 0) {
45+
console.log()
46+
console.log(chalk.red('The script specified as BROWSER environment variable failed.'))
47+
console.log(chalk.cyan(scriptPath) + ' exited with code ' + code + '.')
48+
console.log()
49+
return
50+
}
51+
})
52+
return true
53+
}
54+
55+
function startBrowserProcess(browser, url) {
56+
// If we're on OS X, the user hasn't specifically
57+
// requested a different browser, we can try opening
58+
// Chrome with AppleScript. This lets us reuse an
59+
// existing tab when possible instead of creating a new one.
60+
const shouldTryOpenChromeWithAppleScript =
61+
process.platform === 'darwin' && (typeof browser !== 'string' || browser === OSX_CHROME)
62+
63+
if (shouldTryOpenChromeWithAppleScript) {
64+
try {
65+
// Try our best to reuse existing tab
66+
// on OS X Google Chrome with AppleScript
67+
execSync('ps cax | grep "Google Chrome"')
68+
execSync('osascript openChrome.applescript "' + encodeURI(url) + '"', {
69+
cwd: __dirname,
70+
stdio: 'ignore'
71+
})
72+
return true
73+
} catch (err) {
74+
// Ignore errors.
75+
}
76+
}
77+
78+
// Another special case: on OS X, check if BROWSER has been set to "open".
79+
// In this case, instead of passing `open` to `opn` (which won't work),
80+
// just ignore it (thus ensuring the intended behavior, i.e. opening the system browser):
81+
// https://github.com/facebook/create-react-app/pull/1690#issuecomment-283518768
82+
if (process.platform === 'darwin' && browser === 'open') {
83+
browser = undefined
84+
}
85+
86+
// Fallback to opn
87+
// (It will always open new tab)
88+
try {
89+
var options = { app: browser, wait: false }
90+
opn(url, options).catch(() => {}) // Prevent `unhandledRejection` error.
91+
return true
92+
} catch (err) {
93+
return false
94+
}
95+
}
96+
97+
/**
98+
* Reads the BROWSER environment variable and decides what to do with it. Returns
99+
* true if it opened a browser or ran a node.js script, otherwise false.
100+
*/
101+
function openBrowser(url) {
102+
const { action, value } = getBrowserEnv()
103+
switch (action) {
104+
case Actions.NONE:
105+
// Special case: BROWSER="none" will prevent opening completely.
106+
return false
107+
case Actions.SCRIPT:
108+
return executeNodeScript(value, url)
109+
case Actions.BROWSER:
110+
return startBrowserProcess(value, url)
111+
default:
112+
throw new Error('Not implemented.')
113+
}
114+
}
115+
116+
module.exports = openBrowser

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy