From e093441bad588e98765a05df90f76f75283eda07 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Tue, 30 Jan 2018 16:40:52 +0100 Subject: [PATCH] Universal Webpack (#3578) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Speed up next build * Document webpack config * Speed up next build * Remove comment * Add comment * Clean up rules * Add comments * Run in parallel * Push plugins seperately * Create a new chunk for react * Don’t uglify react since it’s already uglified. Move react to commons in development * Use the minified version directly * Re-add globpattern * Move loaders into a separate variable * Add comment linking to Dan’s explanation * Remove dot * Add universal webpack * Initial dev support * Fix linting * Add changes from Arunoda's work * Made next dev works. But super slow and no HMR support. * Fix client side hot reload * Server side hmr * Only in dev * Add on-demand-entries client + hot-middleware * Add .babelrc support * Speed up on demand entries by running in parallel * Serve static generated files * Add missing config in dev * Add sass support * Add support for .map * Add cssloader config and fix .jsx support * Rename * use same defaults as css-loader. Fix linting * Add NoEmitErrorsPlugin * Add clientBootstrap * Use webpackhotmiddleware on the multi compiler * alpha.3 * Use babel 16.2.x * Fix reloading after error * Remove comment * Release 5.0.0-univeral-alpha.1 * Remove check for React 16 * Release 5.0.0-universal-alpha.2 * React hot loader v4 * Use our static file rendering machanism to serve pages. This should work well since the file path for a page is predictable. * Release 5.0.0-universal-alpha.3 * Remove optional loaders * Release 5.0.0-universal-alpha.4 * Remove clientBootstrap * Remove renderScript * Make sure pages bundles are served correctly * Remove unused import * Revert to using the same code as canary * Fix hot loader * Release 5.0.0-universal-alpha.5 * Check if externals dir exist before applying config * Add typescript support * Add support for transpiling certain packages in node_modules Thanks to @giuseppeg’s work in https://github.com/zeit/next.js/pull/3319 * Add BABEL_DISABLE_CACHE support * Make sourcemaps in production opt-in * Revert "Add support for transpiling certain packages in node_modules" This reverts commit d4b1d9babfb4b9ed4f4b12d56d52dee233e862da. In favor of a better api around this. * Support typescript through next.config.js * Remove comments * Bring back commons.js calculation * Remove unused dependencies * Move base.config.js to webpack.js * Make sure to only invalidate webpackDevMiddleware one after other. * Allow babel-loder caching by default. * Add comment about preact support * Bring back buildir replace * Remove obsolete plugin * Remove build replace, speed up build * Resolve page entries like pages/day/index.js to pages/day.js * Add componentDidCatch back * Compile to bundles * Use config.distDir everywhere * Make sure the file is an array * Remove console.log * Apply optimization to uglifyjs * Add comment pointing to source * Create entries the same way in dev and production * Remove unused and broken pagesGlobPattern * day/index.js is automatically turned into day.js at build time * Remove poweredByHeader option * Load pages with the correct path. * Release 5.0.0-universal-alpha.6 * Make sure react-dom/server can be overwritten by module-alias * Only add react-hot-loader babel plugin in dev * Release 5.0.0-universal-alpha.7 * Revert tests * Release 5.0.0-universal-alpha.10 * Make sure next/head is working properly. * Add wepack alias for 'next' back. * Make sure overriding className in next/head works * Alias react too * Add missing r * Fragment fallback has to wrap the children * Use min.js * Remove css.js * Remove wallaby.js * Release 5.0.0-universal-alpha.11 * Resolve relative to workdir instead of next * Make sure we touch the right file * Resolve next modules * Remove dotjsx removal plugins since we use webpack on the server * Revert "Resolve relative to workdir instead of next" This reverts commit a13f3e4ab565df9e2c9a3dfc8eb4009c0c2e02ed. * Externalize any locally loaded module lives outside of app dir. * Remove server aliases * Check node_modules reliably * Add symlink to next for tests * Make sure dynamic imports work locally. This is why we need it: https://github.com/webpack/webpack/blob/b545b519b2024e3f8be3041385bd326bf5d24449/lib/MainTemplate.js#L68 We need to have the finally clause in the above in __webpack_require__. webpack output option strictModuleExceptionHandling does that. * dynmaic -> dynamic * Remove webpack-node-externals * Make sure dynamic imports support SSR. * Remove css support in favor of next-css * Make sure we load path from `/` since it’s included in the path matching * Catch when ensurepage couldn’t be fulfilled for `.js.map` * Register require cache flusher for both client and server * Add comment explaining this is to facilitate hot reloading * Only load module when needed * Remove unused modules * Release 5.0.0-universal-alpha.12 * Only log the `found babel` message once * Make sure ondemand entries working correctly. Now we are just using a single instance of OnDemandEntryHandler. * Better sourcemaps * Release 5.0.0-universal-alpha.13 * Lock uglify version to 1.1.6 * Release 5.0.0-universal-alpha.14 * Fix a typo. * Introduce multi-zones support for mircofrontends * Add section on css --- asset.js | 1 + bin/next-dev | 4 +- client/index.js | 12 +- client/next-dev.js | 3 +- client/on-demand-entries-client.js | 12 +- client/webpack-hot-middleware-client.js | 14 +- css.js | 1 - errors/powered-by-header-option-removed.md | 15 + examples/hello-world/pages/about2.js | 3 + examples/hello-world/pages/day/index.js | 3 + examples/with-zones/README.md | 71 ++ examples/with-zones/blog/.gitignore | 2 + examples/with-zones/blog/next.config.js | 6 + examples/with-zones/blog/now.json | 3 + examples/with-zones/blog/package.json | 14 + examples/with-zones/blog/pages/blog.js | 5 + examples/with-zones/home/.gitignore | 2 + examples/with-zones/home/components/Header.js | 5 + examples/with-zones/home/next.config.js | 6 + examples/with-zones/home/now.json | 3 + examples/with-zones/home/package.json | 14 + examples/with-zones/home/pages/about.js | 10 + examples/with-zones/home/pages/index.js | 15 + examples/with-zones/home/static/nextjs.png | Bin 0 -> 70130 bytes examples/with-zones/home/static/zeit.png | Bin 0 -> 59856 bytes examples/with-zones/package.json | 20 + examples/with-zones/rules-dev.json | 6 + examples/with-zones/rules-prod.json | 6 + lib/asset.js | 10 + lib/css.js | 1 - lib/dynamic.js | 5 + lib/head.js | 2 +- lib/link.js | 1 + lib/router/router.js | 55 +- package.json | 27 +- readme.md | 34 +- server/build/babel/plugins/handle-import.js | 39 +- .../plugins/remove-dotjsx-from-import.js | 15 - server/build/babel/preset.js | 21 +- server/build/index.js | 48 +- .../build/loaders/hot-self-accept-loader.js | 6 - server/build/plugins/nextjs-ssr-import.js | 29 + server/build/plugins/watch-pages-plugin.js | 27 - server/build/replace.js | 23 - server/build/webpack.js | 603 ++++----- server/build/webpack/utils.js | 68 + server/config.js | 7 +- server/document.js | 3 +- server/hot-reloader.js | 77 +- server/index.js | 84 +- server/on-demand-entry-handler.js | 163 +-- server/render.js | 24 +- server/resolve.js | 8 + server/utils.js | 38 +- test/.gitignore | 1 + test/integration/basic/test/dynamic.js | 6 +- .../integration/production/test/index.test.js | 20 - test/node_modules/next | 1 + wallaby.js | 31 - yarn.lock | 1092 +++++------------ 60 files changed, 1219 insertions(+), 1606 deletions(-) create mode 100644 asset.js delete mode 100644 css.js create mode 100644 errors/powered-by-header-option-removed.md create mode 100644 examples/hello-world/pages/about2.js create mode 100644 examples/hello-world/pages/day/index.js create mode 100644 examples/with-zones/README.md create mode 100644 examples/with-zones/blog/.gitignore create mode 100644 examples/with-zones/blog/next.config.js create mode 100644 examples/with-zones/blog/now.json create mode 100644 examples/with-zones/blog/package.json create mode 100644 examples/with-zones/blog/pages/blog.js create mode 100644 examples/with-zones/home/.gitignore create mode 100644 examples/with-zones/home/components/Header.js create mode 100644 examples/with-zones/home/next.config.js create mode 100644 examples/with-zones/home/now.json create mode 100644 examples/with-zones/home/package.json create mode 100644 examples/with-zones/home/pages/about.js create mode 100644 examples/with-zones/home/pages/index.js create mode 100644 examples/with-zones/home/static/nextjs.png create mode 100644 examples/with-zones/home/static/zeit.png create mode 100644 examples/with-zones/package.json create mode 100644 examples/with-zones/rules-dev.json create mode 100644 examples/with-zones/rules-prod.json create mode 100644 lib/asset.js delete mode 100644 lib/css.js delete mode 100644 server/build/babel/plugins/remove-dotjsx-from-import.js create mode 100644 server/build/plugins/nextjs-ssr-import.js delete mode 100644 server/build/plugins/watch-pages-plugin.js delete mode 100644 server/build/replace.js create mode 100644 server/build/webpack/utils.js create mode 100644 test/.gitignore create mode 120000 test/node_modules/next delete mode 100644 wallaby.js diff --git a/asset.js b/asset.js new file mode 100644 index 0000000000000..fd0bd5dbb15ec --- /dev/null +++ b/asset.js @@ -0,0 +1 @@ +module.exports = require('./dist/lib/asset') diff --git a/bin/next-dev b/bin/next-dev index bfdfc29c27809..edf2255b85bac 100755 --- a/bin/next-dev +++ b/bin/next-dev @@ -1,11 +1,9 @@ #!/usr/bin/env node -import 'source-map-support/register' import { resolve, join } from 'path' import parseArgs from 'minimist' import { existsSync, readFileSync } from 'fs' import Server from '../server' import { printAndExit } from '../lib/utils' -import pkgUp from 'pkg-up' const argv = parseArgs(process.argv.slice(2), { alias: { @@ -64,7 +62,7 @@ srv.start(argv.port, argv.hostname) .catch((err) => { if (err.code === 'EADDRINUSE') { let errorMessage = `Port ${argv.port} is already in use.` - const pkgAppPath = pkgUp.sync('.') + const pkgAppPath = require('pkg-up').sync('.') const appPackage = JSON.parse(readFileSync(pkgAppPath, 'utf8')) const nextScript = Object.entries(appPackage.scripts).find(scriptLine => scriptLine[1] === 'next') if (nextScript) errorMessage += `\nUse \`npm run ${nextScript[0]} -- -p \`.` diff --git a/client/index.js b/client/index.js index 0283d98197fdd..78d953e5ae28f 100644 --- a/client/index.js +++ b/client/index.js @@ -6,6 +6,7 @@ import EventEmitter from '../lib/EventEmitter' import App from '../lib/app' import { loadGetInitialProps, getURL } from '../lib/utils' import PageLoader from '../lib/page-loader' +import * as asset from '../lib/asset' // Polyfill Promise globally // This is needed because Webpack2's dynamic loading(common chunks) code @@ -29,6 +30,9 @@ const { location } = window +// With this, static assets will work across zones +asset.setAssetPrefix(assetPrefix) + const asPath = getURL() const pageLoader = new PageLoader(buildId, assetPrefix) @@ -93,10 +97,7 @@ export default async ({ ErrorDebugComponent: passedDebugComponent, stripAnsi: pa } export async function render (props) { - // There are some errors we should ignore. - // Next.js rendering logic knows how to handle them. - // These are specially 404 errors - if (props.err && !props.err.ignore) { + if (props.err) { await renderError(props.err) return } @@ -159,7 +160,8 @@ async function doRender ({ Component, props, hash, err, emitter: emitterProp = e let isInitialRender = true function renderReactElement (reactEl, domEl) { - if (isInitialRender) { + // The check for `.hydrate` is there to support React alternatives like preact + if (isInitialRender && typeof ReactDOM.hydrate === 'function') { ReactDOM.hydrate(reactEl, domEl) isInitialRender = false } else { diff --git a/client/next-dev.js b/client/next-dev.js index ef771c32c6156..7f5e13e0005f2 100644 --- a/client/next-dev.js +++ b/client/next-dev.js @@ -1,10 +1,11 @@ -import 'react-hot-loader/patch' import stripAnsi from 'strip-ansi' import initNext, * as next from './' import ErrorDebugComponent from '../lib/error-debug' import initOnDemandEntries from './on-demand-entries-client' import initWebpackHMR from './webpack-hot-middleware-client' +require('@zeit/source-map-support/browser-source-map-support') + window.next = next initNext({ ErrorDebugComponent, stripAnsi }) diff --git a/client/on-demand-entries-client.js b/client/on-demand-entries-client.js index 8b5588d56297a..65ed2c2913989 100644 --- a/client/on-demand-entries-client.js +++ b/client/on-demand-entries-client.js @@ -3,6 +3,12 @@ import Router from '../lib/router' import fetch from 'unfetch' +const { + __NEXT_DATA__: { + assetPrefix + } +} = window + export default () => { Router.ready(() => { Router.router.events.on('routeChangeComplete', ping) @@ -10,16 +16,16 @@ export default () => { async function ping () { try { - const url = `/_next/on-demand-entries-ping?page=${Router.pathname}` + const url = `${assetPrefix}/_next/on-demand-entries-ping?page=${Router.pathname}` const res = await fetch(url, { - credentials: 'same-origin' + credentials: 'omit' }) const payload = await res.json() if (payload.invalid) { // Payload can be invalid even if the page is not exists. // So, we need to make sure it's exists before reloading. const pageRes = await fetch(location.href, { - credentials: 'same-origin' + credentials: 'omit' }) if (pageRes.status === 200) { location.reload() diff --git a/client/webpack-hot-middleware-client.js b/client/webpack-hot-middleware-client.js index 10dbf28dc191f..24477fe5da9fb 100644 --- a/client/webpack-hot-middleware-client.js +++ b/client/webpack-hot-middleware-client.js @@ -1,7 +1,19 @@ -import webpackHotMiddlewareClient from 'webpack-hot-middleware/client?overlay=false&reload=true&path=/_next/webpack-hmr' +import webpackHotMiddlewareClient from 'webpack-hot-middleware/client?autoConnect=false' import Router from '../lib/router' +const { + __NEXT_DATA__: { + assetPrefix + } +} = window + export default () => { + webpackHotMiddlewareClient.setOptionsAndConnect({ + overlay: false, + reload: true, + path: `${assetPrefix}/_next/webpack-hmr` + }) + const handlers = { reload (route) { if (route === '/_error') { diff --git a/css.js b/css.js deleted file mode 100644 index e4d6d15f9f3b8..0000000000000 --- a/css.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./dist/lib/css') diff --git a/errors/powered-by-header-option-removed.md b/errors/powered-by-header-option-removed.md new file mode 100644 index 0000000000000..216fbda849f52 --- /dev/null +++ b/errors/powered-by-header-option-removed.md @@ -0,0 +1,15 @@ +# The poweredByHeader has been removed + +#### Why This Error Occurred + +Starting at Next.js version 5.0.0 the `poweredByHeader` option has been removed. + +#### Possible Ways to Fix It + +If you still want to remove `x-powered-by` you can use one of the custom-server examples. + +And then manually remove the header using `res.removeHeader('x-powered-by')` + +### Useful Links + +- [Custom Server documentation + examples](https://github.com/zeit/next.js#custom-server-and-routing) diff --git a/examples/hello-world/pages/about2.js b/examples/hello-world/pages/about2.js new file mode 100644 index 0000000000000..44ce657168845 --- /dev/null +++ b/examples/hello-world/pages/about2.js @@ -0,0 +1,3 @@ +export default () => ( +
About 2
+) diff --git a/examples/hello-world/pages/day/index.js b/examples/hello-world/pages/day/index.js new file mode 100644 index 0000000000000..5a58100829934 --- /dev/null +++ b/examples/hello-world/pages/day/index.js @@ -0,0 +1,3 @@ +export default () => ( +
Hello Day
+) diff --git a/examples/with-zones/README.md b/examples/with-zones/README.md new file mode 100644 index 0000000000000..5349c81422e54 --- /dev/null +++ b/examples/with-zones/README.md @@ -0,0 +1,71 @@ +[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-zones) + +# Using multiple zones + +With Next.js you can use multiple apps as a single app using it's multi-zones feature. +This is an example showing how to use it. + +In this example, we've two apps: 'home' and 'blog'. +We also have a set of rules defined in `rules.json` for the proxy. + +Now let's start two of our app using: + +``` +npm run home +npm run blog +``` + +Then start the proxy: + +``` +npm run proxy +``` + +Now you can visit http://localhost:9000 and access and develop both apps a single app. + +### Proxy Rules + +This is the place we define rules for our proxy. Here are the rules(in `rules.json`) available for this app: + +```json +{ + "rules": [ + {"pathname": "/blog", "method":["GET", "POST", "OPTIONS"], "dest": "http://localhost:5000"}, + {"pathname": "/**", "dest": "http://localhost:4000"} + ] +} +``` + +These rules are based on ZEIT now [path alias](https://zeit.co/docs/features/path-aliases) rules and use [`micro-proxy`](https://github.com/zeit/micro-proxy) as the proxy. + +## Special Notes + +* All pages should be unique across zones. A page with the same name should not exist in multiple zones. Otherwise, there'll be unexpected behaviour in client side navigation. + * According to the above example, a page named `blog` should not be exist in the `home` zone. + +## Production Deployment + +Here's how are going to deploy this application into production. + +* Open the `now.json` file in both `blog` and `home` directories and change the aliases as you wish. +* Then update `rules-prod.json` accordingly. +* Now deploy both apps: + +~~~sh +cd home +now && now alias +cd ../blog +now && now alias +cd .. +~~~ + +* Finally, set the path alias rules with + +~~~sh +now alias with-zones.now.sh -r rules-prod.json +~~~ + +> You can use a domain name of your choice in the above command instead of `with-zones.now.sh`. + +That's it. +Now you can access the final app via: diff --git a/examples/with-zones/blog/.gitignore b/examples/with-zones/blog/.gitignore new file mode 100644 index 0000000000000..f74c78183c917 --- /dev/null +++ b/examples/with-zones/blog/.gitignore @@ -0,0 +1,2 @@ +.next +node_modules diff --git a/examples/with-zones/blog/next.config.js b/examples/with-zones/blog/next.config.js new file mode 100644 index 0000000000000..d930ee9c80d8c --- /dev/null +++ b/examples/with-zones/blog/next.config.js @@ -0,0 +1,6 @@ +const { NOW_URL } = process.env +const { alias } = require('./now.json') + +module.exports = { + assetPrefix: NOW_URL ? `https://${alias}` : 'http://localhost:5000' +} diff --git a/examples/with-zones/blog/now.json b/examples/with-zones/blog/now.json new file mode 100644 index 0000000000000..f575903587170 --- /dev/null +++ b/examples/with-zones/blog/now.json @@ -0,0 +1,3 @@ +{ + "alias": "with-zones-blog.now.sh" +} diff --git a/examples/with-zones/blog/package.json b/examples/with-zones/blog/package.json new file mode 100644 index 0000000000000..cc274c2fe3524 --- /dev/null +++ b/examples/with-zones/blog/package.json @@ -0,0 +1,14 @@ +{ + "name": "with-zones-blog", + "version": "1.0.0", + "scripts": { + "build": "next build", + "start": "next start -p 4000" + }, + "dependencies": { + "next": "zones", + "react": "^16.0.0", + "react-dom": "^16.0.0" + }, + "license": "ISC" +} diff --git a/examples/with-zones/blog/pages/blog.js b/examples/with-zones/blog/pages/blog.js new file mode 100644 index 0000000000000..1f8661265321f --- /dev/null +++ b/examples/with-zones/blog/pages/blog.js @@ -0,0 +1,5 @@ +export default () => ( +
+ This is our blog +
+) diff --git a/examples/with-zones/home/.gitignore b/examples/with-zones/home/.gitignore new file mode 100644 index 0000000000000..f74c78183c917 --- /dev/null +++ b/examples/with-zones/home/.gitignore @@ -0,0 +1,2 @@ +.next +node_modules diff --git a/examples/with-zones/home/components/Header.js b/examples/with-zones/home/components/Header.js new file mode 100644 index 0000000000000..b631afc81b5ce --- /dev/null +++ b/examples/with-zones/home/components/Header.js @@ -0,0 +1,5 @@ +export default () => ( +
+

The Company

+
+) diff --git a/examples/with-zones/home/next.config.js b/examples/with-zones/home/next.config.js new file mode 100644 index 0000000000000..e76728e674352 --- /dev/null +++ b/examples/with-zones/home/next.config.js @@ -0,0 +1,6 @@ +const { NOW_URL } = process.env +const { alias } = require('./now.json') + +module.exports = { + assetPrefix: NOW_URL ? `https://${alias}` : 'http://localhost:4000' +} diff --git a/examples/with-zones/home/now.json b/examples/with-zones/home/now.json new file mode 100644 index 0000000000000..f519fe4ca8ced --- /dev/null +++ b/examples/with-zones/home/now.json @@ -0,0 +1,3 @@ +{ + "alias": "with-zones-home.now.sh" +} diff --git a/examples/with-zones/home/package.json b/examples/with-zones/home/package.json new file mode 100644 index 0000000000000..f534c02a7a077 --- /dev/null +++ b/examples/with-zones/home/package.json @@ -0,0 +1,14 @@ +{ + "name": "with-zones-home", + "version": "1.0.0", + "scripts": { + "build": "next build", + "start": "next start -p 4000" + }, + "dependencies": { + "next": "zones", + "react": "^16.0.0", + "react-dom": "^16.0.0" + }, + "license": "ISC" +} diff --git a/examples/with-zones/home/pages/about.js b/examples/with-zones/home/pages/about.js new file mode 100644 index 0000000000000..79cbefd0edef6 --- /dev/null +++ b/examples/with-zones/home/pages/about.js @@ -0,0 +1,10 @@ +import asset from 'next/asset' +import Link from 'next/link' + +export default () => ( +
+

This is the about page.

+
Go Back
+ +
+) diff --git a/examples/with-zones/home/pages/index.js b/examples/with-zones/home/pages/index.js new file mode 100644 index 0000000000000..c251da2e5d428 --- /dev/null +++ b/examples/with-zones/home/pages/index.js @@ -0,0 +1,15 @@ +import Link from 'next/link' +import asset from 'next/asset' +import dynamic from 'next/dynamic' + +const Header = dynamic(import('../components/Header')) + +export default () => ( +
+
+

This is our homepage

+ + + +
+) diff --git a/examples/with-zones/home/static/nextjs.png b/examples/with-zones/home/static/nextjs.png new file mode 100644 index 0000000000000000000000000000000000000000..98cbbf09ade8691527aa8d9b0d8248740c6386bd GIT binary patch literal 70130 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
N_r5X5a-PH!bM2AgAujF9EkK$=mQ);>d^{d< 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 XF{?xTo&|`drfu7zyE$&-{y+X7x1QF( literal 0 HcmV?d00001 diff --git a/examples/with-zones/home/static/zeit.png b/examples/with-zones/home/static/zeit.png new file mode 100644 index 0000000000000000000000000000000000000000..8b80fabb35ed12ccbc4c67554c4387e68dbc580c GIT binary patch literal 59856 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 literal 0 HcmV?d00001 diff --git a/examples/with-zones/package.json b/examples/with-zones/package.json new file mode 100644 index 0000000000000..3269a598f3f15 --- /dev/null +++ b/examples/with-zones/package.json @@ -0,0 +1,20 @@ +{ + "name": "with-zones", + "version": "1.0.0", + "scripts": { + "home": "next home -p 4000", + "home-build": "next build home", + "home-start": "next start home -p 4000", + "blog": "next blog -p 5000", + "blog-build": "next build blog", + "blog-start": "next start blog -p 5000", + "proxy": "micro-proxy -r rules-dev.json" + }, + "dependencies": { + "micro-proxy": "^1.0.0", + "next": "latest", + "react": "^16.0.0", + "react-dom": "^16.0.0" + }, + "license": "ISC" +} diff --git a/examples/with-zones/rules-dev.json b/examples/with-zones/rules-dev.json new file mode 100644 index 0000000000000..680a330286beb --- /dev/null +++ b/examples/with-zones/rules-dev.json @@ -0,0 +1,6 @@ +{ + "rules": [ + {"pathname": "/blog", "method":["GET", "POST", "OPTIONS"], "dest": "http://localhost:5000"}, + {"pathname": "/**", "dest": "http://localhost:4000"} + ] +} diff --git a/examples/with-zones/rules-prod.json b/examples/with-zones/rules-prod.json new file mode 100644 index 0000000000000..aa8f6da66c276 --- /dev/null +++ b/examples/with-zones/rules-prod.json @@ -0,0 +1,6 @@ +{ + "rules": [ + {"pathname": "/blog", "method":["GET", "POST", "OPTIONS"], "dest": "https://with-zones-blog.now.sh"}, + {"pathname": "/**", "dest": "https://with-zones-home.now.sh"} + ] +} diff --git a/lib/asset.js b/lib/asset.js new file mode 100644 index 0000000000000..f9dfe50c0a21a --- /dev/null +++ b/lib/asset.js @@ -0,0 +1,10 @@ +let assetPrefix + +export default function asset (path) { + const pathWithoutSlash = path.replace(/^\//, '') + return `${assetPrefix}/static/${pathWithoutSlash}` +} + +export function setAssetPrefix (url) { + assetPrefix = url +} diff --git a/lib/css.js b/lib/css.js deleted file mode 100644 index b87b38863e4ad..0000000000000 --- a/lib/css.js +++ /dev/null @@ -1 +0,0 @@ -throw new Error(`'next/css' has been removed in Next.js 2.0. Please refer to the migration guide: https://github.com/zeit/next.js/wiki/Migrating-from-next-css`) diff --git a/lib/dynamic.js b/lib/dynamic.js index 939e1114befa7..43d49999d4441 100644 --- a/lib/dynamic.js +++ b/lib/dynamic.js @@ -160,6 +160,11 @@ export function flushChunks () { } export class SameLoopPromise { + static resolve (value) { + const promise = new SameLoopPromise((done) => done(value)) + return promise + } + constructor (cb) { this.onResultCallbacks = [] this.onErrorCallbacks = [] diff --git a/lib/head.js b/lib/head.js index 5dadb1b6dfde1..71b374f9d9e31 100644 --- a/lib/head.js +++ b/lib/head.js @@ -33,7 +33,7 @@ function reduceComponents (components) { .filter(unique()) .reverse() .map((c) => { - const className = (c.className ? c.className + ' ' : '') + 'next-head' + const className = (c.props && c.props.className ? c.props.className + ' ' : '') + 'next-head' return React.cloneElement(c, { className }) }) } diff --git a/lib/link.js b/lib/link.js index c23a931f224c7..ee16d7153daa0 100644 --- a/lib/link.js +++ b/lib/link.js @@ -153,6 +153,7 @@ export default class Link extends Component { function isLocal (href) { const url = parse(href, false, true) const origin = parse(getLocationOrigin(), false, true) + return !url.host || (url.protocol === origin.protocol && url.host === origin.host) } diff --git a/lib/router/router.js b/lib/router/router.js index 222499aba40c6..f03107bfea435 100644 --- a/lib/router/router.js +++ b/lib/router/router.js @@ -129,7 +129,6 @@ export default class Router { } this.abortComponentLoad(as) - const { pathname, query } = parse(url, true) // If the url change is only related to a hash change // We should not proceed. We should only change the state. @@ -139,6 +138,8 @@ export default class Router { return } + const { pathname, query } = parse(url, true) + // If asked to change the current URL we should reload the current page // (not location.reload() but reload getInitalProps and other Next.js stuffs) // We also need to set the method = replaceState always @@ -209,10 +210,6 @@ export default class Router { this.components[route] = routeInfo } catch (err) { - if (err.cancelled) { - return { error: err } - } - if (err.buildIdMismatched) { // Now we need to reload the page or do the action asked by the user _notifyBuildIdMismatch(as) @@ -223,9 +220,21 @@ export default class Router { } if (err.statusCode === 404) { - // Indicate main error display logic to - // ignore rendering this error as a runtime error. - err.ignore = true + // If there's 404 error for the page, it could be due to two reasons. + // 1. Page is not exists + // 2. Page is exists in a different zone + // We are not sure whether this is actual 404 or exists in a different zone. + // So, doing a hard reload is the proper way to deal with this. + window.location.href = as + + // Changing the URL doesn't block executing the current code path. + // So, we need to mark it as a cancelled error and stop the routing logic. + err.cancelled = true + return { error: err } + } + + if (err.cancelled) { + return { error: err } } const Component = this.ErrorComponent @@ -301,29 +310,19 @@ export default class Router { cancelled = true } - try { - const Component = await this.fetchRoute(route) - - if (cancelled) { - const error = new Error(`Abort fetching component for route: "${route}"`) - error.cancelled = true - throw error - } + const Component = await this.fetchRoute(route) - if (cancel === this.componentLoadCancel) { - this.componentLoadCancel = null - } + if (cancelled) { + const error = new Error(`Abort fetching component for route: "${route}"`) + error.cancelled = true + throw error + } - return Component - } catch (err) { - // There's an error in loading the route. - // Usually this happens when there's a failure in the webpack build - // So in that case, we need to load the page with full SSR - // That'll clean the invalid exising client side information. - // (Like cached routes) - window.location.href = as - throw err + if (cancel === this.componentLoadCancel) { + this.componentLoadCancel = null } + + return Component } async getInitialProps (Component, ctx) { diff --git a/package.json b/package.json index 1f06ce8ba6a0b..c51f0d6fe3a54 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "4.4.0-canary.3", + "version": "5.0.0-universal-alpha.14", "description": "Minimalistic framework for server-rendered React applications", "main": "./dist/server/next.js", "license": "MIT", @@ -18,6 +18,7 @@ "dynamic.js", "prefetch.js", "router.js", + "asset.js", "error.js" ], "bin": { @@ -29,8 +30,9 @@ "pretestonly": "taskr pretest", "testonly": "cross-env NODE_PATH=test/lib jest \\.test.js", "posttestonly": "taskr posttest", + "testall": "npm run testonly -- --coverage --forceExit --runInBand --verbose --bail", "pretest": "npm run lint", - "test": "npm run testonly -- --coverage --forceExit --runInBand --verbose --bail", + "test": "cross-env npm run testall || npm run testall", "coveralls": "nyc --instrument=false --source-map=false report --temp-directory=./coverage --reporter=text-lcov | coveralls", "lint": "standard 'bin/*' 'client/**/*.js' 'examples/**/*.js' 'lib/**/*.js' 'pages/**/*.js' 'server/**/*.js' 'test/**/*.js'", "prepublish": "npm run release", @@ -48,15 +50,13 @@ "bin/*": "standard" }, "dependencies": { + "@zeit/source-map-support": "0.6.0", "ansi-html": "0.0.7", "babel-core": "6.26.0", - "babel-generator": "6.26.0", "babel-loader": "7.1.2", - "babel-plugin-module-resolver": "2.7.1", "babel-plugin-react-require": "3.0.0", "babel-plugin-syntax-dynamic-import": "6.18.0", "babel-plugin-transform-class-properties": "6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", "babel-plugin-transform-object-rest-spread": "6.26.0", "babel-plugin-transform-react-jsx-source": "6.22.0", "babel-plugin-transform-react-remove-prop-types": "0.4.8", @@ -69,10 +69,11 @@ "cross-spawn": "5.1.0", "del": "3.0.0", "etag": "1.8.1", + "find-up": "2.1.0", "fresh": "0.5.2", "friendly-errors-webpack-plugin": "1.6.1", "glob": "7.1.2", - "glob-promise": "3.2.0", + "glob-promise": "3.3.0", "hoist-non-react-statics": "2.3.1", "htmlescape": "1.1.1", "http-status": "1.0.1", @@ -87,25 +88,25 @@ "pkg-up": "2.0.0", "prop-types": "15.6.0", "prop-types-exact": "1.1.1", - "react-hot-loader": "3.1.1", + "react-hot-loader": "4.0.0-beta.14", "recursive-copy": "2.0.6", + "resolve": "1.5.0", "send": "0.16.1", - "source-map-support": "0.4.18", "strip-ansi": "3.0.1", "styled-jsx": "2.2.1", "touch": "3.1.0", + "uglifyjs-webpack-plugin": "1.1.6", "unfetch": "3.0.0", "url": "0.11.0", "uuid": "3.1.0", "walk": "2.3.9", - "webpack": "3.6.0", + "webpack": "3.10.0", "webpack-dev-middleware": "1.12.0", - "webpack-hot-middleware": "2.19.1", + "webpack-hot-middleware": "2.21.0", "write-file-webpack-plugin": "4.2.0", "xss-filters": "1.2.7" }, "devDependencies": { - "uglifyjs-webpack-plugin": "^1.1.1", "@taskr/babel": "1.1.0", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", @@ -129,8 +130,8 @@ "node-notifier": "5.1.2", "nyc": "11.2.1", "portfinder": "1.0.13", - "react": "16.0.0", - "react-dom": "16.0.0", + "react": "16.2.0", + "react-dom": "16.2.0", "standard": "9.0.2", "taskr": "1.1.0", "wd": "1.4.1" diff --git a/readme.md b/readme.md index d2fa37c23dfbb..54114c536aa33 100644 --- a/readme.md +++ b/readme.md @@ -164,6 +164,14 @@ export default () =>

hi there

To use more sophisticated CSS-in-JS solutions, you typically have to implement style flushing for server-side rendering. We enable this by allowing you to define your own [custom ``](#user-content-custom-document) component that wraps each page. +#### Importing CSS / Sass / Less files + +To support importing `.css` `.scss` or `.less` files you can use these modules, which configure sensible defaults for server rendered applications. + +- ![@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css) +- ![@zeit/next-sass](https://github.com/zeit/next-plugins/tree/master/packages/next-sass) +- ![@zeit/next-less](https://github.com/zeit/next-plugins/tree/master/packages/next-less) + ### Static file serving (e.g.: images) Create a folder called `static` in your project root directory. From your code you can then reference those files with `/static/` URLs: @@ -1006,7 +1014,7 @@ In order to extend our usage of `webpack`, you can define a function that extend // (But you could use ES2015 features supported by your Node.js version) module.exports = { - webpack: (config, { buildId, dev }) => { + webpack: (config, { buildId, dev, isServer, defaultLoaders }) => { // Perform customizations to webpack config // Important: return the modified config @@ -1021,7 +1029,15 @@ module.exports = { } ``` -*Warning: Adding loaders to support new file types (css, less, svg, etc.) is __not__ recommended because only the client code gets bundled via webpack and thus it won't work on the initial server rendering. Babel plugins are a good alternative because they're applied consistently between server/client rendering (e.g. [babel-plugin-inline-react-svg](https://github.com/kesne/babel-plugin-inline-react-svg)).* +Some commonly asked for features are available as modules: + +- ![@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css) +- ![@zeit/next-sass](https://github.com/zeit/next-plugins/tree/master/packages/next-sass) +- ![@zeit/next-less](https://github.com/zeit/next-plugins/tree/master/packages/next-less) +- ![@zeit/next-preact](https://github.com/zeit/next-plugins/tree/master/packages/next-preact) +- ![@zeit/next-typescript](https://github.com/zeit/next-plugins/tree/master/packages/next-typescript) + +*Warning: The `webpack` function is executed twice, once for the server and once for the client. This allows you to distinguish between client and server configuration using the `isServer` property* ### Customizing babel config @@ -1214,20 +1230,6 @@ If you want to create re-usable React components that you can embed in your Next Next.js bundles [styled-jsx](https://github.com/zeit/styled-jsx) supporting scoped css. However you can use any CSS-in-JS solution in your Next app by just including your favorite library [as mentioned before](#css-in-js) in the document. -
- How do I use CSS preprocessors like SASS / SCSS / LESS? - -Next.js bundles [styled-jsx](https://github.com/zeit/styled-jsx) supporting scoped css. However you can use any CSS preprocessor solution in your Next app by following one of these examples: - -- [with-external-scoped-css](./examples/with-external-scoped-css) -- [with-scoped-stylesheets-and-postcss](./examples/with-scoped-stylesheets-and-postcss) -- [with-global-stylesheet](./examples/with-global-stylesheet) -- [with-styled-jsx-scss](./examples/with-styled-jsx-scss) -- [with-styled-jsx-plugins](./examples/with-styled-jsx-plugins) - -
- -
What syntactic features are transpiled? How do I change them? diff --git a/server/build/babel/plugins/handle-import.js b/server/build/babel/plugins/handle-import.js index eb3d985a69854..86397e9e2e5c3 100644 --- a/server/build/babel/plugins/handle-import.js +++ b/server/build/babel/plugins/handle-import.js @@ -16,32 +16,23 @@ const TYPE_IMPORT = 'Import' const buildImport = (args) => (template(` ( - typeof require.resolveWeak !== 'function' ? - new (require('next/dynamic').SameLoopPromise)((resolve, reject) => { - eval('require.ensure = function (deps, callback) { callback(require) }') - require.ensure([], (require) => { + new (require('next/dynamic').SameLoopPromise)((resolve, reject) => { + const weakId = require.resolveWeak(SOURCE) + try { + const weakModule = __webpack_require__(weakId) + return resolve(weakModule) + } catch (err) {} + + require.ensure([], (require) => { + try { let m = require(SOURCE) m.__webpackChunkName = '${args.name}' - resolve(m); - }, 'chunks/${args.name}'); - }) - : - new (require('next/dynamic').SameLoopPromise)((resolve, reject) => { - const weakId = require.resolveWeak(SOURCE) - try { - const weakModule = __webpack_require__(weakId) - return resolve(weakModule) - } catch (err) {} - - require.ensure([], (require) => { - try { - let m = require(SOURCE) - resolve(m) - } catch(error) { - reject(error) - } - }, 'chunks/${args.name}'); - }) + resolve(m) + } catch(error) { + reject(error) + } + }, 'chunks/${args.name}'); + }) ) `)) diff --git a/server/build/babel/plugins/remove-dotjsx-from-import.js b/server/build/babel/plugins/remove-dotjsx-from-import.js deleted file mode 100644 index b43b61ba099d1..0000000000000 --- a/server/build/babel/plugins/remove-dotjsx-from-import.js +++ /dev/null @@ -1,15 +0,0 @@ -// This plugins removes the `.jsx` extension from import statements. Because we transpile .jsx files to .js in .next -// E.g. `import Hello from '../components/hello.jsx'` will become `import Hello from '../components/hello'` -module.exports = function ({types}) { - return { - name: 'remove-dotjsx-from-import', - visitor: { - ImportDeclaration (path) { - const value = path.node.source.value - if (value.slice(-4) === '.jsx') { - path.node.source = types.stringLiteral(value.slice(0, -4)) - } - } - } - } -} diff --git a/server/build/babel/preset.js b/server/build/babel/preset.js index a7d051b96fbc2..59c6e95069d29 100644 --- a/server/build/babel/preset.js +++ b/server/build/babel/preset.js @@ -1,5 +1,3 @@ -const relativeResolve = require('../root-module-relative-path').default(require) - // Resolve styled-jsx plugins function styledJsxOptions (opts) { if (!opts) { @@ -45,29 +43,12 @@ module.exports = (context, opts = {}) => ({ require.resolve('babel-preset-react') ], plugins: [ - require.resolve('./plugins/remove-dotjsx-from-import'), require.resolve('babel-plugin-react-require'), require.resolve('./plugins/handle-import'), require.resolve('babel-plugin-transform-object-rest-spread'), require.resolve('babel-plugin-transform-class-properties'), [require.resolve('babel-plugin-transform-runtime'), opts['transform-runtime'] || {}], [require.resolve('styled-jsx/babel'), styledJsxOptions(opts['styled-jsx'])], - ...plugins, - [ - require.resolve('babel-plugin-module-resolver'), - { - alias: { - 'babel-runtime': relativeResolve('babel-runtime/package'), - 'next/link': relativeResolve('../../../lib/link'), - 'next/prefetch': relativeResolve('../../../lib/prefetch'), - 'next/css': relativeResolve('../../../lib/css'), - 'next/dynamic': relativeResolve('../../../lib/dynamic'), - 'next/head': relativeResolve('../../../lib/head'), - 'next/document': relativeResolve('../../../server/document'), - 'next/router': relativeResolve('../../../lib/router'), - 'next/error': relativeResolve('../../../lib/error') - } - } - ] + ...plugins ] }) diff --git a/server/build/index.js b/server/build/index.js index f1f3397d28c76..4b7577bd5803b 100644 --- a/server/build/index.js +++ b/server/build/index.js @@ -1,44 +1,42 @@ -import { tmpdir } from 'os' import { join } from 'path' import fs from 'mz/fs' import uuid from 'uuid' -import del from 'del' -import webpack from './webpack' -import replaceCurrentBuild from './replace' +import webpack from 'webpack' +import getConfig from '../config' +import getBaseWebpackConfig from './webpack' import md5File from 'md5-file/promise' export default async function build (dir, conf = null) { + const config = getConfig(dir, conf) const buildId = uuid.v4() - const tempDir = tmpdir() - const buildDir = join(tempDir, uuid.v4()) try { - await fs.access(tempDir, fs.constants.W_OK) + await fs.access(dir, fs.constants.W_OK) } catch (err) { console.error(`> Failed, build directory is not writeable. https://err.sh/zeit/next.js/build-dir-not-writeable`) throw err } - const compiler = await webpack(dir, { buildId, buildDir, conf }) - try { - const stats = await runCompiler(compiler) - await writeBuildStats(buildDir, stats) - await writeBuildId(buildDir, buildId) + const configs = await Promise.all([ + getBaseWebpackConfig(dir, { buildId, isServer: false, config }), + getBaseWebpackConfig(dir, { buildId, isServer: true, config }) + ]) + + await runCompiler(configs) + + await writeBuildStats(dir, config) + await writeBuildId(dir, buildId, config) } catch (err) { - console.error(`> Failed to build on ${buildDir}`) + console.error(`> Failed to build`) throw err } - - await replaceCurrentBuild(dir, buildDir) - - // no need to wait - del(buildDir, { force: true }) } function runCompiler (compiler) { - return new Promise((resolve, reject) => { - compiler.run((err, stats) => { + return new Promise(async (resolve, reject) => { + const webpackCompiler = await webpack(await compiler) + webpackCompiler.run((err, stats) => { if (err) return reject(err) const jsonStats = stats.toJson() @@ -55,21 +53,21 @@ function runCompiler (compiler) { }) } -async function writeBuildStats (dir, stats) { +async function writeBuildStats (dir, config) { // Here we can't use hashes in webpack chunks. // That's because the "app.js" is not tied to a chunk. // It's created by merging a few assets. (commons.js and main.js) // So, we need to generate the hash ourself. const assetHashMap = { 'app.js': { - hash: await md5File(join(dir, '.next', 'app.js')) + hash: await md5File(join(dir, config.distDir, 'app.js')) } } - const buildStatsPath = join(dir, '.next', 'build-stats.json') + const buildStatsPath = join(dir, config.distDir, 'build-stats.json') await fs.writeFile(buildStatsPath, JSON.stringify(assetHashMap), 'utf8') } -async function writeBuildId (dir, buildId) { - const buildIdPath = join(dir, '.next', 'BUILD_ID') +async function writeBuildId (dir, buildId, config) { + const buildIdPath = join(dir, config.distDir, 'BUILD_ID') await fs.writeFile(buildIdPath, buildId, 'utf8') } diff --git a/server/build/loaders/hot-self-accept-loader.js b/server/build/loaders/hot-self-accept-loader.js index 1c6968d215621..3f0aa8cc5ce85 100644 --- a/server/build/loaders/hot-self-accept-loader.js +++ b/server/build/loaders/hot-self-accept-loader.js @@ -8,12 +8,6 @@ module.exports = function (content, sourceMap) { this.callback(null, `${content} (function (Component, route) { if (!module.hot) return - if (!__resourceQuery) return - - var qs = require('querystring') - var params = qs.parse(__resourceQuery.slice(1)) - if (params.entry == null) return - module.hot.accept() Component.__route = route diff --git a/server/build/plugins/nextjs-ssr-import.js b/server/build/plugins/nextjs-ssr-import.js new file mode 100644 index 0000000000000..d6de3ddb7d3d8 --- /dev/null +++ b/server/build/plugins/nextjs-ssr-import.js @@ -0,0 +1,29 @@ +import { join, sep } from 'path' + +// This plugin modifies the require-ensure code generated by Webpack +// to work with Next.js SSR +export default class NextJsSsrImportPlugin { + constructor ({ dir, dist }) { + this.dir = dir + this.dist = dist + } + + apply (compiler) { + compiler.plugin('compilation', (compilation) => { + compilation.mainTemplate.plugin('require-ensure', (code) => { + // Update to load chunks from our custom chunks directory + const chunksDirPath = join(this.dir, this.dist, 'dist') + let updatedCode = code.replace('require("./"', `require("${chunksDirPath}${sep}"`) + + // Replace a promise equivalent which runs in the same loop + // If we didn't do this webpack's module loading process block us from + // doing SSR for chunks + updatedCode = updatedCode.replace( + 'return Promise.resolve();', + `return require('next/dynamic').SameLoopPromise.resolve();` + ) + return updatedCode + }) + }) + } +} diff --git a/server/build/plugins/watch-pages-plugin.js b/server/build/plugins/watch-pages-plugin.js deleted file mode 100644 index c258c3293cfed..0000000000000 --- a/server/build/plugins/watch-pages-plugin.js +++ /dev/null @@ -1,27 +0,0 @@ -import { resolve, join } from 'path' - -export default class WatchPagesPlugin { - constructor (dir) { - this.dir = resolve(dir, 'pages') - } - - apply (compiler) { - compiler.plugin('compilation', (compilation) => { - compilation.plugin('optimize-assets', (assets, callback) => { - // transpile pages/_document.js and descendants, - // but don't need the bundle file - delete assets[join('bundles', 'pages', '_document.js')] - callback() - }) - }) - - compiler.plugin('emit', (compilation, callback) => { - // watch the pages directory - compilation.contextDependencies = [ - ...compilation.contextDependencies, - this.dir - ] - callback() - }) - } -} diff --git a/server/build/replace.js b/server/build/replace.js deleted file mode 100644 index 22ff9e4a18f09..0000000000000 --- a/server/build/replace.js +++ /dev/null @@ -1,23 +0,0 @@ -import mv from 'mv' -import { join } from 'path' -import getConfig from '../config' - -export default async function replaceCurrentBuild (dir, buildDir) { - const dist = getConfig(dir).distDir - const _dir = join(dir, dist) - const _buildDir = join(buildDir, '.next') - const oldDir = join(buildDir, '.next.old') - - try { - await move(_dir, oldDir) - } catch (err) { - if (err.code !== 'ENOENT') throw err - } - await move(_buildDir, _dir) - return oldDir -} - -function move (from, to) { - return new Promise((resolve, reject) => - mv(from, to, err => err ? reject(err) : resolve())) -} diff --git a/server/build/webpack.js b/server/build/webpack.js index 02277eeccd5d6..1fabfde4fe321 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -1,242 +1,45 @@ -import { resolve, join, sep } from 'path' -import { createHash } from 'crypto' -import { realpathSync, existsSync } from 'fs' +import path, {sep} from 'path' import webpack from 'webpack' -import glob from 'glob-promise' +import resolve from 'resolve' +import UglifyJSPlugin from 'uglifyjs-webpack-plugin' +import CaseSensitivePathPlugin from 'case-sensitive-paths-webpack-plugin' import WriteFilePlugin from 'write-file-webpack-plugin' import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin' -import CaseSensitivePathPlugin from 'case-sensitive-paths-webpack-plugin' -import UglifyJSPlugin from 'uglifyjs-webpack-plugin' -import UnlinkFilePlugin from './plugins/unlink-file-plugin' +import {getPages} from './webpack/utils' +import CombineAssetsPlugin from './plugins/combine-assets-plugin' import PagesPlugin from './plugins/pages-plugin' +import NextJsSsrImportPlugin from './plugins/nextjs-ssr-import' import DynamicChunksPlugin from './plugins/dynamic-chunks-plugin' -import CombineAssetsPlugin from './plugins/combine-assets-plugin' -import getConfig from '../config' -import * as babelCore from 'babel-core' +import UnlinkFilePlugin from './plugins/unlink-file-plugin' import findBabelConfig from './babel/find-config' -import rootModuleRelativePath from './root-module-relative-path' -const documentPage = join('pages', '_document.js') +const nextDir = path.join(__dirname, '..', '..', '..') +const nextNodeModulesDir = path.join(nextDir, 'node_modules') +const nextPagesDir = path.join(nextDir, 'pages') const defaultPages = [ '_error.js', '_document.js' ] -const nextPagesDir = join(__dirname, '..', '..', 'pages') -const nextNodeModulesDir = join(__dirname, '..', '..', '..', 'node_modules') const interpolateNames = new Map(defaultPages.map((p) => { - return [join(nextPagesDir, p), `dist/pages/${p}`] + return [path.join(nextPagesDir, p), `dist/bundles/pages/${p}`] })) -const relativeResolve = rootModuleRelativePath(require) - -async function getPages ({dir, dev, pagesGlobPattern}) { - let pages - - if (dev) { - pages = await glob('pages/+(_document|_error).+(js|jsx)', { cwd: dir }) - } else { - pages = await glob(pagesGlobPattern, { cwd: dir }) - } - - return pages -} - -function getPageEntries (pages) { - const entries = {} - for (const p of pages) { - entries[join('bundles', p.replace('.jsx', '.js'))] = [`./${p}?entry`] - } - - // The default pages (_document.js and _error.js) are only added when they're not provided by the user - for (const p of defaultPages) { - const entryName = join('bundles', 'pages', p) - if (!entries[entryName]) { - entries[entryName] = [join(nextPagesDir, p) + '?entry'] - } - } - - return entries -} - -export default async function createCompiler (dir, { buildId, dev = false, quiet = false, buildDir, conf = null } = {}) { - // Resolve relative path to absolute path - dir = realpathSync(resolve(dir)) - - // Used to track the amount of pages for webpack commons chunk plugin - let totalPages - - // Loads next.config.js and custom configuration provided in custom server initialization - const config = getConfig(dir, conf) - - // Middlewares to handle on-demand entries and hot updates in development - const devEntries = dev ? [ - join(__dirname, '..', '..', 'client', 'webpack-hot-middleware-client'), - join(__dirname, '..', '..', 'client', 'on-demand-entries-client') - ] : [] - - const mainJS = require.resolve(`../../client/next${dev ? '-dev' : ''}`) // Uses client/next-dev in development for code splitting dev dependencies - - const entry = async () => { - // Get entries for pages in production mode. In development only _document and _error are added. Because pages are added by on-demand-entry-handler. - const pages = await getPages({dir, dev, pagesGlobPattern: config.pagesGlobPattern}) - const pageEntries = getPageEntries(pages) - - // Used for commons chunk calculations - totalPages = pages.length - if (pages.indexOf(documentPage) !== -1) { - totalPages = totalPages - 1 - } - - const entries = { - 'main.js': [ - ...devEntries, // Adds hot middleware and ondemand entries in development - ...config.clientBootstrap || [], // clientBootstrap can be used to load polyfills before code execution - mainJS // Main entrypoint in the client folder - ], - ...pageEntries - } - - return entries - } - - const plugins = [ - // Defines NODE_ENV as development/production. This is used by some npm modules to determine if they should optimize. - new webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production') - }), - new CaseSensitivePathPlugin(), // Since on macOS the filesystem is case-insensitive this will make sure your path are case-sensitive - new webpack.IgnorePlugin(/(precomputed)/, /node_modules.+(elliptic)/), - // Provide legacy options to webpack - new webpack.LoaderOptionsPlugin({ - options: { - context: dir, - customInterpolateName (url, name, opts) { - return interpolateNames.get(this.resourcePath) || url - } - } - }), - // Writes all generated files to disk, even in development. For SSR. - new WriteFilePlugin({ - exitOnErrors: false, - log: false, - // required not to cache removed files - useHashIndex: false - }), - // Moves common modules into commons.js - new webpack.optimize.CommonsChunkPlugin({ - name: 'commons', - filename: 'commons.js', - minChunks (module, count) { - // We need to move react-dom explicitly into common chunks. - // Otherwise, if some other page or module uses it, it might - // included in that bundle too. - if (dev && module.context && module.context.indexOf(`${sep}react${sep}`) >= 0) { - return true - } - - if (dev && module.context && module.context.indexOf(`${sep}react-dom${sep}`) >= 0) { - return true - } - - // In the dev we use on-demand-entries. - // So, it makes no sense to use commonChunks based on the minChunks count. - // Instead, we move all the code in node_modules into each of the pages. - if (dev) { - return false - } - - // If there are one or two pages, only move modules to common if they are - // used in all of the pages. Otherwise, move modules used in at-least - // 1/2 of the total pages into commons. - if (totalPages <= 2) { - return count >= totalPages - } - return count >= totalPages * 0.5 - } - }), - // This chunk splits out react and react-dom in production to make sure it does not go through uglify. This saved multiple seconds on production builds. - // See https://twitter.com/dan_abramov/status/944040306420408325 - new webpack.optimize.CommonsChunkPlugin({ - name: 'react', - filename: 'react.js', - minChunks (module, count) { - if (dev) { - return false - } - - if (module.resource && module.resource.includes(`${sep}react-dom${sep}`) && count >= 0) { - return true - } - - if (module.resource && module.resource.includes(`${sep}react${sep}`) && count >= 0) { - return true - } - - return false - } - }), - // This chunk contains all the webpack related code. So, all the changes - // related to that happens to this chunk. - // It won't touch commons.js and that gives us much better re-build perf. - new webpack.optimize.CommonsChunkPlugin({ - name: 'manifest', - filename: 'manifest.js' - }), - - // This adds Next.js route definitions to page bundles - new PagesPlugin(), - // Implements support for dynamic imports - new DynamicChunksPlugin() - ] - - if (dev) { - plugins.push( - new webpack.HotModuleReplacementPlugin(), - new webpack.NoEmitOnErrorsPlugin(), - new UnlinkFilePlugin() - ) - if (!quiet) { - plugins.push(new FriendlyErrorsWebpackPlugin()) - } - } else { - plugins.push(new webpack.IgnorePlugin(/react-hot-loader/)) - plugins.push( - // Minifies javascript bundles - new UglifyJSPlugin({ - exclude: /react\.js/, - parallel: true, - sourceMap: false, - uglifyOptions: { - compress: { - comparisons: false - } - } - }) - ) - plugins.push( - // Combines manifest.js commons.js and main.js into app.js in production - new CombineAssetsPlugin({ - input: ['manifest.js', 'react.js', 'commons.js', 'main.js'], - output: 'app.js' - }), - ) - // Implements scope hoisting which speeds up browser execution of javascript - plugins.push(new webpack.optimize.ModuleConcatenationPlugin()) - } - - const nodePathList = (process.env.NODE_PATH || '') - .split(process.platform === 'win32' ? ';' : ':') - .filter((p) => !!p) - +function babelConfig (dir, {isServer, dev}) { const mainBabelOptions = { cacheDirectory: true, - presets: [] + presets: [], + plugins: [ + dev && !isServer && require.resolve('react-hot-loader/babel') + ].filter(Boolean) } const externalBabelConfig = findBabelConfig(dir) if (externalBabelConfig) { - console.log(`> Using external babel configuration`) - console.log(`> Location: "${externalBabelConfig.loc}"`) + // Log it out once + if (!isServer) { + console.log(`> Using external babel configuration`) + console.log(`> Location: "${externalBabelConfig.loc}"`) + } // It's possible to turn off babelrc support via babelrc itself. // In that case, we should add our default preset. // That's why we need to do this. @@ -251,188 +54,252 @@ export default async function createCompiler (dir, { buildId, dev = false, quiet mainBabelOptions.presets.push(require.resolve('./babel/preset')) } - const devLoaders = dev ? [{ - test: /\.(js|jsx)(\?[^?]*)?$/, - loader: 'hot-self-accept-loader', - include: [ - join(dir, 'pages'), - nextPagesDir - ] - }, { - test: /\.(js|jsx)(\?[^?]*)?$/, - loader: 'react-hot-loader/webpack', - exclude: /node_modules/ - }] : [] + return mainBabelOptions +} - const loaders = [{ - test: /\.json$/, - loader: 'json-loader' - }, { - test: /\.(js|jsx|json)(\?[^?]*)?$/, - loader: 'emit-file-loader', - include: [dir, nextPagesDir], - exclude (str) { - return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0 - }, - options: { - name: 'dist/[path][name].[ext]', - // We need to strip off .jsx on the server. Otherwise require without .jsx doesn't work. - interpolateName: (name) => name.replace('.jsx', '.js'), - validateFileName (file) { - const cases = [{from: '.js', to: '.jsx'}, {from: '.jsx', to: '.js'}] +function externalsConfig (dir, isServer) { + const externals = [] - for (const item of cases) { - const {from, to} = item - if (file.slice(-(from.length)) !== from) { - continue - } - - const filePath = file.slice(0, -(from.length)) + to + if (!isServer) { + return externals + } - if (existsSync(filePath)) { - throw new Error(`Both ${from} and ${to} file found. Please make sure you only have one of both.`) - } - } - }, - // By default, our babel config does not transpile ES2015 module syntax because - // webpack knows how to handle them. (That's how it can do tree-shaking) - // But Node.js doesn't know how to handle them. So, we have to transpile them here. - transform ({ content, sourceMap, interpolatedName }) { - // Only handle .js files - if (!(/\.(js|jsx)$/.test(interpolatedName))) { - return { content, sourceMap } - } + // This will externalize all the 'next/xxx' modules to load from + // node_modules always. + // This is very useful in Next.js development where we use symlinked version + // of Next.js or using next/xxx inside test apps. + externals.push((context, request, callback) => { + resolve(request, { basedir: dir, preserveSymlinks: true }, (err, res) => { + if (err) { + return callback() + } - const transpiled = babelCore.transform(content, { - babelrc: false, - sourceMaps: dev ? 'both' : false, - // Here we need to resolve all modules to the absolute paths. - // Earlier we did it with the babel-preset. - // But since we don't transpile ES2015 in the preset this is not resolving. - // That's why we need to do it here. - // See more: https://github.com/zeit/next.js/issues/951 - plugins: [ - require.resolve(join(__dirname, './babel/plugins/remove-dotjsx-from-import.js')), - [require.resolve('babel-plugin-transform-es2015-modules-commonjs')], - [ - require.resolve('babel-plugin-module-resolver'), - { - alias: { - 'babel-runtime': relativeResolve('babel-runtime/package'), - 'next/link': relativeResolve('../../lib/link'), - 'next/prefetch': relativeResolve('../../lib/prefetch'), - 'next/css': relativeResolve('../../lib/css'), - 'next/dynamic': relativeResolve('../../lib/dynamic'), - 'next/head': relativeResolve('../../lib/head'), - 'next/document': relativeResolve('../../server/document'), - 'next/router': relativeResolve('../../lib/router'), - 'next/error': relativeResolve('../../lib/error'), - 'styled-jsx/style': relativeResolve('styled-jsx/style') - } - } - ] - ], - inputSourceMap: sourceMap - }) + if (res.match(/node_modules/)) { + return callback(null, `commonjs ${request}`) + } - // Strip ?entry to map back to filesystem and work with iTerm, etc. - let { map } = transpiled - let output = transpiled.code + callback() + }) + }) - if (map) { - let nodeMap = Object.assign({}, map) - nodeMap.sources = nodeMap.sources.map((source) => source.replace(/\?entry/, '')) - delete nodeMap.sourcesContent + return externals +} - // Output explicit inline source map that source-map-support can pickup via requireHook mode. - // Since these are not formal chunks, the devtool infrastructure in webpack does not output - // a source map for these files. - const sourceMapUrl = new Buffer(JSON.stringify(nodeMap), 'utf-8').toString('base64') - output = `${output}\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${sourceMapUrl}` - } +export default async function getBaseWebpackConfig (dir, {dev = false, isServer = false, buildId, config}) { + const babelLoaderOptions = babelConfig(dir, {dev, isServer}) - return { - content: output, - sourceMap: transpiled.map - } - } + const defaultLoaders = { + babel: { + loader: 'babel-loader', + options: babelLoaderOptions } - }, { - loader: 'babel-loader', - include: nextPagesDir, - exclude (str) { - return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0 - }, - options: { - babelrc: false, - cacheDirectory: true, - presets: [require.resolve('./babel/preset')] - } - }, { - test: /\.(js|jsx)(\?[^?]*)?$/, - loader: 'babel-loader', - include: [dir], - exclude (str) { - return /node_modules/.test(str) - }, - options: mainBabelOptions - }] + } + + let totalPages let webpackConfig = { + devtool: dev ? 'source-map' : false, + name: isServer ? 'server' : 'client', + cache: true, + target: isServer ? 'node' : 'web', + externals: externalsConfig(dir, isServer), context: dir, - entry, + entry: async () => { + const pages = await getPages(dir, {dev, isServer}) + totalPages = Object.keys(pages).length + const mainJS = require.resolve(`../../client/next${dev ? '-dev' : ''}`) + const clientConfig = !isServer ? { + 'main.js': [ + dev && !isServer && path.join(__dirname, '..', '..', 'client', 'webpack-hot-middleware-client'), + dev && !isServer && path.join(__dirname, '..', '..', 'client', 'on-demand-entries-client'), + mainJS + ].filter(Boolean) + } : {} + return { + ...clientConfig, + ...pages + } + }, output: { - path: buildDir ? join(buildDir, '.next') : join(dir, config.distDir), + path: path.join(dir, config.distDir, isServer ? 'dist' : ''), // server compilation goes to `.next/dist` filename: '[name]', libraryTarget: 'commonjs2', - publicPath: `/_next/webpack/`, - strictModuleExceptionHandling: true, - devtoolModuleFilenameTemplate ({ resourcePath }) { - const hash = createHash('sha1') - hash.update(Date.now() + '') - const id = hash.digest('hex').slice(0, 7) - - // append hash id for cache busting - return `webpack:///${resourcePath}?${id}` - }, + publicPath: `${config.assetPrefix}/_next/webpack/`, // This saves chunks with the name given via require.ensure() - chunkFilename: '[name]-[chunkhash].js' + chunkFilename: '[name]-[chunkhash].js', + strictModuleExceptionHandling: true, + devtoolModuleFilenameTemplate: '[absolute-resource-path]' }, + performance: { hints: false }, resolve: { + extensions: ['.js', '.jsx', '.json'], + modules: [ + nextNodeModulesDir, + 'node_modules' + ], alias: { + next: nextDir, // This bypasses React's check for production mode. Since we know it is in production this way. // This allows us to exclude React from being uglified. Saving multiple seconds per build. + react: dev ? 'react/cjs/react.development.js' : 'react/cjs/react.production.min.js', 'react-dom': dev ? 'react-dom/cjs/react-dom.development.js' : 'react-dom/cjs/react-dom.production.min.js' - }, - extensions: ['.js', '.jsx', '.json'], - modules: [ - nextNodeModulesDir, - 'node_modules', - ...nodePathList - ] + } }, resolveLoader: { modules: [ nextNodeModulesDir, 'node_modules', - join(__dirname, 'loaders'), - ...nodePathList + path.join(__dirname, 'loaders') ] }, - plugins, module: { rules: [ - ...devLoaders, - ...loaders - ] + dev && !isServer && { + test: /\.(js|jsx)(\?[^?]*)?$/, + loader: 'hot-self-accept-loader', + include: [ + path.join(dir, 'pages'), + nextPagesDir + ] + }, + { + test: /\.+(js|jsx)$/, + include: [dir], + exclude: /node_modules/, + use: defaultLoaders.babel + } + ].filter(Boolean) }, - devtool: dev ? 'cheap-module-inline-source-map' : false, - performance: { hints: false } + plugins: [ + new webpack.IgnorePlugin(/(precomputed)/, /node_modules.+(elliptic)/), + dev && new webpack.NoEmitOnErrorsPlugin(), + dev && !isServer && new FriendlyErrorsWebpackPlugin(), + dev && new webpack.NamedModulesPlugin(), + dev && !isServer && new webpack.HotModuleReplacementPlugin(), // Hot module replacement + dev && new UnlinkFilePlugin(), + dev && new CaseSensitivePathPlugin(), // Since on macOS the filesystem is case-insensitive this will make sure your path are case-sensitive + dev && new webpack.LoaderOptionsPlugin({ + options: { + context: dir, + customInterpolateName (url, name, opts) { + return interpolateNames.get(this.resourcePath) || url + } + } + }), + dev && new WriteFilePlugin({ + exitOnErrors: false, + log: false, + // required not to cache removed files + useHashIndex: false + }), + !dev && new webpack.IgnorePlugin(/react-hot-loader/), + !isServer && !dev && new UglifyJSPlugin({ + exclude: /react\.js/, + parallel: true, + sourceMap: false, + uglifyOptions: { + compress: { + arrows: false, + booleans: false, + collapse_vars: false, + comparisons: false, + computed_props: false, + hoist_funs: false, + hoist_props: false, + hoist_vars: false, + if_return: false, + inline: false, + join_vars: false, + keep_infinity: true, + loops: false, + negate_iife: false, + properties: false, + reduce_funcs: false, + reduce_vars: false, + sequences: false, + side_effects: false, + switches: false, + top_retain: false, + toplevel: false, + typeofs: false, + unused: false, + conditionals: false, + dead_code: true, + evaluate: false + } + } + }), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production') + }), + !isServer && new CombineAssetsPlugin({ + input: ['manifest.js', 'react.js', 'commons.js', 'main.js'], + output: 'app.js' + }), + !dev && new webpack.optimize.ModuleConcatenationPlugin(), + !isServer && new PagesPlugin(), + !isServer && new DynamicChunksPlugin(), + isServer && new NextJsSsrImportPlugin({ dir, dist: config.distDir }), + !isServer && new webpack.optimize.CommonsChunkPlugin({ + name: `commons`, + filename: `commons.js`, + minChunks (module, count) { + // We need to move react-dom explicitly into common chunks. + // Otherwise, if some other page or module uses it, it might + // included in that bundle too. + if (dev && module.context && module.context.indexOf(`${sep}react${sep}`) >= 0) { + return true + } + + if (dev && module.context && module.context.indexOf(`${sep}react-dom${sep}`) >= 0) { + return true + } + + // In the dev we use on-demand-entries. + // So, it makes no sense to use commonChunks based on the minChunks count. + // Instead, we move all the code in node_modules into each of the pages. + if (dev) { + return false + } + + // If there are one or two pages, only move modules to common if they are + // used in all of the pages. Otherwise, move modules used in at-least + // 1/2 of the total pages into commons. + if (totalPages <= 2) { + return count >= totalPages + } + return count >= totalPages * 0.5 + } + }), + !isServer && new webpack.optimize.CommonsChunkPlugin({ + name: 'react', + filename: 'react.js', + minChunks (module, count) { + if (dev) { + return false + } + + if (module.resource && module.resource.includes(`${sep}react-dom${sep}`) && count >= 0) { + return true + } + + if (module.resource && module.resource.includes(`${sep}react${sep}`) && count >= 0) { + return true + } + + return false + } + }), + !isServer && new webpack.optimize.CommonsChunkPlugin({ + name: 'manifest', + filename: 'manifest.js' + }) + ].filter(Boolean) } - if (config.webpack) { - console.log(`> Using "webpack" config function defined in ${config.configOrigin}.`) - webpackConfig = await config.webpack(webpackConfig, { buildId, dev }) + if (typeof config.webpack === 'function') { + webpackConfig = config.webpack(webpackConfig, {dir, dev, isServer, buildId, config, defaultLoaders}) } - return webpack(webpackConfig) + + return webpackConfig } diff --git a/server/build/webpack/utils.js b/server/build/webpack/utils.js new file mode 100644 index 0000000000000..60e6490969fb9 --- /dev/null +++ b/server/build/webpack/utils.js @@ -0,0 +1,68 @@ +import path from 'path' +import glob from 'glob-promise' + +const nextPagesDir = path.join(__dirname, '..', '..', '..', 'pages') + +export async function getPages (dir, {dev, isServer}) { + const pageFiles = await getPagePaths(dir, {dev, isServer}) + + return getPageEntries(pageFiles, {isServer}) +} + +async function getPagePaths (dir, {dev, isServer}) { + let pages + + if (dev) { + pages = await glob(isServer ? 'pages/+(_document|_error).+(js|jsx|ts|tsx)' : 'pages/_error.+(js|jsx|ts|tsx)', { cwd: dir }) + } else { + pages = await glob(isServer ? 'pages/**/*.+(js|jsx|ts|tsx)' : 'pages/**/!(_document)*.+(js|jsx|ts|tsx)', { cwd: dir }) + } + + return pages +} + +// Convert page path into single entry +export function createEntry (filePath, name) { + const parsedPath = path.parse(filePath) + let entryName = name || filePath + + // This makes sure we compile `pages/blog/index.js` to `pages/blog.js`. + // Excludes `pages/index.js` from this rule since we do want `/` to route to `pages/index.js` + if (parsedPath.dir !== 'pages' && parsedPath.name === 'index') { + entryName = `${parsedPath.dir}.js` + } + + // Makes sure supported extensions are stripped off. The outputted file should always be `.js` + entryName = entryName.replace(/\.+(jsx|tsx|ts)/, '.js') + + return { + name: path.join('bundles', entryName), + files: [parsedPath.root ? filePath : `./${filePath}`] // The entry always has to be an array. + } +} + +// Convert page paths into entries +export function getPageEntries (pagePaths, {isServer}) { + const entries = {} + + for (const filePath of pagePaths) { + const entry = createEntry(filePath) + entries[entry.name] = entry.files + } + + const errorPagePath = path.join(nextPagesDir, '_error.js') + const errorPageEntry = createEntry(errorPagePath, 'pages/_error.js') // default error.js + if (!entries[errorPageEntry.name]) { + entries[errorPageEntry.name] = errorPageEntry.files + } + + if (isServer) { + const documentPagePath = path.join(nextPagesDir, '_document.js') + const documentPageEntry = createEntry(documentPagePath, 'pages/_document.js') + if (!entries[documentPageEntry.name]) { + entries[documentPageEntry.name] = documentPageEntry.files + } + } + + return entries +} diff --git a/server/config.js b/server/config.js index 395b92c526ab5..5aabc60bd9fbb 100644 --- a/server/config.js +++ b/server/config.js @@ -5,12 +5,10 @@ const cache = new Map() const defaultConfig = { webpack: null, webpackDevMiddleware: null, - poweredByHeader: true, distDir: '.next', assetPrefix: '', configOrigin: 'default', - useFileSystemPublicRoutes: true, - pagesGlobPattern: 'pages/**/*.+(js|jsx)' + useFileSystemPublicRoutes: true } export default function getConfig (dir, customConfig) { @@ -34,6 +32,9 @@ function loadConfig (dir, customConfig) { if (path && path.length) { const userConfigModule = require(path) userConfig = userConfigModule.default || userConfigModule + if (userConfig.poweredByHeader === true || userConfig.poweredByHeader === false) { + console.warn('> the `poweredByHeader` option has been removed https://err.sh/zeit/next.js/powered-by-header-option-removed') + } userConfig.configOrigin = 'next.config.js' } diff --git a/server/document.js b/server/document.js index 05de031640c63..49eea8a5190c0 100644 --- a/server/document.js +++ b/server/document.js @@ -4,7 +4,7 @@ import htmlescape from 'htmlescape' import flush from 'styled-jsx/server' const Fragment = React.Fragment || function Fragment ({ children }) { - return children + return
{children}
} export default class Document extends Component { @@ -106,7 +106,6 @@ export class Main extends Component { render () { const { html, errorHtml } = this.context._documentProps - return (
diff --git a/server/hot-reloader.js b/server/hot-reloader.js index 94ffa55074e27..fb4b92deb9be7 100644 --- a/server/hot-reloader.js +++ b/server/hot-reloader.js @@ -2,12 +2,14 @@ import { join, relative, sep } from 'path' import WebpackDevMiddleware from 'webpack-dev-middleware' import WebpackHotMiddleware from 'webpack-hot-middleware' import onDemandEntryHandler from './on-demand-entry-handler' -import webpack from './build/webpack' +import webpack from 'webpack' +import getBaseWebpackConfig from './build/webpack' import clean from './build/clean' import getConfig from './config' import UUID from 'uuid' import { - IS_BUNDLED_PAGE + IS_BUNDLED_PAGE, + addCorsSupport } from './utils' export default class HotReloader { @@ -34,6 +36,15 @@ export default class HotReloader { } async run (req, res) { + // Usually CORS support is not needed for the hot-reloader (this is dev only feature) + // With when the app runs for multi-zones support behind a proxy, + // the current page is trying to access this URL via assetPrefix. + // That's when the CORS support is needed. + const { preflight } = addCorsSupport(req, res) + if (preflight) { + return + } + for (const fn of this.middlewares) { await new Promise((resolve, reject) => { fn(req, res, (err) => { @@ -45,15 +56,19 @@ export default class HotReloader { } async start () { - const [compiler] = await Promise.all([ - webpack(this.dir, { buildId: this.buildId, dev: true, quiet: this.quiet }), - clean(this.dir) + await clean(this.dir) + + const configs = await Promise.all([ + getBaseWebpackConfig(this.dir, { dev: true, isServer: false, config: this.config }), + getBaseWebpackConfig(this.dir, { dev: true, isServer: true, config: this.config }) ]) + const compiler = webpack(configs) + const buildTools = await this.prepareBuildTools(compiler) this.assignBuildTools(buildTools) - this.stats = await this.waitUntilValid() + this.stats = (await this.waitUntilValid()).stats[0] } async stop (webpackDevMiddleware) { @@ -71,11 +86,15 @@ export default class HotReloader { async reload () { this.stats = null - const [compiler] = await Promise.all([ - webpack(this.dir, { buildId: this.buildId, dev: true, quiet: this.quiet }), - clean(this.dir) + await clean(this.dir) + + const configs = await Promise.all([ + getBaseWebpackConfig(this.dir, { dev: true, isServer: false, config: this.config }), + getBaseWebpackConfig(this.dir, { dev: true, isServer: true, config: this.config }) ]) + const compiler = webpack(configs) + const buildTools = await this.prepareBuildTools(compiler) this.stats = await this.waitUntilValid(buildTools.webpackDevMiddleware) @@ -97,25 +116,28 @@ export default class HotReloader { } async prepareBuildTools (compiler) { - compiler.plugin('after-emit', (compilation, callback) => { - const { assets } = compilation - - if (this.prevAssets) { - for (const f of Object.keys(assets)) { - deleteCache(assets[f].existsAt) - } - for (const f of Object.keys(this.prevAssets)) { - if (!assets[f]) { - deleteCache(this.prevAssets[f].existsAt) + // This flushes require.cache after emitting the files. Providing 'hot reloading' of server files. + compiler.compilers.forEach((singleCompiler) => { + singleCompiler.plugin('after-emit', (compilation, callback) => { + const { assets } = compilation + + if (this.prevAssets) { + for (const f of Object.keys(assets)) { + deleteCache(assets[f].existsAt) + } + for (const f of Object.keys(this.prevAssets)) { + if (!assets[f]) { + deleteCache(this.prevAssets[f].existsAt) + } } } - } - this.prevAssets = assets + this.prevAssets = assets - callback() + callback() + }) }) - compiler.plugin('done', (stats) => { + compiler.compilers[0].plugin('done', (stats) => { const { compilation } = stats const chunkNames = new Set( compilation.chunks @@ -193,12 +215,13 @@ export default class HotReloader { const webpackDevMiddleware = WebpackDevMiddleware(compiler, webpackDevMiddlewareConfig) - const webpackHotMiddleware = WebpackHotMiddleware(compiler, { + const webpackHotMiddleware = WebpackHotMiddleware(compiler.compilers[0], { path: '/_next/webpack-hmr', log: false, heartbeat: 2500 }) - const onDemandEntries = onDemandEntryHandler(webpackDevMiddleware, compiler, { + + const onDemandEntries = onDemandEntryHandler(webpackDevMiddleware, compiler.compilers, { dir: this.dir, dev: true, reload: this.reload.bind(this), @@ -249,8 +272,8 @@ export default class HotReloader { this.webpackHotMiddleware.publish({ action, data: args }) } - ensurePage (page) { - return this.onDemandEntries.ensurePage(page) + async ensurePage (page) { + await this.onDemandEntries.ensurePage(page) } } diff --git a/server/index.js b/server/index.js index 31d1c8150cb92..6b3493822e3c1 100644 --- a/server/index.js +++ b/server/index.js @@ -1,3 +1,4 @@ +require('@zeit/source-map-support').install() import { resolve, join, sep } from 'path' import { parse as parseUrl } from 'url' import { parse as parseQs } from 'querystring' @@ -11,28 +12,11 @@ import { renderScriptError } from './render' import Router from './router' -import { getAvailableChunks } from './utils' +import { getAvailableChunks, isInternalUrl } from './utils' import getConfig from './config' // We need to go up one more level since we are in the `dist` directory import pkg from '../../package' -import reactPkg from 'react/package' - -// TODO: Remove this in Next.js 5 -if (!(/^16\./.test(reactPkg.version))) { - const message = ` -Error: Next.js 4 requires React 16. -Install React 16 with: - npm remove react react-dom - npm install --save react@16 react-dom@16 -` - console.error(message) - process.exit(1) -} - -const internalPrefixes = [ - /^\/_next\//, - /^\/static\// -] +import * as asset from '../lib/asset' const blockedPages = { '/_document': true, @@ -41,14 +25,6 @@ const blockedPages = { export default class Server { constructor ({ dir = '.', dev = false, staticMarkup = false, quiet = false, conf = null } = {}) { - // When in dev mode, remap the inline source maps that we generate within the webpack portion - // of the build. - if (dev) { - require('source-map-support').install({ - hookRequire: true - }) - } - this.dir = resolve(dir) this.dev = dev this.quiet = quiet @@ -74,6 +50,9 @@ export default class Server { availableChunks: dev ? {} : getAvailableChunks(this.dir, this.dist) } + // With this, static assets will work across zones + asset.setAssetPrefix(this.config.assetPrefix) + this.defineRoutes() } @@ -182,6 +161,23 @@ export default class Server { await this.serveStatic(req, res, p) }, + '/_next/:buildId/page/:path*.js.map': async (req, res, params) => { + const paths = params.path || [''] + const page = `/${paths.join('/')}` + + if (this.dev) { + try { + await this.hotReloader.ensurePage(page) + } catch (err) { + await this.render404(req, res) + } + } + + const dist = getConfig(this.dir).distDir + const path = join(this.dir, dist, 'bundles', 'pages', `${page}.js.map`) + await serveStatic(req, res, path) + }, + '/_next/:buildId/page/_error*': async (req, res, params) => { if (!this.handleBuildId(params.buildId, res)) { const error = new Error('INVALID_BUILD_ID') @@ -196,9 +192,6 @@ export default class Server { '/_next/:buildId/page/:path*.js': async (req, res, params) => { const paths = params.path || [''] - // URL is asks for ${page}.js (to support loading assets from static dirs) - // But there's no .js in the actual page. - // So, we need to remove .js to get the page name. const page = `/${paths.join('/')}` if (!this.handleBuildId(params.buildId, res)) { @@ -222,11 +215,13 @@ export default class Server { } } - let p = join(this.dir, this.dist, 'bundles', 'pages', paths.join('/')) - if (!fs.existsSync(`${p}.js`)) { - p = join(p, 'index') // It's possible to have index.js in a subfolder - } - await this.serveStatic(req, res, `${p}.js`) + const p = join(this.dir, this.dist, 'bundles', 'pages', `${page}.js`) + await this.serveStatic(req, res, p) + }, + + '/_next/static/:path*': async (req, res, params) => { + const p = join(this.dist, 'static', ...(params.path || [])) + await this.serveStatic(req, res, p) }, // It's very important keep this route's param optional. @@ -293,7 +288,7 @@ export default class Server { } async render (req, res, pathname, query, parsedUrl) { - if (this.isInternalUrl(req)) { + if (isInternalUrl(req.url)) { return this.handleRequest(req, res, parsedUrl) } @@ -301,10 +296,8 @@ export default class Server { return await this.render404(req, res, parsedUrl) } - if (this.config.poweredByHeader) { - res.setHeader('X-Powered-By', `Next.js ${pkg.version}`) - } const html = await this.renderToHTML(req, res, pathname, query) + res.setHeader('X-Powered-By', `Next.js ${pkg.version}`) return sendHTML(req, res, html, req.method, this.renderOpts) } @@ -318,7 +311,8 @@ export default class Server { } try { - return await renderToHTML(req, res, pathname, query, this.renderOpts) + const out = await renderToHTML(req, res, pathname, query, this.renderOpts) + return out } catch (err) { if (err.code === 'ENOENT') { res.statusCode = 404 @@ -393,16 +387,6 @@ export default class Server { return true } - isInternalUrl (req) { - for (const prefix of internalPrefixes) { - if (prefix.test(req.url)) { - return true - } - } - - return false - } - readBuildId () { const buildIdPath = join(this.dir, this.dist, 'BUILD_ID') const buildId = fs.readFileSync(buildIdPath, 'utf8') diff --git a/server/on-demand-entry-handler.js b/server/on-demand-entry-handler.js index fdd55328dfc4b..f723c95141f7a 100644 --- a/server/on-demand-entry-handler.js +++ b/server/on-demand-entry-handler.js @@ -1,20 +1,21 @@ import DynamicEntryPlugin from 'webpack/lib/DynamicEntryPlugin' import { EventEmitter } from 'events' -import { join } from 'path' +import { join, relative } from 'path' import { parse } from 'url' -import resolvePath from './resolve' import touch from 'touch' +import resolvePath from './resolve' +import {createEntry} from './build/webpack/utils' import { MATCH_ROUTE_NAME, IS_BUNDLED_PAGE } from './utils' const ADDED = Symbol('added') const BUILDING = Symbol('building') const BUILT = Symbol('built') -export default function onDemandEntryHandler (devMiddleware, compiler, { +export default function onDemandEntryHandler (devMiddleware, compilers, { dir, dev, reload, - maxInactiveAge = 1000 * 25, + maxInactiveAge = 1000 * 60, pagesBufferLength = 2 }) { let entries = {} @@ -25,81 +26,90 @@ export default function onDemandEntryHandler (devMiddleware, compiler, { let reloading = false let stopped = false let reloadCallbacks = new EventEmitter() + // Keep the names of compilers which are building pages at a given moment. + const currentBuilders = new Set() + + compilers.forEach(compiler => { + compiler.plugin('make', function (compilation, done) { + invalidator.startBuilding() + currentBuilders.add(compiler.name) + + const allEntries = Object.keys(entries).map((page) => { + const { name, entry } = entries[page] + entries[page].status = BUILDING + return addEntry(compilation, this.context, name, entry) + }) - compiler.plugin('make', function (compilation, done) { - invalidator.startBuilding() - - const allEntries = Object.keys(entries).map((page) => { - const { name, entry } = entries[page] - entries[page].status = BUILDING - return addEntry(compilation, this.context, name, entry) + Promise.all(allEntries) + .then(() => done()) + .catch(done) }) - Promise.all(allEntries) - .then(() => done()) - .catch(done) - }) + compiler.plugin('done', function (stats) { + // Wait until all the compilers mark the build as done. + currentBuilders.delete(compiler.name) + if (currentBuilders.size !== 0) return - compiler.plugin('done', function (stats) { - const { compilation } = stats - const hardFailedPages = compilation.errors - .filter(e => { - // Make sure to only pick errors which marked with missing modules - const hasNoModuleFoundError = /ENOENT/.test(e.message) || /Module not found/.test(e.message) - if (!hasNoModuleFoundError) return false + const { compilation } = stats + const hardFailedPages = compilation.errors + .filter(e => { + // Make sure to only pick errors which marked with missing modules + const hasNoModuleFoundError = /ENOENT/.test(e.message) || /Module not found/.test(e.message) + if (!hasNoModuleFoundError) return false - // The page itself is missing. So this is a failed page. - if (IS_BUNDLED_PAGE.test(e.module.name)) return true + // The page itself is missing. So this is a failed page. + if (IS_BUNDLED_PAGE.test(e.module.name)) return true - // No dependencies means this is a top level page. - // So this is a failed page. - return e.module.dependencies.length === 0 - }) - .map(e => e.module.chunks) - .reduce((a, b) => [...a, ...b], []) - .map(c => { - const pageName = MATCH_ROUTE_NAME.exec(c.name)[1] - return normalizePage(`/${pageName}`) + // No dependencies means this is a top level page. + // So this is a failed page. + return e.module.dependencies.length === 0 + }) + .map(e => e.module.chunks) + .reduce((a, b) => [...a, ...b], []) + .map(c => { + const pageName = MATCH_ROUTE_NAME.exec(c.name)[1] + return normalizePage(`/${pageName}`) + }) + + // Call all the doneCallbacks + Object.keys(entries).forEach((page) => { + const entryInfo = entries[page] + if (entryInfo.status !== BUILDING) return + + // With this, we are triggering a filesystem based watch trigger + // It'll memorize some timestamp related info related to common files used + // in the page + // That'll reduce the page building time significantly. + if (!touchedAPage) { + setTimeout(() => { + touch.sync(entryInfo.pathname) + }, 1000) + touchedAPage = true + } + + entryInfo.status = BUILT + entries[page].lastActiveTime = Date.now() + doneCallbacks.emit(page) }) - // Call all the doneCallbacks - Object.keys(entries).forEach((page) => { - const entryInfo = entries[page] - if (entryInfo.status !== BUILDING) return - - // With this, we are triggering a filesystem based watch trigger - // It'll memorize some timestamp related info related to common files used - // in the page - // That'll reduce the page building time significantly. - if (!touchedAPage) { - setTimeout(() => { - touch.sync(entryInfo.pathname) - }, 1000) - touchedAPage = true + invalidator.doneBuilding(compiler.name) + + if (hardFailedPages.length > 0 && !reloading) { + console.log(`> Reloading webpack due to inconsistant state of pages(s): ${hardFailedPages.join(', ')}`) + reloading = true + reload() + .then(() => { + console.log('> Webpack reloaded.') + reloadCallbacks.emit('done') + stop() + }) + .catch(err => { + console.error(`> Webpack reloading failed: ${err.message}`) + console.error(err.stack) + process.exit(1) + }) } - - entryInfo.status = BUILT - entries[page].lastActiveTime = Date.now() - doneCallbacks.emit(page) }) - - invalidator.doneBuilding() - - if (hardFailedPages.length > 0 && !reloading) { - console.log(`> Reloading webpack due to inconsistant state of pages(s): ${hardFailedPages.join(', ')}`) - reloading = true - reload() - .then(() => { - console.log('> Webpack reloaded.') - reloadCallbacks.emit('done') - stop() - }) - .catch(err => { - console.error(`> Webpack reloading failed: ${err.message}`) - console.error(err.stack) - process.exit(1) - }) - } }) const disposeHandler = setInterval(function () { @@ -130,9 +140,7 @@ export default function onDemandEntryHandler (devMiddleware, compiler, { const pagePath = join(dir, 'pages', page) const pathname = await resolvePath(pagePath) - const name = join('bundles', pathname.substring(dir.length)) - - const entry = [`${pathname}?entry`] + const {name, files} = createEntry(relative(dir, pathname)) await new Promise((resolve, reject) => { const entryInfo = entries[page] @@ -144,19 +152,19 @@ export default function onDemandEntryHandler (devMiddleware, compiler, { } if (entryInfo.status === BUILDING) { - doneCallbacks.on(page, processCallback) + doneCallbacks.once(page, handleCallback) return } } console.log(`> Building page: ${page}`) - entries[page] = { name, entry, pathname, status: ADDED } - doneCallbacks.on(page, processCallback) + entries[page] = { name, entry: files, pathname, status: ADDED } + doneCallbacks.once(page, handleCallback) invalidator.invalidate() - function processCallback (err) { + function handleCallback (err) { if (err) return reject(err) resolve() } @@ -216,6 +224,7 @@ export default function onDemandEntryHandler (devMiddleware, compiler, { } } +// Based on https://github.com/webpack/webpack/blob/master/lib/DynamicEntryPlugin.js#L29-L37 function addEntry (compilation, context, name, entry) { return new Promise((resolve, reject) => { const dep = DynamicEntryPlugin.createDependency(entry, name) @@ -272,6 +281,7 @@ function sendJson (res, payload) { class Invalidator { constructor (devMiddleware) { this.devMiddleware = devMiddleware + // contains an array of types of compilers currently building this.building = false this.rebuildAgain = false } @@ -296,6 +306,7 @@ class Invalidator { doneBuilding () { this.building = false + if (this.rebuildAgain) { this.rebuildAgain = false this.invalidate() diff --git a/server/render.js b/server/render.js index d3ab29ce052dc..e56bdbb7b43f9 100644 --- a/server/render.js +++ b/server/render.js @@ -6,7 +6,6 @@ import generateETag from 'etag' import fresh from 'fresh' import requireModule from './require' import getConfig from './config' -import resolvePath from './resolve' import { Router } from '../lib/router' import { loadGetInitialProps } from '../lib/utils' import { getAvailableChunks } from './utils' @@ -53,9 +52,12 @@ async function doRender (req, res, pathname, query, { const dist = getConfig(dir).distDir + const pagePath = join(dir, dist, 'dist', 'bundles', 'pages', page) + const documentPath = join(dir, dist, 'dist', 'bundles', 'pages', '_document') + let [Component, Document] = await Promise.all([ - requireModule(join(dir, dist, 'dist', 'pages', page)), - requireModule(join(dir, dist, 'dist', 'pages', '_document')) + requireModule(pagePath), + requireModule(documentPath) ]) Component = Component.default || Component Document = Document.default || Document @@ -120,22 +122,6 @@ async function doRender (req, res, pathname, query, { return '' + renderToStaticMarkup(doc) } -export async function renderScript (req, res, page, opts) { - try { - const dist = getConfig(opts.dir).distDir - const path = join(opts.dir, dist, 'bundles', 'pages', page) - const realPath = await resolvePath(path) - await serveStatic(req, res, realPath) - } catch (err) { - if (err.code === 'ENOENT') { - renderScriptError(req, res, page, err, {}, opts) - return - } - - throw err - } -} - export async function renderScriptError (req, res, page, error, customFields, { dev }) { // Asks CDNs and others to not to cache the errored page res.setHeader('Cache-Control', 'no-store, must-revalidate') diff --git a/server/resolve.js b/server/resolve.js index 543dded791122..d33fee65184aa 100644 --- a/server/resolve.js +++ b/server/resolve.js @@ -28,12 +28,16 @@ function getPaths (id) { if (i.slice(-3) === '.js') return [i] if (i.slice(-4) === '.jsx') return [i] + if (i.slice(-4) === '.tsx') return [i] + if (i.slice(-3) === '.ts') return [i] if (i.slice(-5) === '.json') return [i] if (i[i.length - 1] === sep) { return [ i + 'index.js', i + 'index.jsx', + i + 'index.ts', + i + 'index.tsx', i + 'index.json' ] } @@ -43,6 +47,10 @@ function getPaths (id) { join(i, 'index.js'), i + '.jsx', join(i, 'index.jsx'), + i + '.tsx', + join(i, 'index.tsx'), + i + '.ts', + join(i, 'index.ts'), i + '.json', join(i, 'index.json') ] diff --git a/server/utils.js b/server/utils.js index 5821a8617495e..3e546e8b3b8f3 100644 --- a/server/utils.js +++ b/server/utils.js @@ -1,8 +1,8 @@ import { join } from 'path' import { readdirSync, existsSync } from 'fs' -export const IS_BUNDLED_PAGE = /^bundles[/\\]pages.*\.(js|jsx)$/ -export const MATCH_ROUTE_NAME = /^bundles[/\\]pages[/\\](.*)\.(js|jsx)$/ +export const IS_BUNDLED_PAGE = /^bundles[/\\]pages.*\.js$/ +export const MATCH_ROUTE_NAME = /^bundles[/\\]pages[/\\](.*)\.js$/ export function getAvailableChunks (dir, dist) { const chunksDir = join(dir, dist, 'chunks') @@ -20,3 +20,37 @@ export function getAvailableChunks (dir, dist) { return chunksMap } + +const internalPrefixes = [ + /^\/_next\//, + /^\/static\// +] + +export function isInternalUrl (url) { + for (const prefix of internalPrefixes) { + if (prefix.test(url)) { + return true + } + } + + return false +} + +export function addCorsSupport (req, res) { + if (!req.headers.origin) { + return { preflight: false } + } + + res.setHeader('Access-Control-Allow-Origin', req.headers.origin) + res.setHeader('Access-Control-Request-Method', req.headers.origin) + res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET') + res.setHeader('Access-Control-Allow-Headers', req.headers.origin) + + if (req.method === 'OPTIONS') { + res.writeHead(200) + res.end() + return { preflight: true } + } + + return { preflight: false } +} diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000000000..cf4bab9ddde9f --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +!node_modules diff --git a/test/integration/basic/test/dynamic.js b/test/integration/basic/test/dynamic.js index 1744e4a1c8265..7c83c7744e00e 100644 --- a/test/integration/basic/test/dynamic.js +++ b/test/integration/basic/test/dynamic.js @@ -11,17 +11,17 @@ export default (context, render) => { return cheerio.load(html) } - it('should render dynmaic import components', async () => { + it('should render dynamic import components', async () => { const $ = await get$('/dynamic/ssr') expect($('p').text()).toBe('Hello World 1') }) - it('should stop render dynmaic import components', async () => { + it('should stop render dynamic import components', async () => { const $ = await get$('/dynamic/no-ssr') expect($('p').text()).toBe('loading...') }) - it('should stop render dynmaic import components with custom loading', async () => { + it('should stop render dynamic import components with custom loading', async () => { const $ = await get$('/dynamic/no-ssr-custom-loading') expect($('p').text()).toBe('LOADING') }) diff --git a/test/integration/production/test/index.test.js b/test/integration/production/test/index.test.js index 217818f9d9a96..1916c81abf26e 100644 --- a/test/integration/production/test/index.test.js +++ b/test/integration/production/test/index.test.js @@ -145,26 +145,6 @@ describe('Production Usage', () => { 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 = { - getHeader () { - return false - }, - 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/node_modules/next b/test/node_modules/next new file mode 120000 index 0000000000000..c25bddb6dd466 --- /dev/null +++ b/test/node_modules/next @@ -0,0 +1 @@ +../.. \ No newline at end of file diff --git a/wallaby.js b/wallaby.js deleted file mode 100644 index dedab25e4baf1..0000000000000 --- a/wallaby.js +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = function (wallaby) { - return { - files: [ - 'server/**/*.js', - 'client/**/*.js', - 'lib/**/*.js', - 'dist/**/*.js', - 'test/**/*.*', - '!test/**/*.test.js' - ], - - tests: [ - 'test/**/*.test.js', - '!test/integration/**/*.test.js' - ], - - compilers: { - '**/*.js': wallaby.compilers.babel() - }, - - env: { - type: 'node', - runner: 'node', - params: { - env: 'NODE_PATH=test/lib' - } - }, - - testFramework: 'jest' - } -} diff --git a/yarn.lock b/yarn.lock index b9aa4c9ac8bed..98bccd3de9d74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,51 +2,6 @@ # yarn lockfile v1 -"@semantic-release/commit-analyzer@^3.0.1": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@semantic-release/commit-analyzer/-/commit-analyzer-3.0.7.tgz#dc955444a6d3d2ae9b8e21f90c2c80c4e9142b2f" - dependencies: - "@semantic-release/error" "^2.0.0" - conventional-changelog-angular "^1.4.0" - conventional-commits-parser "^2.0.0" - import-from "^2.1.0" - lodash "^4.17.4" - pify "^3.0.0" - -"@semantic-release/condition-travis@^6.0.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@semantic-release/condition-travis/-/condition-travis-6.1.0.tgz#7962c728f4c19389b57759c7ff9ee08df9b15795" - dependencies: - "@semantic-release/error" "^2.0.0" - github "^11.0.0" - parse-github-repo-url "^1.4.1" - semver "^5.0.3" - travis-deploy-once "^3.0.0" - -"@semantic-release/error@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@semantic-release/error/-/error-2.0.0.tgz#f156ecd509f5288c48bc7425a8abe22f975d1f8b" - -"@semantic-release/last-release-npm@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@semantic-release/last-release-npm/-/last-release-npm-2.0.2.tgz#c91b1ccb48b0d7095b107be6ebc2c0c08bd88c27" - dependencies: - "@semantic-release/error" "^2.0.0" - npm-registry-client "^8.4.0" - npmlog "^4.0.0" - -"@semantic-release/release-notes-generator@^4.0.0": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-4.0.5.tgz#46cc2f16bdb60fe9674bbcd616bfe0f8bb35347c" - dependencies: - "@semantic-release/error" "^2.0.0" - conventional-changelog-angular "^1.4.0" - conventional-changelog-core "^1.9.0" - get-stream "^3.0.0" - import-from "^2.1.0" - lodash "^4.17.4" - pify "^3.0.0" - "@taskr/babel@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@taskr/babel/-/babel-1.1.0.tgz#f5af6b236395cbd013d3f67328ca73651e0299a1" @@ -75,12 +30,11 @@ dependencies: chokidar "^1.7.0" -JSONStream@^1.0.4: - version "1.3.1" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.1.tgz#707f761e01dae9e16f1bcf93703b78c70966579a" +"@zeit/source-map-support@0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@zeit/source-map-support/-/source-map-support-0.6.0.tgz#3808cbe343ae786a9a5cad06fd5a1aab210baea0" dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" + source-map "^0.6.0" abab@^1.0.3: version "1.0.4" @@ -127,13 +81,6 @@ acorn@^5.0.0, acorn@^5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" -agent-base@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" - dependencies: - extend "~3.0.0" - semver "~5.0.1" - aggregate-error@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-1.0.0.tgz#888344dad0220a72e3af50906117f48771925fac" @@ -149,6 +96,10 @@ ajv-keywords@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + ajv@^4.7.0, ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -156,6 +107,15 @@ ajv@^4.7.0, ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" +ajv@^5.0.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.4.tgz#3daf9a8b67221299fdae8d82d117ed8e6c80244b" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + json-schema-traverse "^0.3.0" + json-stable-stringify "^1.0.1" + ajv@^5.1.0, ajv@^5.1.5: version "5.2.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2" @@ -228,7 +188,7 @@ append-transform@^0.4.0: dependencies: default-require-extensions "^1.0.0" -aproba@^1.0.3: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -292,18 +252,10 @@ array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" -array-ify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" - array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -373,11 +325,11 @@ async@2.0.1: dependencies: lodash "^4.8.0" -async@^1.4.0, async@^1.5.2, async@~1.5.2: +async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.1.4: +async@^2.0.0, async@^2.1.2, async@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" dependencies: @@ -448,7 +400,7 @@ babel-eslint@8.0.1: babel-types "7.0.0-beta.0" babylon "7.0.0-beta.22" -babel-generator@6.26.0, babel-generator@^6.18.0, babel-generator@^6.26.0: +babel-generator@^6.18.0, babel-generator@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" dependencies: @@ -628,14 +580,6 @@ babel-plugin-jest-hoist@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz#2cef637259bd4b628a6cace039de5fcd14dbb006" -babel-plugin-module-resolver@2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-2.7.1.tgz#18be3c42ddf59f7a456c9e0512cd91394f6e4be1" - dependencies: - find-babel-config "^1.0.1" - glob "^7.1.1" - resolve "^1.2.0" - babel-plugin-react-require@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-react-require/-/babel-plugin-react-require-3.0.0.tgz#2e4e7b4496b93a654a1c80042276de4e4eeb20e3" @@ -773,7 +717,7 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-commonjs@6.26.0, babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" dependencies: @@ -1150,12 +1094,6 @@ bl@^1.0.0: dependencies: readable-stream "^2.0.5" -bl@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" - dependencies: - readable-stream "~2.0.5" - block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -1321,9 +1259,23 @@ builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" -builtins@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" +cacache@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.2.tgz#105a93a162bbedf3a25da42e1939ed99ffb145f8" + dependencies: + bluebird "^3.5.0" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^1.3.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.1" + ssri "^5.0.0" + unique-filename "^1.1.0" + y18n "^3.2.1" caching-transform@^1.0.0: version "1.0.1" @@ -1347,21 +1299,10 @@ callsites@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" @@ -1447,6 +1388,10 @@ chokidar@^1.7.0: optionalDependencies: fsevents "^1.0.0" +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + chromedriver@2.32.3: version "2.32.3" resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.32.3.tgz#ce84f055bee7cbfe56f31182b276f33256b12bf1" @@ -1525,15 +1470,6 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -codeclimate-test-reporter@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/codeclimate-test-reporter/-/codeclimate-test-reporter-0.5.0.tgz#93fa06b1c18e4117349128dc4e38aad08043828e" - dependencies: - async "~1.5.2" - commander "2.9.0" - lcov-parse "0.0.10" - request "~2.79.0" - color-convert@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" @@ -1550,27 +1486,18 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" - commander@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" +commander@~2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" -compare-func@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.2.tgz#99dd0ba457e1f9bc722b12c08ec33eeab31fa648" - dependencies: - array-ify "^1.0.0" - dot-prop "^3.0.0" - compress-commons@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f" @@ -1584,7 +1511,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.6.0, concat-stream@^1.5.2: +concat-stream@1.6.0, concat-stream@^1.5.0, concat-stream@^1.5.2: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1592,13 +1519,6 @@ concat-stream@1.6.0, concat-stream@^1.5.2: readable-stream "^2.2.2" typedarray "^0.0.6" -config-chain@~1.1.8: - version "1.1.11" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -1625,65 +1545,6 @@ content-type@~1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" -conventional-changelog-angular@^1.4.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-1.5.1.tgz#974e73aa1c39c392e4364f2952bd9a62904e9ea3" - dependencies: - compare-func "^1.3.1" - q "^1.4.1" - -conventional-changelog-core@^1.9.0: - version "1.9.2" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-1.9.2.tgz#a09b6b959161671ff45b93cc9efb0444e7c845c0" - dependencies: - conventional-changelog-writer "^2.0.1" - conventional-commits-parser "^2.0.0" - dateformat "^1.0.12" - get-pkg-repo "^1.0.0" - git-raw-commits "^1.2.0" - git-remote-origin-url "^2.0.0" - git-semver-tags "^1.2.2" - lodash "^4.0.0" - normalize-package-data "^2.3.5" - q "^1.4.1" - read-pkg "^1.1.0" - read-pkg-up "^1.0.1" - through2 "^2.0.0" - -conventional-changelog-writer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-2.0.1.tgz#47c10d0faba526b78d194389d1e931d09ee62372" - dependencies: - compare-func "^1.3.1" - conventional-commits-filter "^1.0.0" - dateformat "^1.0.11" - handlebars "^4.0.2" - json-stringify-safe "^5.0.1" - lodash "^4.0.0" - meow "^3.3.0" - semver "^5.0.1" - split "^1.0.0" - through2 "^2.0.0" - -conventional-commits-filter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-1.0.0.tgz#6fc2a659372bc3f2339cf9ffff7e1b0344b93039" - dependencies: - is-subset "^0.1.1" - modify-values "^1.0.0" - -conventional-commits-parser@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-2.0.0.tgz#71d01910cb0a99aeb20c144e50f81f4df3178447" - dependencies: - JSONStream "^1.0.4" - is-text-path "^1.0.0" - lodash "^4.2.1" - meow "^3.3.0" - split2 "^2.0.0" - through2 "^2.0.0" - trim-off-newlines "^1.0.0" - convert-source-map@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" @@ -1700,6 +1561,17 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -1708,7 +1580,7 @@ core-js@^2.4.0, core-js@^2.5.0: version "2.5.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" -core-util-is@1.0.2, core-util-is@^1.0.1, core-util-is@~1.0.0: +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -1852,11 +1724,9 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": dependencies: cssom "0.3.x" -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - dependencies: - array-find-index "^1.0.1" +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" d@1: version "1.0.0" @@ -1864,12 +1734,6 @@ d@1: dependencies: es5-ext "^0.10.9" -dargs@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" - dependencies: - number-is-nan "^1.0.0" - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -1884,36 +1748,29 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -dateformat@^1.0.11, dateformat@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" - dependencies: - get-stdin "^4.0.1" - meow "^3.3.0" - debug-log@^1.0.0, debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" -debug@2, debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.3, debug@^2.6.8: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - debug@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" +debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.3, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + debug@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: +decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2070,11 +1927,14 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" -dot-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" +duplexify@^3.1.2, duplexify@^3.4.2: + version "3.5.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.1.tgz#4e1516be68838bc90a49994f0b39a6e5960befcd" dependencies: - is-obj "^1.0.0" + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" ecc-jsbn@~0.1.1: version "0.1.1" @@ -2124,7 +1984,7 @@ encoding@^0.1.11: dependencies: iconv-lite "~0.4.13" -end-of-stream@^1.0.0: +end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" dependencies: @@ -2489,7 +2349,7 @@ express@4.15.5: utils-merge "1.0.0" vary "~1.1.1" -extend@3, extend@~3.0.0, extend@~3.0.1: +extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -2516,7 +2376,7 @@ fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" -fast-levenshtein@~2.0.4: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -2595,13 +2455,6 @@ finalhandler@~1.0.6: statuses "~1.3.1" unpipe "~1.0.0" -find-babel-config@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.1.0.tgz#acc01043a6749fec34429be6b64f542ebb5d6355" - dependencies: - json5 "^0.5.1" - path-exists "^3.0.0" - find-cache-dir@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" @@ -2622,6 +2475,12 @@ find-root@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" +find-up@2.1.0, find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -2629,12 +2488,6 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - dependencies: - locate-path "^2.0.0" - fkill@5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/fkill/-/fkill-5.1.0.tgz#d07c20a6bee698b02ae727fdcad61fbcdec198b8" @@ -2657,12 +2510,12 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -follow-redirects@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" +flush-write-stream@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.2.tgz#c81b90d8746766f1a609a46809946c45dd8ae417" dependencies: - debug "^2.2.0" - stream-consume "^0.1.0" + inherits "^2.0.1" + readable-stream "^2.0.4" for-in@^1.0.1: version "1.0.2" @@ -2693,14 +2546,6 @@ forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" -form-data@~1.0.0-rc4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" - dependencies: - async "^2.0.1" - combined-stream "^1.0.5" - mime-types "^2.1.11" - form-data@~2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" @@ -2733,13 +2578,21 @@ friendly-errors-webpack-plugin@1.6.1: error-stack-parser "^2.0.0" string-length "^1.0.1" -fs-extra@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" dependencies: graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" fs.realpath@^1.0.0: version "1.0.0" @@ -2804,20 +2657,6 @@ get-own-enumerable-property-symbols@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b" -get-pkg-repo@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz#c73b489c06d80cc5536c2c853f9e05232056972d" - dependencies: - hosted-git-info "^2.1.4" - meow "^3.3.0" - normalize-package-data "^2.3.0" - parse-github-repo-url "^1.3.0" - through2 "^2.0.0" - -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - get-stdin@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" @@ -2832,63 +2671,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -git-head@^1.2.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/git-head/-/git-head-1.20.1.tgz#036d16a4b374949e4e3daf15827903686d3ccd52" - dependencies: - git-refs "^1.1.3" - -git-raw-commits@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-1.2.0.tgz#0f3a8bfd99ae0f2d8b9224d58892975e9a52d03c" - dependencies: - dargs "^4.0.1" - lodash.template "^4.0.2" - meow "^3.3.0" - split2 "^2.0.0" - through2 "^2.0.0" - -git-refs@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/git-refs/-/git-refs-1.1.3.tgz#83097cb3a92585c4a4926ec54e2182df9e20e89d" - dependencies: - path-object "^2.3.0" - slash "^1.0.0" - walk "^2.3.9" - -git-remote-origin-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" - dependencies: - gitconfiglocal "^1.0.0" - pify "^2.3.0" - -git-semver-tags@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-1.2.2.tgz#a2139be1bf6e337e125f3eb8bb8fc6f5d4d6445f" - dependencies: - meow "^3.3.0" - semver "^5.0.1" - -gitconfiglocal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" - dependencies: - ini "^1.3.2" - -github@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/github/-/github-11.0.0.tgz#edb32df5efb33cad004ebf0bdd2a4b30bb63a854" - dependencies: - follow-redirects "0.0.7" - https-proxy-agent "^1.0.0" - mime "^1.2.11" - netrc "^0.1.4" - -github@~0.1.10: - version "0.1.16" - resolved "https://registry.yarnpkg.com/github/-/github-0.1.16.tgz#895d2a85b0feb7980d89ac0ce4f44dcaa03f17b5" - glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -2902,12 +2684,9 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob-promise@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-3.2.0.tgz#fa53179ef42b7c5a6450e77374ab54c9708b7fe9" - dependencies: - codeclimate-test-reporter "^0.5.0" - semantic-release "^8.0.3" +glob-promise@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-3.3.0.tgz#d1eb3625c4e6dcbb9b96eeae4425d5a3b135fed2" glob@7.1.2, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2: version "7.1.2" @@ -2966,19 +2745,15 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6: +graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" -handlebars@^4.0.2, handlebars@^4.0.3: +handlebars@^4.0.3: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" dependencies: @@ -3097,7 +2872,7 @@ hoek@4.x.x: version "4.2.0" resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" -hoist-non-react-statics@2.3.1: +hoist-non-react-statics@2.3.1, hoist-non-react-statics@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" @@ -3108,7 +2883,7 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" -hosted-git-info@^2.1.4, hosted-git-info@^2.4.2: +hosted-git-info@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" @@ -3177,14 +2952,6 @@ https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -https-proxy-agent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" - dependencies: - agent-base "2" - debug "2" - extend "3" - husky@0.14.3: version "0.14.3" resolved "https://registry.yarnpkg.com/husky/-/husky-0.14.3.tgz#c69ed74e2d2779769a17ba8399b54ce0b63c12c3" @@ -3205,16 +2972,14 @@ ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + ignore@^3.0.9, ignore@^3.2.0: version "3.3.5" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" -import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - dependencies: - resolve-from "^3.0.0" - imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -3248,7 +3013,7 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" -ini@^1.2.0, ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: +ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" @@ -3393,7 +3158,7 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" -is-obj@^1.0.0, is-obj@^1.0.1: +is-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" @@ -3449,20 +3214,10 @@ is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" -is-subset@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" - is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" -is-text-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - dependencies: - text-extensions "^1.0.0" - is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -3858,7 +3613,7 @@ json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -3866,20 +3621,10 @@ json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - optionalDependencies: - graceful-fs "^4.1.6" - jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" @@ -4052,49 +3797,6 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash._baseassign@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" - dependencies: - lodash._basecopy "^3.0.0" - lodash.keys "^3.0.0" - -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - -lodash._bindcallback@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - -lodash._createassigner@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" - dependencies: - lodash._bindcallback "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash.restparam "^3.0.0" - -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - -lodash._reinterpolate@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - -lodash.assign@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" - dependencies: - lodash._baseassign "^3.0.0" - lodash._createassigner "^3.0.0" - lodash.keys "^3.0.0" - lodash.assignin@^4.0.9: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" @@ -4119,22 +3821,6 @@ lodash.foreach@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - lodash.map@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" @@ -4155,39 +3841,18 @@ lodash.reject@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - lodash.some@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" -lodash.template@^4.0.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" - dependencies: - lodash._reinterpolate "~3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" - dependencies: - lodash._reinterpolate "~3.0.0" - lodash@4.16.2: version "4.16.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.2.tgz#3e626db827048a699281a8a125226326cfc0e652" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1, lodash@^4.8.0: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.8.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -lodash@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.3.1.tgz#a4663b53686b895ff074e2ba504dfb76a8e2b770" - log-driver@1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" @@ -4221,14 +3886,7 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: dependencies: js-tokens "^3.0.0" -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - -lru-cache@^4.0.0, lru-cache@^4.0.1: +lru-cache@^4.0.0, lru-cache@^4.0.1, lru-cache@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" dependencies: @@ -4247,10 +3905,6 @@ makeerror@1.0.x: dependencies: tmpl "1.0.x" -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - maximatch@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/maximatch/-/maximatch-0.1.0.tgz#86cd8d6b04c9f307c05a6b9419906d0360fb13a2" @@ -4300,21 +3954,6 @@ memory-fs@^0.4.0, memory-fs@~0.4.1: errno "^0.1.3" readable-stream "^2.0.1" -meow@^3.3.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -4362,7 +4001,7 @@ mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7: +mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: @@ -4372,7 +4011,7 @@ mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" -mime@1.4.1, mime@^1.2.11, mime@^1.3.4: +mime@1.4.1, mime@^1.3.4: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" @@ -4404,7 +4043,7 @@ minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: +minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -4412,6 +4051,21 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" +mississippi@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-1.3.0.tgz#d201583eb12327e3c5c1642a404a9cacf94e34f5" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^1.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + mk-dirs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mk-dirs/-/mk-dirs-1.0.0.tgz#44ee67f82341c6762718e88e85e577882e1f67fd" @@ -4435,14 +4089,21 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkd dependencies: minimist "0.0.8" -modify-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.0.tgz#e2b6cdeb9ce19f99317a53722f3dbf5df5eaaab2" - moment@^2.11.2: version "2.19.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167" +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + mri@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.0.tgz#5c0a3f29c8ccffbbb1ec941dcec09d71fa32f36a" @@ -4491,14 +4152,6 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" -nerf-dart@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/nerf-dart/-/nerf-dart-1.0.0.tgz#e6dab7febf5ad816ea81cf5c629c5a0ebde72c1a" - -netrc@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/netrc/-/netrc-0.1.4.tgz#6be94fcaca8d77ade0a9670dc460914c94472444" - node-fetch@1.7.3, node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -4562,11 +4215,7 @@ node-pre-gyp@^0.6.36: tar "^2.2.1" tar-pack "^3.4.0" -node-uuid@~1.4.7: - version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" - -nopt@^4.0.0, nopt@^4.0.1: +nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" dependencies: @@ -4579,13 +4228,7 @@ nopt@~1.0.10: dependencies: abbrev "1" -nopt@~3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - dependencies: - abbrev "1" - -normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, "normalize-package-data@~1.0.1 || ^2.0.0": +normalize-package-data@^2.3.2: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -4604,38 +4247,12 @@ normalize-path@^2.0.0, normalize-path@^2.0.1: dependencies: remove-trailing-separator "^1.0.1" -"npm-package-arg@^3.0.0 || ^4.0.0 || ^5.0.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-5.1.2.tgz#fb18d17bb61e60900d6312619919bd753755ab37" - dependencies: - hosted-git-info "^2.4.2" - osenv "^0.1.4" - semver "^5.1.0" - validate-npm-package-name "^3.0.0" - npm-path@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.3.tgz#15cff4e1c89a38da77f56f6055b24f975dfb2bbe" dependencies: which "^1.2.10" -npm-registry-client@^8.4.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.5.0.tgz#4878fb6fa1f18a5dc08ae83acf94d0d0112d7ed0" - dependencies: - concat-stream "^1.5.2" - graceful-fs "^4.1.6" - normalize-package-data "~1.0.1 || ^2.0.0" - npm-package-arg "^3.0.0 || ^4.0.0 || ^5.0.0" - once "^1.3.3" - request "^2.74.0" - retry "^0.10.0" - semver "2 >=2.2.1 || 3.x || 4 || 5" - slide "^1.1.3" - ssri "^4.1.2" - optionalDependencies: - npmlog "2 || ^3.1.0 || ^4.0.0" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -4650,21 +4267,7 @@ npm-which@^3.0.1: npm-path "^2.0.2" which "^1.2.10" -npmconf@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/npmconf/-/npmconf-2.1.2.tgz#66606a4a736f1e77a059aa071a79c94ab781853a" - dependencies: - config-chain "~1.1.8" - inherits "~2.0.0" - ini "^1.2.0" - mkdirp "^0.5.0" - nopt "~3.0.1" - once "~1.3.0" - osenv "^0.1.0" - semver "2 || 3 || 4" - uid-number "0.0.5" - -"npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.0, npmlog@^4.0.2: +npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: @@ -4752,18 +4355,12 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" -once@^1.3.0, once@^1.3.3, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" -once@~1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - dependencies: - wrappy "1" - onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" @@ -4815,7 +4412,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@^0.1.0, osenv@^0.1.4: +osenv@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: @@ -4844,26 +4441,18 @@ p-map@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - -p-retry@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-1.0.0.tgz#3927332a4b7d70269b535515117fc547da1a6968" - dependencies: - retry "^0.10.0" - -p-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-series/-/p-series-1.0.0.tgz#7ec9e7b4406cc32066298a6f9860e55e91b36e07" - dependencies: - p-reduce "^1.0.0" - pako@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + parse-asn1@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" @@ -4874,10 +4463,6 @@ parse-asn1@^5.0.0: evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" -parse-github-repo-url@^1.3.0, parse-github-repo-url@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" - parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -4934,13 +4519,6 @@ path-match@1.2.4: http-errors "~1.4.0" path-to-regexp "^1.0.0" -path-object@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/path-object/-/path-object-2.3.0.tgz#03e46653e5c375c60af1cabdd94bc6448a5d9110" - dependencies: - core-util-is "^1.0.1" - lodash.assign "^3.0.0" - path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" @@ -5093,6 +4671,10 @@ progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + promise@^7.0.1, promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -5114,10 +4696,6 @@ prop-types@15.6.0, prop-types@^15.5.4, prop-types@^15.6.0: loose-envify "^1.3.1" object-assign "^4.1.1" -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - proxy-addr@~1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918" @@ -5143,6 +4721,21 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" +pump@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.2.tgz#3b3ee6512f94f0e575538c17995f9f16990a5d51" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.3.5" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.3.5.tgz#1b671c619940abcaeac0ad0e3a3c164be760993b" + dependencies: + duplexify "^3.1.2" + inherits "^2.0.1" + pump "^1.0.0" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -5155,18 +4748,10 @@ q@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" -q@^1.4.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - qs@6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" -qs@~6.2.0: - version "6.2.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" - qs@~6.3.0: version "6.3.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" @@ -5213,38 +4798,35 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-deep-force-update@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-2.1.1.tgz#8ea4263cd6455a050b37445b3f08fd839d86e909" - -react-dom@16.0.0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.0.0.tgz#9cc3079c3dcd70d4c6e01b84aab2a7e34c303f58" +react-dom@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.0" -react-hot-loader@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-3.1.1.tgz#e06db8cd0841c41e3ab0b395b2b774126fc8914e" +react-hot-loader@4.0.0-beta.14: + version "4.0.0-beta.14" + resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.0.0-beta.14.tgz#9575065aadda9c53ef455e757b8b36c1fd14e5d6" dependencies: + fast-levenshtein "^2.0.6" global "^4.3.0" - react-deep-force-update "^2.1.1" - react-proxy "^3.0.0-alpha.0" + hoist-non-react-statics "^2.3.1" + react-stand-in "^4.0.0-beta.14" redbox-react "^1.3.6" source-map "^0.6.1" -react-proxy@^3.0.0-alpha.0: - version "3.0.0-alpha.1" - resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-3.0.0-alpha.1.tgz#4400426bcfa80caa6724c7755695315209fa4b07" +react-stand-in@^4.0.0-beta.14: + version "4.0.0-beta.14" + resolved "https://registry.yarnpkg.com/react-stand-in/-/react-stand-in-4.0.0-beta.14.tgz#0a06a94b44bc4ca1d06575414acf400585d84e35" dependencies: - lodash "^4.6.1" + shallowequal "^1.0.2" -react@16.0.0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.0.0.tgz#ce7df8f1941b036f02b2cca9dbd0cb1f0e855e2d" +react@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -5265,7 +4847,7 @@ read-pkg-up@^2.0.0: find-up "^2.0.0" read-pkg "^2.0.0" -read-pkg@^1.0.0, read-pkg@^1.1.0: +read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: @@ -5281,7 +4863,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -5293,17 +4875,6 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - readdirp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" @@ -5351,13 +4922,6 @@ redbox-react@^1.3.6: prop-types "^15.5.4" sourcemapped-stacktrace "^1.1.6" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" @@ -5416,7 +4980,7 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2.79.0, request@~2.79.0: +request@2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" dependencies: @@ -5468,7 +5032,7 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@^2.74.0, request@^2.79.0, request@^2.81.0: +request@^2.79.0, request@^2.81.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: @@ -5495,32 +5059,6 @@ request@^2.74.0, request@^2.79.0, request@^2.81.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@~2.74.0: - version "2.74.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - bl "~1.1.2" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~1.0.0-rc4" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - node-uuid "~1.4.7" - oauth-sign "~0.8.1" - qs "~6.2.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5537,10 +5075,6 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -require-relative@^0.8.7: - version "0.8.7" - resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" - require-uncached@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -5556,15 +5090,17 @@ resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.1.6, resolve@^1.2.0: +resolve@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + dependencies: + path-parse "^1.0.5" + +resolve@^1.1.6: version "1.4.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" dependencies: @@ -5577,10 +5113,6 @@ restore-cursor@^1.0.1: exit-hook "^1.0.0" onetime "^1.0.0" -retry@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" - rewrite-imports@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/rewrite-imports/-/rewrite-imports-1.0.0.tgz#a4705c3829006e4f7541bf29d534d8d3b1717c83" @@ -5620,6 +5152,12 @@ run-parallel@^1.1.2: version "1.1.6" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.6.tgz#29003c9a2163e01e2d2dfc90575f2c6c1d61a039" +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" @@ -5652,42 +5190,17 @@ sax@^1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -semantic-release@^8.0.3: - version "8.2.1" - resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-8.2.1.tgz#0bd4c2d372b328b2617fb34688937e58387f1bc1" +schema-utils@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.3.tgz#e2a594d3395834d5e15da22b48be13517859458e" dependencies: - "@semantic-release/commit-analyzer" "^3.0.1" - "@semantic-release/condition-travis" "^6.0.0" - "@semantic-release/error" "^2.0.0" - "@semantic-release/last-release-npm" "^2.0.0" - "@semantic-release/release-notes-generator" "^4.0.0" - execa "^0.8.0" - fs-extra "^4.0.2" - git-head "^1.2.1" - github "^11.0.0" - lodash "^4.0.0" - nerf-dart "^1.0.0" - nopt "^4.0.0" - normalize-package-data "^2.3.4" - npmconf "^2.1.2" - npmlog "^4.0.0" - p-series "^1.0.0" - parse-github-repo-url "^1.3.0" - require-relative "^0.8.7" - semver "^5.4.1" - -"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1: + ajv "^5.0.0" + ajv-keywords "^2.1.0" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" -"semver@2 || 3 || 4": - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - -semver@~5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" - send@0.15.6: version "0.15.6" resolved "https://registry.yarnpkg.com/send/-/send-0.15.6.tgz#20f23a9c925b762ab82705fe2f9db252ace47e34" @@ -5724,6 +5237,10 @@ send@0.16.1: range-parser "~1.2.0" statuses "~1.3.1" +serialize-javascript@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" + serve-static@1.12.6: version "1.12.6" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.6.tgz#b973773f63449934da54e5beba5e31d9f4211577" @@ -5756,6 +5273,10 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shallowequal@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.0.2.tgz#1561dbdefb8c01408100319085764da3fcf83f8f" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -5790,7 +5311,7 @@ slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" -slide@^1.1.3, slide@^1.1.5: +slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" @@ -5810,7 +5331,7 @@ source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" -source-map-support@0.4.18, source-map-support@^0.4.15: +source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: @@ -5820,7 +5341,7 @@ source-map@0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" -source-map@0.6.1, source-map@^0.6.1: +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -5865,18 +5386,6 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" -split2@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493" - dependencies: - through2 "^2.0.2" - -split@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - dependencies: - through "2" - sprintf-js@^1.0.3: version "1.1.1" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" @@ -5899,9 +5408,9 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -ssri@^4.1.2: - version "4.1.6" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-4.1.6.tgz#0cb49b6ac84457e7bdd466cb730c3cb623e9a25b" +ssri@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.0.0.tgz#13c19390b606c821f2a10d02b351c1729b94d8cf" dependencies: safe-buffer "^5.1.0" @@ -5950,9 +5459,12 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" -stream-consume@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" +stream-each@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" stream-http@^2.3.1: version "2.7.2" @@ -5964,6 +5476,10 @@ stream-http@^2.3.1: to-arraybuffer "^1.0.0" xtend "^4.0.0" +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + stream-to-observable@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.1.0.tgz#45bf1d9f2d7dc09bed81f1c307c430e68b84cffe" @@ -6000,7 +5516,7 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@^0.10.25, string_decoder@~0.10.x: +string_decoder@^0.10.25: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -6048,12 +5564,6 @@ strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - dependencies: - get-stdin "^4.0.1" - strip-indent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" @@ -6179,10 +5689,6 @@ test-exclude@^4.1.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" -text-extensions@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.7.0.tgz#faaaba2625ed746d568a23e4d0aacd9bf08a8b39" - text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6203,14 +5709,14 @@ throat@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" -through2@^2.0.0, through2@^2.0.2: +through2@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" dependencies: readable-stream "^2.1.5" xtend "~4.0.1" -through@2, "through@>=2.2.7 <3", through@^2.3.6: +through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -6260,32 +5766,6 @@ tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" -travis-ci@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/travis-ci/-/travis-ci-2.1.1.tgz#98696265af827ae3576f31aa06d876e74b4b082e" - dependencies: - github "~0.1.10" - lodash "~1.3.1" - request "~2.74.0" - underscore.string "~2.2.0rc" - -travis-deploy-once@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/travis-deploy-once/-/travis-deploy-once-3.0.0.tgz#079f7c2d56472ef8e87d540c9b108bed9d9e1fdd" - dependencies: - chalk "^2.1.0" - p-retry "^1.0.0" - semver "^5.4.1" - travis-ci "^2.1.1" - -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - -trim-off-newlines@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" - trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -6333,6 +5813,13 @@ ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" +uglify-es@^3.3.4: + version "3.3.9" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + uglify-js@^2.6, uglify-js@^2.8.29: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -6346,6 +5833,19 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" +uglifyjs-webpack-plugin@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.6.tgz#f4ba8449edcf17835c18ba6ae99b9d610857fb19" + dependencies: + cacache "^10.0.1" + find-cache-dir "^1.0.0" + schema-utils "^0.4.2" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + uglifyjs-webpack-plugin@^0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" @@ -6354,10 +5854,6 @@ uglifyjs-webpack-plugin@^0.4.6: uglify-js "^2.8.29" webpack-sources "^1.0.1" -uid-number@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.5.tgz#5a3db23ef5dbd55b81fce0ec9a2ac6fccdebb81e" - uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -6369,10 +5865,6 @@ underscore.string@3.3.4: sprintf-js "^1.0.3" util-deprecate "^1.0.2" -underscore.string@~2.2.0rc: - version "2.2.1" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.2.1.tgz#d7c0fa2af5d5a1a67f4253daee98132e733f0f19" - unfetch@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-3.0.0.tgz#8d1e0513a4ecd0e5ff2d41a6ba77771aae8b6482" @@ -6381,9 +5873,17 @@ uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" -universalify@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" +unique-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" unpipe@~1.0.0: version "1.0.0" @@ -6427,12 +5927,6 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -validate-npm-package-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - dependencies: - builtins "^1.0.3" - vargs@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff" @@ -6455,7 +5949,7 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" -walk@2.3.9, walk@^2.3.9: +walk@2.3.9: version "2.3.9" resolved "https://registry.yarnpkg.com/walk/-/walk-2.3.9.tgz#31b4db6678f2ae01c39ea9fb8725a9031e558a7b" dependencies: @@ -6517,9 +6011,9 @@ webpack-dev-middleware@1.12.0: range-parser "^1.0.3" time-stamp "^2.0.0" -webpack-hot-middleware@2.19.1: - version "2.19.1" - resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.19.1.tgz#5db32c31c955c1ead114d37c7519ea554da0d405" +webpack-hot-middleware@2.21.0: + version "2.21.0" + resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.21.0.tgz#7b3c113a7a4b301c91e0749573c7aab28b414b52" dependencies: ansi-html "0.0.7" html-entities "^1.2.0" @@ -6533,9 +6027,16 @@ webpack-sources@^1.0.1: source-list-map "^2.0.0" source-map "~0.5.3" -webpack@3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.6.0.tgz#a89a929fbee205d35a4fa2cc487be9cbec8898bc" +webpack-sources@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" @@ -6616,6 +6117,13 @@ worker-farm@^1.3.1: errno "^0.1.4" xtend "^4.0.1" +worker-farm@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae" + dependencies: + errno "^0.1.4" + xtend "^4.0.1" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"