penambahan web socket
This commit is contained in:
No files matched your search
+330
@@ -0,0 +1,330 @@
|
||||
import * as fs from 'node:fs';
|
||||
import { homedir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { updateConfig } from 'c12/update';
|
||||
import { defineCommand } from 'citty';
|
||||
import { colors } from 'consola/utils';
|
||||
import { addDependency } from 'nypm';
|
||||
import { $fetch } from 'ofetch';
|
||||
import { resolve } from 'pathe';
|
||||
import { readPackageJSON } from 'pkg-types';
|
||||
import { satisfies } from 'semver';
|
||||
import { joinURL } from 'ufo';
|
||||
import { r as runCommand } from '../shared/cli.vXg4eLNu.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { g as getNuxtVersion } from '../shared/cli.DHenkA1C.mjs';
|
||||
import { a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import { f as fetchModules, c as checkNuxtCompatibility, g as getRegistryFromContent } from '../shared/cli.Cr-OCgdO.mjs';
|
||||
import 'node:url';
|
||||
import 'node:crypto';
|
||||
import 'std-env';
|
||||
import '../shared/cli.DhJ3cH8w.mjs';
|
||||
import 'consola';
|
||||
import 'confbox';
|
||||
|
||||
const add = defineCommand({
|
||||
meta: {
|
||||
name: "add",
|
||||
description: "Add Nuxt modules"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
moduleName: {
|
||||
type: "positional",
|
||||
description: "Specify one or more modules to install by name, separated by spaces"
|
||||
},
|
||||
skipInstall: {
|
||||
type: "boolean",
|
||||
description: "Skip npm install"
|
||||
},
|
||||
skipConfig: {
|
||||
type: "boolean",
|
||||
description: "Skip nuxt.config.ts update"
|
||||
},
|
||||
dev: {
|
||||
type: "boolean",
|
||||
description: "Install modules as dev dependencies"
|
||||
}
|
||||
},
|
||||
async setup(ctx) {
|
||||
const cwd = resolve(ctx.args.cwd);
|
||||
const modules = ctx.args._.map((e) => e.trim()).filter(Boolean);
|
||||
const projectPkg = await readPackageJSON(cwd).catch(() => ({}));
|
||||
if (!projectPkg.dependencies?.nuxt && !projectPkg.devDependencies?.nuxt) {
|
||||
logger.warn(`No \`nuxt\` dependency detected in \`${cwd}\`.`);
|
||||
const shouldContinue = await logger.prompt(
|
||||
`Do you want to continue anyway?`,
|
||||
{
|
||||
type: "confirm",
|
||||
initial: false,
|
||||
cancel: "default"
|
||||
}
|
||||
);
|
||||
if (shouldContinue !== true) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
const maybeResolvedModules = await Promise.all(modules.map((moduleName) => resolveModule(moduleName, cwd)));
|
||||
const resolvedModules = maybeResolvedModules.filter((x) => x != null);
|
||||
logger.info(`Resolved \`${resolvedModules.map((x) => x.pkgName).join("`, `")}\`, adding module${resolvedModules.length > 1 ? "s" : ""}...`);
|
||||
await addModules(resolvedModules, { ...ctx.args, cwd }, projectPkg);
|
||||
if (!ctx.args.skipInstall) {
|
||||
const args = Object.entries(ctx.args).filter(([k]) => k in cwdArgs || k in logLevelArgs).map(([k, v]) => `--${k}=${v}`);
|
||||
await runCommand("prepare", args);
|
||||
}
|
||||
}
|
||||
});
|
||||
async function addModules(modules, { skipInstall, skipConfig, cwd, dev }, projectPkg) {
|
||||
if (!skipInstall) {
|
||||
const installedModules = [];
|
||||
const notInstalledModules = [];
|
||||
const dependencies = /* @__PURE__ */ new Set([
|
||||
...Object.keys(projectPkg.dependencies || {}),
|
||||
...Object.keys(projectPkg.devDependencies || {})
|
||||
]);
|
||||
for (const module of modules) {
|
||||
if (dependencies.has(module.pkgName)) {
|
||||
installedModules.push(module);
|
||||
} else {
|
||||
notInstalledModules.push(module);
|
||||
}
|
||||
}
|
||||
if (installedModules.length > 0) {
|
||||
const installedModulesList = installedModules.map((module) => module.pkgName).join("`, `");
|
||||
const are = installedModules.length > 1 ? "are" : "is";
|
||||
logger.info(`\`${installedModulesList}\` ${are} already installed`);
|
||||
}
|
||||
if (notInstalledModules.length > 0) {
|
||||
const isDev = Boolean(projectPkg.devDependencies?.nuxt) || dev;
|
||||
const notInstalledModulesList = notInstalledModules.map((module) => module.pkg).join("`, `");
|
||||
const dependency = notInstalledModules.length > 1 ? "dependencies" : "dependency";
|
||||
const a = notInstalledModules.length > 1 ? "" : " a";
|
||||
logger.info(`Installing \`${notInstalledModulesList}\` as${a}${isDev ? " development" : ""} ${dependency}`);
|
||||
const res = await addDependency(notInstalledModules.map((module) => module.pkg), {
|
||||
cwd,
|
||||
dev: isDev,
|
||||
installPeerDependencies: true
|
||||
}).then(() => true).catch(
|
||||
(error) => {
|
||||
logger.error(error);
|
||||
const failedModulesList = notInstalledModules.map((module) => colors.cyan(module.pkg)).join("`, `");
|
||||
const s = notInstalledModules.length > 1 ? "s" : "";
|
||||
return logger.prompt(`Install failed for \`${failedModulesList}\`. Do you want to continue adding the module${s} to ${colors.cyan("nuxt.config")}?`, {
|
||||
type: "confirm",
|
||||
initial: false,
|
||||
cancel: "default"
|
||||
});
|
||||
}
|
||||
);
|
||||
if (res !== true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!skipConfig) {
|
||||
await updateConfig({
|
||||
cwd,
|
||||
configFile: "nuxt.config",
|
||||
async onCreate() {
|
||||
logger.info(`Creating \`nuxt.config.ts\``);
|
||||
return getDefaultNuxtConfig();
|
||||
},
|
||||
async onUpdate(config) {
|
||||
if (!config.modules) {
|
||||
config.modules = [];
|
||||
}
|
||||
for (const resolved of modules) {
|
||||
if (config.modules.includes(resolved.pkgName)) {
|
||||
logger.info(`\`${resolved.pkgName}\` is already in the \`modules\``);
|
||||
continue;
|
||||
}
|
||||
logger.info(`Adding \`${resolved.pkgName}\` to the \`modules\``);
|
||||
config.modules.push(resolved.pkgName);
|
||||
}
|
||||
}
|
||||
}).catch((error) => {
|
||||
logger.error(`Failed to update \`nuxt.config\`: ${error.message}`);
|
||||
logger.error(`Please manually add \`${modules.map((module) => module.pkgName).join("`, `")}\` to the \`modules\` in \`nuxt.config.ts\``);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
function getDefaultNuxtConfig() {
|
||||
return `
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
modules: []
|
||||
})`;
|
||||
}
|
||||
const packageRegex = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?([a-z0-9-~][a-z0-9-._~]*)(@[^@]+)?$/;
|
||||
async function resolveModule(moduleName, cwd) {
|
||||
let pkgName = moduleName;
|
||||
let pkgVersion;
|
||||
const reMatch = moduleName.match(packageRegex);
|
||||
if (reMatch) {
|
||||
if (reMatch[3]) {
|
||||
pkgName = `${reMatch[1] || ""}${reMatch[2] || ""}`;
|
||||
pkgVersion = reMatch[3].slice(1);
|
||||
}
|
||||
} else {
|
||||
logger.error(`Invalid package name \`${pkgName}\`.`);
|
||||
return false;
|
||||
}
|
||||
const modulesDB = await fetchModules().catch((err) => {
|
||||
logger.warn(`Cannot search in the Nuxt Modules database: ${err}`);
|
||||
return [];
|
||||
});
|
||||
const matchedModule = modulesDB.find(
|
||||
(module) => module.name === moduleName || pkgVersion && module.name === pkgName || module.npm === pkgName || module.aliases?.includes(pkgName)
|
||||
);
|
||||
if (matchedModule?.npm) {
|
||||
pkgName = matchedModule.npm;
|
||||
}
|
||||
if (matchedModule && matchedModule.compatibility.nuxt) {
|
||||
const nuxtVersion = await getNuxtVersion(cwd);
|
||||
if (!checkNuxtCompatibility(matchedModule, nuxtVersion)) {
|
||||
logger.warn(
|
||||
`The module \`${pkgName}\` is not compatible with Nuxt \`${nuxtVersion}\` (requires \`${matchedModule.compatibility.nuxt}\`)`
|
||||
);
|
||||
const shouldContinue = await logger.prompt(
|
||||
"Do you want to continue installing incompatible version?",
|
||||
{
|
||||
type: "confirm",
|
||||
initial: false,
|
||||
cancel: "default"
|
||||
}
|
||||
);
|
||||
if (!shouldContinue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const versionMap = matchedModule.compatibility.versionMap;
|
||||
if (versionMap) {
|
||||
for (const [_nuxtVersion, _moduleVersion] of Object.entries(versionMap)) {
|
||||
if (satisfies(nuxtVersion, _nuxtVersion)) {
|
||||
if (!pkgVersion) {
|
||||
pkgVersion = _moduleVersion;
|
||||
} else {
|
||||
logger.warn(
|
||||
`Recommended version of \`${pkgName}\` for Nuxt \`${nuxtVersion}\` is \`${_moduleVersion}\` but you have requested \`${pkgVersion}\``
|
||||
);
|
||||
pkgVersion = await logger.prompt("Choose a version:", {
|
||||
type: "select",
|
||||
options: [_moduleVersion, pkgVersion],
|
||||
cancel: "undefined"
|
||||
});
|
||||
if (!pkgVersion) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let version = pkgVersion || "latest";
|
||||
const pkgScope = pkgName.startsWith("@") ? pkgName.split("/")[0] : null;
|
||||
const meta = await detectNpmRegistry(pkgScope);
|
||||
const headers = {};
|
||||
if (meta.authToken) {
|
||||
headers.Authorization = `Bearer ${meta.authToken}`;
|
||||
}
|
||||
const pkgDetails = await $fetch(joinURL(meta.registry, `${pkgName}`), { headers });
|
||||
if (pkgDetails["dist-tags"]?.[version]) {
|
||||
version = pkgDetails["dist-tags"][version];
|
||||
} else {
|
||||
version = Object.keys(pkgDetails.versions)?.findLast((v) => satisfies(v, version)) || version;
|
||||
}
|
||||
const pkg = pkgDetails.versions[version];
|
||||
const pkgDependencies = Object.assign(
|
||||
pkg.dependencies || {},
|
||||
pkg.devDependencies || {}
|
||||
);
|
||||
if (!pkgDependencies.nuxt && !pkgDependencies["nuxt-edge"] && !pkgDependencies["@nuxt/kit"]) {
|
||||
logger.warn(`It seems that \`${pkgName}\` is not a Nuxt module.`);
|
||||
const shouldContinue = await logger.prompt(
|
||||
`Do you want to continue installing ${colors.cyan(pkgName)} anyway?`,
|
||||
{
|
||||
type: "confirm",
|
||||
initial: false,
|
||||
cancel: "default"
|
||||
}
|
||||
);
|
||||
if (!shouldContinue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return {
|
||||
nuxtModule: matchedModule,
|
||||
pkg: `${pkgName}@${version}`,
|
||||
pkgName,
|
||||
pkgVersion: version
|
||||
};
|
||||
}
|
||||
function getNpmrcPaths() {
|
||||
const userNpmrcPath = join(homedir(), ".npmrc");
|
||||
const cwdNpmrcPath = join(process.cwd(), ".npmrc");
|
||||
return [cwdNpmrcPath, userNpmrcPath];
|
||||
}
|
||||
async function getAuthToken(registry) {
|
||||
const paths = getNpmrcPaths();
|
||||
const authTokenRegex = new RegExp(`^//${registry.replace(/^https?:\/\//, "").replace(/\/$/, "")}/:_authToken=(.+)$`, "m");
|
||||
for (const npmrcPath of paths) {
|
||||
let fd;
|
||||
try {
|
||||
fd = await fs.promises.open(npmrcPath, "r");
|
||||
if (await fd.stat().then((r) => r.isFile())) {
|
||||
const npmrcContent = await fd.readFile("utf-8");
|
||||
const authTokenMatch = npmrcContent.match(authTokenRegex)?.[1];
|
||||
if (authTokenMatch) {
|
||||
return authTokenMatch.trim();
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
} finally {
|
||||
await fd?.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async function detectNpmRegistry(scope) {
|
||||
const registry = await getRegistry(scope);
|
||||
const authToken = await getAuthToken(registry);
|
||||
return {
|
||||
registry,
|
||||
authToken
|
||||
};
|
||||
}
|
||||
async function getRegistry(scope) {
|
||||
if (process.env.COREPACK_NPM_REGISTRY) {
|
||||
return process.env.COREPACK_NPM_REGISTRY;
|
||||
}
|
||||
const registry = await getRegistryFromFile(getNpmrcPaths(), scope);
|
||||
if (registry) {
|
||||
process.env.COREPACK_NPM_REGISTRY = registry;
|
||||
}
|
||||
return registry || "https://registry.npmjs.org";
|
||||
}
|
||||
async function getRegistryFromFile(paths, scope) {
|
||||
for (const npmrcPath of paths) {
|
||||
let fd;
|
||||
try {
|
||||
fd = await fs.promises.open(npmrcPath, "r");
|
||||
if (await fd.stat().then((r) => r.isFile())) {
|
||||
const npmrcContent = await fd.readFile("utf-8");
|
||||
const registry = getRegistryFromContent(npmrcContent, scope);
|
||||
if (registry) {
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
} finally {
|
||||
await fd?.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export { add as default };
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
import { existsSync, promises } from 'node:fs';
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { resolve, extname, dirname } from 'pathe';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { pascalCase, camelCase } from 'scule';
|
||||
import { a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:url';
|
||||
import 'exsolve';
|
||||
import 'consola';
|
||||
import 'node:path';
|
||||
import 'std-env';
|
||||
|
||||
const httpMethods = [
|
||||
"connect",
|
||||
"delete",
|
||||
"get",
|
||||
"head",
|
||||
"options",
|
||||
"post",
|
||||
"put",
|
||||
"trace",
|
||||
"patch"
|
||||
];
|
||||
const api = ({ name, args, nuxtOptions }) => {
|
||||
return {
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.serverDir, `api/${name}${applySuffix(args, httpMethods, "method")}.ts`),
|
||||
contents: `
|
||||
export default defineEventHandler(event => {
|
||||
return 'Hello ${name}'
|
||||
})
|
||||
`
|
||||
};
|
||||
};
|
||||
|
||||
const app = ({ args, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, "app.vue"),
|
||||
contents: args.pages ? `
|
||||
<script setup lang="ts"><\/script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<NuxtLayout>
|
||||
<NuxtPage/>
|
||||
</NuxtLayout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
` : `
|
||||
<script setup lang="ts"><\/script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Hello World!</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
`
|
||||
});
|
||||
|
||||
const appConfig = ({ nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, "app.config.ts"),
|
||||
contents: `
|
||||
export default defineAppConfig({})
|
||||
`
|
||||
});
|
||||
|
||||
const component = ({ name, args, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, `components/${name}${applySuffix(
|
||||
args,
|
||||
["client", "server"],
|
||||
"mode"
|
||||
)}.vue`),
|
||||
contents: `
|
||||
<script setup lang="ts"><\/script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
Component: ${name}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
`
|
||||
});
|
||||
|
||||
const composable = ({ name, nuxtOptions }) => {
|
||||
const nameWithoutUsePrefix = name.replace(/^use-?/, "");
|
||||
const nameWithUsePrefix = `use${pascalCase(nameWithoutUsePrefix)}`;
|
||||
return {
|
||||
path: resolve(nuxtOptions.srcDir, `composables/${name}.ts`),
|
||||
contents: `
|
||||
export const ${nameWithUsePrefix} = () => {
|
||||
return ref()
|
||||
}
|
||||
`
|
||||
};
|
||||
};
|
||||
|
||||
const error = ({ nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, "error.vue"),
|
||||
contents: `
|
||||
<script setup lang="ts">
|
||||
import type { NuxtError } from '#app'
|
||||
|
||||
const props = defineProps({
|
||||
error: Object as () => NuxtError
|
||||
})
|
||||
<\/script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>{{ error.statusCode }}</h1>
|
||||
<NuxtLink to="/">Go back home</NuxtLink>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
`
|
||||
});
|
||||
|
||||
const layer = ({ name, nuxtOptions }) => {
|
||||
return {
|
||||
path: resolve(nuxtOptions.rootDir, `layers/${name}/nuxt.config.ts`),
|
||||
contents: `
|
||||
export default defineNuxtConfig({})
|
||||
`
|
||||
};
|
||||
};
|
||||
|
||||
const layout = ({ name, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.dir.layouts, `${name}.vue`),
|
||||
contents: `
|
||||
<script setup lang="ts"><\/script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
Layout: ${name}
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
`
|
||||
});
|
||||
|
||||
const middleware = ({ name, args, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.dir.middleware, `${name}${applySuffix(args, ["global"])}.ts`),
|
||||
contents: `
|
||||
export default defineNuxtRouteMiddleware((to, from) => {})
|
||||
`
|
||||
});
|
||||
|
||||
const module = ({ name, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.rootDir, "modules", `${name}.ts`),
|
||||
contents: `
|
||||
import { defineNuxtModule } from 'nuxt/kit'
|
||||
|
||||
export default defineNuxtModule({
|
||||
meta: {
|
||||
name: '${name}'
|
||||
},
|
||||
setup () {}
|
||||
})
|
||||
`
|
||||
});
|
||||
|
||||
const page = ({ name, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.dir.pages, `${name}.vue`),
|
||||
contents: `
|
||||
<script setup lang="ts"><\/script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
Page: ${name}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
`
|
||||
});
|
||||
|
||||
const plugin = ({ name, args, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.dir.plugins, `${name}${applySuffix(args, ["client", "server"], "mode")}.ts`),
|
||||
contents: `
|
||||
export default defineNuxtPlugin(nuxtApp => {})
|
||||
`
|
||||
});
|
||||
|
||||
const serverMiddleware = ({ name, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.serverDir, "middleware", `${name}.ts`),
|
||||
contents: `
|
||||
export default defineEventHandler(event => {})
|
||||
`
|
||||
});
|
||||
|
||||
const serverPlugin = ({ name, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.serverDir, "plugins", `${name}.ts`),
|
||||
contents: `
|
||||
export default defineNitroPlugin(nitroApp => {})
|
||||
`
|
||||
});
|
||||
|
||||
const serverRoute = ({ name, args, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.serverDir, args.api ? "api" : "routes", `${name}.ts`),
|
||||
contents: `
|
||||
export default defineEventHandler(event => {})
|
||||
`
|
||||
});
|
||||
|
||||
const serverUtil = ({ name, nuxtOptions }) => ({
|
||||
path: resolve(nuxtOptions.srcDir, nuxtOptions.serverDir, "utils", `${name}.ts`),
|
||||
contents: `
|
||||
export function ${camelCase(name)}() {}
|
||||
`
|
||||
});
|
||||
|
||||
const templates = {
|
||||
"api": api,
|
||||
"app": app,
|
||||
"app-config": appConfig,
|
||||
"component": component,
|
||||
"composable": composable,
|
||||
"error": error,
|
||||
"layer": layer,
|
||||
"layout": layout,
|
||||
"middleware": middleware,
|
||||
"module": module,
|
||||
"page": page,
|
||||
"plugin": plugin,
|
||||
"server-middleware": serverMiddleware,
|
||||
"server-plugin": serverPlugin,
|
||||
"server-route": serverRoute,
|
||||
"server-util": serverUtil
|
||||
};
|
||||
function applySuffix(args, suffixes, unwrapFrom) {
|
||||
let suffix = "";
|
||||
for (const s of suffixes) {
|
||||
if (args[s]) {
|
||||
suffix += `.${s}`;
|
||||
}
|
||||
}
|
||||
if (unwrapFrom && args[unwrapFrom] && suffixes.includes(args[unwrapFrom])) {
|
||||
suffix += `.${args[unwrapFrom]}`;
|
||||
}
|
||||
return suffix;
|
||||
}
|
||||
|
||||
const templateNames = Object.keys(templates);
|
||||
const add = defineCommand({
|
||||
meta: {
|
||||
name: "add",
|
||||
description: "Create a new template file."
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
force: {
|
||||
type: "boolean",
|
||||
description: "Force override file if it already exists",
|
||||
default: false
|
||||
},
|
||||
template: {
|
||||
type: "positional",
|
||||
required: true,
|
||||
valueHint: templateNames.join("|"),
|
||||
description: `Specify which template to generate`
|
||||
},
|
||||
name: {
|
||||
type: "positional",
|
||||
required: true,
|
||||
description: "Specify name of the generated file"
|
||||
}
|
||||
},
|
||||
async run(ctx) {
|
||||
const cwd = resolve(ctx.args.cwd);
|
||||
const templateName = ctx.args.template;
|
||||
if (!templateNames.includes(templateName)) {
|
||||
logger.error(
|
||||
`Template ${templateName} is not supported. Possible values: ${Object.keys(
|
||||
templates
|
||||
).join(", ")}`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const ext = extname(ctx.args.name);
|
||||
const name = ext === ".vue" || ext === ".ts" ? ctx.args.name.replace(ext, "") : ctx.args.name;
|
||||
if (!name) {
|
||||
logger.error("name argument is missing!");
|
||||
process.exit(1);
|
||||
}
|
||||
const kit = await loadKit(cwd);
|
||||
const config = await kit.loadNuxtConfig({ cwd });
|
||||
const template = templates[templateName];
|
||||
const res = template({ name, args: ctx.args, nuxtOptions: config });
|
||||
if (!ctx.args.force && existsSync(res.path)) {
|
||||
logger.error(
|
||||
`File exists: ${res.path} . Use --force to override or use a different name.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const parentDir = dirname(res.path);
|
||||
if (!existsSync(parentDir)) {
|
||||
logger.info("Creating directory", parentDir);
|
||||
if (templateName === "page") {
|
||||
logger.info("This enables vue-router functionality!");
|
||||
}
|
||||
await promises.mkdir(parentDir, { recursive: true });
|
||||
}
|
||||
await promises.writeFile(res.path, `${res.contents.trim()}
|
||||
`);
|
||||
logger.info(`\u{1FA84} Generated a new ${templateName} in ${res.path}`);
|
||||
}
|
||||
});
|
||||
|
||||
export { add as default };
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
import { promises } from 'node:fs';
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { defu } from 'defu';
|
||||
import { createApp, lazyEventHandler, eventHandler, toNodeListener } from 'h3';
|
||||
import { listen } from 'listhen';
|
||||
import { resolve, join } from 'pathe';
|
||||
import { o as overrideEnv } from '../shared/cli.BEUGgaW4.mjs';
|
||||
import { c as clearDir } from '../shared/cli.pLQ0oPGc.mjs';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { e as extendsArgs, d as dotEnvArgs, l as legacyRootDirArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:url';
|
||||
import 'exsolve';
|
||||
import 'consola';
|
||||
import 'node:path';
|
||||
import 'std-env';
|
||||
|
||||
const analyze = defineCommand({
|
||||
meta: {
|
||||
name: "analyze",
|
||||
description: "Build nuxt and analyze production bundle (experimental)"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
...legacyRootDirArgs,
|
||||
...dotEnvArgs,
|
||||
...extendsArgs,
|
||||
name: {
|
||||
type: "string",
|
||||
description: "Name of the analysis",
|
||||
default: "default",
|
||||
valueHint: "name"
|
||||
},
|
||||
serve: {
|
||||
type: "boolean",
|
||||
description: "Serve the analysis results",
|
||||
negativeDescription: "Skip serving the analysis results",
|
||||
default: true
|
||||
}
|
||||
},
|
||||
async run(ctx) {
|
||||
overrideEnv("production");
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const name = ctx.args.name || "default";
|
||||
const slug = name.trim().replace(/[^\w-]/g, "_");
|
||||
const startTime = Date.now();
|
||||
const { loadNuxt, buildNuxt } = await loadKit(cwd);
|
||||
const nuxt = await loadNuxt({
|
||||
cwd,
|
||||
dotenv: {
|
||||
cwd,
|
||||
fileName: ctx.args.dotenv
|
||||
},
|
||||
overrides: defu(ctx.data?.overrides, {
|
||||
...ctx.args.extends && { extends: ctx.args.extends },
|
||||
build: {
|
||||
analyze: {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
vite: {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
chunkFileNames: "_nuxt/[name].js",
|
||||
entryFileNames: "_nuxt/[name].js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
logLevel: ctx.args.logLevel
|
||||
})
|
||||
});
|
||||
const analyzeDir = nuxt.options.analyzeDir;
|
||||
const buildDir = nuxt.options.buildDir;
|
||||
const outDir = nuxt.options.nitro.output?.dir || join(nuxt.options.rootDir, ".output");
|
||||
nuxt.options.build.analyze = defu(nuxt.options.build.analyze, {
|
||||
filename: join(analyzeDir, "client.html")
|
||||
});
|
||||
await clearDir(analyzeDir);
|
||||
await buildNuxt(nuxt);
|
||||
const endTime = Date.now();
|
||||
const meta = {
|
||||
name,
|
||||
slug,
|
||||
startTime,
|
||||
endTime,
|
||||
analyzeDir,
|
||||
buildDir,
|
||||
outDir
|
||||
};
|
||||
await nuxt.callHook("build:analyze:done", meta);
|
||||
await promises.writeFile(
|
||||
join(analyzeDir, "meta.json"),
|
||||
JSON.stringify(meta, null, 2),
|
||||
"utf-8"
|
||||
);
|
||||
logger.info(`Analyze results are available at: \`${analyzeDir}\``);
|
||||
logger.warn("Do not deploy analyze results! Use `nuxi build` before deploying.");
|
||||
if (ctx.args.serve !== false && !process.env.CI) {
|
||||
const app = createApp();
|
||||
const serveFile = (filePath) => lazyEventHandler(async () => {
|
||||
const contents = await promises.readFile(filePath, "utf-8");
|
||||
return eventHandler((event) => {
|
||||
event.node.res.end(contents);
|
||||
});
|
||||
});
|
||||
logger.info("Starting stats server...");
|
||||
app.use("/client", serveFile(join(analyzeDir, "client.html")));
|
||||
app.use("/nitro", serveFile(join(analyzeDir, "nitro.html")));
|
||||
app.use(
|
||||
eventHandler(
|
||||
() => `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Nuxt Bundle Stats (experimental)</title>
|
||||
</head>
|
||||
<h1>Nuxt Bundle Stats (experimental)</h1>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/nitro">Nitro server bundle stats</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/client">Client bundle stats</a>
|
||||
</li>
|
||||
</ul>
|
||||
</html>
|
||||
`
|
||||
)
|
||||
);
|
||||
await listen(toNodeListener(app));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export { analyze as default };
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { resolve, relative } from 'pathe';
|
||||
import { s as showVersions } from '../shared/cli.Dz2be-Ai.mjs';
|
||||
import { o as overrideEnv } from '../shared/cli.BEUGgaW4.mjs';
|
||||
import { a as clearBuildDir } from '../shared/cli.pLQ0oPGc.mjs';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { l as legacyRootDirArgs, e as extendsArgs, b as envNameArgs, d as dotEnvArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:fs';
|
||||
import 'consola/utils';
|
||||
import 'exsolve';
|
||||
import 'node:url';
|
||||
import 'consola';
|
||||
import 'node:path';
|
||||
import 'std-env';
|
||||
|
||||
const buildCommand = defineCommand({
|
||||
meta: {
|
||||
name: "build",
|
||||
description: "Build Nuxt for production deployment"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
prerender: {
|
||||
type: "boolean",
|
||||
description: "Build Nuxt and prerender static routes"
|
||||
},
|
||||
preset: {
|
||||
type: "string",
|
||||
description: "Nitro server preset"
|
||||
},
|
||||
...dotEnvArgs,
|
||||
...envNameArgs,
|
||||
...extendsArgs,
|
||||
...legacyRootDirArgs
|
||||
},
|
||||
async run(ctx) {
|
||||
overrideEnv("production");
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
showVersions(cwd);
|
||||
const kit = await loadKit(cwd);
|
||||
const nuxt = await kit.loadNuxt({
|
||||
cwd,
|
||||
dotenv: {
|
||||
cwd,
|
||||
fileName: ctx.args.dotenv
|
||||
},
|
||||
envName: ctx.args.envName,
|
||||
// c12 will fall back to NODE_ENV
|
||||
overrides: {
|
||||
logLevel: ctx.args.logLevel,
|
||||
// TODO: remove in 3.8
|
||||
_generate: ctx.args.prerender,
|
||||
nitro: {
|
||||
static: ctx.args.prerender,
|
||||
preset: ctx.args.preset || process.env.NITRO_PRESET || process.env.SERVER_PRESET
|
||||
},
|
||||
...ctx.args.extends && { extends: ctx.args.extends },
|
||||
...ctx.data?.overrides
|
||||
}
|
||||
});
|
||||
let nitro;
|
||||
try {
|
||||
nitro = kit.useNitro?.();
|
||||
logger.info(`Building for Nitro preset: \`${nitro.options.preset}\``);
|
||||
} catch {
|
||||
}
|
||||
await clearBuildDir(nuxt.options.buildDir);
|
||||
await kit.writeTypes(nuxt);
|
||||
nuxt.hook("build:error", (err) => {
|
||||
logger.error("Nuxt Build Error:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
await kit.buildNuxt(nuxt);
|
||||
if (ctx.args.prerender) {
|
||||
if (!nuxt.options.ssr) {
|
||||
logger.warn(
|
||||
"HTML content not prerendered because `ssr: false` was set. You can read more in `https://nuxt.com/docs/getting-started/deployment#static-hosting`."
|
||||
);
|
||||
}
|
||||
const dir = nitro?.options.output.publicDir;
|
||||
const publicDir = dir ? relative(process.cwd(), dir) : ".output/public";
|
||||
logger.success(
|
||||
`You can now deploy \`${publicDir}\` to any static hosting!`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export { buildCommand as default };
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { defineCommand } from 'citty';
|
||||
import { resolve } from 'pathe';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { c as cleanupNuxtDirs } from '../shared/cli.At9IMXtr.mjs';
|
||||
import { l as legacyRootDirArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:url';
|
||||
import 'exsolve';
|
||||
import 'node:fs';
|
||||
import 'ohash';
|
||||
import '../shared/cli.B9AmABr3.mjs';
|
||||
import 'consola';
|
||||
import '../shared/cli.pLQ0oPGc.mjs';
|
||||
import 'node:path';
|
||||
import 'node:process';
|
||||
import 'std-env';
|
||||
|
||||
const cleanup = defineCommand({
|
||||
meta: {
|
||||
name: "cleanup",
|
||||
description: "Clean up generated Nuxt files and caches"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...legacyRootDirArgs
|
||||
},
|
||||
async run(ctx) {
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const { loadNuxtConfig } = await loadKit(cwd);
|
||||
const nuxtOptions = await loadNuxtConfig({ cwd, overrides: { dev: true } });
|
||||
await cleanupNuxtDirs(nuxtOptions.rootDir, nuxtOptions.buildDir);
|
||||
}
|
||||
});
|
||||
|
||||
export { cleanup as default };
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { resolve } from 'pathe';
|
||||
import { isTest } from 'std-env';
|
||||
import { l as legacyRootDirArgs, d as dotEnvArgs, b as envNameArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:path';
|
||||
import 'consola';
|
||||
import '../shared/cli.B9AmABr3.mjs';
|
||||
import 'node:url';
|
||||
|
||||
const devChild = defineCommand({
|
||||
meta: {
|
||||
name: "_dev",
|
||||
description: "Run Nuxt development server (internal command to start child process)"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
...envNameArgs,
|
||||
...dotEnvArgs,
|
||||
...legacyRootDirArgs,
|
||||
clear: {
|
||||
type: "boolean",
|
||||
description: "Clear console on restart",
|
||||
negativeDescription: "Disable clear console on restart"
|
||||
}
|
||||
},
|
||||
async run(ctx) {
|
||||
if (!process.send && !isTest) {
|
||||
console.warn("`nuxi _dev` is an internal command and should not be used directly. Please use `nuxi dev` instead.");
|
||||
}
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const { initialize } = await import('./index.mjs').then(function (n) { return n.c; });
|
||||
await initialize({ cwd, args: ctx.args }, ctx);
|
||||
}
|
||||
});
|
||||
|
||||
export { devChild as default };
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
import { fork } from 'node:child_process';
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { isSocketSupported } from 'get-port-please';
|
||||
import { createProxyServer } from 'httpxy';
|
||||
import { listen } from 'listhen';
|
||||
import { getArgs, parseArgs } from 'listhen/cli';
|
||||
import { resolve } from 'pathe';
|
||||
import { satisfies } from 'semver';
|
||||
import { isTest, isBun, isDeno } from 'std-env';
|
||||
import { i as initialize, r as resolveLoadingTemplate, a as renderError, b as isSocketURL, p as parseSocketURL } from './index.mjs';
|
||||
import { s as showVersions } from '../shared/cli.Dz2be-Ai.mjs';
|
||||
import { o as overrideEnv } from '../shared/cli.BEUGgaW4.mjs';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { e as extendsArgs, b as envNameArgs, l as legacyRootDirArgs, d as dotEnvArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'defu';
|
||||
import 'node:http';
|
||||
import 'node:events';
|
||||
import 'node:fs';
|
||||
import 'node:fs/promises';
|
||||
import 'node:url';
|
||||
import 'exsolve';
|
||||
import 'h3';
|
||||
import 'perfect-debounce';
|
||||
import 'ufo';
|
||||
import '../shared/cli.pLQ0oPGc.mjs';
|
||||
import '../shared/cli.At9IMXtr.mjs';
|
||||
import 'ohash';
|
||||
import 'youch';
|
||||
import 'consola/utils';
|
||||
import 'consola';
|
||||
import 'node:path';
|
||||
|
||||
const startTime = Date.now();
|
||||
const forkSupported = !isTest && (!isBun || isBunForkSupported());
|
||||
const listhenArgs = getArgs();
|
||||
const command = defineCommand({
|
||||
meta: {
|
||||
name: "dev",
|
||||
description: "Run Nuxt development server"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
...dotEnvArgs,
|
||||
...legacyRootDirArgs,
|
||||
...envNameArgs,
|
||||
...extendsArgs,
|
||||
clear: {
|
||||
type: "boolean",
|
||||
description: "Clear console on restart",
|
||||
negativeDescription: "Disable clear console on restart"
|
||||
},
|
||||
fork: {
|
||||
type: "boolean",
|
||||
description: forkSupported ? "Disable forked mode" : "Enable forked mode",
|
||||
negativeDescription: "Disable forked mode",
|
||||
default: forkSupported,
|
||||
alias: ["f"]
|
||||
},
|
||||
...{
|
||||
...listhenArgs,
|
||||
"port": {
|
||||
...listhenArgs.port,
|
||||
description: "Port to listen on (default: `NUXT_PORT || NITRO_PORT || PORT || nuxtOptions.devServer.port`)",
|
||||
alias: ["p"]
|
||||
},
|
||||
"open": {
|
||||
...listhenArgs.open,
|
||||
alias: ["o"],
|
||||
default: false
|
||||
},
|
||||
"host": {
|
||||
...listhenArgs.host,
|
||||
alias: ["h"],
|
||||
description: "Host to listen on (default: `NUXT_HOST || NITRO_HOST || HOST || nuxtOptions.devServer?.host`)"
|
||||
},
|
||||
"clipboard": { ...listhenArgs.clipboard, default: false },
|
||||
"https.domains": {
|
||||
...listhenArgs["https.domains"],
|
||||
description: "Comma separated list of domains and IPs, the autogenerated certificate should be valid for (https: true)"
|
||||
}
|
||||
},
|
||||
sslCert: {
|
||||
type: "string",
|
||||
description: "(DEPRECATED) Use `--https.cert` instead."
|
||||
},
|
||||
sslKey: {
|
||||
type: "string",
|
||||
description: "(DEPRECATED) Use `--https.key` instead."
|
||||
}
|
||||
},
|
||||
async run(ctx) {
|
||||
overrideEnv("development");
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
showVersions(cwd);
|
||||
const { loadNuxtConfig } = await loadKit(cwd);
|
||||
const nuxtOptions = await loadNuxtConfig({
|
||||
cwd,
|
||||
dotenv: { cwd, fileName: ctx.args.dotenv },
|
||||
envName: ctx.args.envName,
|
||||
// c12 will fall back to NODE_ENV
|
||||
overrides: {
|
||||
dev: true,
|
||||
logLevel: ctx.args.logLevel,
|
||||
...ctx.args.extends && { extends: ctx.args.extends },
|
||||
...ctx.data?.overrides
|
||||
}
|
||||
});
|
||||
const listenOptions = resolveListenOptions(nuxtOptions, ctx.args);
|
||||
if (!ctx.args.fork) {
|
||||
const { listener, close: close2 } = await initialize({
|
||||
cwd,
|
||||
args: ctx.args,
|
||||
hostname: listenOptions.hostname,
|
||||
public: listenOptions.public,
|
||||
publicURLs: void 0,
|
||||
proxy: {
|
||||
https: listenOptions.https
|
||||
}
|
||||
}, { data: ctx.data }, listenOptions);
|
||||
return {
|
||||
listener,
|
||||
async close() {
|
||||
await close2();
|
||||
await listener.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
const devProxy = await createDevProxy(cwd, nuxtOptions, listenOptions);
|
||||
const nuxtSocketEnv = process.env.NUXT_SOCKET ? process.env.NUXT_SOCKET === "1" : void 0;
|
||||
const useSocket = nuxtSocketEnv ?? (nuxtOptions._majorVersion === 4 && await isSocketSupported());
|
||||
const urls = await devProxy.listener.getURLs();
|
||||
const { onRestart, onReady, close } = await initialize({
|
||||
cwd,
|
||||
args: ctx.args,
|
||||
hostname: listenOptions.hostname,
|
||||
public: listenOptions.public,
|
||||
publicURLs: urls.map((r) => r.url),
|
||||
proxy: {
|
||||
url: devProxy.listener.url,
|
||||
urls,
|
||||
https: devProxy.listener.https,
|
||||
addr: devProxy.listener.address
|
||||
}
|
||||
// if running with nuxt v4 or `NUXT_SOCKET=1`, we use the socket listener
|
||||
// otherwise pass 'true' to listen on a random port instead
|
||||
}, {}, useSocket ? void 0 : true);
|
||||
onReady((address) => devProxy.setAddress(address));
|
||||
const fork2 = startSubprocess(cwd, ctx.args, ctx.rawArgs, listenOptions);
|
||||
onRestart(async (devServer) => {
|
||||
const [subprocess] = await Promise.all([
|
||||
fork2,
|
||||
devServer.close().catch(() => {
|
||||
})
|
||||
]);
|
||||
await subprocess.initialize(devProxy, useSocket);
|
||||
});
|
||||
return {
|
||||
listener: devProxy.listener,
|
||||
async close() {
|
||||
await close();
|
||||
const subprocess = await fork2;
|
||||
subprocess.kill(0);
|
||||
await devProxy.listener.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
async function createDevProxy(cwd, nuxtOptions, listenOptions) {
|
||||
let loadingMessage = "Nuxt dev server is starting...";
|
||||
let error;
|
||||
let address;
|
||||
let loadingTemplate = nuxtOptions.devServer.loadingTemplate;
|
||||
const proxy = createProxyServer({});
|
||||
proxy.on("proxyReq", (proxyReq, req) => {
|
||||
if (!proxyReq.hasHeader("x-forwarded-for")) {
|
||||
const address2 = req.socket.remoteAddress;
|
||||
if (address2) {
|
||||
proxyReq.appendHeader("x-forwarded-for", address2);
|
||||
}
|
||||
}
|
||||
if (!proxyReq.hasHeader("x-forwarded-port")) {
|
||||
const localPort = req?.socket?.localPort;
|
||||
if (localPort) {
|
||||
proxyReq.setHeader("x-forwarded-port", req.socket.localPort);
|
||||
}
|
||||
}
|
||||
if (!proxyReq.hasHeader("x-forwarded-Proto")) {
|
||||
const encrypted = req?.connection?.encrypted;
|
||||
proxyReq.setHeader("x-forwarded-proto", encrypted ? "https" : "http");
|
||||
}
|
||||
});
|
||||
const listener = await listen((req, res) => {
|
||||
if (error) {
|
||||
renderError(req, res, error);
|
||||
return;
|
||||
}
|
||||
if (!address) {
|
||||
res.statusCode = 503;
|
||||
res.setHeader("Content-Type", "text/html");
|
||||
res.setHeader("Cache-Control", "no-store");
|
||||
if (loadingTemplate) {
|
||||
res.end(loadingTemplate({ loading: loadingMessage }));
|
||||
return;
|
||||
}
|
||||
async function resolveLoadingMessage() {
|
||||
loadingTemplate = await resolveLoadingTemplate(cwd);
|
||||
res.end(loadingTemplate({ loading: loadingMessage }));
|
||||
}
|
||||
return resolveLoadingMessage();
|
||||
}
|
||||
const target = isSocketURL(address) ? parseSocketURL(address) : address;
|
||||
proxy.web(req, res, { target });
|
||||
}, listenOptions);
|
||||
listener.server.on("upgrade", (req, socket, head) => {
|
||||
if (!address) {
|
||||
if (!socket.destroyed) {
|
||||
socket.end();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const target = isSocketURL(address) ? parseSocketURL(address) : address;
|
||||
return proxy.ws(req, socket, { target, xfwd: true }, head).catch(() => {
|
||||
if (!socket.destroyed) {
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
});
|
||||
return {
|
||||
listener,
|
||||
setAddress: (_addr) => {
|
||||
address = _addr;
|
||||
},
|
||||
setLoadingMessage: (_msg) => {
|
||||
loadingMessage = _msg;
|
||||
},
|
||||
setError: (_error) => {
|
||||
error = _error;
|
||||
},
|
||||
clearError() {
|
||||
error = void 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
async function startSubprocess(cwd, args, rawArgs, listenOptions) {
|
||||
let childProc;
|
||||
let devProxy;
|
||||
let ready;
|
||||
const kill = (signal) => {
|
||||
if (childProc) {
|
||||
childProc.kill(signal === 0 && isDeno ? "SIGTERM" : signal);
|
||||
childProc = void 0;
|
||||
}
|
||||
};
|
||||
async function initialize2(proxy, socket) {
|
||||
devProxy = proxy;
|
||||
const urls = await devProxy.listener.getURLs();
|
||||
await ready;
|
||||
childProc.send({
|
||||
type: "nuxt:internal:dev:context",
|
||||
socket,
|
||||
context: {
|
||||
cwd,
|
||||
args,
|
||||
hostname: listenOptions.hostname,
|
||||
public: listenOptions.public,
|
||||
publicURLs: urls.map((r) => r.url),
|
||||
proxy: {
|
||||
url: devProxy.listener.url,
|
||||
urls,
|
||||
https: devProxy.listener.https
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
async function restart() {
|
||||
devProxy?.clearError();
|
||||
if (process.platform === "win32") {
|
||||
kill("SIGTERM");
|
||||
} else {
|
||||
kill("SIGHUP");
|
||||
}
|
||||
childProc = fork(globalThis.__nuxt_cli__.devEntry, rawArgs, {
|
||||
execArgv: ["--enable-source-maps", process.argv.find((a) => a.includes("--inspect"))].filter(Boolean),
|
||||
env: {
|
||||
...process.env,
|
||||
__NUXT__FORK: "true"
|
||||
}
|
||||
});
|
||||
childProc.on("close", (errorCode) => {
|
||||
if (errorCode) {
|
||||
process.exit(errorCode);
|
||||
}
|
||||
});
|
||||
ready = new Promise((resolve2, reject) => {
|
||||
childProc.on("error", reject);
|
||||
childProc.on("message", (message) => {
|
||||
if (message.type === "nuxt:internal:dev:fork-ready") {
|
||||
resolve2();
|
||||
} else if (message.type === "nuxt:internal:dev:ready") {
|
||||
devProxy.setAddress(message.address);
|
||||
if (startTime) {
|
||||
logger.debug(`Dev server ready for connections in ${Date.now() - startTime}ms`);
|
||||
}
|
||||
} else if (message.type === "nuxt:internal:dev:loading") {
|
||||
devProxy.setAddress(void 0);
|
||||
devProxy.setLoadingMessage(message.message);
|
||||
devProxy.clearError();
|
||||
} else if (message.type === "nuxt:internal:dev:loading:error") {
|
||||
devProxy.setAddress(void 0);
|
||||
devProxy.setError(message.error);
|
||||
} else if (message.type === "nuxt:internal:dev:restart") {
|
||||
restart();
|
||||
} else if (message.type === "nuxt:internal:dev:rejection") {
|
||||
logger.info(`Restarting Nuxt due to error: \`${message.message}\``);
|
||||
restart();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
for (const signal of [
|
||||
"exit",
|
||||
"SIGTERM",
|
||||
"SIGINT",
|
||||
"SIGQUIT"
|
||||
]) {
|
||||
process.once(signal, () => {
|
||||
kill(signal === "exit" ? 0 : signal);
|
||||
});
|
||||
}
|
||||
await restart();
|
||||
return {
|
||||
initialize: initialize2,
|
||||
restart,
|
||||
kill
|
||||
};
|
||||
}
|
||||
function resolveListenOptions(nuxtOptions, args) {
|
||||
const _port = args.port ?? args.p ?? process.env.NUXT_PORT ?? process.env.NITRO_PORT ?? process.env.PORT ?? nuxtOptions.devServer.port;
|
||||
const _hostname = typeof args.host === "string" ? args.host : args.host === true ? "" : process.env.NUXT_HOST ?? process.env.NITRO_HOST ?? process.env.HOST ?? (nuxtOptions.devServer?.host || void 0) ?? void 0;
|
||||
const _public = args.public ?? (_hostname && !["localhost", "127.0.0.1", "::1"].includes(_hostname)) ? true : void 0;
|
||||
const _httpsCert = args["https.cert"] || args.sslCert || process.env.NUXT_SSL_CERT || process.env.NITRO_SSL_CERT || typeof nuxtOptions.devServer.https !== "boolean" && nuxtOptions.devServer.https && "cert" in nuxtOptions.devServer.https && nuxtOptions.devServer.https.cert || "";
|
||||
const _httpsKey = args["https.key"] || args.sslKey || process.env.NUXT_SSL_KEY || process.env.NITRO_SSL_KEY || typeof nuxtOptions.devServer.https !== "boolean" && nuxtOptions.devServer.https && "key" in nuxtOptions.devServer.https && nuxtOptions.devServer.https.key || "";
|
||||
const _httpsPfx = args["https.pfx"] || typeof nuxtOptions.devServer.https !== "boolean" && nuxtOptions.devServer.https && "pfx" in nuxtOptions.devServer.https && nuxtOptions.devServer.https.pfx || "";
|
||||
const _httpsPassphrase = args["https.passphrase"] || typeof nuxtOptions.devServer.https !== "boolean" && nuxtOptions.devServer.https && "passphrase" in nuxtOptions.devServer.https && nuxtOptions.devServer.https.passphrase || "";
|
||||
const httpsEnabled = !!(args.https ?? nuxtOptions.devServer.https);
|
||||
const _listhenOptions = parseArgs({
|
||||
...args,
|
||||
"open": args.o || args.open,
|
||||
"https": httpsEnabled,
|
||||
"https.cert": _httpsCert,
|
||||
"https.key": _httpsKey,
|
||||
"https.pfx": _httpsPfx,
|
||||
"https.passphrase": _httpsPassphrase
|
||||
});
|
||||
const httpsOptions = httpsEnabled && {
|
||||
...nuxtOptions.devServer.https,
|
||||
..._listhenOptions.https
|
||||
};
|
||||
return {
|
||||
..._listhenOptions,
|
||||
port: _port,
|
||||
hostname: _hostname,
|
||||
public: _public,
|
||||
https: httpsOptions,
|
||||
baseURL: nuxtOptions.app.baseURL.startsWith("./") ? nuxtOptions.app.baseURL.slice(1) : nuxtOptions.app.baseURL
|
||||
};
|
||||
}
|
||||
function isBunForkSupported() {
|
||||
const bunVersion = globalThis.Bun.version;
|
||||
return satisfies(bunVersion, ">=1.2");
|
||||
}
|
||||
|
||||
export { command as default };
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { resolve } from 'pathe';
|
||||
import { x } from 'tinyexec';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { l as legacyRootDirArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'consola';
|
||||
import 'node:path';
|
||||
import 'std-env';
|
||||
import 'node:url';
|
||||
|
||||
const devtools = defineCommand({
|
||||
meta: {
|
||||
name: "devtools",
|
||||
description: "Enable or disable devtools in a Nuxt project"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
command: {
|
||||
type: "positional",
|
||||
description: "Command to run",
|
||||
valueHint: "enable|disable"
|
||||
},
|
||||
...legacyRootDirArgs
|
||||
},
|
||||
async run(ctx) {
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
if (!["enable", "disable"].includes(ctx.args.command)) {
|
||||
logger.error(`Unknown command \`${ctx.args.command}\`.`);
|
||||
process.exit(1);
|
||||
}
|
||||
await x(
|
||||
"npx",
|
||||
["@nuxt/devtools-wizard@latest", ctx.args.command, cwd],
|
||||
{
|
||||
throwOnError: true,
|
||||
nodeOptions: {
|
||||
stdio: "inherit",
|
||||
cwd
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export { devtools as default };
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import { defineCommand } from 'citty';
|
||||
import { l as legacyRootDirArgs, e as extendsArgs, b as envNameArgs, d as dotEnvArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import buildCommand from './build.mjs';
|
||||
import 'node:path';
|
||||
import 'node:process';
|
||||
import 'std-env';
|
||||
import 'consola';
|
||||
import '../shared/cli.B9AmABr3.mjs';
|
||||
import 'node:url';
|
||||
import 'pathe';
|
||||
import '../shared/cli.Dz2be-Ai.mjs';
|
||||
import 'node:fs';
|
||||
import 'consola/utils';
|
||||
import 'exsolve';
|
||||
import '../shared/cli.qKvs7FJ2.mjs';
|
||||
import '../shared/cli.BEUGgaW4.mjs';
|
||||
import '../shared/cli.pLQ0oPGc.mjs';
|
||||
|
||||
const generate = defineCommand({
|
||||
meta: {
|
||||
name: "generate",
|
||||
description: "Build Nuxt and prerender all routes"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
preset: {
|
||||
type: "string",
|
||||
description: "Nitro server preset"
|
||||
},
|
||||
...dotEnvArgs,
|
||||
...envNameArgs,
|
||||
...extendsArgs,
|
||||
...legacyRootDirArgs
|
||||
},
|
||||
async run(ctx) {
|
||||
ctx.args.prerender = true;
|
||||
await buildCommand.run(
|
||||
// @ts-expect-error types do not match
|
||||
ctx
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export { generate as default };
|
||||
+466
@@ -0,0 +1,466 @@
|
||||
import process from 'node:process';
|
||||
import defu from 'defu';
|
||||
import { listen } from 'listhen';
|
||||
import { Server } from 'node:http';
|
||||
import { getSocketAddress, cleanSocket } from 'get-port-please';
|
||||
import EventEmitter from 'node:events';
|
||||
import { watch, existsSync } from 'node:fs';
|
||||
import { mkdir } from 'node:fs/promises';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { resolveModulePath } from 'exsolve';
|
||||
import { toNodeListener } from 'h3';
|
||||
import { resolve } from 'pathe';
|
||||
import { debounce } from 'perfect-debounce';
|
||||
import { provider } from 'std-env';
|
||||
import { joinURL } from 'ufo';
|
||||
import { a as clearBuildDir } from '../shared/cli.pLQ0oPGc.mjs';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as loadNuxtManifest, r as resolveNuxtManifest, w as writeNuxtManifest } from '../shared/cli.At9IMXtr.mjs';
|
||||
import { Youch } from 'youch';
|
||||
|
||||
function formatSocketURL(socketPath, ssl = false) {
|
||||
const protocol = ssl ? "https" : "http";
|
||||
const encodedPath = process.platform === "win32" ? encodeURIComponent(socketPath) : socketPath.replace(/\//g, "%2F");
|
||||
return `${protocol}+unix://${encodedPath}`;
|
||||
}
|
||||
function isSocketURL(url) {
|
||||
return url.startsWith("http+unix://") || url.startsWith("https+unix://");
|
||||
}
|
||||
function parseSocketURL(url) {
|
||||
if (!isSocketURL(url)) {
|
||||
throw new Error(`Invalid socket URL: ${url}`);
|
||||
}
|
||||
const ssl = url.startsWith("https+unix://");
|
||||
const path = url.slice(ssl ? "https+unix://".length : "http+unix://".length);
|
||||
const socketPath = decodeURIComponent(path.replace(/%2F/g, "/"));
|
||||
return { socketPath, protocol: ssl ? "https" : "http" };
|
||||
}
|
||||
async function createSocketListener(handler, proxyAddress) {
|
||||
const socketPath = getSocketAddress({
|
||||
name: "nuxt-dev",
|
||||
random: true
|
||||
});
|
||||
const server = new Server(handler);
|
||||
await cleanSocket(socketPath);
|
||||
await new Promise((resolve) => server.listen({ path: socketPath }, resolve));
|
||||
const url = formatSocketURL(socketPath);
|
||||
return {
|
||||
url,
|
||||
address: { address: "localhost", port: 3e3, ...proxyAddress, socketPath },
|
||||
async close() {
|
||||
try {
|
||||
server.removeAllListeners();
|
||||
await new Promise((resolve, reject) => server.close((err) => err ? reject(err) : resolve()));
|
||||
} finally {
|
||||
await cleanSocket(socketPath);
|
||||
}
|
||||
},
|
||||
getURLs: async () => [{ url, type: "network" }],
|
||||
https: false,
|
||||
server
|
||||
};
|
||||
}
|
||||
|
||||
async function renderError(req, res, error) {
|
||||
const youch = new Youch();
|
||||
res.statusCode = 500;
|
||||
res.setHeader("Content-Type", "text/html");
|
||||
const html = await youch.toHTML(error, {
|
||||
request: {
|
||||
url: req.url,
|
||||
method: req.method,
|
||||
headers: req.headers
|
||||
}
|
||||
});
|
||||
res.end(html);
|
||||
}
|
||||
|
||||
const RESTART_RE = /^(?:nuxt\.config\.[a-z0-9]+|\.nuxtignore|\.nuxtrc|\.config\/nuxt(?:\.config)?\.[a-z0-9]+)$/;
|
||||
class NuxtDevServer extends EventEmitter {
|
||||
constructor(options) {
|
||||
super();
|
||||
this.options = options;
|
||||
this.loadDebounced = debounce(this.load);
|
||||
let _initResolve;
|
||||
const _initPromise = new Promise((resolve2) => {
|
||||
_initResolve = resolve2;
|
||||
});
|
||||
this.once("ready", () => {
|
||||
_initResolve();
|
||||
});
|
||||
this.cwd = options.cwd;
|
||||
this.handler = async (req, res) => {
|
||||
if (this._loadingError) {
|
||||
this._renderError(req, res);
|
||||
return;
|
||||
}
|
||||
await _initPromise;
|
||||
if (this._handler) {
|
||||
this._handler(req, res);
|
||||
} else {
|
||||
this._renderLoadingScreen(req, res);
|
||||
}
|
||||
};
|
||||
this.listener = void 0;
|
||||
}
|
||||
_handler;
|
||||
_distWatcher;
|
||||
_configWatcher;
|
||||
_currentNuxt;
|
||||
_loadingMessage;
|
||||
_loadingError;
|
||||
cwd;
|
||||
loadDebounced;
|
||||
handler;
|
||||
listener;
|
||||
_renderError(req, res) {
|
||||
renderError(req, res, this._loadingError);
|
||||
}
|
||||
async _renderLoadingScreen(req, res) {
|
||||
res.statusCode = 503;
|
||||
res.setHeader("Content-Type", "text/html");
|
||||
const loadingTemplate = this.options.loadingTemplate || this._currentNuxt?.options.devServer.loadingTemplate || await resolveLoadingTemplate(this.cwd);
|
||||
res.end(
|
||||
loadingTemplate({
|
||||
loading: this._loadingMessage || "Loading..."
|
||||
})
|
||||
);
|
||||
}
|
||||
async init() {
|
||||
await this.load();
|
||||
this._watchConfig();
|
||||
}
|
||||
closeWatchers() {
|
||||
this._distWatcher?.close();
|
||||
this._configWatcher?.();
|
||||
}
|
||||
async load(reload, reason) {
|
||||
try {
|
||||
await this._load(reload, reason);
|
||||
this._loadingError = void 0;
|
||||
} catch (error) {
|
||||
console.error(`Cannot ${reload ? "restart" : "start"} nuxt: `, error);
|
||||
this._handler = void 0;
|
||||
this._loadingError = error;
|
||||
this._loadingMessage = "Error while loading Nuxt. Please check console and fix errors.";
|
||||
this.emit("loading:error", error);
|
||||
}
|
||||
}
|
||||
async close() {
|
||||
if (this._currentNuxt) {
|
||||
await this._currentNuxt.close();
|
||||
}
|
||||
}
|
||||
async _load(reload, reason) {
|
||||
const action = reload ? "Restarting" : "Starting";
|
||||
this._loadingMessage = `${reason ? `${reason}. ` : ""}${action} Nuxt...`;
|
||||
this._handler = void 0;
|
||||
this.emit("loading", this._loadingMessage);
|
||||
if (reload) {
|
||||
console.info(this._loadingMessage);
|
||||
}
|
||||
await this.close();
|
||||
const kit = await loadKit(this.options.cwd);
|
||||
const devServerDefaults = resolveDevServerDefaults({}, await this.listener.getURLs().then((r) => r.map((r2) => r2.url)));
|
||||
this._currentNuxt = await kit.loadNuxt({
|
||||
cwd: this.options.cwd,
|
||||
dev: true,
|
||||
ready: false,
|
||||
envName: this.options.envName,
|
||||
dotenv: {
|
||||
cwd: this.options.cwd,
|
||||
fileName: this.options.dotenv.fileName
|
||||
},
|
||||
defaults: defu(this.options.defaults, devServerDefaults),
|
||||
overrides: {
|
||||
logLevel: this.options.logLevel,
|
||||
...this.options.overrides,
|
||||
vite: {
|
||||
clearScreen: this.options.clear,
|
||||
...this.options.overrides.vite
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!process.env.NUXI_DISABLE_VITE_HMR) {
|
||||
this._currentNuxt.hooks.hook("vite:extend", ({ config }) => {
|
||||
if (config.server) {
|
||||
config.server.hmr = {
|
||||
protocol: void 0,
|
||||
...config.server.hmr,
|
||||
port: void 0,
|
||||
host: void 0,
|
||||
server: this.listener.server
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
this._currentNuxt.hooks.hookOnce("close", () => {
|
||||
this.listener.server.removeAllListeners("upgrade");
|
||||
});
|
||||
if (!reload) {
|
||||
const previousManifest = await loadNuxtManifest(this._currentNuxt.options.buildDir);
|
||||
const newManifest = resolveNuxtManifest(this._currentNuxt);
|
||||
const promise = writeNuxtManifest(this._currentNuxt, newManifest);
|
||||
this._currentNuxt.hooks.hookOnce("ready", async () => {
|
||||
await promise;
|
||||
});
|
||||
if (previousManifest && newManifest && previousManifest._hash !== newManifest._hash) {
|
||||
await clearBuildDir(this._currentNuxt.options.buildDir);
|
||||
}
|
||||
}
|
||||
await this._currentNuxt.ready();
|
||||
const unsub = this._currentNuxt.hooks.hook("restart", async (options) => {
|
||||
unsub();
|
||||
if (options?.hard) {
|
||||
this.emit("restart");
|
||||
return;
|
||||
}
|
||||
await this.load(true);
|
||||
});
|
||||
if (this._currentNuxt.server && "upgrade" in this._currentNuxt.server) {
|
||||
this.listener.server.on("upgrade", (req, socket, head) => {
|
||||
const nuxt = this._currentNuxt;
|
||||
if (!nuxt || !nuxt.server)
|
||||
return;
|
||||
const viteHmrPath = joinURL(
|
||||
nuxt.options.app.baseURL.startsWith("./") ? nuxt.options.app.baseURL.slice(1) : nuxt.options.app.baseURL,
|
||||
nuxt.options.app.buildAssetsDir
|
||||
);
|
||||
if (req.url?.startsWith(viteHmrPath)) {
|
||||
return;
|
||||
}
|
||||
nuxt.server.upgrade(req, socket, head);
|
||||
});
|
||||
}
|
||||
await this._currentNuxt.hooks.callHook("listen", this.listener.server, this.listener);
|
||||
const addr = this.listener.address;
|
||||
this._currentNuxt.options.devServer.host = addr.address;
|
||||
this._currentNuxt.options.devServer.port = addr.port;
|
||||
this._currentNuxt.options.devServer.url = getAddressURL(addr, !!this.listener.https);
|
||||
this._currentNuxt.options.devServer.https = this.options.devContext.proxy?.https;
|
||||
if (this.listener.https && !process.env.NODE_TLS_REJECT_UNAUTHORIZED) {
|
||||
console.warn("You might need `NODE_TLS_REJECT_UNAUTHORIZED=0` environment variable to make https work.");
|
||||
}
|
||||
await Promise.all([
|
||||
kit.writeTypes(this._currentNuxt).catch(console.error),
|
||||
kit.buildNuxt(this._currentNuxt)
|
||||
]);
|
||||
if (!this._currentNuxt.server) {
|
||||
throw new Error("Nitro server has not been initialized.");
|
||||
}
|
||||
const distDir = resolve(this._currentNuxt.options.buildDir, "dist");
|
||||
await mkdir(distDir, { recursive: true });
|
||||
this._distWatcher = watch(distDir);
|
||||
this._distWatcher.on("change", () => {
|
||||
this.loadDebounced(true, ".nuxt/dist directory has been removed");
|
||||
});
|
||||
this._handler = toNodeListener(this._currentNuxt.server.app);
|
||||
this.emit("ready", "socketPath" in addr ? formatSocketURL(addr.socketPath, !!this.listener.https) : `http://127.0.0.1:${addr.port}`);
|
||||
}
|
||||
_watchConfig() {
|
||||
this._configWatcher = createConfigWatcher(
|
||||
this.cwd,
|
||||
this.options.dotenv.fileName,
|
||||
() => this.emit("restart"),
|
||||
(file) => this.loadDebounced(true, `${file} updated`)
|
||||
);
|
||||
}
|
||||
}
|
||||
function getAddressURL(addr, https) {
|
||||
const proto = https ? "https" : "http";
|
||||
let host = addr.address.includes(":") ? `[${addr.address}]` : addr.address;
|
||||
if (host === "[::]") {
|
||||
host = "localhost";
|
||||
}
|
||||
const port = addr.port || 3e3;
|
||||
return `${proto}://${host}:${port}/`;
|
||||
}
|
||||
function resolveDevServerOverrides(listenOptions) {
|
||||
if (listenOptions.public || provider === "codesandbox") {
|
||||
return {
|
||||
devServer: { cors: { origin: "*" } },
|
||||
vite: { server: { allowedHosts: true } }
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
function resolveDevServerDefaults(listenOptions, urls = []) {
|
||||
const defaultConfig = {};
|
||||
if (urls) {
|
||||
defaultConfig.vite = {
|
||||
server: {
|
||||
allowedHosts: urls.filter((u) => !isSocketURL(u)).map((u) => new URL(u).hostname)
|
||||
}
|
||||
};
|
||||
}
|
||||
if (listenOptions.hostname) {
|
||||
const protocol = listenOptions.https ? "https" : "http";
|
||||
defaultConfig.devServer = { cors: { origin: [`${protocol}://${listenOptions.hostname}`, ...urls] } };
|
||||
defaultConfig.vite = defu(defaultConfig.vite, { server: { allowedHosts: [listenOptions.hostname] } });
|
||||
}
|
||||
return defaultConfig;
|
||||
}
|
||||
function createConfigWatcher(cwd, dotenvFileName = ".env", onRestart, onReload) {
|
||||
const configWatcher = watch(cwd);
|
||||
let configDirWatcher = existsSync(resolve(cwd, ".config")) ? createConfigDirWatcher(cwd, onReload) : void 0;
|
||||
const dotenvFileNames = new Set(Array.isArray(dotenvFileName) ? dotenvFileName : [dotenvFileName]);
|
||||
configWatcher.on("change", (_event, file) => {
|
||||
if (dotenvFileNames.has(file)) {
|
||||
onRestart();
|
||||
}
|
||||
if (RESTART_RE.test(file)) {
|
||||
onReload(file);
|
||||
}
|
||||
if (file === ".config") {
|
||||
configDirWatcher ||= createConfigDirWatcher(cwd, onReload);
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
configWatcher.close();
|
||||
configDirWatcher?.();
|
||||
};
|
||||
}
|
||||
function createConfigDirWatcher(cwd, onReload) {
|
||||
const configDir = resolve(cwd, ".config");
|
||||
const configDirWatcher = watch(configDir);
|
||||
configDirWatcher.on("change", (_event, file) => {
|
||||
if (RESTART_RE.test(file)) {
|
||||
onReload(file);
|
||||
}
|
||||
});
|
||||
return () => configDirWatcher.close();
|
||||
}
|
||||
async function resolveLoadingTemplate(cwd) {
|
||||
const nuxtPath = resolveModulePath("nuxt", { from: cwd, try: true });
|
||||
const uiTemplatesPath = resolveModulePath("@nuxt/ui-templates", { from: nuxtPath || cwd });
|
||||
const r = await import(pathToFileURL(uiTemplatesPath).href);
|
||||
return r.loading || ((params) => `<h2>${params.loading}</h2>`);
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
process.env.NODE_ENV = "development";
|
||||
class IPC {
|
||||
enabled = !!process.send && !process.title?.includes("vitest") && process.env.__NUXT__FORK;
|
||||
constructor() {
|
||||
if (this.enabled) {
|
||||
process.once("unhandledRejection", (reason) => {
|
||||
this.send({ type: "nuxt:internal:dev:rejection", message: reason instanceof Error ? reason.toString() : "Unhandled Rejection" });
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
process.on("message", (message) => {
|
||||
if (message.type === "nuxt:internal:dev:context") {
|
||||
initialize(message.context, {}, message.socket ? void 0 : true);
|
||||
}
|
||||
});
|
||||
this.send({ type: "nuxt:internal:dev:fork-ready" });
|
||||
}
|
||||
send(message) {
|
||||
if (this.enabled) {
|
||||
process.send?.(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
const ipc = new IPC();
|
||||
async function initialize(devContext, ctx = {}, _listenOptions) {
|
||||
const devServerOverrides = resolveDevServerOverrides({
|
||||
public: devContext.public
|
||||
});
|
||||
const devServerDefaults = resolveDevServerDefaults({
|
||||
hostname: devContext.hostname,
|
||||
https: devContext.proxy?.https
|
||||
}, devContext.publicURLs);
|
||||
const devServer = new NuxtDevServer({
|
||||
cwd: devContext.cwd,
|
||||
overrides: defu(
|
||||
ctx.data?.overrides,
|
||||
{ extends: devContext.args.extends },
|
||||
devServerOverrides
|
||||
),
|
||||
defaults: devServerDefaults,
|
||||
logLevel: devContext.args.logLevel,
|
||||
clear: !!devContext.args.clear,
|
||||
dotenv: { cwd: devContext.cwd, fileName: devContext.args.dotenv },
|
||||
envName: devContext.args.envName,
|
||||
devContext: {
|
||||
proxy: devContext.proxy
|
||||
}
|
||||
});
|
||||
const listenOptions = _listenOptions === true || process.env._PORT ? { port: process.env._PORT ?? 0, hostname: "127.0.0.1", showURL: false } : _listenOptions;
|
||||
devServer.listener = listenOptions ? await listen(devServer.handler, listenOptions) : await createSocketListener(devServer.handler, devContext.proxy?.addr);
|
||||
if (process.env.DEBUG) {
|
||||
console.debug(`Using ${listenOptions ? "network" : "socket"} listener for Nuxt dev server.`);
|
||||
}
|
||||
devServer.listener._url = devServer.listener.url;
|
||||
if (devContext.proxy?.url) {
|
||||
devServer.listener.url = devContext.proxy.url;
|
||||
}
|
||||
if (devContext.proxy?.urls) {
|
||||
const _getURLs = devServer.listener.getURLs.bind(devServer.listener);
|
||||
devServer.listener.getURLs = async () => Array.from(/* @__PURE__ */ new Set([...devContext.proxy?.urls || [], ...await _getURLs()]));
|
||||
}
|
||||
let address;
|
||||
if (ipc.enabled) {
|
||||
devServer.on("loading:error", (_error) => {
|
||||
ipc.send({
|
||||
type: "nuxt:internal:dev:loading:error",
|
||||
error: {
|
||||
message: _error.message,
|
||||
stack: _error.stack,
|
||||
name: _error.name,
|
||||
code: "code" in _error ? _error.code : void 0
|
||||
}
|
||||
});
|
||||
});
|
||||
devServer.on("loading", (message) => {
|
||||
ipc.send({ type: "nuxt:internal:dev:loading", message });
|
||||
});
|
||||
devServer.on("restart", () => {
|
||||
ipc.send({ type: "nuxt:internal:dev:restart" });
|
||||
});
|
||||
devServer.on("ready", (payload) => {
|
||||
ipc.send({ type: "nuxt:internal:dev:ready", address: payload });
|
||||
});
|
||||
} else {
|
||||
devServer.on("ready", (payload) => {
|
||||
address = payload;
|
||||
});
|
||||
}
|
||||
await devServer.init();
|
||||
if (process.env.DEBUG) {
|
||||
console.debug(`Dev server (internal) initialized in ${Date.now() - start}ms`);
|
||||
}
|
||||
return {
|
||||
listener: devServer.listener,
|
||||
close: async () => {
|
||||
devServer.closeWatchers();
|
||||
await devServer.close();
|
||||
},
|
||||
onReady: (callback) => {
|
||||
if (address) {
|
||||
callback(address);
|
||||
} else {
|
||||
devServer.once("ready", (payload) => callback(payload));
|
||||
}
|
||||
},
|
||||
onRestart: (callback) => {
|
||||
let restarted = false;
|
||||
function restart() {
|
||||
if (!restarted) {
|
||||
restarted = true;
|
||||
callback(devServer);
|
||||
}
|
||||
}
|
||||
devServer.once("restart", restart);
|
||||
process.once("uncaughtException", restart);
|
||||
process.once("unhandledRejection", restart);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const index = {
|
||||
__proto__: null,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
export { renderError as a, isSocketURL as b, index as c, initialize as i, parseSocketURL as p, resolveLoadingTemplate as r };
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { defineCommand } from 'citty';
|
||||
|
||||
const index = defineCommand({
|
||||
meta: {
|
||||
name: "module",
|
||||
description: "Manage Nuxt modules"
|
||||
},
|
||||
args: {},
|
||||
subCommands: {
|
||||
add: () => import('./add.mjs').then((r) => r.default || r),
|
||||
search: () => import('./search.mjs').then((r) => r.default || r)
|
||||
}
|
||||
});
|
||||
|
||||
export { index as default };
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
import os from 'node:os';
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import clipboardy from 'clipboardy';
|
||||
import { detectPackageManager } from 'nypm';
|
||||
import { resolve } from 'pathe';
|
||||
import { readPackageJSON } from 'pkg-types';
|
||||
import { splitByCase } from 'scule';
|
||||
import { isMinimal } from 'std-env';
|
||||
import { v as version } from '../shared/cli.DhJ3cH8w.mjs';
|
||||
import { t as tryResolveNuxt } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { g as getPackageManagerVersion } from '../shared/cli.BSm0_9Hr.mjs';
|
||||
import { l as legacyRootDirArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:url';
|
||||
import 'exsolve';
|
||||
import 'consola';
|
||||
import 'node:child_process';
|
||||
import 'node:path';
|
||||
|
||||
const info = defineCommand({
|
||||
meta: {
|
||||
name: "info",
|
||||
description: "Get information about Nuxt project"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...legacyRootDirArgs
|
||||
},
|
||||
async run(ctx) {
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const nuxtConfig = await getNuxtConfig(cwd);
|
||||
const { dependencies = {}, devDependencies = {} } = await readPackageJSON(cwd).catch(() => ({}));
|
||||
const nuxtPath = tryResolveNuxt(cwd);
|
||||
async function getDepVersion(name) {
|
||||
for (const url of [cwd, nuxtPath]) {
|
||||
if (!url) {
|
||||
continue;
|
||||
}
|
||||
const pkg = await readPackageJSON(name, { url }).catch(() => null);
|
||||
if (pkg) {
|
||||
return pkg.version;
|
||||
}
|
||||
}
|
||||
return dependencies[name] || devDependencies[name];
|
||||
}
|
||||
async function listModules(arr = []) {
|
||||
const info = [];
|
||||
for (let m of arr) {
|
||||
if (Array.isArray(m)) {
|
||||
m = m[0];
|
||||
}
|
||||
const name = normalizeConfigModule(m, cwd);
|
||||
if (name) {
|
||||
const npmName = name.split("/").splice(0, 2).join("/");
|
||||
const v = await getDepVersion(npmName);
|
||||
info.push(`\`${v ? `${name}@${v}` : name}\``);
|
||||
}
|
||||
}
|
||||
return info.join(", ");
|
||||
}
|
||||
const nuxtVersion = await getDepVersion("nuxt") || await getDepVersion("nuxt-nightly") || await getDepVersion("nuxt-edge") || await getDepVersion("nuxt3") || "-";
|
||||
const isLegacy = nuxtVersion.startsWith("2");
|
||||
const builder = !isLegacy ? nuxtConfig.builder || "-" : nuxtConfig.bridge?.vite ? "vite" : nuxtConfig.buildModules?.includes("nuxt-vite") ? "vite" : "webpack";
|
||||
let packageManager = (await detectPackageManager(cwd))?.name;
|
||||
if (packageManager) {
|
||||
packageManager += `@${getPackageManagerVersion(packageManager)}`;
|
||||
}
|
||||
const infoObj = {
|
||||
OperatingSystem: os.type(),
|
||||
NodeVersion: process.version,
|
||||
NuxtVersion: nuxtVersion,
|
||||
CLIVersion: version,
|
||||
NitroVersion: await getDepVersion("nitropack"),
|
||||
PackageManager: packageManager ?? "unknown",
|
||||
Builder: typeof builder === "string" ? builder : "custom",
|
||||
UserConfig: Object.keys(nuxtConfig).map((key) => `\`${key}\``).join(", "),
|
||||
RuntimeModules: await listModules(nuxtConfig.modules),
|
||||
BuildModules: await listModules(nuxtConfig.buildModules || [])
|
||||
};
|
||||
logger.log("Working directory:", cwd);
|
||||
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}\``}
|
||||
`;
|
||||
}
|
||||
const copied = !isMinimal && await clipboardy.write(infoStr).then(() => true).catch(() => false);
|
||||
const isNuxt3 = !isLegacy;
|
||||
const isBridge = !isNuxt3 && infoObj.BuildModules.includes("bridge");
|
||||
const repo = isBridge ? "nuxt/bridge" : "nuxt/nuxt";
|
||||
const log = [
|
||||
(isNuxt3 || isBridge) && `\u{1F449} Report an issue: https://github.com/${repo}/issues/new?template=bug-report.yml`,
|
||||
(isNuxt3 || isBridge) && `\u{1F449} Suggest an improvement: https://github.com/${repo}/discussions/new`,
|
||||
`\u{1F449} Read documentation: ${isNuxt3 || isBridge ? "https://nuxt.com" : "https://v2.nuxt.com"}`
|
||||
].filter(Boolean).join("\n");
|
||||
const splitter = "------------------------------";
|
||||
logger.log(`Nuxt project info: ${copied ? "(copied to clipboard)" : ""}
|
||||
|
||||
${splitter}
|
||||
${infoStr}${splitter}
|
||||
|
||||
${log}
|
||||
`);
|
||||
}
|
||||
});
|
||||
function normalizeConfigModule(module, rootDir) {
|
||||
if (!module) {
|
||||
return null;
|
||||
}
|
||||
if (typeof module === "string") {
|
||||
return module.split(rootDir).pop().split("node_modules").pop().replace(/^\//, "");
|
||||
}
|
||||
if (typeof module === "function") {
|
||||
return `${module.name}()`;
|
||||
}
|
||||
if (Array.isArray(module)) {
|
||||
return normalizeConfigModule(module[0], rootDir);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async function getNuxtConfig(rootDir) {
|
||||
try {
|
||||
const { createJiti } = await import('jiti');
|
||||
const jiti = createJiti(rootDir, {
|
||||
interopDefault: true,
|
||||
// allow using `~` and `@` in `nuxt.config`
|
||||
alias: {
|
||||
"~": rootDir,
|
||||
"@": rootDir
|
||||
}
|
||||
});
|
||||
globalThis.defineNuxtConfig = (c) => c;
|
||||
const result = await jiti.import("./nuxt.config", { default: true });
|
||||
delete globalThis.defineNuxtConfig;
|
||||
return result;
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export { info as default };
|
||||
+388
@@ -0,0 +1,388 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { colors } from 'consola/utils';
|
||||
import { downloadTemplate, startShell } from 'giget';
|
||||
import { installDependencies } from 'nypm';
|
||||
import { $fetch } from 'ofetch';
|
||||
import { resolve, relative, join } from 'pathe';
|
||||
import { readPackageJSON, writePackageJSON } from 'pkg-types';
|
||||
import { hasTTY } from 'std-env';
|
||||
import { x } from 'tinyexec';
|
||||
import { r as runCommand } from '../shared/cli.vXg4eLNu.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:url';
|
||||
import 'node:crypto';
|
||||
import 'node:path';
|
||||
import '../shared/cli.DhJ3cH8w.mjs';
|
||||
import 'consola';
|
||||
|
||||
const themeColor = "\x1B[38;2;0;220;130m";
|
||||
const icon = [
|
||||
` .d$b.`,
|
||||
` i$$A$$L .d$b`,
|
||||
` .$$F\` \`$$L.$$A$$.`,
|
||||
` j$$' \`4$$:\` \`$$.`,
|
||||
` j$$' .4$: \`$$.`,
|
||||
` j$$\` .$$: \`4$L`,
|
||||
` :$$:____.d$$: _____.:$$:`,
|
||||
` \`4$$$$$$$$P\` .i$$$$$$$$P\``
|
||||
];
|
||||
const nuxtIcon = icon.map((line) => line.split("").join(themeColor)).join("\n");
|
||||
|
||||
const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/nuxt/starter/templates/templates";
|
||||
const DEFAULT_TEMPLATE_NAME = "v4";
|
||||
const pms = {
|
||||
npm: void 0,
|
||||
pnpm: void 0,
|
||||
yarn: void 0,
|
||||
bun: void 0,
|
||||
deno: void 0
|
||||
};
|
||||
const packageManagerOptions = Object.keys(pms);
|
||||
async function getModuleDependencies(moduleName) {
|
||||
try {
|
||||
const response = await $fetch(`https://registry.npmjs.org/${moduleName}/latest`);
|
||||
const dependencies = response.dependencies || {};
|
||||
return Object.keys(dependencies);
|
||||
} catch (err) {
|
||||
logger.warn(`Could not get dependencies for ${moduleName}: ${err}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
function filterModules(modules, allDependencies) {
|
||||
const result = {
|
||||
toInstall: [],
|
||||
skipped: []
|
||||
};
|
||||
for (const module of modules) {
|
||||
const isDependency = modules.some((otherModule) => {
|
||||
if (otherModule === module)
|
||||
return false;
|
||||
const deps = allDependencies[otherModule] || [];
|
||||
return deps.includes(module);
|
||||
});
|
||||
if (isDependency) {
|
||||
result.skipped.push(module);
|
||||
} else {
|
||||
result.toInstall.push(module);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async function getTemplateDependencies(templateDir) {
|
||||
try {
|
||||
const packageJsonPath = join(templateDir, "package.json");
|
||||
if (!existsSync(packageJsonPath)) {
|
||||
return [];
|
||||
}
|
||||
const packageJson = await import(packageJsonPath);
|
||||
const directDeps = {
|
||||
...packageJson.dependencies,
|
||||
...packageJson.devDependencies
|
||||
};
|
||||
const directDepNames = Object.keys(directDeps);
|
||||
const allDeps = new Set(directDepNames);
|
||||
const transitiveDepsResults = await Promise.all(
|
||||
directDepNames.map((dep) => getModuleDependencies(dep))
|
||||
);
|
||||
transitiveDepsResults.forEach((deps) => {
|
||||
deps.forEach((dep) => allDeps.add(dep));
|
||||
});
|
||||
return Array.from(allDeps);
|
||||
} catch (err) {
|
||||
logger.warn(`Could not read template dependencies: ${err}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
const init = defineCommand({
|
||||
meta: {
|
||||
name: "init",
|
||||
description: "Initialize a fresh project"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
dir: {
|
||||
type: "positional",
|
||||
description: "Project directory",
|
||||
default: ""
|
||||
},
|
||||
template: {
|
||||
type: "string",
|
||||
alias: "t",
|
||||
description: "Template name"
|
||||
},
|
||||
force: {
|
||||
type: "boolean",
|
||||
alias: "f",
|
||||
description: "Override existing directory"
|
||||
},
|
||||
offline: {
|
||||
type: "boolean",
|
||||
description: "Force offline mode"
|
||||
},
|
||||
preferOffline: {
|
||||
type: "boolean",
|
||||
description: "Prefer offline mode"
|
||||
},
|
||||
install: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
description: "Skip installing dependencies"
|
||||
},
|
||||
gitInit: {
|
||||
type: "boolean",
|
||||
description: "Initialize git repository"
|
||||
},
|
||||
shell: {
|
||||
type: "boolean",
|
||||
description: "Start shell after installation in project directory"
|
||||
},
|
||||
packageManager: {
|
||||
type: "string",
|
||||
description: "Package manager choice (npm, pnpm, yarn, bun)"
|
||||
},
|
||||
modules: {
|
||||
type: "string",
|
||||
required: false,
|
||||
description: "Nuxt modules to install (comma separated without spaces)",
|
||||
negativeDescription: "Skip module installation prompt",
|
||||
alias: "M"
|
||||
},
|
||||
nightly: {
|
||||
type: "string",
|
||||
description: "Use Nuxt nightly release channel (3x or latest)"
|
||||
}
|
||||
},
|
||||
async run(ctx) {
|
||||
if (hasTTY) {
|
||||
process.stdout.write(`
|
||||
${nuxtIcon}
|
||||
|
||||
`);
|
||||
}
|
||||
logger.info(colors.bold(`Welcome to Nuxt!`.split("").map((m) => `${themeColor}${m}`).join("")));
|
||||
if (ctx.args.dir === "") {
|
||||
ctx.args.dir = await logger.prompt("Where would you like to create your project?", {
|
||||
placeholder: "./nuxt-app",
|
||||
type: "text",
|
||||
default: "nuxt-app",
|
||||
cancel: "reject"
|
||||
}).catch(() => process.exit(1));
|
||||
}
|
||||
const cwd = resolve(ctx.args.cwd);
|
||||
let templateDownloadPath = resolve(cwd, ctx.args.dir);
|
||||
logger.info(`Creating a new project in ${colors.cyan(relative(cwd, templateDownloadPath) || templateDownloadPath)}.`);
|
||||
const templateName = ctx.args.template || DEFAULT_TEMPLATE_NAME;
|
||||
if (typeof templateName !== "string") {
|
||||
logger.error("Please specify a template!");
|
||||
process.exit(1);
|
||||
}
|
||||
let shouldForce = Boolean(ctx.args.force);
|
||||
const shouldVerify = !shouldForce && existsSync(templateDownloadPath);
|
||||
if (shouldVerify) {
|
||||
const selectedAction = await logger.prompt(
|
||||
`The directory ${colors.cyan(templateDownloadPath)} already exists. What would you like to do?`,
|
||||
{
|
||||
type: "select",
|
||||
options: ["Override its contents", "Select different directory", "Abort"]
|
||||
}
|
||||
);
|
||||
switch (selectedAction) {
|
||||
case "Override its contents":
|
||||
shouldForce = true;
|
||||
break;
|
||||
case "Select different directory": {
|
||||
templateDownloadPath = resolve(cwd, await logger.prompt("Please specify a different directory:", {
|
||||
type: "text",
|
||||
cancel: "reject"
|
||||
}).catch(() => process.exit(1)));
|
||||
break;
|
||||
}
|
||||
// 'Abort' or Ctrl+C
|
||||
default:
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
let template;
|
||||
try {
|
||||
template = await downloadTemplate(templateName, {
|
||||
dir: templateDownloadPath,
|
||||
force: shouldForce,
|
||||
offline: Boolean(ctx.args.offline),
|
||||
preferOffline: Boolean(ctx.args.preferOffline),
|
||||
registry: process.env.NUXI_INIT_REGISTRY || DEFAULT_REGISTRY
|
||||
});
|
||||
} catch (err) {
|
||||
if (process.env.DEBUG) {
|
||||
throw err;
|
||||
}
|
||||
logger.error(err.toString());
|
||||
process.exit(1);
|
||||
}
|
||||
if (ctx.args.nightly !== void 0 && !ctx.args.offline && !ctx.args.preferOffline) {
|
||||
const response = await $fetch("https://registry.npmjs.org/nuxt-nightly");
|
||||
const nightlyChannelTag = ctx.args.nightly || "latest";
|
||||
const nightlyChannelVersion = response["dist-tags"][nightlyChannelTag];
|
||||
if (!nightlyChannelVersion) {
|
||||
logger.error(`Nightly channel version for tag '${nightlyChannelTag}' not found.`);
|
||||
process.exit(1);
|
||||
}
|
||||
const nightlyNuxtPackageJsonVersion = `npm:nuxt-nightly@${nightlyChannelVersion}`;
|
||||
const packageJsonPath = resolve(cwd, ctx.args.dir);
|
||||
const packageJson = await readPackageJSON(packageJsonPath);
|
||||
if (packageJson.dependencies && "nuxt" in packageJson.dependencies) {
|
||||
packageJson.dependencies.nuxt = nightlyNuxtPackageJsonVersion;
|
||||
} else if (packageJson.devDependencies && "nuxt" in packageJson.devDependencies) {
|
||||
packageJson.devDependencies.nuxt = nightlyNuxtPackageJsonVersion;
|
||||
}
|
||||
await writePackageJSON(join(packageJsonPath, "package.json"), packageJson);
|
||||
}
|
||||
function detectCurrentPackageManager() {
|
||||
const userAgent = process.env.npm_config_user_agent;
|
||||
if (!userAgent) {
|
||||
return;
|
||||
}
|
||||
const [name] = userAgent.split("/");
|
||||
if (packageManagerOptions.includes(name)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
const currentPackageManager = detectCurrentPackageManager();
|
||||
const packageManagerArg = ctx.args.packageManager;
|
||||
const packageManagerSelectOptions = packageManagerOptions.map((pm) => ({
|
||||
label: pm,
|
||||
value: pm,
|
||||
hint: currentPackageManager === pm ? "current" : void 0
|
||||
}));
|
||||
const selectedPackageManager = packageManagerOptions.includes(packageManagerArg) ? packageManagerArg : await logger.prompt("Which package manager would you like to use?", {
|
||||
type: "select",
|
||||
options: packageManagerSelectOptions,
|
||||
initial: currentPackageManager,
|
||||
cancel: "reject"
|
||||
}).catch(() => process.exit(1));
|
||||
if (ctx.args.install === false) {
|
||||
logger.info("Skipping install dependencies step.");
|
||||
} else {
|
||||
logger.start("Installing dependencies...");
|
||||
try {
|
||||
await installDependencies({
|
||||
cwd: template.dir,
|
||||
packageManager: {
|
||||
name: selectedPackageManager,
|
||||
command: selectedPackageManager
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
if (process.env.DEBUG) {
|
||||
throw err;
|
||||
}
|
||||
logger.error(err.toString());
|
||||
process.exit(1);
|
||||
}
|
||||
logger.success("Installation completed.");
|
||||
}
|
||||
if (ctx.args.gitInit === void 0) {
|
||||
ctx.args.gitInit = await logger.prompt("Initialize git repository?", {
|
||||
type: "confirm",
|
||||
cancel: "reject"
|
||||
}).catch(() => process.exit(1));
|
||||
}
|
||||
if (ctx.args.gitInit) {
|
||||
logger.info("Initializing git repository...\n");
|
||||
try {
|
||||
await x("git", ["init", template.dir], {
|
||||
throwOnError: true,
|
||||
nodeOptions: {
|
||||
stdio: "inherit"
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
logger.warn(`Failed to initialize git repository: ${err}`);
|
||||
}
|
||||
}
|
||||
const modulesToAdd = [];
|
||||
if (ctx.args.modules !== void 0) {
|
||||
modulesToAdd.push(
|
||||
...(ctx.args.modules || "").split(",").map((module) => module.trim()).filter(Boolean)
|
||||
);
|
||||
} else if (!ctx.args.offline && !ctx.args.preferOffline) {
|
||||
const modulesPromise = $fetch("https://api.nuxt.com/modules");
|
||||
const wantsUserModules = await logger.prompt(
|
||||
`Would you like to install any of the official modules?`,
|
||||
{
|
||||
type: "confirm",
|
||||
cancel: "reject"
|
||||
}
|
||||
).catch(() => process.exit(1));
|
||||
if (wantsUserModules) {
|
||||
const [response, templateDeps] = await Promise.all([
|
||||
modulesPromise,
|
||||
getTemplateDependencies(template.dir)
|
||||
]);
|
||||
const officialModules = response.modules.filter((module) => module.type === "official" && module.npm !== "@nuxt/devtools").filter((module) => !templateDeps.includes(module.npm));
|
||||
if (officialModules.length === 0) {
|
||||
logger.info("All official modules are already included in this template.");
|
||||
} else {
|
||||
const selectedOfficialModules = await logger.prompt(
|
||||
"Pick the modules to install:",
|
||||
{
|
||||
type: "multiselect",
|
||||
options: officialModules.map((module) => ({
|
||||
label: `${colors.bold(colors.greenBright(module.npm))} \u2013 ${module.description.replace(/\.$/, "")}`,
|
||||
value: module.npm
|
||||
})),
|
||||
required: false
|
||||
}
|
||||
);
|
||||
if (selectedOfficialModules === void 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
if (selectedOfficialModules.length > 0) {
|
||||
const modules = selectedOfficialModules;
|
||||
const allDependencies = Object.fromEntries(
|
||||
await Promise.all(modules.map(
|
||||
async (module) => [module, await getModuleDependencies(module)]
|
||||
))
|
||||
);
|
||||
const { toInstall, skipped } = filterModules(modules, allDependencies);
|
||||
if (skipped.length) {
|
||||
logger.info(`The following modules are already included as dependencies of another module and will not be installed: ${skipped.map((m) => colors.cyan(m)).join(", ")}`);
|
||||
}
|
||||
modulesToAdd.push(...toInstall);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modulesToAdd.length > 0) {
|
||||
const args = [
|
||||
"add",
|
||||
...modulesToAdd,
|
||||
`--cwd=${templateDownloadPath}`,
|
||||
ctx.args.install ? "" : "--skipInstall",
|
||||
ctx.args.logLevel ? `--logLevel=${ctx.args.logLevel}` : ""
|
||||
].filter(Boolean);
|
||||
await runCommand("module", args);
|
||||
}
|
||||
logger.log(
|
||||
`
|
||||
\u2728 Nuxt project has been created with the \`${template.name}\` template. Next steps:`
|
||||
);
|
||||
const relativeTemplateDir = relative(process.cwd(), template.dir) || ".";
|
||||
const runCmd = selectedPackageManager === "deno" ? "task" : "run";
|
||||
const nextSteps = [
|
||||
!ctx.args.shell && relativeTemplateDir.length > 1 && `\`cd ${relativeTemplateDir}\``,
|
||||
`Start development server with \`${selectedPackageManager} ${runCmd} dev\``
|
||||
].filter(Boolean);
|
||||
for (const step of nextSteps) {
|
||||
logger.log(` \u203A ${step}`);
|
||||
}
|
||||
if (ctx.args.shell) {
|
||||
startShell(template.dir);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export { init as default };
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { resolve, relative } from 'pathe';
|
||||
import { a as clearBuildDir } from '../shared/cli.pLQ0oPGc.mjs';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { l as legacyRootDirArgs, e as extendsArgs, b as envNameArgs, a as logLevelArgs, c as cwdArgs, d as dotEnvArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:fs';
|
||||
import 'node:url';
|
||||
import 'exsolve';
|
||||
import 'consola';
|
||||
import 'node:path';
|
||||
import 'std-env';
|
||||
|
||||
const prepare = defineCommand({
|
||||
meta: {
|
||||
name: "prepare",
|
||||
description: "Prepare Nuxt for development/build"
|
||||
},
|
||||
args: {
|
||||
...dotEnvArgs,
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
...envNameArgs,
|
||||
...extendsArgs,
|
||||
...legacyRootDirArgs
|
||||
},
|
||||
async run(ctx) {
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || "production";
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const { loadNuxt, buildNuxt, writeTypes } = await loadKit(cwd);
|
||||
const nuxt = await loadNuxt({
|
||||
cwd,
|
||||
dotenv: {
|
||||
cwd,
|
||||
fileName: ctx.args.dotenv
|
||||
},
|
||||
envName: ctx.args.envName,
|
||||
// c12 will fall back to NODE_ENV
|
||||
overrides: {
|
||||
_prepare: true,
|
||||
logLevel: ctx.args.logLevel,
|
||||
...ctx.args.extends && { extends: ctx.args.extends },
|
||||
...ctx.data?.overrides
|
||||
}
|
||||
});
|
||||
await clearBuildDir(nuxt.options.buildDir);
|
||||
await buildNuxt(nuxt);
|
||||
await writeTypes(nuxt);
|
||||
logger.success(
|
||||
"Types generated in",
|
||||
relative(process.cwd(), nuxt.options.buildDir)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export { prepare as default };
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
import { existsSync, promises } from 'node:fs';
|
||||
import { dirname, relative } from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { setupDotenv } from 'c12';
|
||||
import { defineCommand } from 'citty';
|
||||
import { box, colors } from 'consola/utils';
|
||||
import { getArgs } from 'listhen/cli';
|
||||
import { resolve } from 'pathe';
|
||||
import { x } from 'tinyexec';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { d as dotEnvArgs, l as legacyRootDirArgs, e as extendsArgs, b as envNameArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:url';
|
||||
import 'exsolve';
|
||||
import 'consola';
|
||||
import 'std-env';
|
||||
|
||||
const command = defineCommand({
|
||||
meta: {
|
||||
name: "preview",
|
||||
description: "Launches Nitro server for local testing after `nuxi build`."
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
...envNameArgs,
|
||||
...extendsArgs,
|
||||
...legacyRootDirArgs,
|
||||
port: getArgs().port,
|
||||
...dotEnvArgs
|
||||
},
|
||||
async run(ctx) {
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || "production";
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const { loadNuxt } = await loadKit(cwd);
|
||||
const resolvedOutputDir = await new Promise((res) => {
|
||||
loadNuxt({
|
||||
cwd,
|
||||
envName: ctx.args.envName,
|
||||
// c12 will fall back to NODE_ENV
|
||||
ready: true,
|
||||
overrides: {
|
||||
...ctx.args.extends && { extends: ctx.args.extends },
|
||||
modules: [
|
||||
function(_, nuxt) {
|
||||
nuxt.hook("nitro:init", (nitro) => {
|
||||
res(resolve(nuxt.options.srcDir || cwd, nitro.options.output.dir || ".output", "nitro.json"));
|
||||
});
|
||||
}
|
||||
]
|
||||
}
|
||||
}).then((nuxt) => nuxt.close()).catch(() => "");
|
||||
});
|
||||
const defaultOutput = resolve(cwd, ".output", "nitro.json");
|
||||
const nitroJSONPaths = [resolvedOutputDir, defaultOutput].filter(Boolean);
|
||||
const nitroJSONPath = nitroJSONPaths.find((p) => existsSync(p));
|
||||
if (!nitroJSONPath) {
|
||||
logger.error(
|
||||
"Cannot find `nitro.json`. Did you run `nuxi build` first? Search path:\n",
|
||||
nitroJSONPaths
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const outputPath = dirname(nitroJSONPath);
|
||||
const nitroJSON = JSON.parse(await promises.readFile(nitroJSONPath, "utf-8"));
|
||||
if (!nitroJSON.commands.preview) {
|
||||
logger.error("Preview is not supported for this build.");
|
||||
process.exit(1);
|
||||
}
|
||||
const info = [
|
||||
["Node.js:", `v${process.versions.node}`],
|
||||
["Nitro Preset:", nitroJSON.preset],
|
||||
["Working directory:", relative(process.cwd(), outputPath)]
|
||||
];
|
||||
const _infoKeyLen = Math.max(...info.map(([label]) => label.length));
|
||||
logger.log(
|
||||
box(
|
||||
[
|
||||
"You are running Nuxt production build in preview mode.",
|
||||
`For production deployments, please directly use ${colors.cyan(
|
||||
nitroJSON.commands.preview
|
||||
)} command.`,
|
||||
"",
|
||||
...info.map(
|
||||
([label, value]) => `${label.padEnd(_infoKeyLen, " ")} ${colors.cyan(value)}`
|
||||
)
|
||||
].join("\n"),
|
||||
{
|
||||
title: colors.yellow("Preview Mode"),
|
||||
style: {
|
||||
borderColor: "yellow"
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
const envFileName = ctx.args.dotenv || ".env";
|
||||
const envExists = existsSync(resolve(cwd, envFileName));
|
||||
if (envExists) {
|
||||
logger.info(
|
||||
`Loading \`${envFileName}\`. This will not be loaded when running the server in production.`
|
||||
);
|
||||
await setupDotenv({ cwd, fileName: envFileName });
|
||||
} else if (ctx.args.dotenv) {
|
||||
logger.error(`Cannot find \`${envFileName}\`.`);
|
||||
}
|
||||
const { port } = _resolveListenOptions(ctx.args);
|
||||
logger.info(`Starting preview command: \`${nitroJSON.commands.preview}\``);
|
||||
const [command2, ...commandArgs] = nitroJSON.commands.preview.split(" ");
|
||||
logger.log("");
|
||||
await x(command2, commandArgs, {
|
||||
throwOnError: true,
|
||||
nodeOptions: {
|
||||
stdio: "inherit",
|
||||
cwd: outputPath,
|
||||
env: {
|
||||
...process.env,
|
||||
NUXT_PORT: port,
|
||||
NITRO_PORT: port
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
function _resolveListenOptions(args) {
|
||||
const _port = args.port ?? args.p ?? process.env.NUXT_PORT ?? process.env.NITRO_PORT ?? process.env.PORT;
|
||||
return {
|
||||
port: _port
|
||||
};
|
||||
}
|
||||
|
||||
export { command as default };
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
import { defineCommand } from 'citty';
|
||||
import { colors } from 'consola/utils';
|
||||
import Fuse from 'fuse.js';
|
||||
import { upperFirst, kebabCase } from 'scule';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { g as getNuxtVersion } from '../shared/cli.DHenkA1C.mjs';
|
||||
import { c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import { f as fetchModules, c as checkNuxtCompatibility } from '../shared/cli.Cr-OCgdO.mjs';
|
||||
import 'consola';
|
||||
import 'pkg-types';
|
||||
import 'semver';
|
||||
import 'node:path';
|
||||
import 'node:process';
|
||||
import 'std-env';
|
||||
import 'node:url';
|
||||
import 'confbox';
|
||||
import 'ofetch';
|
||||
|
||||
const { format: formatNumber } = Intl.NumberFormat("en-GB", {
|
||||
notation: "compact",
|
||||
maximumFractionDigits: 1
|
||||
});
|
||||
const search = defineCommand({
|
||||
meta: {
|
||||
name: "search",
|
||||
description: "Search in Nuxt modules"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
query: {
|
||||
type: "positional",
|
||||
description: "keywords to search for",
|
||||
required: true
|
||||
},
|
||||
nuxtVersion: {
|
||||
type: "string",
|
||||
description: "Filter by Nuxt version and list compatible modules only (auto detected by default)",
|
||||
required: false,
|
||||
valueHint: "2|3"
|
||||
}
|
||||
},
|
||||
async setup(ctx) {
|
||||
const nuxtVersion = await getNuxtVersion(ctx.args.cwd);
|
||||
return findModuleByKeywords(ctx.args._.join(" "), nuxtVersion);
|
||||
}
|
||||
});
|
||||
async function findModuleByKeywords(query, nuxtVersion) {
|
||||
const allModules = await fetchModules();
|
||||
const compatibleModules = allModules.filter(
|
||||
(m) => checkNuxtCompatibility(m, nuxtVersion)
|
||||
);
|
||||
const fuse = new Fuse(compatibleModules, {
|
||||
threshold: 0.1,
|
||||
keys: [
|
||||
{ name: "name", weight: 1 },
|
||||
{ name: "npm", weight: 1 },
|
||||
{ name: "repo", weight: 1 },
|
||||
{ name: "tags", weight: 1 },
|
||||
{ name: "category", weight: 1 },
|
||||
{ name: "description", weight: 0.5 },
|
||||
{ name: "maintainers.name", weight: 0.5 },
|
||||
{ name: "maintainers.github", weight: 0.5 }
|
||||
]
|
||||
});
|
||||
const { bold, green, magenta, cyan, gray, yellow } = colors;
|
||||
const results = fuse.search(query).map((result) => {
|
||||
const res = {
|
||||
name: bold(result.item.name),
|
||||
homepage: cyan(result.item.website),
|
||||
compatibility: `nuxt: ${result.item.compatibility?.nuxt || "*"}`,
|
||||
repository: gray(result.item.github),
|
||||
description: gray(result.item.description),
|
||||
package: gray(result.item.npm),
|
||||
install: cyan(`npx nuxi module add ${result.item.name}`),
|
||||
stars: yellow(formatNumber(result.item.stats.stars)),
|
||||
monthlyDownloads: yellow(formatNumber(result.item.stats.downloads))
|
||||
};
|
||||
if (result.item.github === result.item.website) {
|
||||
delete res.homepage;
|
||||
}
|
||||
if (result.item.name === result.item.npm) {
|
||||
delete res.packageName;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
if (!results.length) {
|
||||
logger.info(
|
||||
`No Nuxt modules found matching query ${magenta(query)} for Nuxt ${cyan(nuxtVersion)}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
logger.success(
|
||||
`Found ${results.length} Nuxt ${results.length > 1 ? "modules" : "module"} matching ${cyan(query)} ${nuxtVersion ? `for Nuxt ${cyan(nuxtVersion)}` : ""}:
|
||||
`
|
||||
);
|
||||
for (const foundModule of results) {
|
||||
let maxLength = 0;
|
||||
const entries = Object.entries(foundModule).map(([key, val]) => {
|
||||
const label = upperFirst(kebabCase(key)).replace(/-/g, " ");
|
||||
if (label.length > maxLength) {
|
||||
maxLength = label.length;
|
||||
}
|
||||
return [label, val || "-"];
|
||||
});
|
||||
let infoStr = "";
|
||||
for (const [label, value] of entries) {
|
||||
infoStr += `${bold(label === "Install" ? "\u2192 " : "- ") + green(label.padEnd(maxLength + 2)) + value}
|
||||
`;
|
||||
}
|
||||
logger.log(infoStr);
|
||||
}
|
||||
}
|
||||
|
||||
export { search as default };
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { resolve } from 'pathe';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { l as legacyRootDirArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'consola';
|
||||
import 'node:path';
|
||||
import 'std-env';
|
||||
import 'node:url';
|
||||
|
||||
const test = defineCommand({
|
||||
meta: {
|
||||
name: "test",
|
||||
description: "Run tests"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
...legacyRootDirArgs,
|
||||
dev: {
|
||||
type: "boolean",
|
||||
description: "Run in dev mode"
|
||||
},
|
||||
watch: {
|
||||
type: "boolean",
|
||||
description: "Watch mode"
|
||||
}
|
||||
},
|
||||
async run(ctx) {
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || "test";
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const { runTests } = await importTestUtils();
|
||||
await runTests({
|
||||
rootDir: cwd,
|
||||
dev: ctx.args.dev,
|
||||
watch: ctx.args.watch,
|
||||
...{}
|
||||
});
|
||||
}
|
||||
});
|
||||
async function importTestUtils() {
|
||||
let err;
|
||||
for (const pkg of [
|
||||
"@nuxt/test-utils-nightly",
|
||||
"@nuxt/test-utils-edge",
|
||||
"@nuxt/test-utils"
|
||||
]) {
|
||||
try {
|
||||
const exports = await import(pkg);
|
||||
if (!exports.runTests) {
|
||||
throw new Error("Invalid version of `@nuxt/test-utils` is installed!");
|
||||
}
|
||||
return exports;
|
||||
} catch (_err) {
|
||||
err = _err;
|
||||
}
|
||||
}
|
||||
logger.error(err);
|
||||
throw new Error("`@nuxt/test-utils` seems missing. Run `npm i -D @nuxt/test-utils` or `yarn add -D @nuxt/test-utils` to install.");
|
||||
}
|
||||
|
||||
export { test as default };
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { resolveModulePath } from 'exsolve';
|
||||
import { resolve } from 'pathe';
|
||||
import { readTSConfig } from 'pkg-types';
|
||||
import { isBun } from 'std-env';
|
||||
import { x } from 'tinyexec';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as legacyRootDirArgs, e as extendsArgs, d as dotEnvArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:url';
|
||||
import 'node:path';
|
||||
import 'consola';
|
||||
import '../shared/cli.B9AmABr3.mjs';
|
||||
|
||||
const typecheck = defineCommand({
|
||||
meta: {
|
||||
name: "typecheck",
|
||||
description: "Runs `vue-tsc` to check types throughout your app."
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
...dotEnvArgs,
|
||||
...extendsArgs,
|
||||
...legacyRootDirArgs
|
||||
},
|
||||
async run(ctx) {
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || "production";
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const [supportsProjects, resolvedTypeScript, resolvedVueTsc] = await Promise.all([
|
||||
readTSConfig(cwd).then((r) => !!r.references?.length),
|
||||
// Prefer local install if possible
|
||||
resolveModulePath("typescript", { try: true }),
|
||||
resolveModulePath("vue-tsc/bin/vue-tsc.js", { try: true }),
|
||||
writeTypes(cwd, ctx.args.dotenv, ctx.args.logLevel, {
|
||||
...ctx.data?.overrides,
|
||||
...ctx.args.extends && { extends: ctx.args.extends }
|
||||
})
|
||||
]);
|
||||
const typeCheckArgs = supportsProjects ? ["-b", "--noEmit"] : ["--noEmit"];
|
||||
if (resolvedTypeScript && resolvedVueTsc) {
|
||||
return await x(resolvedVueTsc, typeCheckArgs, {
|
||||
throwOnError: true,
|
||||
nodeOptions: {
|
||||
stdio: "inherit",
|
||||
cwd
|
||||
}
|
||||
});
|
||||
}
|
||||
if (isBun) {
|
||||
await x("bun", ["install", "typescript", "vue-tsc", "--global", "--silent"], {
|
||||
throwOnError: true,
|
||||
nodeOptions: { stdio: "inherit", cwd }
|
||||
});
|
||||
return await x("bunx", ["vue-tsc", ...typeCheckArgs], {
|
||||
throwOnError: true,
|
||||
nodeOptions: {
|
||||
stdio: "inherit",
|
||||
cwd
|
||||
}
|
||||
});
|
||||
}
|
||||
await x("npx", ["-p", "vue-tsc", "-p", "typescript", "vue-tsc", ...typeCheckArgs], {
|
||||
throwOnError: true,
|
||||
nodeOptions: { stdio: "inherit", cwd }
|
||||
});
|
||||
}
|
||||
});
|
||||
async function writeTypes(cwd, dotenv, logLevel, overrides) {
|
||||
const { loadNuxt, buildNuxt, writeTypes: writeTypes2 } = await loadKit(cwd);
|
||||
const nuxt = await loadNuxt({
|
||||
cwd,
|
||||
dotenv: { cwd, fileName: dotenv },
|
||||
overrides: {
|
||||
_prepare: true,
|
||||
logLevel,
|
||||
...overrides
|
||||
}
|
||||
});
|
||||
await writeTypes2(nuxt);
|
||||
await buildNuxt(nuxt);
|
||||
await nuxt.close();
|
||||
}
|
||||
|
||||
export { typecheck as default };
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import process from 'node:process';
|
||||
import { defineCommand } from 'citty';
|
||||
import { colors } from 'consola/utils';
|
||||
import { detectPackageManager, addDependency, dedupeDependencies } from 'nypm';
|
||||
import { resolve } from 'pathe';
|
||||
import { readPackageJSON } from 'pkg-types';
|
||||
import { l as loadKit } from '../shared/cli.qKvs7FJ2.mjs';
|
||||
import { l as logger } from '../shared/cli.B9AmABr3.mjs';
|
||||
import { c as cleanupNuxtDirs, n as nuxtVersionToGitIdentifier } from '../shared/cli.At9IMXtr.mjs';
|
||||
import { g as getPackageManagerVersion } from '../shared/cli.BSm0_9Hr.mjs';
|
||||
import { g as getNuxtVersion } from '../shared/cli.DHenkA1C.mjs';
|
||||
import { l as legacyRootDirArgs, a as logLevelArgs, c as cwdArgs } from '../shared/cli.CTXRG5Cu.mjs';
|
||||
import 'node:url';
|
||||
import 'exsolve';
|
||||
import 'consola';
|
||||
import 'ohash';
|
||||
import '../shared/cli.pLQ0oPGc.mjs';
|
||||
import 'node:child_process';
|
||||
import 'semver';
|
||||
import 'node:path';
|
||||
import 'std-env';
|
||||
|
||||
function checkNuxtDependencyType(pkg) {
|
||||
if (pkg.dependencies?.nuxt) {
|
||||
return "dependencies";
|
||||
}
|
||||
if (pkg.devDependencies?.nuxt) {
|
||||
return "devDependencies";
|
||||
}
|
||||
return "dependencies";
|
||||
}
|
||||
const nuxtVersionTags = {
|
||||
"3.x": "3x",
|
||||
"4.x": "latest"
|
||||
};
|
||||
async function getNightlyVersion(packageNames) {
|
||||
const nuxtVersion = await logger.prompt(
|
||||
"Which nightly Nuxt release channel do you want to install? (3.x or 4.x)",
|
||||
{
|
||||
type: "select",
|
||||
options: ["3.x", "4.x"],
|
||||
default: "4.x",
|
||||
cancel: "reject"
|
||||
}
|
||||
).catch(() => process.exit(1));
|
||||
const npmPackages = packageNames.map((p) => `${p}@npm:${p}-nightly@${nuxtVersionTags[nuxtVersion]}`);
|
||||
return { npmPackages, nuxtVersion };
|
||||
}
|
||||
async function getRequiredNewVersion(packageNames, channel) {
|
||||
if (channel === "nightly") {
|
||||
return getNightlyVersion(packageNames);
|
||||
}
|
||||
return { npmPackages: packageNames.map((p) => `${p}@latest`), nuxtVersion: "4" };
|
||||
}
|
||||
const upgrade = defineCommand({
|
||||
meta: {
|
||||
name: "upgrade",
|
||||
description: "Upgrade Nuxt"
|
||||
},
|
||||
args: {
|
||||
...cwdArgs,
|
||||
...logLevelArgs,
|
||||
...legacyRootDirArgs,
|
||||
dedupe: {
|
||||
type: "boolean",
|
||||
description: "Dedupe dependencies after upgrading"
|
||||
},
|
||||
force: {
|
||||
type: "boolean",
|
||||
alias: "f",
|
||||
description: "Force upgrade to recreate lockfile and node_modules"
|
||||
},
|
||||
channel: {
|
||||
type: "string",
|
||||
alias: "ch",
|
||||
default: "stable",
|
||||
description: "Specify a channel to install from (default: stable)",
|
||||
valueHint: "stable|nightly"
|
||||
}
|
||||
},
|
||||
async run(ctx) {
|
||||
const cwd = resolve(ctx.args.cwd || ctx.args.rootDir);
|
||||
const packageManager = await detectPackageManager(cwd);
|
||||
if (!packageManager) {
|
||||
logger.error(
|
||||
`Unable to determine the package manager used by this project.
|
||||
|
||||
No lock files found in \`${cwd}\`, and no \`packageManager\` field specified in \`package.json\`.
|
||||
|
||||
Please either add the \`packageManager\` field to \`package.json\` or execute the installation command for your package manager. For example, you can use \`pnpm i\`, \`npm i\`, \`bun i\`, or \`yarn i\`, and then try again.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const { name: packageManagerName, lockFile: lockFileCandidates } = packageManager;
|
||||
const packageManagerVersion = getPackageManagerVersion(packageManagerName);
|
||||
logger.info("Package manager:", packageManagerName, packageManagerVersion);
|
||||
const currentVersion = await getNuxtVersion(cwd, false) || "[unknown]";
|
||||
logger.info("Current Nuxt version:", currentVersion);
|
||||
const pkg = await readPackageJSON(cwd).catch(() => null);
|
||||
const nuxtDependencyType = pkg ? checkNuxtDependencyType(pkg) : "dependencies";
|
||||
const corePackages = ["@nuxt/kit", "@nuxt/schema", "@nuxt/vite-builder", "@nuxt/webpack-builder", "@nuxt/rspack-builder"];
|
||||
const packagesToUpdate = pkg ? corePackages.filter((p) => pkg.dependencies?.[p] || pkg.devDependencies?.[p]) : [];
|
||||
const { npmPackages, nuxtVersion } = await getRequiredNewVersion(["nuxt", ...packagesToUpdate], ctx.args.channel);
|
||||
const toRemove = ["node_modules"];
|
||||
const lockFile = normaliseLockFile(cwd, lockFileCandidates);
|
||||
if (lockFile) {
|
||||
toRemove.push(lockFile);
|
||||
}
|
||||
const forceRemovals = toRemove.map((p) => colors.cyan(p)).join(" and ");
|
||||
let method = ctx.args.force ? "force" : ctx.args.dedupe ? "dedupe" : void 0;
|
||||
method ||= await logger.prompt(
|
||||
`Would you like to dedupe your lockfile (recommended) or recreate ${forceRemovals}? This can fix problems with hoisted dependency versions and ensure you have the most up-to-date dependencies.`,
|
||||
{
|
||||
type: "select",
|
||||
initial: "dedupe",
|
||||
cancel: "reject",
|
||||
options: [
|
||||
{
|
||||
label: "dedupe lockfile",
|
||||
value: "dedupe",
|
||||
hint: "recommended"
|
||||
},
|
||||
{
|
||||
label: `recreate ${forceRemovals}`,
|
||||
value: "force"
|
||||
},
|
||||
{
|
||||
label: "skip",
|
||||
value: "skip"
|
||||
}
|
||||
]
|
||||
}
|
||||
).catch(() => process.exit(1));
|
||||
const versionType = ctx.args.channel === "nightly" ? "nightly" : "latest stable";
|
||||
logger.info(`Installing ${versionType} Nuxt ${nuxtVersion} release...`);
|
||||
await addDependency(npmPackages, {
|
||||
cwd,
|
||||
packageManager,
|
||||
dev: nuxtDependencyType === "devDependencies"
|
||||
});
|
||||
if (method === "force") {
|
||||
logger.info(
|
||||
`Recreating ${forceRemovals}. If you encounter any issues, revert the changes and try with \`--no-force\``
|
||||
);
|
||||
await dedupeDependencies({ recreateLockfile: true });
|
||||
}
|
||||
if (method === "dedupe") {
|
||||
logger.info("Try deduping dependencies...");
|
||||
await dedupeDependencies();
|
||||
}
|
||||
let buildDir = ".nuxt";
|
||||
try {
|
||||
const { loadNuxtConfig } = await loadKit(cwd);
|
||||
const nuxtOptions = await loadNuxtConfig({ cwd });
|
||||
buildDir = nuxtOptions.buildDir;
|
||||
} catch {
|
||||
}
|
||||
await cleanupNuxtDirs(cwd, buildDir);
|
||||
const upgradedVersion = await getNuxtVersion(cwd, false) || "[unknown]";
|
||||
logger.info("Upgraded Nuxt version:", upgradedVersion);
|
||||
if (upgradedVersion === "[unknown]") {
|
||||
return;
|
||||
}
|
||||
if (upgradedVersion === currentVersion) {
|
||||
logger.success("You're using the latest version of Nuxt.");
|
||||
} else {
|
||||
logger.success(
|
||||
"Successfully upgraded Nuxt from",
|
||||
currentVersion,
|
||||
"to",
|
||||
upgradedVersion
|
||||
);
|
||||
if (currentVersion === "[unknown]") {
|
||||
return;
|
||||
}
|
||||
const commitA = nuxtVersionToGitIdentifier(currentVersion);
|
||||
const commitB = nuxtVersionToGitIdentifier(upgradedVersion);
|
||||
if (commitA && commitB) {
|
||||
logger.info(
|
||||
"Changelog:",
|
||||
`https://github.com/nuxt/nuxt/compare/${commitA}...${commitB}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
function normaliseLockFile(cwd, lockFiles) {
|
||||
if (typeof lockFiles === "string") {
|
||||
lockFiles = [lockFiles];
|
||||
}
|
||||
const lockFile = lockFiles?.find((file) => existsSync(resolve(cwd, file)));
|
||||
if (lockFile === void 0) {
|
||||
logger.error(`Unable to find any lock files in ${cwd}`);
|
||||
return void 0;
|
||||
}
|
||||
return lockFile;
|
||||
}
|
||||
|
||||
export { upgrade as default };
|
||||
Reference in New Issue
Block a user