mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
fix(cli): config cache invalidation + refactors (#5500)
This commit is contained in:
parent
52ad79baeb
commit
d0afaa1daf
@ -3,7 +3,8 @@ import path from 'path'
|
||||
import consola from 'consola'
|
||||
import minimist from 'minimist'
|
||||
import { name, version } from '../package.json'
|
||||
import { loadNuxtConfig, forceExit } from './utils'
|
||||
import { forceExit } from './utils'
|
||||
import { loadNuxtConfig } from './utils/config'
|
||||
import { indent, foldLines, colorize } from './utils/formatting'
|
||||
import { startSpaces, optionSpaces, forceExitTimeout } from './utils/constants'
|
||||
import { detectTypeScript } from './utils/typescript'
|
||||
|
@ -2,7 +2,8 @@ import consola from 'consola'
|
||||
import chalk from 'chalk'
|
||||
import opener from 'opener'
|
||||
import { common, server } from '../options'
|
||||
import { showBanner, eventsMapping, formatPath } from '../utils'
|
||||
import { eventsMapping, formatPath } from '../utils'
|
||||
import { showBanner } from '../utils/banner'
|
||||
|
||||
export default {
|
||||
name: 'dev',
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { common, server } from '../options'
|
||||
import { showBanner } from '../utils'
|
||||
import { showBanner } from '../utils/banner'
|
||||
|
||||
export default {
|
||||
name: 'start',
|
||||
|
@ -7,4 +7,4 @@ export const imports = _imports
|
||||
export { default as NuxtCommand } from './command'
|
||||
export { default as setup } from './setup'
|
||||
export { default as run } from './run'
|
||||
export { loadNuxtConfig } from './utils'
|
||||
export { loadNuxtConfig } from './utils/config'
|
||||
|
47
packages/cli/src/utils/banner.js
Normal file
47
packages/cli/src/utils/banner.js
Normal file
@ -0,0 +1,47 @@
|
||||
import consola from 'consola'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import env from 'std-env'
|
||||
import chalk from 'chalk'
|
||||
import { successBox } from './formatting'
|
||||
|
||||
export function showBanner(nuxt) {
|
||||
if (env.test) {
|
||||
return
|
||||
}
|
||||
|
||||
if (env.minimalCLI) {
|
||||
for (const listener of nuxt.server.listeners) {
|
||||
consola.info('Listening on: ' + listener.url)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const titleLines = []
|
||||
const messageLines = []
|
||||
|
||||
// Name and version
|
||||
titleLines.push(`${chalk.green.bold('Nuxt.js')} ${nuxt.constructor.version}`)
|
||||
|
||||
// Running mode
|
||||
titleLines.push(`Running in ${nuxt.options.dev ? chalk.bold.blue('development') : chalk.bold.green('production')} mode (${chalk.bold(nuxt.options.mode)})`)
|
||||
|
||||
if (nuxt.options._typescript && nuxt.options._typescript.runtime) {
|
||||
titleLines.push(`TypeScript support is ${chalk.green.bold('enabled')}`)
|
||||
}
|
||||
|
||||
// https://nodejs.org/api/process.html#process_process_memoryusage
|
||||
const { heapUsed, rss } = process.memoryUsage()
|
||||
titleLines.push(`Memory usage: ${chalk.bold(prettyBytes(heapUsed))} (RSS: ${prettyBytes(rss)})`)
|
||||
|
||||
// Listeners
|
||||
for (const listener of nuxt.server.listeners) {
|
||||
messageLines.push(chalk.bold('Listening on: ') + chalk.underline.blue(listener.url))
|
||||
}
|
||||
|
||||
// Add custom badge messages
|
||||
if (nuxt.options.cli.badgeMessages.length) {
|
||||
messageLines.push('', ...nuxt.options.cli.badgeMessages)
|
||||
}
|
||||
|
||||
process.stdout.write(successBox(messageLines.join('\n'), titleLines.join('\n')))
|
||||
}
|
70
packages/cli/src/utils/config.js
Normal file
70
packages/cli/src/utils/config.js
Normal file
@ -0,0 +1,70 @@
|
||||
import path from 'path'
|
||||
import consola from 'consola'
|
||||
import defaultsDeep from 'lodash/defaultsDeep'
|
||||
import { defaultNuxtConfigFile, getDefaultNuxtConfig } from '@nuxt/config'
|
||||
import { clearRequireCache, scanRequireTree } from '@nuxt/utils'
|
||||
import esm from 'esm'
|
||||
|
||||
export async function loadNuxtConfig(argv) {
|
||||
const rootDir = path.resolve(argv._[0] || '.')
|
||||
let nuxtConfigFile
|
||||
let options = {}
|
||||
|
||||
try {
|
||||
nuxtConfigFile = require.resolve(path.resolve(rootDir, argv['config-file']))
|
||||
} catch (e) {
|
||||
if (e.code !== 'MODULE_NOT_FOUND') {
|
||||
throw (e)
|
||||
} else if (argv['config-file'] !== defaultNuxtConfigFile) {
|
||||
consola.fatal('Could not load config file: ' + argv['config-file'])
|
||||
}
|
||||
}
|
||||
|
||||
if (nuxtConfigFile) {
|
||||
if (nuxtConfigFile.endsWith('.ts')) {
|
||||
options = require(nuxtConfigFile) || {}
|
||||
} else {
|
||||
clearRequireCache(nuxtConfigFile)
|
||||
options = esm(module, { cache: false, cjs: { cache: false } })(nuxtConfigFile) || {}
|
||||
}
|
||||
|
||||
if (options.default) {
|
||||
options = options.default
|
||||
}
|
||||
|
||||
if (typeof options === 'function') {
|
||||
try {
|
||||
options = await options()
|
||||
if (options.default) {
|
||||
options = options.default
|
||||
}
|
||||
} catch (error) {
|
||||
consola.error(error)
|
||||
consola.fatal('Error while fetching async configuration')
|
||||
}
|
||||
}
|
||||
|
||||
// Keep _nuxtConfigFile for watching
|
||||
options._nuxtConfigFile = nuxtConfigFile
|
||||
|
||||
// Keep all related files for watching
|
||||
options._nuxtConfigFiles = Array.from(scanRequireTree(nuxtConfigFile))
|
||||
}
|
||||
|
||||
if (typeof options.rootDir !== 'string') {
|
||||
options.rootDir = rootDir
|
||||
}
|
||||
|
||||
// Nuxt Mode
|
||||
options.mode =
|
||||
(argv.spa && 'spa') || (argv.universal && 'universal') || options.mode
|
||||
|
||||
// Server options
|
||||
options.server = defaultsDeep({
|
||||
port: argv.port || undefined,
|
||||
host: argv.hostname || undefined,
|
||||
socket: argv['unix-socket'] || undefined
|
||||
}, options.server || {}, getDefaultNuxtConfig().server)
|
||||
|
||||
return options
|
||||
}
|
@ -1,23 +1,10 @@
|
||||
import path from 'path'
|
||||
import consola from 'consola'
|
||||
import esm from 'esm'
|
||||
import exit from 'exit'
|
||||
import defaultsDeep from 'lodash/defaultsDeep'
|
||||
import { defaultNuxtConfigFile, getDefaultNuxtConfig } from '@nuxt/config'
|
||||
|
||||
import { lock } from '@nuxt/utils'
|
||||
import chalk from 'chalk'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import env from 'std-env'
|
||||
import { successBox, warningBox } from './formatting'
|
||||
|
||||
const esmOptions = {
|
||||
cache: false,
|
||||
cjs: {
|
||||
cache: true,
|
||||
vars: true,
|
||||
namedExports: true
|
||||
}
|
||||
}
|
||||
import { warningBox } from './formatting'
|
||||
|
||||
export const eventsMapping = {
|
||||
add: { icon: '+', color: 'green', action: 'Created' },
|
||||
@ -25,103 +12,6 @@ export const eventsMapping = {
|
||||
unlink: { icon: '-', color: 'red', action: 'Removed' }
|
||||
}
|
||||
|
||||
export async function loadNuxtConfig(argv) {
|
||||
const rootDir = path.resolve(argv._[0] || '.')
|
||||
let nuxtConfigFile
|
||||
let options = {}
|
||||
|
||||
try {
|
||||
nuxtConfigFile = require.resolve(path.resolve(rootDir, argv['config-file']))
|
||||
} catch (e) {
|
||||
if (e.code !== 'MODULE_NOT_FOUND') {
|
||||
throw (e)
|
||||
} else if (argv['config-file'] !== defaultNuxtConfigFile) {
|
||||
consola.fatal('Could not load config file: ' + argv['config-file'])
|
||||
}
|
||||
}
|
||||
|
||||
if (nuxtConfigFile) {
|
||||
options = (nuxtConfigFile.endsWith('.ts') ? require(nuxtConfigFile) : esm(module, esmOptions)(nuxtConfigFile)) || {}
|
||||
if (options.default) {
|
||||
options = options.default
|
||||
}
|
||||
|
||||
if (typeof options === 'function') {
|
||||
try {
|
||||
options = await options()
|
||||
if (options.default) {
|
||||
options = options.default
|
||||
}
|
||||
} catch (error) {
|
||||
consola.error(error)
|
||||
consola.fatal('Error while fetching async configuration')
|
||||
}
|
||||
}
|
||||
|
||||
// Keep _nuxtConfigFile for watching
|
||||
options._nuxtConfigFile = nuxtConfigFile
|
||||
}
|
||||
|
||||
if (typeof options.rootDir !== 'string') {
|
||||
options.rootDir = rootDir
|
||||
}
|
||||
|
||||
// Nuxt Mode
|
||||
options.mode =
|
||||
(argv.spa && 'spa') || (argv.universal && 'universal') || options.mode
|
||||
|
||||
// Server options
|
||||
options.server = defaultsDeep({
|
||||
port: argv.port || undefined,
|
||||
host: argv.hostname || undefined,
|
||||
socket: argv['unix-socket'] || undefined
|
||||
}, options.server || {}, getDefaultNuxtConfig().server)
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
export function showBanner(nuxt) {
|
||||
if (env.test) {
|
||||
return
|
||||
}
|
||||
|
||||
if (env.minimalCLI) {
|
||||
for (const listener of nuxt.server.listeners) {
|
||||
consola.info('Listening on: ' + listener.url)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const titleLines = []
|
||||
const messageLines = []
|
||||
|
||||
// Name and version
|
||||
titleLines.push(`${chalk.green.bold('Nuxt.js')} ${nuxt.constructor.version}`)
|
||||
|
||||
// Running mode
|
||||
titleLines.push(`Running in ${nuxt.options.dev ? chalk.bold.blue('development') : chalk.bold.green('production')} mode (${chalk.bold(nuxt.options.mode)})`)
|
||||
|
||||
if (nuxt.options._typescript && nuxt.options._typescript.runtime) {
|
||||
titleLines.push(`TypeScript support is ${chalk.green.bold('enabled')}`)
|
||||
}
|
||||
|
||||
// https://nodejs.org/api/process.html#process_process_memoryusage
|
||||
const { heapUsed, rss } = process.memoryUsage()
|
||||
titleLines.push(`Memory usage: ${chalk.bold(prettyBytes(heapUsed))} (RSS: ${prettyBytes(rss)})`)
|
||||
|
||||
// Listeners
|
||||
for (const listener of nuxt.server.listeners) {
|
||||
messageLines.push(chalk.bold('Listening on: ') + chalk.underline.blue(listener.url))
|
||||
}
|
||||
|
||||
// Add custom badge messages
|
||||
if (nuxt.options.cli.badgeMessages.length) {
|
||||
messageLines.push('', ...nuxt.options.cli.badgeMessages)
|
||||
}
|
||||
|
||||
process.stdout.write(successBox(messageLines.join('\n'), titleLines.join('\n')))
|
||||
}
|
||||
|
||||
export function formatPath(filePath) {
|
||||
if (!filePath) {
|
||||
return
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { consola } from '../utils'
|
||||
import * as utils from '../../src/utils'
|
||||
import { showBanner } from '../../src/utils/banner'
|
||||
|
||||
jest.mock('std-env', () => ({
|
||||
test: false,
|
||||
@ -15,7 +15,7 @@ describe('cli/utils', () => {
|
||||
{ url: 'second' }
|
||||
]
|
||||
|
||||
utils.showBanner({
|
||||
showBanner({
|
||||
options: {
|
||||
cli: {}
|
||||
},
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { getDefaultNuxtConfig } from '@nuxt/config'
|
||||
import { consola } from '../utils'
|
||||
import { loadNuxtConfig } from '../../src/utils/config'
|
||||
import * as utils from '../../src/utils'
|
||||
import { showBanner } from '../../src/utils/banner'
|
||||
import * as fmt from '../../src/utils/formatting'
|
||||
|
||||
jest.mock('std-env', () => ({
|
||||
@ -18,7 +20,7 @@ describe('cli/utils', () => {
|
||||
universal: true
|
||||
}
|
||||
|
||||
const options = await utils.loadNuxtConfig(argv)
|
||||
const options = await loadNuxtConfig(argv)
|
||||
expect(options.rootDir).toBe(process.cwd())
|
||||
expect(options.mode).toBe('universal')
|
||||
expect(options.server.host).toBe('localhost')
|
||||
@ -33,7 +35,7 @@ describe('cli/utils', () => {
|
||||
spa: true
|
||||
}
|
||||
|
||||
const options = await utils.loadNuxtConfig(argv)
|
||||
const options = await loadNuxtConfig(argv)
|
||||
expect(options.testOption).toBe(true)
|
||||
expect(options.rootDir).toBe('/some/path')
|
||||
expect(options.mode).toBe('spa')
|
||||
@ -48,7 +50,7 @@ describe('cli/utils', () => {
|
||||
'config-file': '../fixtures/nuxt.doesnt-exist.js'
|
||||
}
|
||||
|
||||
const options = await utils.loadNuxtConfig(argv)
|
||||
const options = await loadNuxtConfig(argv)
|
||||
expect(options.testOption).not.toBeDefined()
|
||||
|
||||
expect(consola.fatal).toHaveBeenCalledTimes(1)
|
||||
@ -64,7 +66,7 @@ describe('cli/utils', () => {
|
||||
'unix-socket': '/var/run/async.sock'
|
||||
}
|
||||
|
||||
const options = await utils.loadNuxtConfig(argv)
|
||||
const options = await loadNuxtConfig(argv)
|
||||
expect(options.testOption).toBe(true)
|
||||
expect(options.mode).toBe('supercharged')
|
||||
expect(options.server.host).toBe('async-host')
|
||||
@ -78,7 +80,7 @@ describe('cli/utils', () => {
|
||||
'config-file': '../fixtures/nuxt.async-error.js'
|
||||
}
|
||||
|
||||
const options = await utils.loadNuxtConfig(argv)
|
||||
const options = await loadNuxtConfig(argv)
|
||||
expect(options.testOption).not.toBeDefined()
|
||||
|
||||
expect(consola.error).toHaveBeenCalledTimes(1)
|
||||
@ -130,7 +132,7 @@ describe('cli/utils', () => {
|
||||
{ url: 'second' }
|
||||
]
|
||||
|
||||
utils.showBanner({
|
||||
showBanner({
|
||||
options: {
|
||||
cli: {
|
||||
badgeMessages
|
||||
|
@ -96,8 +96,14 @@ export function getNuxtConfig(_options) {
|
||||
options._nuxtConfigFile = path.resolve(options.rootDir, `${defaultNuxtConfigFile}.js`)
|
||||
}
|
||||
|
||||
// Watch for _nuxtConfigFile changes
|
||||
options.watch.push(options._nuxtConfigFile)
|
||||
if (!options._nuxtConfigFiles) {
|
||||
options._nuxtConfigFiles = [
|
||||
options._nuxtConfigFile
|
||||
]
|
||||
}
|
||||
|
||||
// Watch for config file changes
|
||||
options.watch.push(...options._nuxtConfigFiles)
|
||||
|
||||
// Protect rootDir against buildDir
|
||||
guardDir(options, 'rootDir', 'buildDir')
|
||||
|
@ -5,6 +5,9 @@ Object {
|
||||
"ErrorPage": null,
|
||||
"__normalized__": true,
|
||||
"_nuxtConfigFile": "/var/nuxt/test/nuxt.config.js",
|
||||
"_nuxtConfigFiles": Array [
|
||||
"/var/nuxt/test/nuxt.config.js",
|
||||
],
|
||||
"appTemplatePath": "/var/nuxt/test/.nuxt/views/app.template.html",
|
||||
"build": Object {
|
||||
"_publicPath": "/_nuxt/",
|
||||
|
34
packages/utils/src/cjs.js
Normal file
34
packages/utils/src/cjs.js
Normal file
@ -0,0 +1,34 @@
|
||||
export function clearRequireCache(id) {
|
||||
const entry = require.cache[id]
|
||||
if (!entry || id.includes('node_modules')) {
|
||||
return
|
||||
}
|
||||
|
||||
if (entry.parent) {
|
||||
const i = entry.parent.children.findIndex(e => e.id === id)
|
||||
if (i > -1) {
|
||||
entry.parent.children.splice(i, 1)
|
||||
}
|
||||
}
|
||||
|
||||
for (const child of entry.children) {
|
||||
clearRequireCache(child.id)
|
||||
}
|
||||
|
||||
delete require.cache[id]
|
||||
}
|
||||
|
||||
export function scanRequireTree(id, files = new Set()) {
|
||||
const entry = require.cache[id]
|
||||
if (!entry || id.includes('node_modules') || files.has(id)) {
|
||||
return files
|
||||
}
|
||||
|
||||
files.add(entry.id)
|
||||
|
||||
for (const child of entry.children) {
|
||||
scanRequireTree(child.id, files)
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
@ -6,3 +6,4 @@ export * from './route'
|
||||
export * from './serialize'
|
||||
export * from './task'
|
||||
export * from './timer'
|
||||
export * from './cjs'
|
||||
|
@ -7,6 +7,7 @@ import * as route from '../src/route'
|
||||
import * as serialize from '../src/serialize'
|
||||
import * as task from '../src/task'
|
||||
import * as timer from '../src/timer'
|
||||
import * as cjs from '../src/cjs'
|
||||
|
||||
describe('util: entry', () => {
|
||||
test('should export all methods from utils folder', () => {
|
||||
@ -18,7 +19,8 @@ describe('util: entry', () => {
|
||||
...route,
|
||||
...serialize,
|
||||
...task,
|
||||
...timer
|
||||
...timer,
|
||||
...cjs
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user