2017-01-12 04:14:49 +00:00
|
|
|
import fetch from 'node-fetch'
|
|
|
|
import qs from 'querystring'
|
2017-02-09 13:40:09 +00:00
|
|
|
import http from 'http'
|
2017-05-09 23:24:34 +00:00
|
|
|
import express from 'express'
|
2017-07-20 16:00:45 +00:00
|
|
|
import path from 'path'
|
|
|
|
import portfinder from 'portfinder'
|
|
|
|
import { spawn } from 'child_process'
|
2018-02-26 16:18:46 +00:00
|
|
|
import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs'
|
2017-07-20 16:00:45 +00:00
|
|
|
import fkill from 'fkill'
|
2017-01-12 04:14:49 +00:00
|
|
|
|
|
|
|
import server from '../../dist/server/next'
|
|
|
|
import build from '../../dist/server/build'
|
2017-05-09 23:24:34 +00:00
|
|
|
import _export from '../../dist/server/export'
|
2017-01-12 04:14:49 +00:00
|
|
|
import _pkg from '../../package.json'
|
|
|
|
|
|
|
|
export const nextServer = server
|
|
|
|
export const nextBuild = build
|
2017-05-09 23:24:34 +00:00
|
|
|
export const nextExport = _export
|
2017-01-12 04:14:49 +00:00
|
|
|
export const pkg = _pkg
|
|
|
|
|
2018-02-02 14:43:36 +00:00
|
|
|
export function initNextServerScript (scriptPath, successRegexp, env) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const instance = spawn('node', [scriptPath], { env })
|
|
|
|
|
|
|
|
function handleStdout (data) {
|
|
|
|
const message = data.toString()
|
|
|
|
if (successRegexp.test(message)) {
|
|
|
|
resolve(instance)
|
|
|
|
}
|
|
|
|
process.stdout.write(message)
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleStderr (data) {
|
|
|
|
process.stderr.write(data.toString())
|
|
|
|
}
|
|
|
|
|
|
|
|
instance.stdout.on('data', handleStdout)
|
|
|
|
instance.stderr.on('data', handleStderr)
|
|
|
|
|
|
|
|
instance.on('close', () => {
|
|
|
|
instance.stdout.removeListener('data', handleStdout)
|
|
|
|
instance.stderr.removeListener('data', handleStderr)
|
|
|
|
})
|
|
|
|
|
|
|
|
instance.on('error', (err) => {
|
|
|
|
reject(err)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-10-22 19:00:31 +00:00
|
|
|
export function renderViaAPI (app, pathname, query) {
|
|
|
|
const url = `${pathname}${query ? `?${qs.stringify(query)}` : ''}`
|
2017-05-03 16:40:09 +00:00
|
|
|
return app.renderToHTML({ url }, {}, pathname, query)
|
2017-01-12 04:14:49 +00:00
|
|
|
}
|
|
|
|
|
2017-10-22 19:00:31 +00:00
|
|
|
export function renderViaHTTP (appPort, pathname, query) {
|
2017-11-05 19:17:03 +00:00
|
|
|
return fetchViaHTTP(appPort, pathname, query).then((res) => res.text())
|
|
|
|
}
|
|
|
|
|
|
|
|
export function fetchViaHTTP (appPort, pathname, query) {
|
2017-10-22 19:00:31 +00:00
|
|
|
const url = `http://localhost:${appPort}${pathname}${query ? `?${qs.stringify(query)}` : ''}`
|
2017-11-05 19:17:03 +00:00
|
|
|
return fetch(url)
|
2017-01-12 04:14:49 +00:00
|
|
|
}
|
2017-02-09 13:40:09 +00:00
|
|
|
|
2017-07-20 16:00:45 +00:00
|
|
|
export function findPort () {
|
|
|
|
portfinder.basePort = 20000 + Math.ceil(Math.random() * 10000)
|
|
|
|
return portfinder.getPortPromise()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Launch the app in dev mode.
|
|
|
|
export function launchApp (dir, port) {
|
|
|
|
const cwd = path.resolve(__dirname, '../../')
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const instance = spawn('node', ['dist/bin/next', dir, '-p', port], { cwd })
|
|
|
|
|
|
|
|
function handleStdout (data) {
|
|
|
|
const message = data.toString()
|
|
|
|
if (/> Ready on/.test(message)) {
|
|
|
|
resolve(instance)
|
|
|
|
}
|
|
|
|
process.stdout.write(message)
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleStderr (data) {
|
|
|
|
process.stderr.write(data.toString())
|
|
|
|
}
|
|
|
|
|
|
|
|
instance.stdout.on('data', handleStdout)
|
|
|
|
instance.stderr.on('data', handleStderr)
|
|
|
|
|
|
|
|
instance.on('close', () => {
|
|
|
|
instance.stdout.removeListener('data', handleStdout)
|
|
|
|
instance.stderr.removeListener('data', handleStderr)
|
|
|
|
})
|
|
|
|
|
|
|
|
instance.on('error', (err) => {
|
|
|
|
reject(err)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Kill a launched app
|
|
|
|
export async function killApp (instance) {
|
|
|
|
await fkill(instance.pid)
|
|
|
|
}
|
|
|
|
|
2017-02-09 13:40:09 +00:00
|
|
|
export async function startApp (app) {
|
|
|
|
await app.prepare()
|
|
|
|
const handler = app.getRequestHandler()
|
|
|
|
const server = http.createServer(handler)
|
|
|
|
server.__app = app
|
|
|
|
|
|
|
|
await promiseCall(server, 'listen')
|
|
|
|
return server
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function stopApp (app) {
|
2017-05-09 23:24:34 +00:00
|
|
|
if (server.__app) {
|
|
|
|
await server.__app.close()
|
|
|
|
}
|
2017-02-09 13:40:09 +00:00
|
|
|
await promiseCall(server, 'close')
|
|
|
|
}
|
|
|
|
|
|
|
|
function promiseCall (obj, method, ...args) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const newArgs = [
|
|
|
|
...args,
|
|
|
|
function (err, res) {
|
|
|
|
if (err) return reject(err)
|
|
|
|
resolve(res)
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
obj[method](...newArgs)
|
|
|
|
})
|
|
|
|
}
|
2017-02-26 19:45:16 +00:00
|
|
|
|
|
|
|
export function waitFor (millis) {
|
|
|
|
return new Promise((resolve) => setTimeout(resolve, millis))
|
|
|
|
}
|
2017-05-09 23:24:34 +00:00
|
|
|
|
|
|
|
export async function startStaticServer (dir) {
|
|
|
|
const app = express()
|
|
|
|
const server = http.createServer(app)
|
|
|
|
app.use(express.static(dir))
|
|
|
|
|
|
|
|
await promiseCall(server, 'listen')
|
|
|
|
return server
|
|
|
|
}
|
2018-02-26 16:18:46 +00:00
|
|
|
|
|
|
|
export async function check (contentFn, regex) {
|
|
|
|
while (true) {
|
|
|
|
try {
|
|
|
|
const newContent = await contentFn()
|
|
|
|
if (regex.test(newContent)) break
|
|
|
|
await waitFor(1000)
|
|
|
|
} catch (ex) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class File {
|
|
|
|
constructor (path) {
|
|
|
|
this.path = path
|
|
|
|
this.originalContent = existsSync(this.path) ? readFileSync(this.path, 'utf8') : null
|
|
|
|
}
|
|
|
|
|
|
|
|
write (content) {
|
|
|
|
if (!this.originalContent) {
|
|
|
|
this.originalContent = content
|
|
|
|
}
|
|
|
|
writeFileSync(this.path, content, 'utf8')
|
|
|
|
}
|
|
|
|
|
|
|
|
replace (pattern, newValue) {
|
|
|
|
const newContent = this.originalContent.replace(pattern, newValue)
|
|
|
|
this.write(newContent)
|
|
|
|
}
|
|
|
|
|
|
|
|
delete () {
|
|
|
|
unlinkSync(this.path)
|
|
|
|
}
|
|
|
|
|
|
|
|
restore () {
|
|
|
|
this.write(this.originalContent)
|
|
|
|
}
|
|
|
|
}
|