From 7dd33fedd28ec1c1a903cfe498b4bb1e2da0314e Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 2 Jan 2019 17:47:19 +0330 Subject: [PATCH] feat(builder): validate vue-app dependencies and suggest fix (#4669) --- packages/builder/package.json | 1 + packages/builder/src/builder.js | 55 ++++++++++++++++++++++++++--- packages/config/src/options.js | 8 ----- packages/vue-app/src/index.js | 48 ++++++++++++------------- packages/vue-app/template/router.js | 6 ---- 5 files changed, 75 insertions(+), 43 deletions(-) diff --git a/packages/builder/package.json b/packages/builder/package.json index be609fddc2..2f94315cbb 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -18,6 +18,7 @@ "hash-sum": "^1.0.2", "lodash": "^4.17.11", "pify": "^4.0.1", + "semver": "^5.6.0", "serialize-javascript": "^1.6.1", "upath": "^1.1.0" }, diff --git a/packages/builder/src/builder.js b/packages/builder/src/builder.js index 075173fc21..5f11a2c57e 100644 --- a/packages/builder/src/builder.js +++ b/packages/builder/src/builder.js @@ -7,6 +7,7 @@ import hash from 'hash-sum' import pify from 'pify' import serialize from 'serialize-javascript' import upath from 'upath' +import semver from 'semver' import debounce from 'lodash/debounce' import omit from 'lodash/omit' @@ -75,7 +76,7 @@ export default class Builder { // Resolve template this.template = this.options.build.template || '@nuxt/vue-app' if (typeof this.template === 'string') { - this.template = this.nuxt.resolver.requireModule(this.template) + this.template = this.nuxt.resolver.requireModule(this.template).template } // if(!this.options.dev) { @@ -205,6 +206,13 @@ export default class Builder { } } + // Validate template + try { + this.validateTemplate() + } catch (err) { + consola.fatal(err) + } + consola.success('Builder initialized') consola.debug(`App root: ${this.options.srcDir}`) @@ -237,6 +245,43 @@ export default class Builder { return this } + validateTemplate() { + // Validate template dependencies + const templateDependencies = this.template.dependencies + const dpendencyFixes = [] + for (const depName in templateDependencies) { + const depVersion = templateDependencies[depName] + const requiredVersion = `${depName}@${depVersion}` + + // Load installed version + const pkg = this.nuxt.resolver.requireModule(path.join(depName, 'package.json')) + if (pkg) { + const validVersion = semver.satisfies(pkg.version, depVersion) + if (!validVersion) { + consola.warn(`${requiredVersion} is required but ${depName}@${pkg.version} is installed!`) + dpendencyFixes.push(requiredVersion) + } + } else { + consola.warn(`${depName}@${depVersion} is required but not installed!`) + dpendencyFixes.push(requiredVersion) + } + } + + // Suggest dependency fixes (TODO: automate me) + if (dpendencyFixes.length) { + consola.error( + `Please install missing dependencies:\n`, + '\n', + `Using yarn:\n`, + `yarn add ${dpendencyFixes.join(' ')}\n`, + '\n', + `Using npm:\n`, + `npm i ${dpendencyFixes.join(' ')}\n` + ) + throw new Error('Missing Template Dependencies') + } + } + async generateRoutesAndFiles() { consola.debug(`Generating nuxt files`) @@ -244,7 +289,7 @@ export default class Builder { this.plugins = Array.from(this.normalizePlugins()) // -- Templates -- - let templatesFiles = Array.from(this.template.templatesFiles) + let templatesFiles = Array.from(this.template.files) const templateVars = { options: this.options, @@ -325,7 +370,7 @@ export default class Builder { if (this._defaultPage) { templateVars.router.routes = createRoutes( ['index.vue'], - this.template.templatesDir + '/pages', + this.template.dir + '/pages', '', this.options.router.routeNameSplitter ) @@ -396,7 +441,7 @@ export default class Builder { const customFileExists = fsExtra.existsSync(customPath) return { - src: customFileExists ? customPath : r(this.template.templatesDir, file), + src: customFileExists ? customPath : r(this.template.dir, file), dst: file, custom: customFileExists } @@ -421,7 +466,7 @@ export default class Builder { // -- Loading indicator -- if (this.options.loadingIndicator.name) { const indicatorPath1 = path.resolve( - this.template.templatesDir, + this.template.dir, 'views/loading', this.options.loadingIndicator.name + '.html' ) diff --git a/packages/config/src/options.js b/packages/config/src/options.js index 4f7aa50a4b..83ff6476dd 100644 --- a/packages/config/src/options.js +++ b/packages/config/src/options.js @@ -253,14 +253,6 @@ export function getNuxtConfig(_options) { delete options.render.gzip } - if (options.nuxtAppDir) { - consola.warn('nuxtAppDir is deprecated and will be removed in a future version! Please switch to build.template') - options.build.template = { - templatesDir: options.nuxtAppDir - } - delete options.nuxtAppDir - } - // Apply mode preset const modePreset = options.modes[options.mode || 'universal'] diff --git a/packages/vue-app/src/index.js b/packages/vue-app/src/index.js index 2cf859e2b1..aa4160c958 100644 --- a/packages/vue-app/src/index.js +++ b/packages/vue-app/src/index.js @@ -1,26 +1,26 @@ import path from 'path' -import pkg from '../package.json' +import { dependencies } from '../package.json' -export const meta = pkg - -export const templatesDir = path.join(__dirname, '..', 'template') - -export const templatesFiles = [ - 'App.js', - 'client.js', - 'index.js', - 'middleware.js', - 'router.js', - 'server.js', - 'utils.js', - 'empty.js', - 'components/nuxt-error.vue', - 'components/nuxt-loading.vue', - 'components/nuxt-child.js', - 'components/nuxt-link.server.js', - 'components/nuxt-link.client.js', - 'components/nuxt.js', - 'components/no-ssr.js', - 'views/app.template.html', - 'views/error.html' -] +export const template = { + dependencies, + dir: path.join(__dirname, '..', 'template'), + files: [ + 'App.js', + 'client.js', + 'index.js', + 'middleware.js', + 'router.js', + 'server.js', + 'utils.js', + 'empty.js', + 'components/nuxt-error.vue', + 'components/nuxt-loading.vue', + 'components/nuxt-child.js', + 'components/nuxt-link.server.js', + 'components/nuxt-link.client.js', + 'components/nuxt.js', + 'components/no-ssr.js', + 'views/app.template.html', + 'views/error.html' + ] +} diff --git a/packages/vue-app/template/router.js b/packages/vue-app/template/router.js index fe4b75fcf8..731bd6b7e2 100644 --- a/packages/vue-app/template/router.js +++ b/packages/vue-app/template/router.js @@ -81,12 +81,6 @@ const _routes = recursiveRoutes(router.routes, ' ', _components, 2) }).join('\n')%> Vue.use(Router) -// router-view was changed to RouterView in vue-router 3.0.2 -// Fix: Vue.component('RouterLink') is undefined in vue-router 3.0.0 -if (!Vue.component('RouterLink')) { - Vue.options.components['RouterView'] = Vue.component('router-view') - Vue.options.components['RouterLink'] = Vue.component('router-link') -} <% if (router.scrollBehavior) { %> const scrollBehavior = <%= serializeFunction(router.scrollBehavior) %>