diff --git a/.travis.yml b/.travis.yml index 7db39d1a44..c2a14e7f60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: + - "8.0" - "7.2" - "6.9" before_install: diff --git a/bin/nuxt-build b/bin/nuxt-build index c85d1b6fed..1af998d2be 100755 --- a/bin/nuxt-build +++ b/bin/nuxt-build @@ -52,13 +52,12 @@ if (analyzeBuild) { } console.log('[nuxt] Building...') // eslint-disable-line no-console -new Nuxt(options).then(nuxt => { - nuxt.build() - .then(() => { - console.log('[nuxt] Building done') // eslint-disable-line no-console - }) - .catch((err) => { - console.error(err) // eslint-disable-line no-console - process.exit(1) - }) -}) +var nuxt = module.exports = new Nuxt(options) +nuxt.build() + .then(() => { + console.log('[nuxt] Building done') // eslint-disable-line no-console + }) + .catch((err) => { + console.error(err) // eslint-disable-line no-console + process.exit(1) + }) diff --git a/bin/nuxt-dev b/bin/nuxt-dev index 351a82a680..4b1f733ce6 100755 --- a/bin/nuxt-dev +++ b/bin/nuxt-dev @@ -39,19 +39,14 @@ if (typeof options.rootDir !== 'string') { } options.dev = true // Add hot reloading and watching changes -new Nuxt(options).then(nuxt => { - var server = new nuxt.Server(nuxt) - .listen(process.env.PORT || process.env.npm_package_config_nuxt_port, process.env.HOST || process.env.npm_package_config_nuxt_host) - listenOnConfigChanges(nuxt, server) +var nuxt = module.exports = new Nuxt(options) +var port = process.env.PORT || process.env.npm_package_config_nuxt_port +var host = process.env.HOST || process.env.npm_package_config_nuxt_host +var server = nuxt.server = new nuxt.Server(nuxt).listen(port, host) - nuxt.build() - .catch((err) => { - console.error(err) // eslint-disable-line no-console - process.exit(1) - }) -}) +listenOnConfigChanges(nuxt, server) -function listenOnConfigChanges (nuxt, server) { +function listenOnConfigChanges(nuxt, server) { // Listen on nuxt.config.js changes var build = _.debounce(() => { debug('[nuxt.config.js] changed') @@ -66,20 +61,20 @@ function listenOnConfigChanges (nuxt, server) { } options.rootDir = rootDir nuxt.close() - .then(() => { - nuxt.renderer = null - debug('Rebuilding the app...') - return (new Nuxt(options)).then(nuxt => nuxt.build()) - }) - .then((nuxt) => { - server.nuxt = nuxt - }) - .catch((error) => { - console.error('Error while rebuild the app:', error) // eslint-disable-line no-console - process.exit(1) - }) + .then(() => { + nuxt.renderer = null + debug('Rebuilding the app...') + return new Nuxt(options).build() + }) + .then((nuxt) => { + server.nuxt = nuxt + }) + .catch((error) => { + console.error('Error while rebuild the app:', error) // eslint-disable-line no-console + process.exit(1) + }) }, 200) var nuxtConfigFile = resolve(rootDir, nuxtConfigFileName) - chokidar.watch(nuxtConfigFile, Object.assign({}, nuxt.options.watchers.chokidar, { ignoreInitial: true })) - .on('all', build) + chokidar.watch(nuxtConfigFile, Object.assign({}, nuxt.options.watchers.chokidar, {ignoreInitial: true})) + .on('all', build) } diff --git a/bin/nuxt-generate b/bin/nuxt-generate index 8d085b666c..c187810fa1 100755 --- a/bin/nuxt-generate +++ b/bin/nuxt-generate @@ -20,13 +20,12 @@ if (typeof options.rootDir !== 'string') { options.dev = false // Force production mode (no webpack middleware called) console.log('[nuxt] Generating...') // eslint-disable-line no-console -new Nuxt(options).then(nuxt => { - nuxt.generate() - .then(() => { - console.log('[nuxt] Generate done') // eslint-disable-line no-console - }) - .catch((err) => { - console.error(err) // eslint-disable-line no-console - process.exit(1) - }) -}) +var nuxt = module.exports = new Nuxt(options) +nuxt.generate() + .then(() => { + console.log('[nuxt] Generate done') // eslint-disable-line no-console + }) + .catch((err) => { + console.error(err) // eslint-disable-line no-console + process.exit(1) + }) diff --git a/bin/nuxt-start b/bin/nuxt-start index f39daf9b19..8af26fbaf4 100755 --- a/bin/nuxt-start +++ b/bin/nuxt-start @@ -16,10 +16,7 @@ if (typeof options.rootDir !== 'string') { } options.dev = false // Force production mode (no webpack middleware called) -new Nuxt(options).then(nuxt => { - new nuxt.Server(nuxt) - .listen( - process.env.PORT || process.env.npm_package_config_nuxt_port, - process.env.HOST || process.env.npm_package_config_nuxt_host - ) -}) +var nuxt = module.exports = new Nuxt(options) +var port = process.env.PORT || process.env.npm_package_config_nuxt_port +var host = process.env.HOST || process.env.npm_package_config_nuxt_host +var server = nuxt.server = new nuxt.Server(nuxt).listen(port, host) diff --git a/examples/i18n/layouts/default.vue b/examples/i18n/layouts/default.vue index 09cdd6ddea..ccfcbd8123 100644 --- a/examples/i18n/layouts/default.vue +++ b/examples/i18n/layouts/default.vue @@ -7,7 +7,7 @@ {{ $t('links.home') }} - + {{ $t('links.about') }} diff --git a/examples/i18n/middleware/i18n.js b/examples/i18n/middleware/i18n.js index b04fb950a3..c787ca808a 100644 --- a/examples/i18n/middleware/i18n.js +++ b/examples/i18n/middleware/i18n.js @@ -1,4 +1,7 @@ -export default function ({ app, store, route, params, error, redirect }) { +export default function ({ app, store, route, params, error, redirect, hotReload }) { + // Check if middleware called from hot-reloading, ignore + if (hotReload) return + // Get locale from params const locale = params.lang || 'en' if (store.state.locales.indexOf(locale) === -1) { return error({ message: 'This page could not be found.', statusCode: 404 }) @@ -8,6 +11,6 @@ export default function ({ app, store, route, params, error, redirect }) { app.i18n.locale = store.state.locale // If route is /en/... -> redirect to /... if (locale === 'en' && route.fullPath.indexOf('/en') === 0) { - redirect(route.fullPath.replace(/^\/en/, '/')) + return redirect(route.fullPath.replace(/^\/en/, '/')) } } diff --git a/examples/i18n/package.json b/examples/i18n/package.json index 8668f2c65a..5dd206d014 100644 --- a/examples/i18n/package.json +++ b/examples/i18n/package.json @@ -2,7 +2,7 @@ "name": "nuxt-i18n", "dependencies": { "nuxt": "latest", - "vue-i18n": "^6.0.0" + "vue-i18n": "^7.0.0" }, "scripts": { "dev": "nuxt", diff --git a/examples/i18n/plugins/i18n.js b/examples/i18n/plugins/i18n.js index 02e20adf74..e4859aadc9 100644 --- a/examples/i18n/plugins/i18n.js +++ b/examples/i18n/plugins/i18n.js @@ -3,12 +3,7 @@ import VueI18n from 'vue-i18n' Vue.use(VueI18n) -export default ({ isClient, app, store, route, error, redirect }) => { - console.log(route.path) - if (isClient && route.path === '/fr/about') { - return redirect('/about') - } - console.log(error) +export default ({ app, store }) => { // Set i18n instance on app // This way we can use it in middleware and pages asyncData/fetch app.i18n = new VueI18n({ diff --git a/examples/typescript/index.d.ts b/examples/typescript/index.d.ts deleted file mode 100644 index d4871b2cf0..0000000000 --- a/examples/typescript/index.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -//Deleting this file will cause "TS18003: No inputs were found in config file 'tsconfig.json'" - -//These declarations allow TypeScript to import non-js/ts files without the file extensions (such as .vue files) -declare module "~components/*" { -} - -declare module "~layouts/*" { -} - -declare module "~pages/*" { -} - -declare module "~assets/*" { - -} - -declare module "~static/*" { - -} diff --git a/examples/typescript/modules/typescript.js b/examples/typescript/modules/typescript.js index 9132f52892..efa5413d97 100644 --- a/examples/typescript/modules/typescript.js +++ b/examples/typescript/modules/typescript.js @@ -3,16 +3,16 @@ module.exports = function (options, next) { this.extendBuild((config) => { // Add TypeScript loader config.module.rules.push({ - test: /\.ts$/, - loader: 'ts-loader' + test: /\.ts$/, + loader: 'ts-loader' }) // Add TypeScript loader for vue files for (rule of config.module.rules) { - if (rule.loader === 'vue-loader') { - rule.query.loaders.ts = 'ts-loader?{"appendTsSuffixTo":["\\\\.vue$"]}' - } + if (rule.loader === 'vue-loader') { + rule.query.loaders.ts = 'ts-loader?{"appendTsSuffixTo":["\\\\.vue$"]}' + } } }) next() -} \ No newline at end of file +} diff --git a/examples/typescript/package.json b/examples/typescript/package.json index 6d5a5cdd9d..17973f83f6 100644 --- a/examples/typescript/package.json +++ b/examples/typescript/package.json @@ -4,7 +4,7 @@ "dependencies": { "axios": "^0.16.1", "gsap": "^1.19.1", - "nuxt": "latest", + "nuxt": "^1.0.0-alpha2", "nuxt-class-component": "^1.0.1", "tachyons": "^4.7.0", "vue-class-component": "^5.0.1", @@ -21,4 +21,4 @@ "ts-loader": "^2.0.3", "typescript": "^2.2.2" } -} \ No newline at end of file +} diff --git a/examples/with-ava/package.json b/examples/with-ava/package.json index e05b6c01f1..f8925f9997 100755 --- a/examples/with-ava/package.json +++ b/examples/with-ava/package.json @@ -4,13 +4,13 @@ "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", - "test": "ava" + "test": "ava --serial --verbose" }, "devDependencies": { - "ava": "^0.16.0", - "jsdom": "^9.8.3" + "ava": "^0.19.1", + "jsdom": "^11.0.0" }, "dependencies": { - "nuxt": "^0.9.5" + "nuxt": "^1.0.0-alpha2" } } diff --git a/index.js b/index.js index 3f75098e30..8e7487a896 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,9 @@ -/* -** Nuxt.js -** Made by Chopin Brothers -** @Atinux & @alexchopin -*/ +/*! + * Nuxt.js + * (c) 2016-2017 Chopin Brothers + * Released under the MIT License. + */ -// Until babel-loader 7 is released process.noDeprecation = true var Nuxt = require('./dist/nuxt.js') diff --git a/lib/app/client.js b/lib/app/client.js index 0b47a07cdf..ccb2381d02 100644 --- a/lib/app/client.js +++ b/lib/app/client.js @@ -270,7 +270,7 @@ function addHotReload ($component, depth) { <%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %> router.push(path) } - let context = getContext({ route: router.currentRoute<%= (store ? ', store' : '') %>, isClient: true, next: next.bind(this), error: this.error }, app) + let context = getContext({ route: router.currentRoute<%= (store ? ', store' : '') %>, isClient: true, hotReload: true, next: next.bind(this), error: this.error }, app) <%= (loading ? 'this.$loading.start && this.$loading.start()' : '') %> callMiddleware.call(this, Components, context) .then(() => { @@ -349,6 +349,10 @@ function nuxtReady (app) { cb(app) } }) + // Special JSDOM + if (typeof window._onNuxtLoaded === 'function') { + window._onNuxtLoaded(app) + } // Add router hooks router.afterEach(function (to, from) { app.$nuxt.$emit('routeChanged', to, from) diff --git a/lib/app/index.js b/lib/app/index.js index 9e80d20401..a812d16426 100644 --- a/lib/app/index.js +++ b/lib/app/index.js @@ -12,9 +12,19 @@ import App from '<%= appPath %>' import { getContext } from './utils' +if (process.browser) { + // window.onNuxtReady(() => console.log('Ready')) hook + // Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading) + window._nuxtReadyCbs = [] + window.onNuxtReady = function (cb) { + window._nuxtReadyCbs.push(cb) + } +} + // Import SSR plugins <% plugins.forEach(function (plugin) { if (plugin.ssr) -{ %>import <%= plugin.name %> from '<%= r(plugin.src) %>' +{ %>let <%= plugin.name %> = require('<%= r(plugin.src) %>') +<%= plugin.name %> = <%= plugin.name %>.default || <%= plugin.name %> <% }}) %> // Component: @@ -58,12 +68,6 @@ async function createApp (ssrContext) { store.replaceState(window.__NUXT__.state) } <% } %> - // window.onNuxtReady(() => console.log('Ready')) hook - // Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading) - window._nuxtReadyCbs = [] - window.onNuxtReady = function (cb) { - window._nuxtReadyCbs.push(cb) - } } // root instance diff --git a/lib/app/utils.js b/lib/app/utils.js index 9b88a3a79f..edd88defb2 100644 --- a/lib/app/utils.js +++ b/lib/app/utils.js @@ -61,10 +61,11 @@ export function getContext (context, app) { app: app, <%= (store ? 'store: context.store,' : '') %> route: (context.to ? context.to : context.route), - payload : context.payload, + payload: context.payload, error: context.error, base: '<%= router.base %>', - env: <%= JSON.stringify(env) %> + env: <%= JSON.stringify(env) %>, + hotReload: context.hotReload || false } const next = context.next ctx.params = ctx.route.params || {} diff --git a/lib/build.js b/lib/build.js index 7eb425cf11..968feee155 100644 --- a/lib/build.js +++ b/lib/build.js @@ -76,29 +76,45 @@ export function options () { if (this.dev && isUrl(this.options.build.publicPath)) { this.options.build.publicPath = defaults.publicPath } +} + +export function production () { // Production, create server-renderer - if (!this.dev) { - webpackStats = { - chunks: false, - children: false, - modules: false, - colors: true - } - const serverConfig = getWebpackServerConfig.call(this) - const bundlePath = join(serverConfig.output.path, 'server-bundle.json') - const manifestPath = join(serverConfig.output.path, 'client-manifest.json') - if (fs.existsSync(bundlePath) && fs.existsSync(manifestPath)) { - const bundle = fs.readFileSync(bundlePath, 'utf8') - const manifest = fs.readFileSync(manifestPath, 'utf8') - createRenderer.call(this, JSON.parse(bundle), JSON.parse(manifest)) - addAppTemplate.call(this) - } + webpackStats = { + chunks: false, + children: false, + modules: false, + colors: true + } + const serverConfig = getWebpackServerConfig.call(this) + const bundlePath = join(serverConfig.output.path, 'server-bundle.json') + const manifestPath = join(serverConfig.output.path, 'client-manifest.json') + if (fs.existsSync(bundlePath) && fs.existsSync(manifestPath)) { + const bundle = fs.readFileSync(bundlePath, 'utf8') + const manifest = fs.readFileSync(manifestPath, 'utf8') + createRenderer.call(this, JSON.parse(bundle), JSON.parse(manifest)) + addAppTemplate.call(this) } } export async function build () { - this._nuxtPages = typeof this.createRoutes !== 'function' + // Avoid calling this method multiple times + if (this._buildDone) { + return this + } + // If building + if (this._building) { + return new Promise((resolve) => { + setTimeout(() => { + resolve(this.build()) + }, 300) + }) + } + this._building = true + // Wait for Nuxt.js to be ready + await this.ready() // Check if pages dir exists and warn if not + this._nuxtPages = typeof this.createRoutes !== 'function' if (this._nuxtPages) { if (!fs.existsSync(join(this.srcDir, 'pages'))) { if (fs.existsSync(join(this.srcDir, '..', 'pages'))) { @@ -110,7 +126,7 @@ export async function build () { } } debug(`App root: ${this.srcDir}`) - debug(`Generating .nuxt/${this.options.build.buildNamespace ? (this.options.build.buildNamespace + '/') : ''} files...`) + debug(`Generating ${this.buildDir} files...`) // Create .nuxt/, .nuxt/components and .nuxt/dist folders await remove(r(this.buildDir)) await mkdirp(r(this.buildDir, 'components')) @@ -121,6 +137,8 @@ export async function build () { await generateRoutesAndFiles.call(this) // Generate .nuxt/dist/ files await buildFiles.call(this) + // Flag to set that building is done + this._buildDone = true return this } diff --git a/lib/generate.js b/lib/generate.js index cd780a2492..7525cb843d 100644 --- a/lib/generate.js +++ b/lib/generate.js @@ -42,6 +42,10 @@ export default async function () { const s = Date.now() let errors = [] /* + ** Wait for modules to be initialized + */ + await this.ready() + /* ** Set variables */ this.options.generate = _.defaultsDeep(this.options.generate, defaults) @@ -80,14 +84,21 @@ export default async function () { } } function decorateWithPayloads (routes) { - let routeMap = _(routes).map((route) => { - return [route, {route, payload: {}}] - }).fromPairs().value() + let routeMap = {} + // Fill routeMap for known routes + routes.forEach((route) => { + routeMap[route] = { + route, + payload: null + } + }) + // Fill routeMap with given generate.routes generateRoutes.forEach((route) => { - // route argument is either a string or like {route : "/my_route/1"} - route = _.isString(route) ? route : route.route - if (!routeMap[route]) { - routeMap[route] = {route, payload: route.payload} + // route is either a string or like {route : "/my_route/1"} + const path = _.isString(route) ? route : route.route + routeMap[path] = { + route: path, + payload: route.payload || null } }) return _.values(routeMap) @@ -95,7 +106,8 @@ export default async function () { /* ** Generate only index.html for router.mode = 'hash' */ - let routes = (this.options.router.mode === 'hash') ? [{route: '/'}] : decorateWithPayloads(this.routes) + let routes = (this.options.router.mode === 'hash') ? ['/'] : this.routes + routes = decorateWithPayloads(routes) while (routes.length) { let n = 0 @@ -110,7 +122,7 @@ export default async function () { } } catch (err) { /* istanbul ignore next */ - errors.push({ type: 'unhandled', route, error: err }) + return errors.push({ type: 'unhandled', route, error: err }) } if (this.options.generate.minify) { try { diff --git a/lib/module.js b/lib/module.js index 142c7b7b85..83deb63533 100755 --- a/lib/module.js +++ b/lib/module.js @@ -4,13 +4,26 @@ import path from 'path' import fs from 'fs' import {uniq} from 'lodash' import hash from 'hash-sum' -import {chainFn} from './utils' +import {chainFn, sequence} from './utils' + +const debug = require('debug')('nuxt:module') class Module { constructor (nuxt) { this.nuxt = nuxt this.options = nuxt.options this.modules = [] + this.initing = this.ready() + } + + async ready () { + if (this.initing) { + await this.initing + return this + } + // Install all modules in sequence + await sequence(this.options.modules, this.addModule.bind(this)) + return this } addVendor (vendor) { @@ -31,8 +44,7 @@ class Module { const srcPath = path.parse(src) /* istanbul ignore if */ if (!src || typeof src !== 'string' || !fs.existsSync(src)) { - // eslint-disable-next-line no-console - console.warn('[nuxt] invalid template', template) + debug('[nuxt] invalid template', template) return } // Generate unique and human readable dst filename @@ -52,7 +64,7 @@ class Module { const {dst} = this.addTemplate(template) // Add to nuxt plugins this.options.plugins.push({ - src: '~/.nuxt/' + dst, + src: path.join(this.nuxt.buildDir, dst), ssr: template.ssr }) } @@ -82,8 +94,15 @@ class Module { if (!moduleOpts) { return } + // Allow using babel style array options + if (Array.isArray(moduleOpts)) { + moduleOpts = { + src: moduleOpts[0], + options: moduleOpts[1] + } + } // Allows passing runtime options to each module - const options = moduleOpts.options || {} + const options = moduleOpts.options || (typeof moduleOpts === 'object' ? moduleOpts : {}) const originalSrc = moduleOpts.src || moduleOpts // Resolve module let module = originalSrc diff --git a/lib/nuxt.js b/lib/nuxt.js index 39bc7448d2..ee28be97cf 100644 --- a/lib/nuxt.js +++ b/lib/nuxt.js @@ -16,7 +16,8 @@ import * as utils from './utils' class Nuxt { constructor (options = {}) { const defaults = { - dev: true, + dev: (process.env.NODE_ENV !== 'production'), + buildDir: '.nuxt', env: {}, head: { meta: [], @@ -61,9 +62,6 @@ class Nuxt { watchers: { webpack: {}, chokidar: {} - }, - build: { - buildNamespace: null } } // Sanitization @@ -74,13 +72,14 @@ class Nuxt { } if (typeof options.transition === 'string') options.transition = { name: options.transition } this.options = _.defaultsDeep(options, defaults) + // Ready variable + this._ready = false // Env variables this.dev = this.options.dev // Explicit srcDir, rootDir and buildDir this.dir = (typeof options.rootDir === 'string' && options.rootDir ? options.rootDir : process.cwd()) this.srcDir = (typeof options.srcDir === 'string' && options.srcDir ? resolve(this.dir, options.srcDir) : this.dir) - this.buildDir = (typeof options.build.buildNamespace === 'string' && options.build.buildNamespace) - ? resolve(this.dir, '.nuxt', options.build.buildNamespace) : resolve(this.dir, '.nuxt') + this.buildDir = join(this.dir, options.buildDir) options.rootDir = this.dir options.srcDir = this.srcDir options.buildDir = this.buildDir @@ -124,14 +123,26 @@ class Nuxt { this.utils = utils // Add module integration this.module = new Module(this) - // Install all modules in sequence and then return `this` instance - return utils.sequence(options.modules, this.module.addModule.bind(this.module)) - .then(() => this) - .catch(/* istanbul ignore next */ (err) => { - console.error('[nuxt] error while initializing modules') // eslint-disable-line no-console - console.error(err) // eslint-disable-line no-console - process.exit(1) - }) + // Init nuxt.js + this._ready = this.ready() + // Return nuxt.js instance + return this + } + + async ready () { + if (this._ready) { + await this._ready + return this + } + // Init modules + await this.module.ready() + // Launch build in development but don't wait for it to be finished + if (this.dev) { + this.build() + } else { + build.production.call(this) + } + return this } close (callback) { diff --git a/lib/render.js b/lib/render.js index 2365af27d4..0cc56b79df 100644 --- a/lib/render.js +++ b/lib/render.js @@ -11,6 +11,9 @@ debug.color = 4 setAnsiColors(ansiHTML) export async function render (req, res) { + // Wait for nuxt.js to be ready + await this.ready() + // Check if project is built for production if (!this.renderer && !this.dev) { console.error('> No build files found, please run `nuxt build` before launching `nuxt start`') // eslint-disable-line no-console process.exit(1) @@ -23,6 +26,7 @@ export async function render (req, res) { }, 1000) }) } + // Get context const context = getContext(req, res) res.statusCode = 200 try { @@ -92,6 +96,7 @@ export async function render (req, res) { return err } const html = this.errorTemplate({ + /* istanbul ignore if */ error: err, stack: ansiHTML(encodeHtml(err.stack)) }) @@ -104,6 +109,9 @@ export async function render (req, res) { } export async function renderRoute (url, context = {}) { + // Wait for modules to be initialized + await this.ready() + // Log rendered url debug(`Rendering url ${url}`) // Add url and isSever to the context context.url = url @@ -138,12 +146,11 @@ export async function renderRoute (url, context = {}) { // Function used to do dom checking via jsdom let jsdom = null -export function renderAndGetWindow (url, opts = {}) { +export async function renderAndGetWindow (url, opts = {}) { /* istanbul ignore if */ if (!jsdom) { try { - // https://github.com/tmpvar/jsdom/blob/master/lib/old-api.md - jsdom = require('jsdom/lib/old-api') + jsdom = require('jsdom') } catch (e) { console.error('Fail when calling nuxt.renderAndGetWindow(url)') // eslint-disable-line no-console console.error('jsdom module is not installed') // eslint-disable-line no-console @@ -151,35 +158,32 @@ export function renderAndGetWindow (url, opts = {}) { process.exit(1) } } - let virtualConsole = jsdom.createVirtualConsole().sendTo(console) - // let virtualConsole = new jsdom.VirtualConsole().sendTo(console) - if (opts.virtualConsole === false) { - virtualConsole = undefined + let options = { + resources: 'usable', // load subresources (https://github.com/tmpvar/jsdom#loading-subresources) + runScripts: 'dangerously', + beforeParse (window) { + // Mock window.scrollTo + window.scrollTo = () => {} + } + } + if (opts.virtualConsole !== false) { + options.virtualConsole = new jsdom.VirtualConsole().sendTo(console) } url = url || 'http://localhost:3000' - return new Promise((resolve, reject) => { - jsdom.env({ - url: url, - features: { - FetchExternalResources: ['script', 'link'], - ProcessExternalResources: ['script'] - }, - virtualConsole, - done (err, window) { - if (err) return reject(err) - // Mock window.scrollTo - window.scrollTo = function () {} - // If Nuxt could not be loaded (error from the server-side) - if (!window.__NUXT__) { - let error = new Error('Could not load the nuxt app') - error.body = window.document.getElementsByTagName('body')[0].innerHTML - return reject(error) - } - // Used by nuxt.js to say when the components are loaded and the app ready - window.onNuxtReady(() => { - resolve(window) - }) - } - }) + const { window } = await jsdom.JSDOM.fromURL(url, options) + // If Nuxt could not be loaded (error from the server-side) + const nuxtExists = window.document.body.innerHTML.includes('window.__NUXT__') + if (!nuxtExists) { + /* istanbul ignore next */ + let error = new Error('Could not load the nuxt app') + /* istanbul ignore next */ + error.body = window.document.body.innerHTML + throw error + } + // Used by nuxt.js to say when the components are loaded and the app ready + await new Promise((resolve) => { + window._onNuxtLoaded = () => resolve(window) }) + // Send back window object + return window } diff --git a/lib/server.js b/lib/server.js index 5ad4439529..63766e4563 100644 --- a/lib/server.js +++ b/lib/server.js @@ -10,12 +10,15 @@ class Server { // Initialize this.app = connect() this.server = http.createServer(this.app) - // Add Middleware - this.nuxt.options.serverMiddleware.forEach(m => { - this.useMiddleware(m) + this.nuxt.ready() + .then(() => { + // Add Middleware + this.nuxt.options.serverMiddleware.forEach(m => { + this.useMiddleware(m) + }) + // Add default render middleware + this.useMiddleware(this.render.bind(this)) }) - // Add default render middleware - this.useMiddleware(this.render.bind(this)) return this } @@ -45,8 +48,11 @@ class Server { listen (port, host) { host = host || '127.0.0.1' port = port || 3000 - this.server.listen(port, host, () => { - console.log('Ready on http://%s:%s', host, port) // eslint-disable-line no-console + this.nuxt.ready() + .then(() => { + this.server.listen(port, host, () => { + console.log('Ready on http://%s:%s', host, port) // eslint-disable-line no-console + }) }) return this } diff --git a/package.json b/package.json index c1d7454541..f78ff073d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nuxt", - "version": "1.0.0-alpha2", + "version": "1.0.0-alpha.3", "description": "A minimalistic framework for server-rendered Vue.js applications (inspired by Next.js)", "contributors": [ { @@ -14,7 +14,7 @@ } ], "main": "./index.js", - "types": "./index.d.js", + "types": "./index.d.ts", "license": "MIT", "repository": { "type": "git", @@ -23,6 +23,7 @@ "files": [ "bin", "dist", + "index.d.ts", "index.js" ], "keywords": [ @@ -57,7 +58,7 @@ }, "dependencies": { "ansi-html": "^0.0.7", - "autoprefixer": "^7.1.0", + "autoprefixer": "^7.1.1", "babel-core": "^6.24.1", "babel-loader": "^7.0.0", "babel-preset-es2015": "^6.24.1", @@ -65,40 +66,40 @@ "chokidar": "^1.7.0", "compression": "^1.6.2", "connect": "^3.6.2", - "css-loader": "^0.28.1", - "debug": "^2.6.6", + "css-loader": "^0.28.4", + "debug": "^2.6.8", "etag": "^1.8.0", "extract-text-webpack-plugin": "^2.1.0", "file-loader": "^0.11.1", "fresh": "^0.5.0", "friendly-errors-webpack-plugin": "^1.6.1", "fs-extra": "^3.0.1", - "glob": "^7.1.1", + "glob": "^7.1.2", "hash-sum": "^1.0.2", - "html-minifier": "^3.5.0", + "html-minifier": "^3.5.2", "html-webpack-plugin": "^2.28.0", "lodash": "^4.17.4", "memory-fs": "^0.4.1", - "offline-plugin": "^4.7.0", + "offline-plugin": "^4.8.1", "opencollective": "^1.0.3", - "pify": "^2.3.0", + "pify": "^3.0.0", "post-compile-webpack-plugin": "^0.1.1", "preload-webpack-plugin": "^1.2.2", "progress-bar-webpack-plugin": "^1.9.3", - "script-ext-html-webpack-plugin": "^1.8.0", + "script-ext-html-webpack-plugin": "^1.8.1", "serialize-javascript": "^1.3.0", - "serve-static": "^1.12.2", + "serve-static": "^1.12.3", "url-loader": "^0.5.8", "vue": "~2.3.3", - "vue-loader": "^12.1.0", + "vue-loader": "^12.2.1", "vue-meta": "^1.0.4", "vue-router": "^2.5.3", "vue-server-renderer": "~2.3.3", "vue-ssr-html-stream": "^2.2.0", "vue-template-compiler": "~2.3.3", "vuex": "^2.3.1", - "webpack": "^2.5.1", - "webpack-bundle-analyzer": "^2.8.1", + "webpack": "^2.6.1", + "webpack-bundle-analyzer": "^2.8.2", "webpack-dev-middleware": "^1.10.2", "webpack-hot-middleware": "^2.18.0", "webpack-node-externals": "^1.6.0" @@ -115,12 +116,12 @@ "eslint": "^3.19.0", "eslint-config-standard": "^10.2.1", "eslint-plugin-html": "^2.0.3", - "eslint-plugin-import": "^2.2.0", + "eslint-plugin-import": "^2.3.0", "eslint-plugin-node": "^4.2.2", "eslint-plugin-promise": "^3.5.0", "eslint-plugin-standard": "^3.0.1", - "finalhandler": "^1.0.2", - "jsdom": "^10.1.0", + "finalhandler": "^1.0.3", + "jsdom": "^11.0.0", "json-loader": "^0.5.4", "nyc": "^10.3.2", "request": "^2.81.0", diff --git a/test/basic.dev.test.js b/test/basic.dev.test.js index 9d1f02f968..42e60e22fa 100644 --- a/test/basic.dev.test.js +++ b/test/basic.dev.test.js @@ -14,7 +14,7 @@ test.before('Init Nuxt.js', async t => { rootDir: resolve(__dirname, 'fixtures/basic'), dev: true } - nuxt = await new Nuxt(options) + nuxt = new Nuxt(options) await nuxt.build() server = new nuxt.Server(nuxt) server.listen(port, 'localhost') diff --git a/test/basic.fail.generate.test.js b/test/basic.fail.generate.test.js index b96a8b343d..c1c85a30fa 100644 --- a/test/basic.fail.generate.test.js +++ b/test/basic.fail.generate.test.js @@ -14,7 +14,7 @@ test('Fail with routes() which throw an error', async t => { } } } - const nuxt = await new Nuxt(options) + const nuxt = new Nuxt(options) return new Promise((resolve) => { var oldExit = process.exit var oldCE = console.error // eslint-disable-line no-console diff --git a/test/basic.generate.test.js b/test/basic.generate.test.js index 254dc1453e..cc0c160912 100644 --- a/test/basic.generate.test.js +++ b/test/basic.generate.test.js @@ -17,7 +17,7 @@ test.before('Init Nuxt.js', async t => { let config = require(resolve(rootDir, 'nuxt.config.js')) config.rootDir = rootDir config.dev = false - nuxt = await new Nuxt(config) + nuxt = new Nuxt(config) try { await nuxt.generate() // throw an error (of /validate route) } catch (err) {} @@ -74,9 +74,9 @@ test('/users/2', async t => { t.true(html.includes('

User: 2

')) }) -test('/users/3', async t => { +test('/users/3 (payload given)', async t => { const html = await rp(url('/users/3')) - t.true(html.includes('

User: 3

')) + t.true(html.includes('

User: 3000

')) }) test('/users/4 -> Not found', async t => { diff --git a/test/basic.test.js b/test/basic.test.js index 514ccf39c0..14a63aaa5b 100755 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -16,7 +16,7 @@ test.before('Init Nuxt.js', async t => { rootDir: resolve(__dirname, 'fixtures/basic'), dev: false } - nuxt = await new Nuxt(options) + nuxt = new Nuxt(options) await nuxt.build() server = new nuxt.Server(nuxt) server.listen(port, 'localhost') diff --git a/test/children.test.js b/test/children.test.js index 261b878380..2536ed4e22 100644 --- a/test/children.test.js +++ b/test/children.test.js @@ -13,7 +13,7 @@ test.before('Init Nuxt.js', async t => { rootDir: resolve(__dirname, 'fixtures/children'), dev: false } - nuxt = await new Nuxt(options) + nuxt = new Nuxt(options) await nuxt.build() server = new nuxt.Server(nuxt) server.listen(port, 'localhost') diff --git a/test/dynamic-routes.test.js b/test/dynamic-routes.test.js index 126d433f88..40bd5446d2 100644 --- a/test/dynamic-routes.test.js +++ b/test/dynamic-routes.test.js @@ -6,7 +6,7 @@ const readFile = pify(fs.readFile) test.before('Init Nuxt.js', async t => { const Nuxt = require('../') - const nuxt = await new Nuxt({ + const nuxt = new Nuxt({ rootDir: resolve(__dirname, 'fixtures/dynamic-routes'), dev: false }) diff --git a/test/error.test.js b/test/error.test.js index e12120ed2e..26fba45f6e 100644 --- a/test/error.test.js +++ b/test/error.test.js @@ -13,7 +13,7 @@ test.before('Init Nuxt.js', async t => { rootDir: resolve(__dirname, 'fixtures/error'), dev: false } - nuxt = await new Nuxt(options) + nuxt = new Nuxt(options) await nuxt.build() server = new nuxt.Server(nuxt) server.listen(port, 'localhost') @@ -33,12 +33,8 @@ test('/404 should display an error too', async t => { }) test('/ with renderAndGetWindow()', async t => { - try { - await nuxt.renderAndGetWindow(url('/')) - } catch (e) { - t.true(e.message.includes('Could not load the nuxt app')) - t.true(e.body.includes('render function or template not defined in component')) - } + const err = await t.throws(nuxt.renderAndGetWindow(url('/'))) + t.is(err.response.statusCode, 500) }) // Close server and ask nuxt to stop listening to file changes diff --git a/test/fixtures/basic/nuxt.config.js b/test/fixtures/basic/nuxt.config.js index d6ba223b68..fb6e6734c7 100644 --- a/test/fixtures/basic/nuxt.config.js +++ b/test/fixtures/basic/nuxt.config.js @@ -3,7 +3,7 @@ module.exports = { routes: [ '/users/1', '/users/2', - '/users/3' + { route: '/users/3', payload: { id: 3000 } } ], interval: 200 } diff --git a/test/fixtures/basic/pages/users/_id.vue b/test/fixtures/basic/pages/users/_id.vue index 8cd8e0f0d1..ed71a446ec 100644 --- a/test/fixtures/basic/pages/users/_id.vue +++ b/test/fixtures/basic/pages/users/_id.vue @@ -4,7 +4,8 @@ diff --git a/test/index.test.js b/test/index.test.js index 40be484e4a..f910f1ea5e 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -7,16 +7,18 @@ test('Nuxt.js Class', t => { t.is(typeof Nuxt, 'function') }) -test('Nuxt.js Instance', async t => { - const nuxt = await new Nuxt() +test.serial('Nuxt.js Instance', async t => { + process.env.NODE_ENV = 'production' + const nuxt = new Nuxt() t.is(typeof nuxt, 'object') - t.is(nuxt.dev, true) + t.is(nuxt.dev, false) t.is(typeof nuxt.build, 'function') t.is(typeof nuxt.generate, 'function') + delete process.env.NODE_ENV }) test.serial('Fail when build not done and try to render', async t => { - const nuxt = await new Nuxt({ + const nuxt = new Nuxt({ dev: false, rootDir: resolve(__dirname, 'fixtures/empty') }) @@ -37,7 +39,7 @@ test.serial('Fail when build not done and try to render', async t => { }) test.serial('Fail to build when no pages/ directory but is in the parent', async t => { - const nuxt = await new Nuxt({ + const nuxt = new Nuxt({ dev: false, rootDir: resolve(__dirname, 'fixtures', 'empty', 'pages') }) @@ -58,7 +60,7 @@ test.serial('Fail to build when no pages/ directory but is in the parent', async }) test.serial('Fail to build when no pages/ directory', async t => { - const nuxt = await new Nuxt({ + const nuxt = new Nuxt({ dev: false, rootDir: resolve(__dirname) }) diff --git a/test/module.test.js b/test/module.test.js index 7938b317f8..58e15de574 100755 --- a/test/module.test.js +++ b/test/module.test.js @@ -8,6 +8,8 @@ const url = (route) => 'http://localhost:' + port + route let nuxt = null let server = null +const wp = p => /^win/.test(process.platform) ? p.replace(/[\\/]/g, '\\\\') : p + // Init nuxt.js and create server listening on localhost:4000 test.before('Init Nuxt.js', async t => { const Nuxt = require('../') @@ -15,7 +17,7 @@ test.before('Init Nuxt.js', async t => { let config = require(resolve(rootDir, 'nuxt.config.js')) config.rootDir = rootDir config.dev = false - nuxt = await new Nuxt(config) + nuxt = new Nuxt(config) await nuxt.build() server = new nuxt.Server(nuxt) server.listen(port, 'localhost') @@ -26,7 +28,7 @@ test('Vendor', async t => { }) test('Plugin', async t => { - t.true(nuxt.options.plugins[0].src.startsWith('~/.nuxt/basic.reverse'), 'plugin added to config') + t.true(nuxt.options.plugins[0].src.includes(wp('fixtures/module/.nuxt/basic.reverse.')), 'plugin added to config') const { html } = await nuxt.renderRoute('/') t.true(html.includes('

TXUN

'), 'plugin works') }) diff --git a/test/utils.test.js b/test/utils.test.js index 052db5a900..3a2aff00ff 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -5,7 +5,7 @@ let utils // Init nuxt.js and create server listening on localhost:4000 test.before('Init Nuxt.js', async t => { const Nuxt = require('../') - let nuxt = await new Nuxt({ dev: false }) + let nuxt = new Nuxt({ dev: false }) utils = nuxt.utils }) diff --git a/test/with-config.test.js b/test/with-config.test.js index bbce95a138..07c299f245 100644 --- a/test/with-config.test.js +++ b/test/with-config.test.js @@ -15,7 +15,7 @@ test.before('Init Nuxt.js', async t => { let config = require(resolve(rootDir, 'nuxt.config.js')) config.rootDir = rootDir config.dev = false - nuxt = await new Nuxt(config) + nuxt = new Nuxt(config) await nuxt.build() server = new nuxt.Server(nuxt) server.listen(port, 'localhost') @@ -78,7 +78,7 @@ test('/test/error', async t => { test('/test/user-agent', async t => { const window = await nuxt.renderAndGetWindow(url('/test/user-agent')) const html = window.document.body.innerHTML - t.true(html.includes('
Node.js'))
+  t.true(html.includes('
Mozilla'))
 })
 
 test('/test/about-bis (added with extendRoutes)', async t => {
@@ -110,5 +110,5 @@ test.after('Should be able to start Nuxt with build done', async t => {
   let config = require(resolve(rootDir, 'nuxt.config.js'))
   config.rootDir = rootDir
   config.dev = false
-  nuxt = await new Nuxt(config)
+  nuxt = new Nuxt(config)
 })
diff --git a/yarn.lock b/yarn.lock
index 4fec3b49c9..d77c849ad0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -37,6 +37,10 @@
     ansi-styles "^2.2.1"
     esutils "^2.0.2"
 
+"@types/node@^6.0.46":
+  version "6.0.73"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.73.tgz#85dc4bb6f125377c75ddd2519a1eeb63f0a4ed70"
+
 abab@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
@@ -75,8 +79,8 @@ acorn@^3.0.4:
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
 
 acorn@^4.0.3, acorn@^4.0.4:
-  version "4.0.11"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+  version "4.0.13"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
 
 acorn@^5.0.0, acorn@^5.0.1, acorn@^5.0.3:
   version "5.0.3"
@@ -262,8 +266,8 @@ async@^1.4.0:
   resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
 
 async@^2.1.2:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/async/-/async-2.4.0.tgz#4990200f18ea5b837c2cc4f8c031a6985c385611"
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7"
   dependencies:
     lodash "^4.14.0"
 
@@ -286,12 +290,12 @@ autoprefixer@^6.3.1:
     postcss "^5.2.16"
     postcss-value-parser "^3.2.3"
 
-autoprefixer@^7.1.0:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.1.0.tgz#ae4913adc221fa6ca5ad3a6f8039f6a5c06b3877"
+autoprefixer@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.1.1.tgz#97bc854c7d0b979f8d6489de547a0d17fb307f6d"
   dependencies:
-    browserslist "^2.1.2"
-    caniuse-lite "^1.0.30000669"
+    browserslist "^2.1.3"
+    caniuse-lite "^1.0.30000670"
     normalize-range "^0.1.2"
     num2fraction "^1.2.2"
     postcss "^6.0.1"
@@ -898,8 +902,8 @@ babel-polyfill@6.23.0:
     regenerator-runtime "^0.10.0"
 
 babel-preset-env@^1.2.1:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a"
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.5.1.tgz#d2eca6af179edf27cdc305a84820f601b456dd0b"
   dependencies:
     babel-plugin-check-es2015-constants "^6.22.0"
     babel-plugin-syntax-trailing-function-commas "^6.22.0"
@@ -928,8 +932,9 @@ babel-preset-env@^1.2.1:
     babel-plugin-transform-es2015-unicode-regex "^6.22.0"
     babel-plugin-transform-exponentiation-operator "^6.22.0"
     babel-plugin-transform-regenerator "^6.22.0"
-    browserslist "^1.4.0"
+    browserslist "^2.1.2"
     invariant "^2.2.2"
+    semver "^5.3.0"
 
 babel-preset-es2015@^6.24.1:
   version "6.24.1"
@@ -1186,19 +1191,19 @@ browserify-zlib@^0.1.4:
   dependencies:
     pako "~0.2.0"
 
-browserslist@^1.3.6, browserslist@^1.4.0, browserslist@^1.5.2, browserslist@^1.7.6:
+browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
   version "1.7.7"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
   dependencies:
     caniuse-db "^1.0.30000639"
     electron-to-chromium "^1.2.7"
 
-browserslist@^2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.1.2.tgz#a9dd0791342dab019861c2dd1cd0fd5d83230d39"
+browserslist@^2.1.2, browserslist@^2.1.3:
+  version "2.1.4"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.1.4.tgz#cc526af4a1312b7d2e05653e56d0c8ab70c0e053"
   dependencies:
-    caniuse-lite "^1.0.30000665"
-    electron-to-chromium "^1.3.9"
+    caniuse-lite "^1.0.30000670"
+    electron-to-chromium "^1.3.11"
 
 buf-compare@^1.0.0:
   version "1.0.1"
@@ -1303,12 +1308,12 @@ caniuse-api@^1.5.2:
     lodash.uniq "^4.5.0"
 
 caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
-  version "1.0.30000670"
-  resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000670.tgz#90d33b79e3090e25829c311113c56d6b1788bf43"
+  version "1.0.30000676"
+  resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000676.tgz#82ea578237637c8ff34a28acaade373b624c4ea8"
 
-caniuse-lite@^1.0.30000665, caniuse-lite@^1.0.30000669:
-  version "1.0.30000670"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000670.tgz#c94f7dbf0b68eaadc46d3d203f46e82e7801135e"
+caniuse-lite@^1.0.30000670:
+  version "1.0.30000676"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000676.tgz#1e962123f48073f0c51c4ea0651dd64d25786498"
 
 capture-stack-trace@^1.0.0:
   version "1.0.0"
@@ -1383,14 +1388,14 @@ clap@^1.0.9:
     chalk "^1.1.3"
 
 clean-css@4.1.x:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.2.tgz#6029aea30b1d9520a968a3caee0dabb1184e353a"
+  version "4.1.3"
+  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.3.tgz#07cfe8980edb20d455ddc23aadcf1e04c6e509ce"
   dependencies:
     source-map "0.5.x"
 
 clean-stack@^1.1.1:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-1.2.0.tgz#a465128d62c31fb1a3606d00abfe59dcf652f568"
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-1.3.0.tgz#9e821501ae979986c46b1d66d2d432db2fd4ae31"
 
 clean-yaml-object@^0.1.0:
   version "0.1.0"
@@ -1458,8 +1463,8 @@ co@^4.6.0:
   resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
 
 coa@~1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3"
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.2.tgz#2ba9fec3b4aa43d7a49d7e6c3561e92061b6bcec"
   dependencies:
     q "^1.1.2"
 
@@ -1761,13 +1766,14 @@ css-color-names@0.0.4:
   version "0.0.4"
   resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
 
-css-loader@^0.28.1:
-  version "0.28.1"
-  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.1.tgz#220325599f8f00452d9ceb4c3ca6c8a66798642d"
+css-loader@^0.28.4:
+  version "0.28.4"
+  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.4.tgz#6cf3579192ce355e8b38d5f42dd7a1f2ec898d0f"
   dependencies:
     babel-code-frame "^6.11.0"
     css-selector-tokenizer "^0.7.0"
     cssnano ">=2.6.1 <4"
+    icss-utils "^2.1.0"
     loader-utils "^1.0.2"
     lodash.camelcase "^4.3.0"
     object-assign "^4.0.1"
@@ -1788,14 +1794,6 @@ css-select@^1.1.0:
     domutils "1.5.1"
     nth-check "~1.0.1"
 
-css-selector-tokenizer@^0.6.0:
-  version "0.6.0"
-  resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz#6445f582c7930d241dcc5007a43d6fcb8f073152"
-  dependencies:
-    cssesc "^0.1.0"
-    fastparse "^1.1.1"
-    regexpu-core "^1.0.0"
-
 css-selector-tokenizer@^0.7.0:
   version "0.7.0"
   resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86"
@@ -1906,18 +1904,18 @@ debug@2.2.0, debug@~2.2.0:
   dependencies:
     ms "0.7.1"
 
-debug@2.6.1:
-  version "2.6.1"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351"
-  dependencies:
-    ms "0.7.2"
-
-debug@2.6.7, debug@^2.1.1, debug@^2.2.0, debug@^2.6.3, debug@^2.6.6:
+debug@2.6.7:
   version "2.6.7"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e"
   dependencies:
     ms "2.0.0"
 
+debug@^2.1.1, debug@^2.2.0, debug@^2.6.3, debug@^2.6.8:
+  version "2.6.8"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
+  dependencies:
+    ms "2.0.0"
+
 decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -1996,6 +1994,10 @@ detect-indent@^4.0.0:
   dependencies:
     repeating "^2.0.0"
 
+detect-indent@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d"
+
 diff-match-patch@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.0.tgz#1cc3c83a490d67f95d91e39f6ad1f2e086b63048"
@@ -2120,9 +2122,9 @@ ejs@^2.3.4, ejs@^2.5.6:
   version "2.5.6"
   resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88"
 
-electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.9:
-  version "1.3.11"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.11.tgz#744761df1d67b492b322ce9aa0aba5393260eb61"
+electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.11:
+  version "1.3.13"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.13.tgz#1b3a5eace6e087bb5e257a100b0cbfe81b2891fc"
 
 elliptic@^6.0.0:
   version "6.4.0"
@@ -2193,8 +2195,8 @@ error-stack-parser@^2.0.0:
     stackframe "^1.0.3"
 
 es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
-  version "0.10.18"
-  resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.18.tgz#dc239d3dce4c22b9c939aa180878837a3c0b5c92"
+  version "0.10.21"
+  resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.21.tgz#19a725f9e51d0300bbc1e8e821109fd9daf55925"
   dependencies:
     es6-iterator "2"
     es6-symbol "~3.1"
@@ -2301,9 +2303,9 @@ eslint-plugin-html@^2.0.3:
   dependencies:
     htmlparser2 "^3.8.2"
 
-eslint-plugin-import@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e"
+eslint-plugin-import@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.3.0.tgz#37c801e0ada0e296cbdf20c3f393acb5b52af36b"
   dependencies:
     builtin-modules "^1.1.1"
     contains-path "^0.1.0"
@@ -2314,7 +2316,7 @@ eslint-plugin-import@^2.2.0:
     has "^1.0.1"
     lodash.cond "^4.3.0"
     minimatch "^3.0.3"
-    pkg-up "^1.0.0"
+    read-pkg-up "^2.0.0"
 
 eslint-plugin-node@^4.2.2:
   version "4.2.2"
@@ -2494,8 +2496,8 @@ expand-range@^1.8.1:
     fill-range "^2.1.0"
 
 express@^4.15.2:
-  version "4.15.2"
-  resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35"
+  version "4.15.3"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662"
   dependencies:
     accepts "~1.3.3"
     array-flatten "1.1.1"
@@ -2503,37 +2505,39 @@ express@^4.15.2:
     content-type "~1.0.2"
     cookie "0.3.1"
     cookie-signature "1.0.6"
-    debug "2.6.1"
+    debug "2.6.7"
     depd "~1.1.0"
     encodeurl "~1.0.1"
     escape-html "~1.0.3"
     etag "~1.8.0"
-    finalhandler "~1.0.0"
+    finalhandler "~1.0.3"
     fresh "0.5.0"
     merge-descriptors "1.0.1"
     methods "~1.1.2"
     on-finished "~2.3.0"
     parseurl "~1.3.1"
     path-to-regexp "0.1.7"
-    proxy-addr "~1.1.3"
+    proxy-addr "~1.1.4"
     qs "6.4.0"
     range-parser "~1.2.0"
-    send "0.15.1"
-    serve-static "1.12.1"
+    send "0.15.3"
+    serve-static "1.12.3"
     setprototypeof "1.0.3"
     statuses "~1.3.1"
-    type-is "~1.6.14"
+    type-is "~1.6.15"
     utils-merge "1.0.0"
-    vary "~1.1.0"
+    vary "~1.1.1"
 
 extend@~3.0.0:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
 
 external-editor@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.1.tgz#4c597c6c88fa6410e41dbbaa7b1be2336aa31095"
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972"
   dependencies:
+    iconv-lite "^0.4.17"
+    jschardet "^1.4.2"
     tmp "^0.0.31"
 
 extglob@^0.3.1:
@@ -2594,8 +2598,8 @@ filename-regex@^2.0.0:
   resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
 
 filesize@^3.5.9:
-  version "3.5.9"
-  resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.9.tgz#9e3dd8a9b124f5b2f1fb2ee9cd13a86c707bb222"
+  version "3.5.10"
+  resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f"
 
 fill-range@^2.1.0:
   version "2.2.3"
@@ -2607,7 +2611,7 @@ fill-range@^2.1.0:
     repeat-element "^1.1.2"
     repeat-string "^1.5.2"
 
-finalhandler@1.0.3, finalhandler@^1.0.2, finalhandler@~1.0.0:
+finalhandler@1.0.3, finalhandler@^1.0.3, finalhandler@~1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89"
   dependencies:
@@ -2831,14 +2835,14 @@ glob@^6.0.4:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1:
-  version "7.1.1"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.2:
+  version "7.1.2"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
   dependencies:
     fs.realpath "^1.0.0"
     inflight "^1.0.4"
     inherits "2"
-    minimatch "^3.0.2"
+    minimatch "^3.0.4"
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
@@ -2898,8 +2902,8 @@ gzip-size@^3.0.0:
     duplexer "^0.1.1"
 
 handlebars@^4.0.3:
-  version "4.0.8"
-  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.8.tgz#22b875cd3f0e6cbea30314f144e82bc7a72ff420"
+  version "4.0.10"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f"
   dependencies:
     async "^1.4.0"
     optimist "^0.6.1"
@@ -3025,9 +3029,9 @@ html-entities@^1.2.0:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
 
-html-minifier@^3.2.3, html-minifier@^3.5.0:
-  version "3.5.0"
-  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.0.tgz#98be1b18f87443592722f654e67a1541f22018cb"
+html-minifier@^3.2.3, html-minifier@^3.5.2:
+  version "3.5.2"
+  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.2.tgz#d73bc3ff448942408818ce609bf3fb0ea7ef4eb7"
   dependencies:
     camel-case "3.0.x"
     clean-css "4.1.x"
@@ -3108,13 +3112,23 @@ hullabaloo-config-manager@^1.0.0:
     pkg-dir "^1.0.0"
     resolve-from "^2.0.0"
 
-iconv-lite@0.4.13, iconv-lite@~0.4.13:
+iconv-lite@0.4.13:
   version "0.4.13"
   resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
 
-icss-replace-symbols@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5"
+iconv-lite@^0.4.17, iconv-lite@~0.4.13:
+  version "0.4.17"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.17.tgz#4fdaa3b38acbc2c031b045d0edcdfe1ecab18c8d"
+
+icss-replace-symbols@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
+
+icss-utils@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
+  dependencies:
+    postcss "^6.0.1"
 
 ieee754@^1.1.4:
   version "1.1.8"
@@ -3125,8 +3139,8 @@ ignore-by-default@^1.0.0:
   resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
 
 ignore@^3.0.11, ignore@^3.2.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.0.tgz#3812d22cbe9125f2c2b4915755a1b8abd745a001"
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d"
 
 imurmurhash@^0.1.4:
   version "0.1.4"
@@ -3442,50 +3456,50 @@ isstream@~0.1.2:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
 
-istanbul-lib-coverage@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz#caca19decaef3525b5d6331d701f3f3b7ad48528"
+istanbul-lib-coverage@^1.1.0, istanbul-lib-coverage@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da"
 
 istanbul-lib-hook@^1.0.6:
-  version "1.0.6"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.6.tgz#c0866d1e81cf2d5319249510131fc16dee49231f"
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz#dd6607f03076578fe7d6f2a630cf143b49bacddc"
   dependencies:
     append-transform "^0.4.0"
 
 istanbul-lib-instrument@^1.7.1:
-  version "1.7.1"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.1.tgz#169e31bc62c778851a99439dd99c3cc12184d360"
+  version "1.7.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.2.tgz#6014b03d3470fb77638d5802508c255c06312e56"
   dependencies:
     babel-generator "^6.18.0"
     babel-template "^6.16.0"
     babel-traverse "^6.18.0"
     babel-types "^6.18.0"
     babylon "^6.13.0"
-    istanbul-lib-coverage "^1.1.0"
+    istanbul-lib-coverage "^1.1.1"
     semver "^5.3.0"
 
 istanbul-lib-report@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.0.tgz#444c4ecca9afa93cf584f56b10f195bf768c0770"
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#f0e55f56655ffa34222080b7a0cd4760e1405fc9"
   dependencies:
-    istanbul-lib-coverage "^1.1.0"
+    istanbul-lib-coverage "^1.1.1"
     mkdirp "^0.5.1"
     path-parse "^1.0.5"
     supports-color "^3.1.2"
 
 istanbul-lib-source-maps@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.0.tgz#8c7706d497e26feeb6af3e0c28fd5b0669598d0e"
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz#a6fe1acba8ce08eebc638e572e294d267008aa0c"
   dependencies:
     debug "^2.6.3"
-    istanbul-lib-coverage "^1.1.0"
+    istanbul-lib-coverage "^1.1.1"
     mkdirp "^0.5.1"
     rimraf "^2.6.1"
     source-map "^0.5.3"
 
 istanbul-reports@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.0.tgz#1ef3b795889219cfb5fad16365f6ce108d5f8c66"
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.1.tgz#042be5c89e175bc3f86523caab29c014e77fee4e"
   dependencies:
     handlebars "^4.0.3"
 
@@ -3595,9 +3609,13 @@ jsbn@~0.1.0:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
 
-jsdom@^10.1.0:
-  version "10.1.0"
-  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-10.1.0.tgz#7765e00fd5c3567f34985a1c86ff466a61dacc6a"
+jschardet@^1.4.2:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.4.2.tgz#2aa107f142af4121d145659d44f50830961e699a"
+
+jsdom@^11.0.0:
+  version "11.0.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.0.0.tgz#1ee507cb2c0b16c875002476b1a8557d951353e5"
   dependencies:
     abab "^1.0.3"
     acorn "^4.0.4"
@@ -3609,7 +3627,7 @@ jsdom@^10.1.0:
     escodegen "^1.6.1"
     html-encoding-sniffer "^1.0.1"
     nwmatcher ">= 1.3.9 < 2.0.0"
-    parse5 "^1.5.1"
+    parse5 "^3.0.2"
     pn "^1.0.0"
     request "^2.79.0"
     request-promise-native "^1.0.3"
@@ -4026,7 +4044,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
 
-"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
+"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
   dependencies:
@@ -4050,10 +4068,6 @@ ms@0.7.1, ms@^0.7.1:
   version "0.7.1"
   resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
 
-ms@0.7.2:
-  version "0.7.2"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
-
 ms@2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -4100,8 +4114,8 @@ no-case@^2.2.0:
     lower-case "^1.1.1"
 
 node-dir@^0.1.10:
-  version "0.1.16"
-  resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.16.tgz#d2ef583aa50b90d93db8cdd26fcea58353957fe4"
+  version "0.1.17"
+  resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
   dependencies:
     minimatch "^3.0.2"
 
@@ -4231,8 +4245,8 @@ number-is-nan@^1.0.0:
   resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
 
 "nwmatcher@>= 1.3.9 < 2.0.0":
-  version "1.3.9"
-  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.0.tgz#b4389362170e7ef9798c3c7716d80ebc0106fccf"
 
 nyc@^10.3.2:
   version "10.3.2"
@@ -4300,9 +4314,9 @@ observable-to-promise@^0.5.0:
     is-observable "^0.2.0"
     symbol-observable "^1.0.4"
 
-offline-plugin@^4.7.0:
-  version "4.7.0"
-  resolved "https://registry.yarnpkg.com/offline-plugin/-/offline-plugin-4.7.0.tgz#4c2fca6cd46c6dd7f29fc94ade21e5f82a62c4df"
+offline-plugin@^4.8.1:
+  version "4.8.1"
+  resolved "https://registry.yarnpkg.com/offline-plugin/-/offline-plugin-4.8.1.tgz#1d73457081185777179c29d9d416f71077a0197a"
   dependencies:
     deep-extend "^0.4.0"
     ejs "^2.3.4"
@@ -4488,9 +4502,11 @@ parse-ms@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d"
 
-parse5@^1.5.1:
-  version "1.5.1"
-  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+parse5@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510"
+  dependencies:
+    "@types/node" "^6.0.46"
 
 parseurl@~1.3.1:
   version "1.3.1"
@@ -4566,6 +4582,10 @@ pify@^2.0.0, pify@^2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
 
+pify@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+
 pinkie-promise@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-1.0.0.tgz#d1da67f5482563bb7cf57f286ae2822ecfbf3670"
@@ -4599,12 +4619,6 @@ pkg-dir@^1.0.0:
   dependencies:
     find-up "^1.0.0"
 
-pkg-up@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26"
-  dependencies:
-    find-up "^1.0.0"
-
 plur@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156"
@@ -4773,31 +4787,31 @@ postcss-minify-selectors@^2.0.4:
     postcss-selector-parser "^2.0.0"
 
 postcss-modules-extract-imports@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.0.1.tgz#8fb3fef9a6dd0420d3f6d4353cf1ff73f2b2a341"
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85"
   dependencies:
-    postcss "^5.0.4"
+    postcss "^6.0.1"
 
 postcss-modules-local-by-default@^1.0.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.1.1.tgz#29a10673fa37d19251265ca2ba3150d9040eb4ce"
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
   dependencies:
-    css-selector-tokenizer "^0.6.0"
-    postcss "^5.0.4"
+    css-selector-tokenizer "^0.7.0"
+    postcss "^6.0.1"
 
 postcss-modules-scope@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.0.2.tgz#ff977395e5e06202d7362290b88b1e8cd049de29"
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
   dependencies:
-    css-selector-tokenizer "^0.6.0"
-    postcss "^5.0.4"
+    css-selector-tokenizer "^0.7.0"
+    postcss "^6.0.1"
 
 postcss-modules-values@^1.1.0:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.2.2.tgz#f0e7d476fe1ed88c5e4c7f97533a3e772ad94ca1"
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
   dependencies:
-    icss-replace-symbols "^1.0.2"
-    postcss "^5.0.14"
+    icss-replace-symbols "^1.1.0"
+    postcss "^6.0.1"
 
 postcss-normalize-charset@^1.1.0:
   version "1.1.1"
@@ -4969,7 +4983,7 @@ 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.3:
+proxy-addr@~1.1.4:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3"
   dependencies:
@@ -5418,9 +5432,9 @@ sax@^1.2.1, sax@~1.2.1:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
 
-script-ext-html-webpack-plugin@^1.8.0:
-  version "1.8.0"
-  resolved "https://registry.yarnpkg.com/script-ext-html-webpack-plugin/-/script-ext-html-webpack-plugin-1.8.0.tgz#0b9e9aec8c78bcd9cefbc5f6e21d2be7a15735cd"
+script-ext-html-webpack-plugin@^1.8.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/script-ext-html-webpack-plugin/-/script-ext-html-webpack-plugin-1.8.1.tgz#36bba726c38bcdebc1e69333e3fd7d718a9b3195"
   dependencies:
     debug "^2.6.3"
 
@@ -5434,24 +5448,6 @@ semver-diff@^2.0.0:
   version "5.3.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
 
-send@0.15.1:
-  version "0.15.1"
-  resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f"
-  dependencies:
-    debug "2.6.1"
-    depd "~1.1.0"
-    destroy "~1.0.4"
-    encodeurl "~1.0.1"
-    escape-html "~1.0.3"
-    etag "~1.8.0"
-    fresh "0.5.0"
-    http-errors "~1.6.1"
-    mime "1.3.4"
-    ms "0.7.2"
-    on-finished "~2.3.0"
-    range-parser "~1.2.0"
-    statuses "~1.3.1"
-
 send@0.15.3:
   version "0.15.3"
   resolved "https://registry.yarnpkg.com/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309"
@@ -5474,16 +5470,7 @@ serialize-javascript@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.3.0.tgz#86a4f3752f5c7e47295449b0bbb63d64ba533f05"
 
-serve-static@1.12.1:
-  version "1.12.1"
-  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039"
-  dependencies:
-    encodeurl "~1.0.1"
-    escape-html "~1.0.3"
-    parseurl "~1.3.1"
-    send "0.15.1"
-
-serve-static@^1.12.2:
+serve-static@1.12.3, serve-static@^1.12.3:
   version "1.12.3"
   resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2"
   dependencies:
@@ -5644,7 +5631,7 @@ stackframe@^1.0.3:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
 
-std-mocks:
+std-mocks@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/std-mocks/-/std-mocks-1.0.1.tgz#d3388876d7beeba3c70fbd8e2bcaf46eb07d79fe"
   dependencies:
@@ -5701,10 +5688,10 @@ string_decoder@^0.10.25, string_decoder@~0.10.x:
   resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
 
 string_decoder@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667"
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.1.tgz#62e200f039955a6810d8df0a33ffc0f013662d98"
   dependencies:
-    buffer-shims "~1.0.0"
+    safe-buffer "^5.0.1"
 
 stringstream@~0.0.4:
   version "0.0.5"
@@ -5827,8 +5814,8 @@ term-size@^0.1.0:
     execa "^0.4.0"
 
 test-exclude@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.0.tgz#04ca70b7390dd38c98d4a003a173806ca7991c91"
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26"
   dependencies:
     arrify "^1.0.1"
     micromatch "^2.3.11"
@@ -5934,7 +5921,7 @@ type-check@~0.3.2:
   dependencies:
     prelude-ls "~1.1.2"
 
-type-is@~1.6.14:
+type-is@~1.6.15:
   version "1.6.15"
   resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
   dependencies:
@@ -5946,15 +5933,15 @@ typedarray@^0.0.6:
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
 
 uglify-js@3.0.x:
-  version "3.0.7"
-  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.7.tgz#5cca9c14abae2dd60ceccdf7da3c672cc8069cec"
+  version "3.0.13"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.13.tgz#1871d736aa1e550c728d7e5a6556579e70925d68"
   dependencies:
     commander "~2.9.0"
     source-map "~0.5.1"
 
-uglify-js@^2.6, uglify-js@^2.8.5:
-  version "2.8.26"
-  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.26.tgz#3a1db8ae0a0aba7f92e1ddadadbd0293d549f90e"
+uglify-js@^2.6, uglify-js@^2.8.27:
+  version "2.8.27"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.27.tgz#47787f912b0f242e5b984343be8e35e95f694c9c"
   dependencies:
     source-map "~0.5.1"
     yargs "~3.10.0"
@@ -6097,7 +6084,7 @@ validate-npm-package-license@^3.0.1:
     spdx-correct "~1.0.0"
     spdx-expression-parse "~1.0.0"
 
-vary@~1.1.0:
+vary@~1.1.0, vary@~1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"
 
@@ -6121,9 +6108,9 @@ vue-hot-reload-api@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.1.0.tgz#9ca58a6e0df9078554ce1708688b6578754d86de"
 
-vue-loader@^12.1.0:
-  version "12.1.0"
-  resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-12.1.0.tgz#f9ca958da1fd4e8c0598d90375c5419d10d35546"
+vue-loader@^12.2.1:
+  version "12.2.1"
+  resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-12.2.1.tgz#53f27c0973d386768f5a75156f4129b5efc6ba55"
   dependencies:
     consolidate "^0.14.0"
     hash-sum "^1.0.2"
@@ -6212,9 +6199,9 @@ webidl-conversions@^4.0.0:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
 
-webpack-bundle-analyzer@^2.8.1:
-  version "2.8.1"
-  resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.8.1.tgz#f452a5e4ae0cd8144d8b0347f2c3c644310daedd"
+webpack-bundle-analyzer@^2.8.2:
+  version "2.8.2"
+  resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.8.2.tgz#8b6240c29a9d63bc72f09d920fb050adbcce9fe8"
   dependencies:
     acorn "^5.0.3"
     chalk "^1.1.3"
@@ -6248,7 +6235,7 @@ webpack-hot-middleware@^2.18.0:
 
 webpack-node-externals@^1.6.0:
   version "1.6.0"
-  resolved "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-1.6.0.tgz#232c62ec6092b100635a3d29d83c1747128df9bd"
+  resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-1.6.0.tgz#232c62ec6092b100635a3d29d83c1747128df9bd"
 
 webpack-sources@^0.1.0:
   version "0.1.5"
@@ -6264,9 +6251,9 @@ webpack-sources@^0.2.3:
     source-list-map "^1.1.1"
     source-map "~0.5.3"
 
-webpack@^2.5.1:
-  version "2.5.1"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.5.1.tgz#61742f0cf8af555b87460a9cd8bba2f1e3ee2fce"
+webpack@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07"
   dependencies:
     acorn "^5.0.0"
     acorn-dynamic-import "^2.0.0"
@@ -6285,7 +6272,7 @@ webpack@^2.5.1:
     source-map "^0.5.3"
     supports-color "^3.1.0"
     tapable "~0.2.5"
-    uglify-js "^2.8.5"
+    uglify-js "^2.8.27"
     watchpack "^1.3.1"
     webpack-sources "^0.2.3"
     yargs "^6.0.0"
@@ -6369,9 +6356,10 @@ write-file-atomic@^2.0.0:
     slide "^1.1.5"
 
 write-json-file@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.1.0.tgz#ba1cf3ac7ee89db26c3d528986e48421389046b7"
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.2.0.tgz#51862506bbb3b619eefab7859f1fd6c6d0530876"
   dependencies:
+    detect-indent "^5.0.0"
     graceful-fs "^4.1.2"
     make-dir "^1.0.0"
     pify "^2.0.0"