feat(cli): `nuxi info` (#503)

This commit is contained in:
pooya parsa 2021-09-07 15:17:17 +02:00 committed by GitHub
parent 0c5234b8c0
commit 49f7b39f6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 165 additions and 1 deletions

View File

@ -27,12 +27,16 @@
"@types/mri": "^1.1.1",
"chokidar": "^3.5.2",
"clear": "^0.1.0",
"clipboardy": "^2.3.0",
"colorette": "^1.3.0",
"debounce-promise": "^3.1.2",
"deep-object-diff": "^1.1.0",
"destr": "^1.1.0",
"flat": "^5.0.2",
"jiti": "^1.11.0",
"listhen": "^0.2.4",
"mri": "^1.1.6",
"scule": "^0.2.1",
"unbuild": "^0.4.2",
"upath": "^2.0.1",
"v8-compile-cache": "^2.3.0"

View File

@ -4,7 +4,8 @@ export const commands = {
dev: () => import('./dev'),
build: () => import('./build'),
prepare: () => import('./prepare'),
usage: () => import('./usage')
usage: () => import('./usage'),
info: () => import('./info')
}
export type Command = keyof typeof commands

View File

@ -0,0 +1,155 @@
import os from 'os'
import { existsSync, readFileSync } from 'fs'
import { resolve, dirname } from 'upath'
import jiti from 'jiti'
import destr from 'destr'
import { splitByCase } from 'scule'
import clipboardy from 'clipboardy'
import { defineNuxtCommand } from './index'
export default defineNuxtCommand({
meta: {
name: 'info',
usage: 'npx nuxi info [rootDir]',
description: 'Get information about nuxt project'
},
async invoke (args) {
// Resolve rootDir
const rootDir = resolve(args._[0] || '.')
// Load nuxt.config
const nuxtConfig = getNuxtConfig(rootDir)
// Find nearest package.json
const { dependencies = {}, devDependencies = {} } = findPackage(rootDir)
// Utils to query a dependency version
const getDepVersion = name => getPkg(name, rootDir)?.version || dependencies[name] || devDependencies[name]
const listModules = (arr = []) => arr
.map(normalizeConfigModule)
.filter(Boolean)
.map((name) => {
const npmName = name.split('/').splice(0, 2).join('/') // @foo/bar/baz => @foo/bar
const v = getDepVersion(npmName)
return '`' + (v ? `${name}@${v}` : name) + '`'
})
.join(', ')
const infoObj = {
OperatingSystem: os.type(),
NodeVersion: process.version,
NuxtVersion: getDepVersion('nuxt') || getDepVersion('nuxt-edge') || (getDepVersion('nuxt3') ? '3-' + getDepVersion('nuxt3') : null),
PackageManager: getPackageManager(rootDir),
Bundler: (nuxtConfig.vite || nuxtConfig?.buildModules?.find(m => m === 'nuxt-vite')) ? 'Vite' : 'Webpack',
UserConfig: Object.keys(nuxtConfig).map(key => '`' + key + '`').join(', '),
RuntimeModules: listModules(nuxtConfig.modules),
BuildModules: listModules(nuxtConfig.buildModules)
}
console.log('RootDir:', rootDir)
let maxLength = 0
const entries = Object.entries(infoObj).map(([key, val]) => {
const label = splitByCase(key).join(' ')
if (label.length > maxLength) { maxLength = label.length }
return [label, val || '-']
})
let infoStr = ''
for (const [label, value] of entries) {
infoStr += '- ' + (label + ': ').padEnd(maxLength + 2) + (value.includes('`') ? value : '`' + value + '`') + '\n'
}
const copied = await clipboardy.write(infoStr).then(() => true).catch(() => false)
const splitter = '------------------------------'
console.log(`Nuxt project info: ${copied ? '(copied to clipboard)' : ''}\n\n${splitter}\n${infoStr}${splitter}\n`)
const isNuxt3 = infoObj.NuxtVersion.startsWith('3') || infoObj.BuildModules.includes('bridge')
const repo = isNuxt3 ? 'nuxt/framework' : 'nuxt/nuxt.js'
console.log([
`👉 Report an issue: https://github.com/${repo}/issues/new`,
`👉 Suggest an improvement: https://github.com/${repo}/discussions/new`,
`👉 Read documentation: ${isNuxt3 ? 'https://v3.nuxtjs.org' : 'https://nuxtjs.org'}`
].join('\n\n') + '\n')
}
})
function normalizeConfigModule (module, rootDir) {
if (!module) {
return null
}
if (typeof module === 'string') {
return module
.split(rootDir).pop() // Strip rootDir
.split('node_modules').pop() // Strip node_modules
.replace(/^\//, '')
}
if (typeof module === 'function') {
return `${module.name}()`
}
if (Array.isArray(module)) {
return normalizeConfigModule(module[0], rootDir)
}
}
function findup (rootDir, fn) {
let dir = rootDir
while (dir !== dirname(dir)) {
const res = fn(dir)
if (res) {
return res
}
dir = dirname(dir)
}
return null
}
function getPackageManager (rootDir) {
return findup(rootDir, (dir) => {
if (existsSync(resolve(dir, 'yarn.lock'))) {
return 'Yarn'
}
if (existsSync(resolve(dir, 'package-lock.json'))) {
return 'npm'
}
}) || 'unknown'
}
function getNuxtConfig (rootDir) {
try {
return jiti(rootDir, { interopDefault: true })('./nuxt.config')
} catch (err) {
// TODO: Show error as warning if it is not 404
return {}
}
}
function getPkg (name, rootDir) {
// Assume it is in {rootDir}/node_modules/${name}/package.json
let pkgPath = resolve(rootDir, 'node_modules', name, 'package.json')
// Try to resolve for more accuracy
try { pkgPath = require.resolve(name + '/package.json', { paths: [rootDir] }) } catch (_err) {
// console.log('not found:', name)
}
return readJSONSync(pkgPath)
}
function findPackage (rootDir) {
return findup(rootDir, (dir) => {
const p = resolve(dir, 'package.json')
if (existsSync(p)) {
return readJSONSync(p)
}
}) || {}
}
function readJSONSync (filePath) {
try {
return destr(readFileSync(filePath, 'utf-8'))
} catch (err) {
// TODO: Warn error
return null
}
}

View File

@ -9769,13 +9769,17 @@ fsevents@~2.3.2:
"@types/mri": ^1.1.1
chokidar: ^3.5.2
clear: ^0.1.0
clipboardy: ^2.3.0
colorette: ^1.3.0
debounce-promise: ^3.1.2
deep-object-diff: ^1.1.0
destr: ^1.1.0
flat: ^5.0.2
fsevents: ~2.3.2
jiti: ^1.11.0
listhen: ^0.2.4
mri: ^1.1.6
scule: ^0.2.1
unbuild: ^0.4.2
upath: ^2.0.1
v8-compile-cache: ^2.3.0