From 324135df5128957041131e96deb6b8122a88f4c7 Mon Sep 17 00:00:00 2001 From: "Xin Du (Clark)" Date: Sat, 22 Dec 2018 21:05:13 +0000 Subject: [PATCH] refactor: @nuxt/utils (#4609) --- distributions/nuxt-legacy/package.json | 1 - distributions/nuxt-start/package.json | 1 - distributions/nuxt/package.json | 1 - packages/builder/package.json | 2 +- packages/builder/src/builder.js | 2 +- packages/common/CHANGELOG.md | 11 - packages/common/data/modern-browsers.json | 12 - packages/common/src/index.js | 3 - packages/config/package.json | 2 +- packages/config/src/options.js | 2 +- packages/core/package.json | 2 +- packages/{common => core}/src/hookable.js | 2 +- packages/core/src/module.js | 2 +- packages/core/src/nuxt.js | 4 +- packages/core/src/resolver.js | 2 +- packages/generator/package.json | 2 +- packages/generator/src/generator.js | 2 +- packages/server/package.json | 2 +- packages/server/src/jsdom.js | 2 +- .../server/src/middleware/modern-browsers.js | 12 + packages/server/src/middleware/modern.js | 3 +- packages/server/src/middleware/nuxt.js | 2 +- packages/server/src/server.js | 2 +- packages/{common => utils}/package.js | 0 packages/{common => utils}/package.json | 4 +- packages/utils/src/context.js | 16 + packages/utils/src/index.js | 7 + packages/utils/src/lang.js | 46 +++ packages/utils/src/resolve.js | 100 ++++++ .../src/utils.js => utils/src/route.js} | 291 ++---------------- packages/utils/src/serialize.js | 22 ++ packages/utils/src/task.js | 37 +++ packages/utils/src/timer.js | 26 ++ packages/vue-renderer/package.json | 2 +- packages/vue-renderer/src/renderer.js | 2 +- packages/webpack/package.json | 2 +- packages/webpack/src/builder.js | 2 +- packages/webpack/src/config/base.js | 2 +- packages/webpack/src/utils/postcss.js | 2 +- packages/webpack/src/utils/style-loader.js | 2 +- test/unit/utils.test.js | 2 +- test/utils/index.js | 2 +- test/utils/nuxt.js | 2 +- 43 files changed, 320 insertions(+), 325 deletions(-) delete mode 100644 packages/common/CHANGELOG.md delete mode 100644 packages/common/data/modern-browsers.json delete mode 100644 packages/common/src/index.js rename packages/{common => core}/src/hookable.js (97%) create mode 100644 packages/server/src/middleware/modern-browsers.js rename packages/{common => utils}/package.js (100%) rename packages/{common => utils}/package.json (81%) create mode 100644 packages/utils/src/context.js create mode 100644 packages/utils/src/index.js create mode 100644 packages/utils/src/lang.js create mode 100644 packages/utils/src/resolve.js rename packages/{common/src/utils.js => utils/src/route.js} (51%) create mode 100644 packages/utils/src/serialize.js create mode 100644 packages/utils/src/task.js create mode 100644 packages/utils/src/timer.js diff --git a/distributions/nuxt-legacy/package.json b/distributions/nuxt-legacy/package.json index c16f4e8939..27c28c61cf 100644 --- a/distributions/nuxt-legacy/package.json +++ b/distributions/nuxt-legacy/package.json @@ -50,7 +50,6 @@ "@babel/register": "^7.0.0", "@nuxt/builder": "2.3.4", "@nuxt/cli": "2.3.4", - "@nuxt/common": "2.3.4", "@nuxt/core": "2.3.4", "@nuxt/generator": "2.3.4", "@nuxt/opencollective": "^0.2.1", diff --git a/distributions/nuxt-start/package.json b/distributions/nuxt-start/package.json index ece97ea7c9..8958b4ab72 100644 --- a/distributions/nuxt-start/package.json +++ b/distributions/nuxt-start/package.json @@ -47,7 +47,6 @@ "bin": "bin/nuxt-start.js", "dependencies": { "@nuxt/cli": "2.3.4", - "@nuxt/common": "2.3.4", "@nuxt/core": "2.3.4" }, "engines": { diff --git a/distributions/nuxt/package.json b/distributions/nuxt/package.json index 353df53e70..d4f82571d2 100644 --- a/distributions/nuxt/package.json +++ b/distributions/nuxt/package.json @@ -50,7 +50,6 @@ "dependencies": { "@nuxt/builder": "2.3.4", "@nuxt/cli": "2.3.4", - "@nuxt/common": "2.3.4", "@nuxt/core": "2.3.4", "@nuxt/generator": "2.3.4", "@nuxt/opencollective": "^0.2.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index eda824c21a..6323c8fba8 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -8,8 +8,8 @@ ], "main": "dist/builder.js", "dependencies": { - "@nuxt/common": "2.3.4", "@nuxt/devalue": "^1.2.0", + "@nuxt/utils": "2.3.4", "@nuxt/vue-app": "2.3.4", "chokidar": "^2.0.4", "consola": "^2.3.0", diff --git a/packages/builder/src/builder.js b/packages/builder/src/builder.js index cb16dd57f8..bbe3f12bc7 100644 --- a/packages/builder/src/builder.js +++ b/packages/builder/src/builder.js @@ -27,7 +27,7 @@ import { determineGlobals, stripWhitespace, isString -} from '@nuxt/common' +} from '@nuxt/utils' import BuildContext from './context' diff --git a/packages/common/CHANGELOG.md b/packages/common/CHANGELOG.md deleted file mode 100644 index 128438c101..0000000000 --- a/packages/common/CHANGELOG.md +++ /dev/null @@ -1,11 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [2.3.4](https://github.com/nuxt/nuxt.js/compare/v2.3.2...v2.3.4) (2018-11-26) - - -### Performance Improvements - -* **pkg:** remove lodash dependency from packages ([#4411](https://github.com/nuxt/nuxt.js/issues/4411)) ([7e1beed](https://github.com/nuxt/nuxt.js/commit/7e1beed)) diff --git a/packages/common/data/modern-browsers.json b/packages/common/data/modern-browsers.json deleted file mode 100644 index db9c24d95f..0000000000 --- a/packages/common/data/modern-browsers.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Edge": "16", - "Firefox": "60", - "Chrome": "61", - "Chrome Headless": "61", - "Chromium": "61", - "Safari": "10.1", - "Opera": "48", - "Yandex": "18", - "Vivaldi": "1.14", - "Mobile Safari": "10.3" -} diff --git a/packages/common/src/index.js b/packages/common/src/index.js deleted file mode 100644 index 41440566ca..0000000000 --- a/packages/common/src/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export { default as Hookable } from './hookable' -export { default as ModernBrowsers } from '../data/modern-browsers.json' -export * from './utils' diff --git a/packages/config/package.json b/packages/config/package.json index 4b4dd371ed..5e41a15ec2 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -8,7 +8,7 @@ ], "main": "dist/config.js", "dependencies": { - "@nuxt/common": "2.3.4", + "@nuxt/utils": "2.3.4", "consola": "^2.3.0", "std-env": "^2.2.1" }, diff --git a/packages/config/src/options.js b/packages/config/src/options.js index 9c10f7df4d..4f7aa50a4b 100644 --- a/packages/config/src/options.js +++ b/packages/config/src/options.js @@ -6,7 +6,7 @@ import pick from 'lodash/pick' import isObject from 'lodash/isObject' import uniq from 'lodash/uniq' import consola from 'consola' -import { guardDir, isNonEmptyString, isPureObject, isUrl } from '@nuxt/common' +import { guardDir, isNonEmptyString, isPureObject, isUrl } from '@nuxt/utils' import { getDefaultNuxtConfig } from './config' export function getNuxtConfig(_options) { diff --git a/packages/core/package.json b/packages/core/package.json index f4b2496412..e1460c740e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -8,10 +8,10 @@ ], "main": "dist/core.js", "dependencies": { - "@nuxt/common": "2.3.4", "@nuxt/config": "2.3.4", "@nuxt/devalue": "^1.2.0", "@nuxt/server": "2.3.4", + "@nuxt/utils": "2.3.4", "@nuxt/vue-renderer": "2.3.4", "consola": "^2.3.0", "debug": "^4.1.0", diff --git a/packages/common/src/hookable.js b/packages/core/src/hookable.js similarity index 97% rename from packages/common/src/hookable.js rename to packages/core/src/hookable.js index 1af2a0863e..792141dbc8 100644 --- a/packages/common/src/hookable.js +++ b/packages/core/src/hookable.js @@ -1,7 +1,7 @@ import consola from 'consola' -import { sequence } from './utils' +import { sequence } from '@nuxt/utils' export default class Hookable { constructor() { diff --git a/packages/core/src/module.js b/packages/core/src/module.js index a8581c6e1e..7e2efe3f82 100644 --- a/packages/core/src/module.js +++ b/packages/core/src/module.js @@ -3,7 +3,7 @@ import fs from 'fs' import hash from 'hash-sum' import consola from 'consola' -import { chainFn, sequence } from '@nuxt/common' +import { chainFn, sequence } from '@nuxt/utils' export default class ModuleContainer { constructor(nuxt) { diff --git a/packages/core/src/nuxt.js b/packages/core/src/nuxt.js index 830f9c84f1..b0aa87398a 100644 --- a/packages/core/src/nuxt.js +++ b/packages/core/src/nuxt.js @@ -2,12 +2,14 @@ import isPlainObject from 'lodash/isPlainObject' import consola from 'consola' -import { Hookable, defineAlias } from '@nuxt/common' +import { defineAlias } from '@nuxt/utils' import { getNuxtConfig } from '@nuxt/config' import { Server } from '@nuxt/server' import { version } from '../package.json' + import ModuleContainer from './module' +import Hookable from './hookable' import Resolver from './resolver' export default class Nuxt extends Hookable { diff --git a/packages/core/src/resolver.js b/packages/core/src/resolver.js index fc7bcd7f16..9b41386f4e 100644 --- a/packages/core/src/resolver.js +++ b/packages/core/src/resolver.js @@ -3,7 +3,7 @@ import { resolve, join } from 'path' import fs from 'fs-extra' import esm from 'esm' -import { startsWithRootAlias, startsWithSrcAlias } from '@nuxt/common' +import { startsWithRootAlias, startsWithSrcAlias } from '@nuxt/utils' export default class Resolver { constructor(nuxt) { diff --git a/packages/generator/package.json b/packages/generator/package.json index 81031d7bb2..0565745e00 100644 --- a/packages/generator/package.json +++ b/packages/generator/package.json @@ -8,7 +8,7 @@ ], "main": "dist/generator.js", "dependencies": { - "@nuxt/common": "2.3.4", + "@nuxt/utils": "2.3.4", "chalk": "^2.4.1", "consola": "^2.3.0", "fs-extra": "^7.0.1", diff --git a/packages/generator/src/generator.js b/packages/generator/src/generator.js index 9ceef92aa8..62d5c99a3a 100644 --- a/packages/generator/src/generator.js +++ b/packages/generator/src/generator.js @@ -4,7 +4,7 @@ import consola from 'consola' import fsExtra from 'fs-extra' import htmlMinifier from 'html-minifier' -import { flatRoutes, isUrl, promisifyRoute, waitFor, isString } from '@nuxt/common' +import { flatRoutes, isUrl, promisifyRoute, waitFor, isString } from '@nuxt/utils' export default class Generator { constructor(nuxt, builder) { diff --git a/packages/server/package.json b/packages/server/package.json index 7cb1d6da45..69b9805e6f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -8,8 +8,8 @@ ], "main": "dist/server.js", "dependencies": { - "@nuxt/common": "2.3.4", "@nuxt/config": "2.3.4", + "@nuxt/utils": "2.3.4", "@nuxtjs/youch": "^4.2.3", "chalk": "^2.4.1", "compression": "^1.7.3", diff --git a/packages/server/src/jsdom.js b/packages/server/src/jsdom.js index c632cbbdfa..3f4511a40b 100644 --- a/packages/server/src/jsdom.js +++ b/packages/server/src/jsdom.js @@ -1,5 +1,5 @@ import consola from 'consola' -import { timeout } from '@nuxt/common' +import { timeout } from '@nuxt/utils' export default async function renderAndGetWindow( url = 'http://localhost:3000', diff --git a/packages/server/src/middleware/modern-browsers.js b/packages/server/src/middleware/modern-browsers.js new file mode 100644 index 0000000000..6e1be23ae5 --- /dev/null +++ b/packages/server/src/middleware/modern-browsers.js @@ -0,0 +1,12 @@ +export default { + Edge: '16', + Firefox: '60', + Chrome: '61', + 'Chrome Headless': '61', + Chromium: '61', + Safari: '10.1', + Opera: '48', + Yandex: '18', + Vivaldi: '1.14', + 'Mobile Safari': '10.3' +} diff --git a/packages/server/src/middleware/modern.js b/packages/server/src/middleware/modern.js index a571a983ec..93bfca5dfa 100644 --- a/packages/server/src/middleware/modern.js +++ b/packages/server/src/middleware/modern.js @@ -1,9 +1,10 @@ import chalk from 'chalk' import consola from 'consola' -import { ModernBrowsers } from '@nuxt/common' import UAParser from 'ua-parser-js' import semver from 'semver' +import ModernBrowsers from './modern-browsers' + const modernBrowsers = Object.keys(ModernBrowsers) .reduce((allBrowsers, browser) => { allBrowsers[browser] = semver.coerce(ModernBrowsers[browser]) diff --git a/packages/server/src/middleware/nuxt.js b/packages/server/src/middleware/nuxt.js index 1484f76a63..6d29b87850 100644 --- a/packages/server/src/middleware/nuxt.js +++ b/packages/server/src/middleware/nuxt.js @@ -2,7 +2,7 @@ import generateETag from 'etag' import fresh from 'fresh' import consola from 'consola' -import { getContext } from '@nuxt/common' +import { getContext } from '@nuxt/utils' export default ({ options, nuxt, renderRoute, resources }) => async function nuxtMiddleware(req, res, next) { // Get context diff --git a/packages/server/src/server.js b/packages/server/src/server.js index 58915b58c8..7c894040c5 100644 --- a/packages/server/src/server.js +++ b/packages/server/src/server.js @@ -4,7 +4,7 @@ import launchMiddleware from 'launch-editor-middleware' import serveStatic from 'serve-static' import servePlaceholder from 'serve-placeholder' import connect from 'connect' -import { determineGlobals, isUrl } from '@nuxt/common' +import { determineGlobals, isUrl } from '@nuxt/utils' import ServerContext from './context' import renderAndGetWindow from './jsdom' diff --git a/packages/common/package.js b/packages/utils/package.js similarity index 100% rename from packages/common/package.js rename to packages/utils/package.js diff --git a/packages/common/package.json b/packages/utils/package.json similarity index 81% rename from packages/common/package.json rename to packages/utils/package.json index 2097996ba6..b6b1024d09 100644 --- a/packages/common/package.json +++ b/packages/utils/package.json @@ -1,12 +1,12 @@ { - "name": "@nuxt/common", + "name": "@nuxt/utils", "version": "2.3.4", "repository": "nuxt/nuxt.js", "license": "MIT", "files": [ "dist" ], - "main": "dist/common.js", + "main": "dist/utils.js", "dependencies": { "consola": "^2.3.0", "serialize-javascript": "^1.5.0" diff --git a/packages/utils/src/context.js b/packages/utils/src/context.js new file mode 100644 index 0000000000..d73187696f --- /dev/null +++ b/packages/utils/src/context.js @@ -0,0 +1,16 @@ + +export const getContext = function getContext(req, res) { + return { req, res } +} + +export const determineGlobals = function determineGlobals(globalName, globals) { + const _globals = {} + for (const global in globals) { + if (typeof globals[global] === 'function') { + _globals[global] = globals[global](globalName) + } else { + _globals[global] = globals[global] + } + } + return _globals +} diff --git a/packages/utils/src/index.js b/packages/utils/src/index.js new file mode 100644 index 0000000000..64028fd3ac --- /dev/null +++ b/packages/utils/src/index.js @@ -0,0 +1,7 @@ +export * from './context' +export * from './lang' +export * from './resolve' +export * from './route' +export * from './serialize' +export * from './task' +export * from './timer' diff --git a/packages/utils/src/lang.js b/packages/utils/src/lang.js new file mode 100644 index 0000000000..4a3c68ca81 --- /dev/null +++ b/packages/utils/src/lang.js @@ -0,0 +1,46 @@ +export const encodeHtml = function encodeHtml(str) { + return str.replace(//g, '>') +} + +export const isString = obj => typeof obj === 'string' || obj instanceof String + +export const isNonEmptyString = obj => obj && isString(obj) + +export const isPureObject = function isPureObject(o) { + return !Array.isArray(o) && typeof o === 'object' +} + +export const isUrl = function isUrl(url) { + return ['http', '//'].some(str => url.startsWith(str)) +} + +export const urlJoin = function urlJoin() { + return [].slice + .call(arguments) + .join('/') + .replace(/\/+/g, '/') + .replace(':/', '://') +} + +/** + * 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] + +const WHITESPACE_REPLACEMENTS = [ + [/[ \t\f\r]+\n/g, '\n'], // strip empty indents + [/{\n{2,}/g, '{\n'], // strip start padding from blocks + [/\n{2,}([ \t\f\r]*})/g, '\n$1'], // strip end padding from blocks + [/\n{3,}/g, '\n\n'], // strip multiple blank lines (1 allowed) + [/\n{2,}$/g, '\n'] // strip blank lines EOF (0 allowed) +] + +export const stripWhitespace = function stripWhitespace(string) { + WHITESPACE_REPLACEMENTS.forEach(([regex, newSubstr]) => { + string = string.replace(regex, newSubstr) + }) + return string +} diff --git a/packages/utils/src/resolve.js b/packages/utils/src/resolve.js new file mode 100644 index 0000000000..999499d701 --- /dev/null +++ b/packages/utils/src/resolve.js @@ -0,0 +1,100 @@ +import path from 'path' +import consola from 'consola' +import escapeRegExp from 'lodash/escapeRegExp' + +export const startsWithAlias = aliasArray => str => aliasArray.some(c => str.startsWith(c)) + +export const startsWithSrcAlias = startsWithAlias(['@', '~']) + +export const startsWithRootAlias = startsWithAlias(['@@', '~~']) + +export const isWindows = /^win/.test(process.platform) + +export const wp = function wp(p = '') { + /* istanbul ignore if */ + if (isWindows) { + return p.replace(/\\/g, '\\\\') + } + return p +} + +export const wChunk = function wChunk(p = '') { + /* istanbul ignore if */ + if (isWindows) { + return p.replace(/\//g, '_') + } + return p +} + +const reqSep = /\//g +const sysSep = escapeRegExp(path.sep) +const normalize = string => string.replace(reqSep, sysSep) + +export const r = function r(...args) { + const lastArg = args[args.length - 1] + + if (startsWithSrcAlias(lastArg)) { + return wp(lastArg) + } + + return wp(path.resolve(...args.map(normalize))) +} + +export const relativeTo = function relativeTo() { + const args = Array.prototype.slice.apply(arguments) + const dir = args.shift() + + // Keep webpack inline loader intact + if (args[0].includes('!')) { + const loaders = args.shift().split('!') + + return loaders.concat(relativeTo(dir, loaders.pop(), ...args)).join('!') + } + + // Resolve path + const _path = r(...args) + + // Check if path is an alias + if (startsWithSrcAlias(_path)) { + return _path + } + + // Make correct relative path + let rp = path.relative(dir, _path) + if (rp[0] !== '.') { + rp = './' + rp + } + + return wp(rp) +} + +export function defineAlias(src, target, prop, opts = {}) { + const { bind = true, warn = false } = opts + + if (Array.isArray(prop)) { + for (const p of prop) { + defineAlias(src, target, p, opts) + } + return + } + + let targetVal = target[prop] + if (bind && typeof targetVal === 'function') { + targetVal = targetVal.bind(target) + } + + let warned = false + + Object.defineProperty(src, prop, { + get: () => { + if (warn && !warned) { + warned = true + consola.warn({ + message: `'${prop}' is deprecated'`, + additional: new Error().stack.split('\n').splice(2).join('\n') + }) + } + return targetVal + } + }) +} diff --git a/packages/common/src/utils.js b/packages/utils/src/route.js similarity index 51% rename from packages/common/src/utils.js rename to packages/utils/src/route.js index b4c52d90cb..432293200e 100644 --- a/packages/common/src/utils.js +++ b/packages/utils/src/route.js @@ -1,193 +1,8 @@ import path from 'path' -import escapeRegExp from 'lodash/escapeRegExp' import get from 'lodash/get' import consola from 'consola' -import serialize from 'serialize-javascript' -export const encodeHtml = function encodeHtml(str) { - return str.replace(//g, '>') -} - -export const getContext = function getContext(req, res) { - return { req, res } -} - -export const waitFor = function waitFor(ms) { - return new Promise(resolve => setTimeout(resolve, ms || 0)) -} - -export const isString = obj => typeof obj === 'string' || obj instanceof String - -export const isNonEmptyString = obj => obj && isString(obj) - -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 { - if (typeof fn === 'function') { - result = await fn() - } else { - result = await fn - } - } finally { - finalFn() - } - return result -} - -export const timeout = function timeout(fn, ms, msg) { - let timerId - const warpPromise = promiseFinally(fn, () => clearTimeout(timerId)) - const timerPromise = new Promise((resolve, reject) => { - timerId = setTimeout(() => reject(new Error(msg)), ms) - }) - return Promise.race([warpPromise, timerPromise]) -} - -export const urlJoin = function urlJoin() { - return [].slice - .call(arguments) - .join('/') - .replace(/\/+/g, '/') - .replace(':/', '://') -} - -export const isUrl = function isUrl(url) { - return ['http', '//'].some(str => url.startsWith(str)) -} - -export const promisifyRoute = function promisifyRoute(fn, ...args) { - // If routes is an array - if (Array.isArray(fn)) { - return Promise.resolve(fn) - } - // If routes is a function expecting a callback - if (fn.length === arguments.length) { - return new Promise((resolve, reject) => { - fn((err, routeParams) => { - if (err) { - reject(err) - } - resolve(routeParams) - }, ...args) - }) - } - let promise = fn(...args) - if ( - !promise || - (!(promise instanceof Promise) && typeof promise.then !== 'function') - ) { - promise = Promise.resolve(promise) - } - return promise -} - -export const sequence = function sequence(tasks, fn) { - return tasks.reduce( - (promise, task) => promise.then(() => fn(task)), - Promise.resolve() - ) -} - -export const parallel = function parallel(tasks, fn) { - return Promise.all(tasks.map(fn)) -} - -export const chainFn = function chainFn(base, fn) { - /* istanbul ignore if */ - if (typeof fn !== 'function') { - return base - } - return function () { - if (typeof base !== 'function') { - return fn.apply(this, arguments) - } - let baseResult = base.apply(this, arguments) - // Allow function to mutate the first argument instead of returning the result - if (baseResult === undefined) { - baseResult = arguments[0] - } - const fnResult = fn.call( - this, - baseResult, - ...Array.prototype.slice.call(arguments, 1) - ) - // Return mutated argument if no result was returned - if (fnResult === undefined) { - return baseResult - } - return fnResult - } -} - -export const isPureObject = function isPureObject(o) { - return !Array.isArray(o) && typeof o === 'object' -} - -export const isWindows = /^win/.test(process.platform) - -export const wp = function wp(p = '') { - /* istanbul ignore if */ - if (isWindows) { - return p.replace(/\\/g, '\\\\') - } - return p -} - -export const wChunk = function wChunk(p = '') { - /* istanbul ignore if */ - if (isWindows) { - return p.replace(/\//g, '_') - } - return p -} - -const reqSep = /\//g -const sysSep = escapeRegExp(path.sep) -const normalize = string => string.replace(reqSep, sysSep) - -export const r = function r(...args) { - const lastArg = args[args.length - 1] - - if (startsWithSrcAlias(lastArg)) { - return wp(lastArg) - } - - return wp(path.resolve(...args.map(normalize))) -} - -export const relativeTo = function relativeTo() { - const args = Array.prototype.slice.apply(arguments) - const dir = args.shift() - - // Keep webpack inline loader intact - if (args[0].includes('!')) { - const loaders = args.shift().split('!') - - return loaders.concat(relativeTo(dir, loaders.pop(), ...args)).join('!') - } - - // Resolve path - const _path = r(...args) - - // Check if path is an alias - if (startsWithSrcAlias(_path)) { - return _path - } - - // Make correct relative path - let rp = path.relative(dir, _path) - if (rp[0] !== '.') { - rp = './' + rp - } - - return wp(rp) -} +import { r } from './resolve' export const flatRoutes = function flatRoutes(router, _path = '', routes = []) { router.forEach((r) => { @@ -383,18 +198,6 @@ export const guardDir = function guardDir(options, key1, key2) { } } -export const determineGlobals = function determineGlobals(globalName, globals) { - const _globals = {} - for (const global in globals) { - if (typeof globals[global] === 'function') { - _globals[global] = globals[global](globalName) - } else { - _globals[global] = globals[global] - } - } - return _globals -} - const getRoutePathExtension = (key) => { if (key === '_') { return '*' @@ -407,76 +210,28 @@ const getRoutePathExtension = (key) => { return key } -/** - * 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] - -const WHITESPACE_REPLACEMENTS = [ - [/[ \t\f\r]+\n/g, '\n'], // strip empty indents - [/{\n{2,}/g, '{\n'], // strip start padding from blocks - [/\n{2,}([ \t\f\r]*})/g, '\n$1'], // strip end padding from blocks - [/\n{3,}/g, '\n\n'], // strip multiple blank lines (1 allowed) - [/\n{2,}$/g, '\n'] // strip blank lines EOF (0 allowed) -] - -export const stripWhitespace = function stripWhitespace(string) { - WHITESPACE_REPLACEMENTS.forEach(([regex, newSubstr]) => { - string = string.replace(regex, newSubstr) - }) - return string -} - -export function defineAlias(src, target, prop, opts = {}) { - const { bind = true, warn = false } = opts - - if (Array.isArray(prop)) { - for (const p of prop) { - defineAlias(src, target, p, opts) - } - return +export const promisifyRoute = function promisifyRoute(fn, ...args) { + // If routes is an array + if (Array.isArray(fn)) { + return Promise.resolve(fn) } - - let targetVal = target[prop] - if (bind && typeof targetVal === 'function') { - targetVal = targetVal.bind(target) + // If routes is a function expecting a callback + if (fn.length === arguments.length) { + return new Promise((resolve, reject) => { + fn((err, routeParams) => { + if (err) { + reject(err) + } + resolve(routeParams) + }, ...args) + }) } - - let warned = false - - Object.defineProperty(src, prop, { - get: () => { - if (warn && !warned) { - warned = true - consola.warn({ - message: `'${prop}' is deprecated'`, - additional: new Error().stack.split('\n').splice(2).join('\n') - }) - } - return targetVal - } - }) + let promise = fn(...args) + if ( + !promise || + (!(promise instanceof Promise) && typeof promise.then !== 'function') + ) { + promise = Promise.resolve(promise) + } + return promise } - -export function serializeFunction(func) { - let open = false - return serialize(func) - .replace(serializeFunction.assignmentRE, (_, spaces) => { - return `${spaces}:function(` - }) - .replace(serializeFunction.internalFunctionRE, (_, spaces, name, args) => { - if (open) { - return `${spaces}${name}:function(${args}) {` - } else { - open = true - return _ - } - }) - .replace(`${func.name}(`, 'function(') -} - -serializeFunction.internalFunctionRE = /^(\s*)(?!(?:if)|(?:for)|(?:while)|(?:switch))(\w+)\s*\((.*?)\)\s*\{/gm -serializeFunction.assignmentRE = /^(\s*):(\w+)\(/gm diff --git a/packages/utils/src/serialize.js b/packages/utils/src/serialize.js new file mode 100644 index 0000000000..a53c59e77a --- /dev/null +++ b/packages/utils/src/serialize.js @@ -0,0 +1,22 @@ + +import serialize from 'serialize-javascript' + +export function serializeFunction(func) { + let open = false + return serialize(func) + .replace(serializeFunction.assignmentRE, (_, spaces) => { + return `${spaces}:function(` + }) + .replace(serializeFunction.internalFunctionRE, (_, spaces, name, args) => { + if (open) { + return `${spaces}${name}:function(${args}) {` + } else { + open = true + return _ + } + }) + .replace(`${func.name}(`, 'function(') +} + +serializeFunction.internalFunctionRE = /^(\s*)(?!(?:if)|(?:for)|(?:while)|(?:switch))(\w+)\s*\((.*?)\)\s*\{/gm +serializeFunction.assignmentRE = /^(\s*):(\w+)\(/gm diff --git a/packages/utils/src/task.js b/packages/utils/src/task.js new file mode 100644 index 0000000000..9a7f31a402 --- /dev/null +++ b/packages/utils/src/task.js @@ -0,0 +1,37 @@ +export const sequence = function sequence(tasks, fn) { + return tasks.reduce( + (promise, task) => promise.then(() => fn(task)), + Promise.resolve() + ) +} + +export const parallel = function parallel(tasks, fn) { + return Promise.all(tasks.map(fn)) +} + +export const chainFn = function chainFn(base, fn) { + /* istanbul ignore if */ + if (typeof fn !== 'function') { + return base + } + return function () { + if (typeof base !== 'function') { + return fn.apply(this, arguments) + } + let baseResult = base.apply(this, arguments) + // Allow function to mutate the first argument instead of returning the result + if (baseResult === undefined) { + baseResult = arguments[0] + } + const fnResult = fn.call( + this, + baseResult, + ...Array.prototype.slice.call(arguments, 1) + ) + // Return mutated argument if no result was returned + if (fnResult === undefined) { + return baseResult + } + return fnResult + } +} diff --git a/packages/utils/src/timer.js b/packages/utils/src/timer.js new file mode 100644 index 0000000000..e4ebabadf3 --- /dev/null +++ b/packages/utils/src/timer.js @@ -0,0 +1,26 @@ +async function promiseFinally(fn, finalFn) { + let result + try { + if (typeof fn === 'function') { + result = await fn() + } else { + result = await fn + } + } finally { + finalFn() + } + return result +} + +export const timeout = function timeout(fn, ms, msg) { + let timerId + const warpPromise = promiseFinally(fn, () => clearTimeout(timerId)) + const timerPromise = new Promise((resolve, reject) => { + timerId = setTimeout(() => reject(new Error(msg)), ms) + }) + return Promise.race([warpPromise, timerPromise]) +} + +export const waitFor = function waitFor(ms) { + return new Promise(resolve => setTimeout(resolve, ms || 0)) +} diff --git a/packages/vue-renderer/package.json b/packages/vue-renderer/package.json index 69c695f9d0..5fbfb96a8a 100644 --- a/packages/vue-renderer/package.json +++ b/packages/vue-renderer/package.json @@ -8,8 +8,8 @@ ], "main": "dist/vue-renderer.js", "dependencies": { - "@nuxt/common": "2.3.4", "@nuxt/devalue": "^1.2.0", + "@nuxt/utils": "2.3.4", "consola": "^2.3.0", "fs-extra": "^7.0.1", "lru-cache": "^5.1.1", diff --git a/packages/vue-renderer/src/renderer.js b/packages/vue-renderer/src/renderer.js index dee1df9aa4..6d4bce59f1 100644 --- a/packages/vue-renderer/src/renderer.js +++ b/packages/vue-renderer/src/renderer.js @@ -5,7 +5,7 @@ import consola from 'consola' import devalue from '@nuxt/devalue' import invert from 'lodash/invert' import template from 'lodash/template' -import { waitFor } from '@nuxt/common' +import { waitFor } from '@nuxt/utils' import { createBundleRenderer } from 'vue-server-renderer' import SPAMetaRenderer from './spa-meta' diff --git a/packages/webpack/package.json b/packages/webpack/package.json index cbb9f57995..cc925e755b 100644 --- a/packages/webpack/package.json +++ b/packages/webpack/package.json @@ -11,8 +11,8 @@ "@babel/core": "^7.2.2", "@babel/polyfill": "^7.2.3", "@nuxt/babel-preset-app": "2.3.4", - "@nuxt/common": "2.3.4", "@nuxt/friendly-errors-webpack-plugin": "^2.4.0", + "@nuxt/utils": "2.3.4", "babel-loader": "^8.0.4", "cache-loader": "^1.2.5", "caniuse-lite": "^1.0.30000923", diff --git a/packages/webpack/src/builder.js b/packages/webpack/src/builder.js index d0358f0b5c..d296da8afd 100644 --- a/packages/webpack/src/builder.js +++ b/packages/webpack/src/builder.js @@ -11,7 +11,7 @@ import { parallel, sequence, wrapArray -} from '@nuxt/common' +} from '@nuxt/utils' import { ClientConfig, ModernConfig, ServerConfig } from './config' import PerfLoader from './utils/perf-loader' diff --git a/packages/webpack/src/config/base.js b/packages/webpack/src/config/base.js index 76f231edd6..a60a870e29 100644 --- a/packages/webpack/src/config/base.js +++ b/packages/webpack/src/config/base.js @@ -11,7 +11,7 @@ import TerserWebpackPlugin from 'terser-webpack-plugin' import WebpackBar from 'webpackbar' import env from 'std-env' -import { isUrl, urlJoin } from '@nuxt/common' +import { isUrl, urlJoin } from '@nuxt/utils' import PerfLoader from '../utils/perf-loader' import StyleLoader from '../utils/style-loader' diff --git a/packages/webpack/src/utils/postcss.js b/packages/webpack/src/utils/postcss.js index fb48315d02..a300aa8ae7 100644 --- a/packages/webpack/src/utils/postcss.js +++ b/packages/webpack/src/utils/postcss.js @@ -5,7 +5,7 @@ import merge from 'lodash/merge' import cloneDeep from 'lodash/cloneDeep' import createResolver from 'postcss-import-resolver' -import { isPureObject } from '@nuxt/common' +import { isPureObject } from '@nuxt/utils' export const orderPresets = { cssnanoLast: (names) => { diff --git a/packages/webpack/src/utils/style-loader.js b/packages/webpack/src/utils/style-loader.js index 02bc507ffe..fe8aa0d561 100644 --- a/packages/webpack/src/utils/style-loader.js +++ b/packages/webpack/src/utils/style-loader.js @@ -1,7 +1,7 @@ import path from 'path' import ExtractCssChunksPlugin from 'extract-css-chunks-webpack-plugin' -import { wrapArray } from '@nuxt/common' +import { wrapArray } from '@nuxt/utils' import PostcssConfig from './postcss' diff --git a/test/unit/utils.test.js b/test/unit/utils.test.js index add1baa0e0..84515e4712 100644 --- a/test/unit/utils.test.js +++ b/test/unit/utils.test.js @@ -1,6 +1,6 @@ import path from 'path' import { waitUntil } from '../utils' -import * as Utils from '../../packages/common/src/index' +import * as Utils from '../../packages/utils/src/index' describe('utils', () => { test('encodeHtml', () => { diff --git a/test/utils/index.js b/test/utils/index.js index 77601e7237..afa91cd8bc 100644 --- a/test/utils/index.js +++ b/test/utils/index.js @@ -1,5 +1,5 @@ import klawSync from 'klaw-sync' -import { waitFor } from '../../packages/common' +import { waitFor } from '../../packages/utils' export { getNuxtConfig } from '../../packages/config' export { default as getPort } from 'get-port' diff --git a/test/utils/nuxt.js b/test/utils/nuxt.js index 47d954a484..fbc44dd99e 100644 --- a/test/utils/nuxt.js +++ b/test/utils/nuxt.js @@ -8,7 +8,7 @@ export { Nuxt } from '../../packages/core/src/index' export { Builder } from '../../packages/builder/src/index' export { Generator } from '../../packages/generator/src/index' export { BundleBuilder } from '../../packages/webpack/src/index' -export * from '../../packages/common/src/index' +export * from '../../packages/utils/src/index' export const loadFixture = async function (fixture, overrides) { const rootDir = path.resolve(__dirname, '..', 'fixtures', fixture)