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

Commit

Permalink
🌅
Browse files Browse the repository at this point in the history
Signed-off-by: David Calavera <david.calavera@gmail.com>
  • Loading branch information
biilmann authored and calavera committed Jan 31, 2019
0 parents commit 88b4c52
Show file tree
Hide file tree
Showing 23 changed files with 683 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "oclif"
}
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*-debug.log
*-error.log
/.nyc_output
/dist
/package-lock.json
/tmp
node_modules
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
netlify-dev-plugin
==================

Netlify development tools plugin

[![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
[![Version](https://img.shields.io/npm/v/netlify-dev-plugin.svg)](https://npmjs.org/package/netlify-dev-plugin)
[![Downloads/week](https://img.shields.io/npm/dw/netlify-dev-plugin.svg)](https://npmjs.org/package/netlify-dev-plugin)
[![License](https://img.shields.io/npm/l/netlify-dev-plugin.svg)](https://github.com/netlify/netlify-dev-plugin/blob/master/package.json)

<!-- toc -->
* [Usage](#usage)
* [Commands](#commands)
<!-- tocstop -->
# Usage
<!-- usage -->
```sh-session
$ npm install -g netlify-dev-plugin
$ oclif-example COMMAND
running command...
$ oclif-example (-v|--version|version)
netlify-dev-plugin/0.1.0 linux-x64 node-v10.15.0
$ oclif-example --help [COMMAND]
USAGE
$ oclif-example COMMAND
...
```
<!-- usagestop -->
# Commands
<!-- commands -->
* [`oclif-example hello`](#oclif-example-hello)

## `oclif-example hello`

Describe the command here

```
USAGE
$ oclif-example hello
OPTIONS
-n, --name=name name to print
DESCRIPTION
...
Extra documentation goes here
```

_See code: [src/commands/hello.js](https://github.com/netlify/netlify-dev-plugin/blob/v0.1.0/src/commands/hello.js)_
<!-- commandsstop -->
4 changes: 4 additions & 0 deletions bin/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env node

require('@oclif/command').run()
.catch(require('@oclif/errors/handle'))
3 changes: 3 additions & 0 deletions bin/run.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@echo off

node "%~dp0\run" %*
56 changes: 56 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"name": "netlify-dev-plugin",
"description": "Netlify development tools plugin",
"version": "0.1.0",
"author": "David Calavera @calavera",
"bugs": "https://github.com/netlify/netlify-dev-plugin/issues",
"dependencies": {
"@oclif/command": "^1",
"@oclif/config": "^1",
"get-port": "^4.1.0",
"http-proxy": "^1.17.0",
"netlify": "ssh+git://git@github.com:netlify/js-client-private",
"netlify-rules-proxy": "ssh+git://git@github.com:netlify/netlify-rules-proxy",
"zip-it-and-ship-it": " ssh+git://git@github.com:netlify/zip-it-and-ship-it.git"
},
"devDependencies": {
"@oclif/dev-cli": "^1",
"@oclif/plugin-help": "^2",
"@oclif/test": "^1",
"chai": "^4",
"eslint": "^5.5",
"eslint-config-oclif": "^3.1",
"globby": "^8",
"mocha": "^5",
"nyc": "^13"
},
"engines": {
"node": ">=8.0.0"
},
"files": [
"/npm-shrinkwrap.json",
"/oclif.manifest.json",
"/src",
"/yarn.lock"
],
"homepage": "https://github.com/netlify/netlify-dev-plugin",
"keywords": [
"oclif-plugin"
],
"license": "MIT",
"oclif": {
"commands": "./src/commands",
"bin": "netlify",
"devPlugins": [
"@oclif/plugin-help"
]
},
"repository": "netlify/netlify-dev-plugin",
"scripts": {
"postpack": "rm -f oclif.manifest.json",
"posttest": "eslint .",
"prepack": "oclif-dev manifest && oclif-dev readme",
"test": "nyc mocha --forbid-only \"test/**/*.test.js\"",
"version": "oclif-dev readme && git add README.md"
}
}
31 changes: 31 additions & 0 deletions src/commands/dev/exec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const { spawn } = require('child_process')
const Command = require('@netlify/cli-utils')
const { getAddons } = require('netlify/src/addons')

class ExecCommand extends Command {
async run() {
const { site } = this.netlify

if (site.id) {
const accessToken = await this.authenticate()
const addons = await getAddons(site.id, accessToken)
addons.forEach(addon => {
for (const key in addon.env) {
process.env[key] = addon.env[key]
}
})
}
spawn(this.argv[0], this.argv.slice(1), { env: process.env, stdio: 'inherit' })
}
}

ExecCommand.description = `Exec command
Runs a command within the netlify dev environment
`

ExecCommand.examples = ['$ netlify exec npm run bootstrap']

ExecCommand.strict = false
ExecCommand.parse = false

module.exports = ExecCommand
142 changes: 142 additions & 0 deletions src/commands/dev/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
const { flags } = require('@oclif/command')
const { spawn } = require('child_process')
const http = require('http')
const httpProxy = require('http-proxy')
const waitPort = require('wait-port')
const getPort = require('get-port')
const { serveFunctions } = require('zip-it-and-ship-it')
const { serverSettings } = require('../../utils/detect-server')
const Command = require('../../base')
const { getAddons } = require('netlify/src/addons')

function cleanExit() {
process.exit()
}

function isFunction(settings, req) {
return settings.functionsPort && req.url.match(/^\/.netlify\/functions\/.+/)
}

function addonUrl(addonUrls, req) {
const m = req.url.match(/^\/.netlify\/([^\/]+)(\/.*)/)
const addonUrl = m && addonUrls[m[1]]
return addonUrl ? `${addonUrl}${m[2]}` : null
}

async function startProxy(settings, addonUrls) {
const rulesProxy = require('netlify-rules-proxy')

await waitPort({ port: settings.proxyPort })
if (settings.functionsPort) {
await waitPort({ port: settings.functionsPort })
}
const port = await getPort({ port: settings.port })
const functionsServer = settings.functionsPort ? `http://localhost:${settings.functionsPort}` : null

const proxy = httpProxy.createProxyServer({
target: {
host: 'localhost',
port: settings.proxyPort
}
})

const rewriter = rulesProxy({ publicFolder: settings.dist })

const server = http.createServer(function(req, res) {
if (isFunction(settings, req)) {
return proxy.web(req, res, { target: functionsServer })
}
let url = addonUrl(addonUrls, req)
if (url) {
return proxy.web(req, res, { target: url })
}

rewriter(req, res, () => {
if (isFunction(settings, req)) {
return proxy.web(req, res, { target: functionsServer })
}
url = addonUrl(addonUrls, req)
if (url) {
return proxy.web(req, res, { target: url })
}

proxy.web(req, res, { target: `http://localhost:${settings.proxyPort}` })
})
})

server.on('upgrade', function(req, socket, head) {
proxy.ws(req, socket, head)
})

server.listen(port)
return `http://localhost:${port}`
}

function startDevServer(settings, log, error) {
const ps = spawn(settings.cmd, settings.args, { env: settings.env })

ps.stdout.on('data', data => {
log(`${data}`.replace(settings.urlRegexp, `$1$2${settings.port}$3`))
})

ps.stderr.on('data', data => {
error(`${data}`)
})

ps.on('close', code => {
process.exit(code)
})

ps.on('SIGINT', cleanExit)
ps.on('SIGTERM', cleanExit)
}

class DevCommand extends Command {
async run() {
const { flags, args } = this.parse(DevCommand)
const { api, site, config } = this.netlify
const functionsDir = flags.functions || (config.build && config.build.functions)
const addonUrls = {}
if (site.id && !flags.offline) {
const accessToken = await this.authenticate()
const addons = await getAddons(site.id, accessToken)
addons.forEach(addon => {
addonUrls[addon.slug] = `${addon.config.site_url}/.netlify/${addon.slug}`
for (const key in addon.env) {
process.env[key] = addon.env[key]
}
})
}
const settings = serverSettings()
startDevServer(settings, this.log, this.error)
if (functionsDir) {
const fnSettings = await serveFunctions({ functionsDir })
settings.functionsPort = fnSettings.port
}

const url = await startProxy(settings, addonUrls)
this.log(`Netlify dev server is now ready on ${url}`)
}
}

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

DevCommand.examples = ['$ netlify dev', '$ netlify dev -c "yarn start"', '$ netlify dev -c hugo']

DevCommand.strict = false

DevCommand.flags = {
cmd: flags.string({ char: 'c', description: 'command to run' }),
devport: flags.integer({ char: 'd', description: 'port of the dev server started by command' }),
port: flags.integer({ char: 'p', description: 'port of netlify dev' }),
dir: flags.integer({ char: 'd', description: 'dir with static files' }),
functions: flags.string({
char: 'f',
description: 'Specify a functions folder to serve'
}),
offline: flags.boolean({ char: 'o', description: 'disables any features that require network access' })
}

module.exports = DevCommand
19 changes: 19 additions & 0 deletions src/commands/functions/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { Command, flags } = require('@oclif/command')

class FunctionsBuildCommand extends Command {
async run() {
this.log(`build a function locally`)
}
}

FunctionsBuildCommand.description = `build functions locally
`

FunctionsBuildCommand.flags = {
name: flags.string({char: 'n', description: 'name to print'}),
}

// TODO make visible once implementation complete
FunctionsBuildCommand.hidden = true

module.exports = FunctionsBuildCommand
Loading

0 comments on commit 88b4c52

Please sign in to comment.