Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dev): support dev https server #208

Merged
merged 1 commit into from
May 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"rollup": "^2.7.2",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-vue": "^6.0.0-beta.1",
"selfsigned": "^1.10.7",
"slash": "^3.0.0",
"vue": "^3.0.0-beta.14",
"ws": "^7.2.3"
Expand Down
10 changes: 3 additions & 7 deletions src/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,11 @@ async function resolveOptions() {
return argv
}

async function runServe(
options: UserConfig & {
port?: number
open?: boolean
}
) {
async function runServe(options: UserConfig) {
const server = require('../dist').createServer(options)

let port = options.port || 3000
const protocol = options.https ? 'https' : 'http'
server.on('error', (e: Error & { code?: string }) => {
if (e.code === 'EADDRINUSE') {
console.log(`Port ${port} is in use, trying another one...`)
Expand Down Expand Up @@ -146,7 +142,7 @@ async function runServe(
}
})
.forEach(({ type, host }) => {
const url = `http://${host}:${chalk.bold(port)}/`
const url = `${protocol}://${host}:${chalk.bold(port)}/`
console.log(` > ${type} ${chalk.cyan(url)}`)
})
})
Expand Down
8 changes: 8 additions & 0 deletions src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Rollup, {
import { Transform } from './transform'
import { DepOptimizationOptions } from './depOptimizer'
import { IKoaProxiesOptions } from 'koa-proxies'
import { ServerOptions } from 'https'

export { Resolver, Transform }

Expand Down Expand Up @@ -84,6 +85,13 @@ export interface SharedConfig {
}

export interface ServerConfig extends SharedConfig {
port?: number
open?: boolean
/**
* Configure https.
*/
https?: boolean
httpsOption?: ServerOptions
/**
* Configure custom proxy rules for the dev server. Uses
* [`koa-proxies`](https://github.com/vagusX/koa-proxies) which in turn uses
Expand Down
48 changes: 45 additions & 3 deletions src/node/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import http, { Server } from 'http'
import { RequestListener, Server } from 'http'
import { ServerOptions } from 'https'
import Koa from 'koa'
import chokidar from 'chokidar'
import { createResolver, InternalResolver } from '../resolver'
Expand All @@ -15,7 +16,9 @@ import { ServerConfig } from '../config'
import { createServerTransformPlugin } from '../transform'
import { serviceWorkerPlugin } from './serverPluginServiceWorker'
import { proxyPlugin } from './serverPluginProxy'

import { createCertificate } from '../utils/createCertificate'
import fs from 'fs-extra'
import path from 'path'
export { rewriteImports } from './serverPluginModuleRewrite'

export type ServerPlugin = (ctx: ServerPluginContext) => void
Expand All @@ -40,7 +43,7 @@ export function createServer(config: ServerConfig = {}): Server {
} = config

const app = new Koa()
const server = http.createServer(app.callback())
const server = resolveServer(config, app.callback())
const watcher = chokidar.watch(root, {
ignored: [/node_modules/]
}) as HMRWatcher
Expand Down Expand Up @@ -82,3 +85,42 @@ export function createServer(config: ServerConfig = {}): Server {

return server
}

function resolveServer(
{ https = false, httpsOption = {} }: ServerConfig,
requestListener: RequestListener
) {
if (https) {
return require('https').createServer(
resolveHttpsConfig(httpsOption),
requestListener
)
} else {
return require('http').createServer(requestListener)
}
}

function resolveHttpsConfig(httpsOption: ServerOptions) {
const { ca, cert, key, pfx } = httpsOption
Object.assign(httpsOption, {
ca: readFileIfExits(ca),
cert: readFileIfExits(cert),
key: readFileIfExits(key),
pfx: readFileIfExits(pfx)
})
if (!httpsOption.key || !httpsOption.cert) {
httpsOption.cert = httpsOption.key = createCertificate()
}
return httpsOption
}

function readFileIfExits(value?: string | Buffer | any) {
if (value && !Buffer.isBuffer(value)) {
try {
return fs.readFileSync(path.resolve(value as string))
} catch (e) {
return value
}
}
return value
}
65 changes: 65 additions & 0 deletions src/node/utils/createCertificate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// https://github.com/webpack/webpack-dev-server/blob/master/lib/utils/createCertificate.js
export function createCertificate() {
const pems = require('selfsigned').generate(null, {
algorithm: 'sha256',
days: 30,
keySize: 2048,
extensions: [
// {
// name: 'basicConstraints',
// cA: true,
// },
{
name: 'keyUsage',
keyCertSign: true,
digitalSignature: true,
nonRepudiation: true,
keyEncipherment: true,
dataEncipherment: true
},
{
name: 'extKeyUsage',
serverAuth: true,
clientAuth: true,
codeSigning: true,
timeStamping: true
},
{
name: 'subjectAltName',
altNames: [
{
// type 2 is DNS
type: 2,
value: 'localhost'
},
{
type: 2,
value: 'localhost.localdomain'
},
{
type: 2,
value: 'lvh.me'
},
{
type: 2,
value: '*.lvh.me'
},
{
type: 2,
value: '[::1]'
},
{
// type 7 is IP
type: 7,
ip: '127.0.0.1'
},
{
type: 7,
ip: 'fe80::1'
}
]
}
]
})
return pems.private + pems.cert
}
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4858,6 +4858,11 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==

[email protected]:
version "0.9.0"
resolved "http://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
integrity sha1-1iQFDtu0SHStyhK7mlLsY8t4JXk=

node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
Expand Down Expand Up @@ -6376,6 +6381,13 @@ saxes@^3.1.9:
dependencies:
xmlchars "^2.1.1"

selfsigned@^1.10.7:
version "1.10.7"
resolved "http://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b"
integrity sha1-2lgZ/QSdVXTyjoipvMbbxubzkGs=
dependencies:
node-forge "0.9.0"

semver-compare@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
Expand Down