diff --git a/.travis.yml b/.travis.yml
index 757e5cbd..0a6a01d4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,7 +8,6 @@ addons:
- google-chrome-stable
language: node_js
node_js:
- - "4"
- "6"
cache:
directories:
diff --git a/appveyor.yml b/appveyor.yml
index 582b44a6..995d7398 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,6 +1,5 @@
environment:
matrix:
- - nodejs_version: "4"
- nodejs_version: "6"
# Install scripts. (runs after repo cloning)
diff --git a/lib/dynamic.js b/lib/dynamic.js
index 73052e53..0638bc38 100644
--- a/lib/dynamic.js
+++ b/lib/dynamic.js
@@ -54,7 +54,8 @@ export default function dynamicComponent (p, o) {
}
loadComponent () {
- promise.then((AsyncComponent) => {
+ promise.then((m) => {
+ const AsyncComponent = m.default || m
// Set a readable displayName for the wrapper component
const asyncCompName = getDisplayName(AsyncComponent)
if (asyncCompName) {
@@ -65,7 +66,7 @@ export default function dynamicComponent (p, o) {
this.setState({ AsyncComponent })
} else {
if (this.isServer) {
- registerChunk(AsyncComponent.__webpackChunkName)
+ registerChunk(m.__webpackChunkName)
}
this.state.AsyncComponent = AsyncComponent
}
@@ -100,9 +101,10 @@ export default function dynamicComponent (p, o) {
const loadModule = (name) => {
const promise = modulePromiseMap[name]
- promise.then((Component) => {
+ promise.then((m) => {
+ const Component = m.default || m
if (this.isServer) {
- registerChunk(Component.__webpackChunkName)
+ registerChunk(m.__webpackChunkName)
}
moduleMap[name] = Component
remainingPromises--
diff --git a/lib/link.js b/lib/link.js
index ed123864..c7da8fa6 100644
--- a/lib/link.js
+++ b/lib/link.js
@@ -15,9 +15,12 @@ export default class Link extends Component {
}
static propTypes = exact({
- href: PropTypes.string,
- as: PropTypes.string,
+ href: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
+ as: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
prefetch: PropTypes.bool,
+ replace: PropTypes.bool,
+ shallow: PropTypes.bool,
+ passHref: PropTypes.bool,
children: PropTypes.oneOfType([
PropTypes.element,
(props, propName) => {
@@ -29,9 +32,7 @@ export default class Link extends Component {
return null
}
- ]).isRequired,
- shallow: PropTypes.bool,
- passHref: PropTypes.bool
+ ]).isRequired
})
componentWillReceiveProps (nextProps) {
diff --git a/package.json b/package.json
index 1e05937c..32203fe1 100644
--- a/package.json
+++ b/package.json
@@ -118,12 +118,14 @@
"coveralls": "2.13.1",
"cross-env": "5.0.1",
"express": "4.15.2",
+ "fkill": "^5.0.0",
"husky": "0.14.3",
"jest-cli": "20.0.4",
"lint-staged": "^4.0.0",
"node-fetch": "1.7.1",
"node-notifier": "5.1.2",
"nyc": "11.0.3",
+ "portfinder": "^1.0.13",
"react": "15.5.4",
"react-dom": "15.5.4",
"standard": "9.0.2",
diff --git a/server/build/babel/plugins/handle-import.js b/server/build/babel/plugins/handle-import.js
index d1f661d7..930effa7 100644
--- a/server/build/babel/plugins/handle-import.js
+++ b/server/build/babel/plugins/handle-import.js
@@ -13,7 +13,6 @@ const buildImport = (args) => (template(`
eval('require.ensure = function (deps, callback) { callback(require) }')
require.ensure([], (require) => {
let m = require(SOURCE)
- m = m.default || m
m.__webpackChunkName = '${args.name}.js'
resolve(m);
}, 'chunks/${args.name}.js');
@@ -23,13 +22,12 @@ const buildImport = (args) => (template(`
const weakId = require.resolveWeak(SOURCE)
try {
const weakModule = __webpack_require__(weakId)
- return resolve(weakModule.default || weakModule)
+ return resolve(weakModule)
} catch (err) {}
require.ensure([], (require) => {
try {
let m = require(SOURCE)
- m = m.default || m
resolve(m)
} catch(error) {
reject(error)
diff --git a/test/integration/basic/pages/hmr/counter.js b/test/integration/basic/pages/hmr/counter.js
new file mode 100644
index 00000000..26b3834b
--- /dev/null
+++ b/test/integration/basic/pages/hmr/counter.js
@@ -0,0 +1,19 @@
+import React from 'react'
+
+export default class Counter extends React.Component {
+ state = { count: 0 }
+
+ incr () {
+ const { count } = this.state
+ this.setState({ count: count + 1 })
+ }
+
+ render () {
+ return (
+
+
COUNT: {this.state.count}
+
+
+ )
+ }
+}
diff --git a/test/integration/basic/test/hmr.js b/test/integration/basic/test/hmr.js
index 79935c2c..c416b73e 100644
--- a/test/integration/basic/test/hmr.js
+++ b/test/integration/basic/test/hmr.js
@@ -4,6 +4,16 @@ import { readFileSync, writeFileSync, renameSync } from 'fs'
import { join } from 'path'
import { waitFor } from 'next-test-utils'
+async function check (contentFn, regex) {
+ while (true) {
+ try {
+ const newContent = await contentFn()
+ if (regex.test(newContent)) break
+ await waitFor(1000)
+ } catch (ex) {}
+ }
+}
+
export default (context, render) => {
describe('Hot Module Reloading', () => {
describe('syntax error', () => {
@@ -21,18 +31,45 @@ export default (context, render) => {
// change the content
writeFileSync(aboutPagePath, erroredContent, 'utf8')
- const errorMessage = await browser
- .waitForElementByCss('pre')
- .elementByCss('pre').text()
- expect(errorMessage.includes('Unterminated JSX contents')).toBeTruthy()
+ await check(
+ () => browser.elementByCss('body').text(),
+ /Unterminated JSX contents/
+ )
// add the original content
writeFileSync(aboutPagePath, originalContent, 'utf8')
- const newContent = await browser
- .waitForElementByCss('.hmr-about-page')
- .elementByCss('p').text()
- expect(newContent).toBe('This is the about page.')
+ await check(
+ () => browser.elementByCss('body').text(),
+ /This is the about page/
+ )
+
+ browser.close()
+ })
+
+ it('should show the error on all pages', async () => {
+ const aboutPagePath = join(__dirname, '../', 'pages', 'hmr', 'about.js')
+
+ const originalContent = readFileSync(aboutPagePath, 'utf8')
+ const erroredContent = originalContent.replace('', 'div')
+
+ // change the content
+ writeFileSync(aboutPagePath, erroredContent, 'utf8')
+
+ const browser = await webdriver(context.appPort, '/hmr/contact')
+
+ await check(
+ () => browser.elementByCss('body').text(),
+ /Unterminated JSX contents/
+ )
+
+ // add the original content
+ writeFileSync(aboutPagePath, originalContent, 'utf8')
+
+ await check(
+ () => browser.elementByCss('body').text(),
+ /This is the contact page/
+ )
browser.close()
})
@@ -52,27 +89,81 @@ export default (context, render) => {
renameSync(contactPagePath, newContactPagePath)
// wait until the 404 page comes
- while (true) {
- try {
- const pageContent = await browser.elementByCss('body').text()
- if (/This page could not be found/.test(pageContent)) break
- } catch (ex) {}
-
- await waitFor(1000)
- }
+ await check(
+ () => browser.elementByCss('body').text(),
+ /This page could not be found/
+ )
// Rename the file back to the original filename
renameSync(newContactPagePath, contactPagePath)
// wait until the page comes back
- while (true) {
- try {
- const pageContent = await browser.elementByCss('body').text()
- if (/This is the contact page/.test(pageContent)) break
- } catch (ex) {}
+ await check(
+ () => browser.elementByCss('body').text(),
+ /This is the contact page/
+ )
- await waitFor(1000)
- }
+ browser.close()
+ })
+ })
+
+ describe('editing a page', () => {
+ it('should detect the changes and display it', async () => {
+ const browser = await webdriver(context.appPort, '/hmr/about')
+ const text = await browser
+ .elementByCss('p').text()
+ expect(text).toBe('This is the about page.')
+
+ const aboutPagePath = join(__dirname, '../', 'pages', 'hmr', 'about.js')
+
+ const originalContent = readFileSync(aboutPagePath, 'utf8')
+ const editedContent = originalContent.replace('This is the about page', 'COOL page')
+
+ // change the content
+ writeFileSync(aboutPagePath, editedContent, 'utf8')
+
+ await check(
+ () => browser.elementByCss('body').text(),
+ /COOL page/
+ )
+
+ // add the original content
+ writeFileSync(aboutPagePath, originalContent, 'utf8')
+
+ await check(
+ () => browser.elementByCss('body').text(),
+ /This is the about page/
+ )
+
+ browser.close()
+ })
+
+ it('should not reload unrelated pages', async () => {
+ const browser = await webdriver(context.appPort, '/hmr/counter')
+ const text = await browser
+ .elementByCss('button').click()
+ .elementByCss('button').click()
+ .elementByCss('p').text()
+ expect(text).toBe('COUNT: 2')
+
+ const aboutPagePath = join(__dirname, '../', 'pages', 'hmr', 'about.js')
+
+ const originalContent = readFileSync(aboutPagePath, 'utf8')
+ const editedContent = originalContent.replace('This is the about page', 'COOL page')
+
+ // Change the about.js page
+ writeFileSync(aboutPagePath, editedContent, 'utf8')
+
+ // wait for 5 seconds
+ await waitFor(5000)
+
+ // Check whether the this page has reloaded or not.
+ const newText = await browser
+ .elementByCss('p').text()
+ expect(newText).toBe('COUNT: 2')
+
+ // restore the about page content.
+ writeFileSync(aboutPagePath, originalContent, 'utf8')
browser.close()
})
diff --git a/test/integration/basic/test/index.test.js b/test/integration/basic/test/index.test.js
index ebd156b1..5ff68a11 100644
--- a/test/integration/basic/test/index.test.js
+++ b/test/integration/basic/test/index.test.js
@@ -2,34 +2,25 @@
import { join } from 'path'
import {
- nextServer,
- renderViaAPI,
renderViaHTTP,
- startApp,
- stopApp
+ findPort,
+ launchApp,
+ killApp
} from 'next-test-utils'
// test suits
-import xPoweredBy from './xpowered-by'
import rendering from './rendering'
-import misc from './misc'
import clientNavigation from './client-navigation'
import hmr from './hmr'
import dynamic from './dynamic'
const context = {}
-context.app = nextServer({
- dir: join(__dirname, '../'),
- dev: true,
- quiet: true
-})
-
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2
describe('Basic Features', () => {
beforeAll(async () => {
- context.server = await startApp(context.app)
- context.appPort = context.server.address().port
+ context.appPort = await findPort()
+ context.server = await launchApp(join(__dirname, '../'), context.appPort, true)
// pre-build all pages at the start
await Promise.all([
@@ -55,15 +46,16 @@ describe('Basic Features', () => {
renderViaHTTP(context.appPort, '/nav/as-path'),
renderViaHTTP(context.appPort, '/nav/as-path-using-router'),
- renderViaHTTP(context.appPort, '/nested-cdm/index')
+ renderViaHTTP(context.appPort, '/nested-cdm/index'),
+
+ renderViaHTTP(context.appPort, '/hmr/about'),
+ renderViaHTTP(context.appPort, '/hmr/contact'),
+ renderViaHTTP(context.appPort, '/hmr/counter')
])
})
- afterAll(() => stopApp(context.server))
+ afterAll(() => killApp(context.server))
- rendering(context, 'Rendering via API', (p, q) => renderViaAPI(context.app, p, q))
rendering(context, 'Rendering via HTTP', (p, q) => renderViaHTTP(context.appPort, p, q))
- xPoweredBy(context)
- misc(context)
clientNavigation(context, (p, q) => renderViaHTTP(context.appPort, p, q))
dynamic(context, (p, q) => renderViaHTTP(context.appPort, p, q))
hmr(context, (p, q) => renderViaHTTP(context.appPort, p, q))
diff --git a/test/integration/basic/test/misc.js b/test/integration/basic/test/misc.js
deleted file mode 100644
index 29926790..00000000
--- a/test/integration/basic/test/misc.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/* global describe, test, expect */
-
-export default function (context) {
- describe('Misc', () => {
- test('finishes response', async () => {
- const res = {
- finished: false,
- end () {
- this.finished = true
- }
- }
- const html = await context.app.renderToHTML({}, res, '/finish-response', {})
- expect(html).toBeFalsy()
- })
- })
-}
diff --git a/test/integration/basic/test/xpowered-by.js b/test/integration/basic/test/xpowered-by.js
deleted file mode 100644
index 253fbc1d..00000000
--- a/test/integration/basic/test/xpowered-by.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/* global describe, test, expect */
-import { pkg } from 'next-test-utils'
-
-export default function ({ app }) {
- describe('X-Powered-By header', () => {
- test('set it by default', async () => {
- const req = { url: '/stateless', headers: {} }
- const headers = {}
- const res = {
- setHeader (key, value) {
- headers[key] = value
- },
- end () {}
- }
-
- await app.render(req, res, req.url)
- expect(headers['X-Powered-By']).toEqual(`Next.js ${pkg.version}`)
- })
-
- test('do not set it when poweredByHeader==false', async () => {
- const req = { url: '/stateless', headers: {} }
- const originalConfigValue = app.config.poweredByHeader
- app.config.poweredByHeader = false
- const res = {
- setHeader (key, value) {
- if (key === 'X-Powered-By') {
- throw new Error('Should not set the X-Powered-By header')
- }
- },
- end () {}
- }
-
- await app.render(req, res, req.url)
- app.config.poweredByHeader = originalConfigValue
- })
- })
-}
diff --git a/test/integration/basic/pages/finish-response.js b/test/integration/production/pages/finish-response.js
similarity index 100%
rename from test/integration/basic/pages/finish-response.js
rename to test/integration/production/pages/finish-response.js
diff --git a/test/integration/production/test/index.test.js b/test/integration/production/test/index.test.js
index b14e3fbf..17ec832a 100644
--- a/test/integration/production/test/index.test.js
+++ b/test/integration/production/test/index.test.js
@@ -2,6 +2,7 @@
import { join } from 'path'
import {
+ pkg,
nextServer,
nextBuild,
startApp,
@@ -89,5 +90,51 @@ describe('Production Usage', () => {
})
})
+ describe('Misc', () => {
+ it('should handle already finished responses', async () => {
+ const res = {
+ finished: false,
+ end () {
+ this.finished = true
+ }
+ }
+ const html = await app.renderToHTML({}, res, '/finish-response', {})
+ expect(html).toBeFalsy()
+ })
+ })
+
+ describe('X-Powered-By header', () => {
+ it('should set it by default', async () => {
+ const req = { url: '/stateless', headers: {} }
+ const headers = {}
+ const res = {
+ setHeader (key, value) {
+ headers[key] = value
+ },
+ end () {}
+ }
+
+ await app.render(req, res, req.url)
+ expect(headers['X-Powered-By']).toEqual(`Next.js ${pkg.version}`)
+ })
+
+ it('should not set it when poweredByHeader==false', async () => {
+ const req = { url: '/stateless', headers: {} }
+ const originalConfigValue = app.config.poweredByHeader
+ app.config.poweredByHeader = false
+ const res = {
+ setHeader (key, value) {
+ if (key === 'X-Powered-By') {
+ throw new Error('Should not set the X-Powered-By header')
+ }
+ },
+ end () {}
+ }
+
+ await app.render(req, res, req.url)
+ app.config.poweredByHeader = originalConfigValue
+ })
+ })
+
dynamicImportTests(context, (p, q) => renderViaHTTP(context.appPort, p, q))
})
diff --git a/test/lib/next-test-utils.js b/test/lib/next-test-utils.js
index 7e81275c..0b4aa26e 100644
--- a/test/lib/next-test-utils.js
+++ b/test/lib/next-test-utils.js
@@ -2,6 +2,10 @@ import fetch from 'node-fetch'
import qs from 'querystring'
import http from 'http'
import express from 'express'
+import path from 'path'
+import portfinder from 'portfinder'
+import { spawn } from 'child_process'
+import fkill from 'fkill'
import server from '../../dist/server/next'
import build from '../../dist/server/build'
@@ -23,6 +27,48 @@ export function renderViaHTTP (appPort, pathname, query = {}) {
return fetch(url).then((res) => res.text())
}
+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)
+}
+
export async function startApp (app) {
await app.prepare()
const handler = app.getRequestHandler()
diff --git a/yarn.lock b/yarn.lock
index a734ed53..fb8f2aa1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -74,6 +74,13 @@ acorn@^5.0.0, acorn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.0.tgz#e468bf609b0672700e02f878ae2f1b360fe24b4f"
+aggregate-error@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-1.0.0.tgz#888344dad0220a72e3af50906117f48771925fac"
+ dependencies:
+ clean-stack "^1.0.0"
+ indent-string "^3.0.0"
+
ajv-keywords@^1.0.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
@@ -290,7 +297,7 @@ async@2.0.1:
dependencies:
lodash "^4.8.0"
-async@^1.4.0:
+async@^1.4.0, async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
@@ -1298,6 +1305,10 @@ circular-json@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d"
+clean-stack@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-1.3.0.tgz#9e821501ae979986c46b1d66d2d432db2fd4ae31"
+
cli-cursor@^1.0.1, cli-cursor@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
@@ -1514,6 +1525,13 @@ cross-env@5.0.1:
cross-spawn "^5.1.0"
is-windows "^1.0.0"
+cross-spawn-async@^2.1.1:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc"
+ dependencies:
+ lru-cache "^4.0.0"
+ which "^1.2.8"
+
cross-spawn@5.1.0, cross-spawn@^5.0.1, cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -2096,6 +2114,14 @@ exec-sh@^0.2.0:
dependencies:
merge "^1.1.3"
+execa@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.1.1.tgz#b09c2a9309bc0ef0501479472db3180f8d4c3edd"
+ dependencies:
+ cross-spawn-async "^2.1.1"
+ object-assign "^4.0.1"
+ strip-eof "^1.0.0"
+
execa@^0.5.0:
version "0.5.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.5.1.tgz#de3fb85cb8d6e91c85bcbceb164581785cb57b36"
@@ -2108,6 +2134,18 @@ execa@^0.5.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.6.3.tgz#57b69a594f081759c69e5370f0d17b9cb11658fe"
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
execa@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
@@ -2321,6 +2359,15 @@ find-up@^2.0.0, find-up@^2.1.0:
dependencies:
locate-path "^2.0.0"
+fkill@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/fkill/-/fkill-5.0.0.tgz#642f746aa631c965afc76c0d56dcc492a1ee504f"
+ dependencies:
+ aggregate-error "^1.0.0"
+ arrify "^1.0.0"
+ execa "^0.6.3"
+ taskkill "^2.0.0"
+
flat-cache@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96"
@@ -3599,7 +3646,7 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
dependencies:
js-tokens "^3.0.0"
-lru-cache@^4.0.1:
+lru-cache@^4.0.0, lru-cache@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55"
dependencies:
@@ -3764,7 +3811,7 @@ mkdirp@0.5.0:
dependencies:
minimist "0.0.8"
-"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
+mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
@@ -4291,6 +4338,14 @@ pluralize@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
+portfinder@^1.0.13:
+ version "1.0.13"
+ resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
+ dependencies:
+ async "^1.5.2"
+ debug "^2.2.0"
+ mkdirp "0.5.x"
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -4371,11 +4426,11 @@ public-encrypt@^4.0.0:
parse-asn1 "^5.0.0"
randombytes "^2.0.1"
-punycode@1.3.2:
+punycode@1.3.2, punycode@^1.2.4:
version "1.3.2"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
-punycode@^1.2.4, punycode@^1.4.1:
+punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
@@ -5181,6 +5236,13 @@ tar@^2.2.1:
fstream "^1.0.2"
inherits "2"
+taskkill@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/taskkill/-/taskkill-2.0.0.tgz#a354305702a964357033027aa949eaed5331b784"
+ dependencies:
+ arrify "^1.0.0"
+ execa "^0.1.1"
+
taskr@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/taskr/-/taskr-1.0.6.tgz#6ba5b671f51703f780fb6335d3dc792cfcf9c192"
@@ -5539,7 +5601,7 @@ which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
-which@^1.2.10, which@^1.2.12, which@^1.2.4, which@^1.2.9:
+which@^1.2.10, which@^1.2.12, which@^1.2.4, which@^1.2.8, which@^1.2.9:
version "1.2.14"
resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
dependencies: