diff --git a/lib/app/client.js b/lib/app/client.js index 7c93bf133d..5f5514fbdf 100644 --- a/lib/app/client.js +++ b/lib/app/client.js @@ -109,7 +109,7 @@ function mapTransitions(Components, to, from) { if (from && from.matched.length && from.matched[0].components.default) { const from_transitions = componentTransitions(from.matched[0].components.default) Object.keys(from_transitions) - .filter((key) => from_transitions[key] && key.toLowerCase().indexOf('leave') !== -1) + .filter((key) => from_transitions[key] && key.toLowerCase().includes('leave')) .forEach((key) => { transitions[key] = from_transitions[key] }) } diff --git a/lib/app/components/nuxt-child.js b/lib/app/components/nuxt-child.js index 63b43738f0..59ab308bde 100644 --- a/lib/app/components/nuxt-child.js +++ b/lib/app/components/nuxt-child.js @@ -23,6 +23,7 @@ export default { transitionProps[key] = transition[key] } }) + let listeners = {} listenersKeys.forEach((key) => { if (typeof transition[key] === 'function') { @@ -30,7 +31,7 @@ export default { } }) // Add triggerScroll event on beforeEnter (fix #1376) - let beforeEnter = listeners.beforeEnter + const beforeEnter = listeners.beforeEnter listeners.beforeEnter = (el) => { // Ensure to trigger scroll event after calling scrollBehavior window.<%= globals.nuxt %>.$nextTick(() => { diff --git a/lib/app/middleware.js b/lib/app/middleware.js index 1b728bdba6..0adfbd9e23 100644 --- a/lib/app/middleware.js +++ b/lib/app/middleware.js @@ -1,18 +1,16 @@ <% if (middleware) { %> -let files = require.context('@/<%= dir.middleware %>', false, /^\.\/(?!<%= ignorePrefix %>)[^.]+\.(<%= extensions %>)$/) -let filenames = files.keys() +const files = require.context('@/<%= dir.middleware %>', false, /^\.\/(?!<%= ignorePrefix %>)[^.]+\.(<%= extensions %>)$/) +const filenames = files.keys() function getModule (filename) { - let file = files(filename) - return file.default - ? file.default - : file + const file = files(filename) + return file.default || file } -let middleware = {} +const middleware = {} // Generate the middleware -for (let filename of filenames) { - let name = filename.replace(/^\.\//, '').replace(/\.(<%= extensions %>)$/, '') +for (const filename of filenames) { + const name = filename.replace(/^\.\//, '').replace(/\.(<%= extensions %>)$/, '') middleware[name] = getModule(filename) } diff --git a/lib/app/server.js b/lib/app/server.js index 07630445a4..3c38315aa7 100644 --- a/lib/app/server.js +++ b/lib/app/server.js @@ -21,7 +21,7 @@ const createNext = (ssrContext) => (opts) => { } opts.query = stringify(opts.query) opts.path = opts.path + (opts.query ? '?' + opts.query : '') - if (opts.path.indexOf('http') !== 0 && ('<%= router.base %>' !== '/' && opts.path.indexOf('<%= router.base %>') !== 0)) { + if (!opts.path.startsWith('http') && ('<%= router.base %>' !== '/' && !opts.path.startsWith('<%= router.base %>'))) { opts.path = urlJoin('<%= router.base %>', opts.path) } // Avoid loop redirect diff --git a/lib/app/store.js b/lib/app/store.js index 08106ce50a..0b37aa5bc8 100644 --- a/lib/app/store.js +++ b/lib/app/store.js @@ -10,7 +10,7 @@ const filenames = files.keys() let storeData = {} // Check if {dir.store}/index.js exists -const indexFilename = filenames.find(name => name.includes('./index.')) +const indexFilename = filenames.find(filename => filename.includes('./index.')) if (indexFilename) { storeData = getModule(indexFilename) diff --git a/lib/app/utils.js b/lib/app/utils.js index 2b17d27387..ecc1c261cc 100644 --- a/lib/app/utils.js +++ b/lib/app/utils.js @@ -496,7 +496,7 @@ function formatUrl (url, query) { if (index !== -1) { protocol = url.substring(0, index) url = url.substring(index + 3) - } else if (url.indexOf('//') === 0) { + } else if (url.startsWith('//')) { url = url.substring(2) } diff --git a/lib/builder/builder.js b/lib/builder/builder.js index f44dcd44c8..9dc2c19604 100644 --- a/lib/builder/builder.js +++ b/lib/builder/builder.js @@ -318,7 +318,6 @@ export default class Builder { templateVars.router.routes, r ) - // router.extendRoutes method if (typeof this.options.router.extendRoutes === 'function') { // let the user extend the routes @@ -349,7 +348,7 @@ export default class Builder { templatesFiles = templatesFiles .map((file) => { // Skip if custom file was already provided in build.templates[] - if (customTemplateFiles.indexOf(file) !== -1) { + if (customTemplateFiles.includes(file)) { return } // Allow override templates using a file with same name in ${srcDir}/app diff --git a/lib/builder/generator.js b/lib/builder/generator.js index 407ca32794..d28aaa615c 100644 --- a/lib/builder/generator.js +++ b/lib/builder/generator.js @@ -1,10 +1,9 @@ import path from 'path' -import _ from 'lodash' import htmlMinifier from 'html-minifier' import Chalk from 'chalk' import fsExtra from 'fs-extra' import consola from 'consola' -import { flatRoutes, isUrl, promisifyRoute, waitFor } from '../common/utils' +import { flatRoutes, isUrl, promisifyRoute, waitFor, isString } from '../common/utils' export default class Generator { constructor(nuxt, builder) { @@ -187,13 +186,13 @@ export default class Generator { // Fill routeMap with given generate.routes generateRoutes.forEach((route) => { // route is either a string or like { route : '/my_route/1', payload: {} } - const path = _.isString(route) ? route : route.route + const path = isString(route) ? route : route.route routeMap[path] = { route: path, payload: route.payload || null } }) - return _.values(routeMap) + return Object.values(routeMap) } async generateRoute({ route, payload = {}, errors = [] }) { diff --git a/lib/builder/webpack/base.js b/lib/builder/webpack/base.js index 6bcbd8c469..d2cfb15835 100644 --- a/lib/builder/webpack/base.js +++ b/lib/builder/webpack/base.js @@ -76,9 +76,9 @@ export default class WebpackBaseConfig { 'process.mode': JSON.stringify(this.options.mode), 'process.static': this.isStatic } - _.each(this.options.env, (value, key) => { + Object.entries(this.options.env).forEach(([key, value]) => { env['process.env.' + key] = - ['boolean', 'number'].indexOf(typeof value) !== -1 + ['boolean', 'number'].includes(typeof value) ? value : JSON.stringify(value) }) @@ -153,15 +153,14 @@ export default class WebpackBaseConfig { test: /\.jsx?$/, exclude: (file) => { // not exclude files outside node_modules - if (/node_modules/.test(file)) { - for (const module of [/\.vue\.js/].concat(this.options.build.transpile)) { - // item in transpile can be string or regex object - if (module.test(file)) { - return false - } - } - return true + if (!/node_modules/.test(file)) { + return false } + + // item in transpile can be string or regex object + const modulesToTranspile = [/\.vue\.js/].concat(this.options.build.transpile) + + return !modulesToTranspile.some(module => module.test(file)) }, use: perfLoader.pool('js', { loader: 'babel-loader', diff --git a/lib/builder/webpack/plugins/vue/client.js b/lib/builder/webpack/plugins/vue/client.js index d8fac901fe..2fe4eff5ea 100644 --- a/lib/builder/webpack/plugins/vue/client.js +++ b/lib/builder/webpack/plugins/vue/client.js @@ -23,7 +23,7 @@ export default class VueSSRClientPlugin { const asyncFiles = allFiles .filter(file => isJS(file) || isCSS(file)) - .filter(file => initialFiles.indexOf(file) < 0) + .filter(file => !initialFiles.includes(file)) const manifest = { publicPath: stats.publicPath, diff --git a/lib/builder/webpack/server.js b/lib/builder/webpack/server.js index 687d0327fd..f40ee52837 100644 --- a/lib/builder/webpack/server.js +++ b/lib/builder/webpack/server.js @@ -13,7 +13,7 @@ export default class WebpackServerConfig extends BaseConfig { } devtool() { - return 'cheap-source-map' + return 'cheap-module-inline-source-map' } env() { diff --git a/lib/builder/webpack/utils/style-loader.js b/lib/builder/webpack/utils/style-loader.js index b93bd91bb5..2dd328f790 100644 --- a/lib/builder/webpack/utils/style-loader.js +++ b/lib/builder/webpack/utils/style-loader.js @@ -1,4 +1,5 @@ import MiniCssExtractPlugin from 'mini-css-extract-plugin' +import { wrapArray } from '../../../common/utils' import PostcssConfig from './postcss' export default class StyleLoader { @@ -19,7 +20,7 @@ export default class StyleLoader { } normalize(loaders) { - loaders = Array.isArray(loaders) ? loaders : [loaders] + loaders = wrapArray(loaders) return loaders.map(loader => (typeof loader === 'string' ? { loader } : loader)) } @@ -28,9 +29,7 @@ export default class StyleLoader { // style-resources-loader // https://github.com/yenshih/style-resources-loader if (extResource) { - const patterns = Array.isArray(extResource) - ? extResource - : [extResource] + const patterns = wrapArray(extResource) return { loader: 'style-resources-loader', diff --git a/lib/common/options.js b/lib/common/options.js index c27f273346..d2217528c8 100644 --- a/lib/common/options.js +++ b/lib/common/options.js @@ -97,18 +97,14 @@ Options.from = function (_options) { // Populate modulesDir options.modulesDir = [] .concat(options.modulesDir) - .concat(path.join(options.nuxtDir, 'node_modules')) - .filter(hasValue) + .concat(path.join(options.nuxtDir, 'node_modules')).filter(hasValue) .map(dir => path.resolve(options.rootDir, dir)) - // Sanitize extensions - if (options.extensions.indexOf('js') === -1) { - options.extensions.unshift('js') - } + const mandatoryExtensions = ['js', 'mjs'] - if (options.extensions.indexOf('mjs') === -1) { - options.extensions.unshift('mjs') - } + options.extensions = mandatoryExtensions + .filter(ext => !options.extensions.includes(ext)) + .concat(options.extensions) // If app.html is defined, set the template path to the user template if (options.appTemplatePath === undefined) { diff --git a/lib/common/utils.js b/lib/common/utils.js index 01d1849e08..730eaec9ab 100644 --- a/lib/common/utils.js +++ b/lib/common/utils.js @@ -14,6 +14,15 @@ export const waitFor = function waitFor(ms) { return new Promise(resolve => setTimeout(resolve, ms || 0)) } +export const isString = function isString(obj) { + return typeof obj === 'string' || obj instanceof String +} +export const startsWithAlias = aliasArray => str => aliasArray.some(c => str.startsWith(c)) + +export const startsWithSrcAlias = startsWithAlias(['@', '~']) + +export const startsWithRootAlias = startsWithAlias(['@@', '~~']) + async function promiseFinally(fn, finalFn) { let result try { @@ -46,7 +55,7 @@ export const urlJoin = function urlJoin() { } export const isUrl = function isUrl(url) { - return url.indexOf('http') === 0 || url.indexOf('//') === 0 + return ['http', '//'].some(str => url.startsWith(str)) } export const promisifyRoute = function promisifyRoute(fn, ...args) { @@ -139,11 +148,10 @@ const reqSep = /\//g const sysSep = _.escapeRegExp(path.sep) const normalize = string => string.replace(reqSep, sysSep) -export const r = function r() { - const args = Array.prototype.slice.apply(arguments) - const lastArg = _.last(args) +export const r = function r(...args) { + const lastArg = args[args.length - 1] - if (lastArg.indexOf('@') === 0 || lastArg.indexOf('~') === 0) { + if (startsWithSrcAlias(lastArg)) { return wp(lastArg) } @@ -155,7 +163,7 @@ export const relativeTo = function relativeTo() { const dir = args.shift() // Keep webpack inline loader intact - if (args[0].indexOf('!') !== -1) { + if (args[0].includes('!')) { const loaders = args.shift().split('!') return loaders.concat(relativeTo(dir, loaders.pop(), ...args)).join('!') @@ -165,7 +173,7 @@ export const relativeTo = function relativeTo() { const _path = r(...args) // Check if path is an alias - if (_path.indexOf('@') === 0 || _path.indexOf('~') === 0) { + if (startsWithSrcAlias(_path)) { return _path } @@ -180,22 +188,22 @@ export const relativeTo = function relativeTo() { export const flatRoutes = function flatRoutes(router, _path = '', routes = []) { router.forEach((r) => { - if (!r.path.includes(':') && !r.path.includes('*')) { - /* istanbul ignore if */ - if (r.children) { - if (_path === '' && r.path === '/') { - routes.push('/') - } - flatRoutes(r.children, _path + r.path + '/', routes) - } else { - _path = _path.replace(/^\/+$/, '/') - routes.push( - (r.path === '' && _path[_path.length - 1] === '/' - ? _path.slice(0, -1) - : _path) + r.path - ) - } + if ([':', '*'].some(c => r.path.includes(c))) { + return } + /* istanbul ignore if */ + if (r.children) { + if (_path === '' && r.path === '/') { + routes.push('/') + } + return flatRoutes(r.children, _path + r.path + '/', routes) + } + _path = _path.replace(/^\/+$/, '/') + routes.push( + (r.path === '' && _path[_path.length - 1] === '/' + ? _path.slice(0, -1) + : _path) + r.path + ) }) return routes } @@ -214,7 +222,7 @@ function cleanChildrenRoutes(routes, isChild = false) { }) routes.forEach((route) => { route.path = isChild ? route.path.replace('/', '') : route.path - if (route.path.indexOf('?') > -1) { + if (route.path.includes('?')) { const names = route.name.split('-') const paths = route.path.split('/') if (!isChild) { @@ -259,15 +267,15 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) { let parent = routes keys.forEach((key, i) => { // remove underscore only, if its the prefix - const sanitizedKey = key.indexOf('_') === 0 - ? key.replace('_', '') - : key + const sanitizedKey = key.startsWith('_') ? key.substr(1) : key + route.name = route.name ? route.name + '-' + sanitizedKey : sanitizedKey route.name += key === '_' ? 'all' : '' route.chunkName = file.replace(/\.(vue|js)$/, '') - const child = _.find(parent, { name: route.name }) + const child = parent.find(parentRoute => parentRoute.name === route.name) + if (child) { child.children = child.children || [] parent = child.children @@ -275,13 +283,9 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) { } else if (key === 'index' && i + 1 === keys.length) { route.path += i > 0 ? '' : '/' } else { - route.path += '/' + - (key === '_' - ? '*' - : key.indexOf('_') === 0 - ? key.replace('_', ':') - : key) - if (key !== '_' && key.indexOf('_') === 0) { + route.path += '/' + getRoutePathExtension(key) + + if (key.startsWith('_') && key.length > 1) { route.path += '?' } } @@ -298,12 +302,13 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) { // Order: /static, /index, /:dynamic // Match exact route before index: /login before /index/_slug if (a.path === '/') { - return /^\/(:|\*)/.test(b.path) ? -1 : 1 + return DYNAMIC_ROUTE_REGEX.test(b.path) ? -1 : 1 } if (b.path === '/') { - return /^\/(:|\*)/.test(a.path) ? 1 : -1 + return DYNAMIC_ROUTE_REGEX.test(a.path) ? 1 : -1 } - let i = 0 + + let i let res = 0 let y = 0 let z = 0 @@ -313,8 +318,8 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) { if (res !== 0) { break } - y = _a[i] === '*' ? 2 : _a[i].indexOf(':') > -1 ? 1 : 0 - z = _b[i] === '*' ? 2 : _b[i].indexOf(':') > -1 ? 1 : 0 + y = _a[i] === '*' ? 2 : _a[i].includes(':') ? 1 : 0 + z = _b[i] === '*' ? 2 : _b[i].includes(':') ? 1 : 0 res = y - z // If a.length >= b.length if (i === _b.length - 1 && res === 0) { @@ -361,3 +366,25 @@ export const determineGlobals = function determineGlobals(globalName, globals) { } return _globals } + +const getRoutePathExtension = (key) => { + if (key === '_') { + return '*' + } + + if (key.startsWith('_')) { + return `:${key.substr(1)}` + } + + return key +} + +const DYNAMIC_ROUTE_REGEX = /^\/(:|\*)/ + +/** + * Wraps value in array if it is not already an array + * + * @param {any} value + * @return {array} + */ +export const wrapArray = value => Array.isArray(value) ? value : [value] diff --git a/lib/core/nuxt.js b/lib/core/nuxt.js index 0cc4a330e3..d9b259e085 100644 --- a/lib/core/nuxt.js +++ b/lib/core/nuxt.js @@ -11,7 +11,7 @@ import esm from 'esm' import ip from 'ip' import Options from '../common/options' -import { sequence } from '../common/utils' +import { sequence, startsWithRootAlias, startsWithSrcAlias } from '../common/utils' import packageJSON from '../../package.json' import ModuleContainer from './module' @@ -254,11 +254,11 @@ export default class Nuxt { return modulePath } - if (path.indexOf('@@') === 0 || path.indexOf('~~') === 0) { + if (startsWithRootAlias(path)) { return join(this.options.rootDir, path.substr(2)) } - if (path.indexOf('@') === 0 || path.indexOf('~') === 0) { + if (startsWithSrcAlias(path)) { return join(this.options.srcDir, path.substr(1)) }