chore: 优化 create app 问题

This commit is contained in:
winixt 2025-09-09 19:37:24 +08:00
parent fd811c5269
commit ad860c8f20
37 changed files with 644 additions and 586 deletions

View File

@ -1,3 +0,0 @@
#!/usr/bin/env node
require('../lib/cli');

View File

@ -0,0 +1,5 @@
#!/usr/bin/env node
import { runMain } from '../dist/index.mjs';
runMain();

View File

@ -17,20 +17,33 @@
"fes" "fes"
], ],
"sideEffects": false, "sideEffects": false,
"main": "dist/index.js", "main": "dist/index.mjs",
"module": "dist/index.mjs",
"bin": { "bin": {
"create-fes-app": "bin/create-fes-app.js" "create-fes-app": "bin/create-fes-app.mjs"
}, },
"files": [ "files": [
"bin", "bin",
"dist", "dist",
"templates/**/*" "templates/**/*"
], ],
"scripts": {
"dev": "tsup --watch --sourcemap",
"build": "tsup"
},
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"citty": "^0.1.6",
"consola": "^3.4.2",
"fs-extra": "^11.3.1", "fs-extra": "^11.3.1",
"validate-npm-package-name": "^3.0.0" "glob": "^11.0.3",
"mustache": "^4.2.0",
"semver": "^7.7.2",
"validate-npm-package-name": "^6.0.2"
},
"devDependencies": {
"@types/validate-npm-package-name": "^4.0.2"
} }
} }

View File

@ -1,77 +0,0 @@
import { copyFileSync, readFileSync, statSync, writeFileSync } from 'node:fs';
import { dirname, join, relative } from 'node:path';
import chalk from 'chalk';
import glob from 'glob';
import mkdirp from 'mkdirp';
import Mustache from 'mustache';
interface GeneratorOptions {
cwd: string;
args: Record<string, any>;
}
interface CopyTplOptions {
templatePath: string;
target: string;
context: Record<string, any>;
}
interface CopyDirectoryOptions {
path: string;
target: string;
context: Record<string, any>;
}
class Generator {
cwd: string;
args: Record<string, any>;
constructor({ cwd, args }: GeneratorOptions) {
this.cwd = cwd;
this.args = args;
}
async run(): Promise<void> {
await this.writing();
}
async writing(): Promise<void> { }
copyTpl(opts: CopyTplOptions): void {
const tpl = readFileSync(opts.templatePath, 'utf-8');
const content = Mustache.render(tpl, opts.context);
mkdirp.sync(dirname(opts.target));
// eslint-disable-next-line no-console
console.log(`${chalk.green('Write:')} ${relative(this.cwd, opts.target)}`);
writeFileSync(opts.target, content, 'utf-8');
}
copyDirectory(opts: CopyDirectoryOptions): void {
const files = glob.sync('**/*', {
cwd: opts.path,
dot: true,
ignore: ['**/node_modules/**'],
});
files.forEach((file) => {
const absFile = join(opts.path, file);
if (statSync(absFile).isDirectory()) {
return;
}
if (file.endsWith('.tpl')) {
return this.copyTpl({
templatePath: absFile,
target: join(opts.target, file.replace(/\.tpl$/, '')),
context: opts.context,
});
}
// eslint-disable-next-line no-console
console.log(`${chalk.green('Copy: ')} ${file}`);
const absTarget = join(opts.target, file);
mkdirp.sync(dirname(absTarget));
copyFileSync(absFile, absTarget);
});
}
}
export default Generator;

View File

@ -1,51 +0,0 @@
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import process from 'node:process';
import { chalk, yParser } from '@fesjs/utils';
const args = yParser(process.argv.slice(2), {
alias: {
version: ['v'],
help: ['h'],
force: ['f'],
merge: ['m'],
proxy: ['x'],
},
boolean: ['version', 'help', 'merge', 'force'],
});
if (args._.length > 1) {
console.log(chalk.yellow('\n Warning: You provided more than one argument. The first one will be used as the app\'s name, the rest are ignored.'));
}
if (args.version && !args._[0]) {
args._[0] = 'version';
const local = existsSync(join(__dirname, '../.local'))
? chalk.cyan('@local')
: '';
const { name, version } = require('../package.json');
console.log(`${name}@${version}${local}`);
}
else if (args.help && !args._[0]) {
console.log(`
Usage: create-fes-app <name>
Options:
-v, --version Output the current version
-h, --help Display help for command
-f, --force Overwrite target directory if it exists
-m, --merge Merge target directory if it exists
-x, --proxy <proxyUrl> Use specified proxy when creating project
`);
}
else {
require('.')
.default({
cwd: process.cwd(),
args,
})
.catch((err) => {
console.error(`Create failed, ${err.message}`);
console.error(err);
});
}

View File

@ -1,22 +0,0 @@
import { Generator } from '@fesjs/utils';
export default class AppGenerator extends Generator {
constructor({ cwd, args, path, targetDir }) {
super({
cwd,
args,
});
this.path = path;
this.targetDir = targetDir;
}
async writing() {
this.copyDirectory({
context: {
version: require('../../package.json').version,
},
path: this.path,
target: this.targetDir,
});
}
}

View File

@ -1,24 +0,0 @@
import { Generator } from '@fesjs/utils';
export default class AppGenerator extends Generator {
constructor({ cwd, args, path, targetDir, name }) {
super({
cwd,
args,
});
this.path = path;
this.targetDir = targetDir;
this.name = name;
}
async writing() {
this.copyDirectory({
context: {
version: require('../../package.json').version,
name: this.name,
},
path: this.path,
target: this.targetDir,
});
}
}

View File

@ -1,121 +0,0 @@
import path from 'node:path';
import process from 'node:process';
import { chalk } from '@fesjs/utils';
import fs from 'fs-extra';
import inquirer from 'inquirer';
import validateProjectName from 'validate-npm-package-name';
import AppGenerator from './generator/App';
import PluginGenerator from './generator/Plugin';
import { clearConsole } from './utils';
export default async ({ cwd, args }) => {
if (args.proxy) {
process.env.HTTP_PROXY = args.proxy;
}
const projectName = args._[0];
const inCurrent = projectName === '.';
const name = inCurrent ? path.relative('../', cwd) : projectName;
const targetDir = path.resolve(cwd, projectName || '.');
const result = validateProjectName(name);
if (!result.validForNewPackages) {
console.error(chalk.red(`Invalid project name: "${name}"`));
result.errors
&& result.errors.forEach((err) => {
console.error(chalk.red.dim(`Error: ${err}`));
});
result.warnings
&& result.warnings.forEach((warn) => {
console.error(chalk.red.dim(`Warning: ${warn}`));
});
throw new Error('Process exited');
}
if (fs.pathExistsSync(targetDir) && !args.merge) {
if (args.force) {
await fs.remove(targetDir);
}
else if (inCurrent) {
clearConsole();
const { ok } = await inquirer.prompt([
{
name: 'ok',
type: 'confirm',
message: 'Generate project in current directory?',
},
]);
if (!ok) {
return null;
}
}
else {
clearConsole();
const { action } = await inquirer.prompt([
{
name: 'action',
type: 'list',
message: `Target directory ${chalk.cyan(targetDir)} already exists. Pick an action:`,
choices: [
{ name: 'Overwrite', value: 'overwrite' },
{ name: 'Merge', value: 'merge' },
{ name: 'Cancel', value: false },
],
},
]);
if (!action) {
return null;
}
if (action === 'overwrite') {
console.log(`\nRemoving ${chalk.cyan(targetDir)}...`);
await fs.remove(targetDir);
}
}
}
clearConsole();
const { template } = await inquirer.prompt([
{
name: 'template',
type: 'list',
message: 'Pick an template:',
choices: [
{ name: 'PC, suitable for management desk front-end applications', value: 'pc' },
{ name: 'H5, suitable for mobile applications', value: 'h5' },
{ name: 'Plugin, suitable for fes plugin', value: 'plugin' },
{ name: 'Cancel', value: false },
],
},
]);
if (template === 'pc' || template === 'h5') {
const generator = new AppGenerator({
cwd,
args,
targetDir,
path: path.join(__dirname, `../templates/app/${template}`),
});
await generator.run();
console.log();
console.log(chalk.green(`project ${projectName} created successfully, please execute the following command to use:`));
console.log(`$ cd ${projectName}`);
console.log('$ pnpm i');
console.log('$ pnpm dev');
console.log();
}
else if (template === 'plugin') {
const generator = new PluginGenerator({
cwd,
args,
targetDir,
path: path.join(__dirname, '../templates/plugin'),
name,
});
await generator.run();
console.log();
console.log(chalk.green(`plugin ${projectName} created successfully, please execute the following command to use:`));
console.log(`$ cd ${projectName}`);
console.log('$ pnpm i');
console.log('$ pnpm dev');
console.log();
}
};

View File

@ -0,0 +1,2 @@
export { main } from './main';
export { runMain } from './run';

View File

@ -0,0 +1,114 @@
import { join, relative, resolve } from 'node:path';
import process from 'node:process';
import { defineCommand } from 'citty';
import consola from 'consola';
import validate from 'validate-npm-package-name';
import pkg from '../package.json' assert { type: 'json' };
import { getWorkPath } from './shared';
import { setupGlobalConsole } from './utils/console';
import { checkEngines } from './utils/engines';
import { copyDirectory } from './utils/gen';
export const main = defineCommand({
meta: {
name: pkg.name,
version: pkg.version,
description: pkg.description,
},
args: {
name: {
type: 'positional',
description: '项目名称',
required: true,
},
proxy: {
type: 'string',
description: '代理地址',
alias: ['-p'],
},
merge: {
type: 'boolean',
description: '是否合并',
alias: ['m'],
},
force: {
type: 'boolean',
description: '是否强制覆盖',
alias: ['f'],
},
},
async setup() {
setupGlobalConsole();
await checkEngines();
},
async run({ args }) {
const inCurrent = args.name === '.';
const cwd = getWorkPath();
const projectName = inCurrent ? relative('../', cwd) : args.name;
const result = validate(projectName);
if (!result.validForNewPackages) {
consola.error(`Invalid project name: "${projectName}"`);
result.errors
&& result.errors.forEach((err) => {
consola.error(`Error: ${err}`);
});
result.warnings
&& result.warnings.forEach((warn) => {
consola.warn(`Warning: ${warn}`);
});
process.exit(0);
}
const template = await consola.prompt('Pick an template:', {
type: 'select',
options: [{
label: 'PC, suitable for management desk front-end applications',
value: 'pc',
}, {
label: 'H5, suitable for mobile applications',
value: 'h5',
}, {
label: 'Plugin, suitable for fes plugin',
value: 'plugin',
}, {
label: 'Cancel',
value: 'cancel',
}],
});
const targetDir = resolve(cwd, projectName || '.');
if (template === 'pc' || template === 'h5') {
copyDirectory({
context: {
version: pkg.version,
},
path: join(__dirname, `../templates/app/${template}`),
target: targetDir,
});
consola.success(`Project ${projectName} created successfully!`);
consola.box([
`cd ${projectName}`,
'pnpm i',
'pnpm dev',
].join('\n'));
}
else if (template === 'plugin') {
copyDirectory({
context: {
version: pkg.version,
name: projectName,
},
path: join(__dirname, '../templates/plugin'),
target: targetDir,
});
consola.success(`plugin ${projectName} created successfully, please execute the following command to use:`);
consola.box([
`cd ${projectName}`,
'pnpm i',
'pnpm dev',
].join('\n'));
}
},
});

View File

@ -0,0 +1,5 @@
import { runMain as _runMain } from 'citty';
import { main } from './main';
export const runMain = () => _runMain(main);

View File

@ -0,0 +1,27 @@
import { readFileSync, rmSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import process from 'node:process';
import { fileURLToPath } from 'node:url';
export const OWNER_DIR = join(dirname(fileURLToPath(import.meta.url)), '..');
export function getWorkPath() {
return process.env.PWD || process.cwd();
}
export function removeSync(dir: string) {
rmSync(dir, {
recursive: true,
force: true,
});
}
export function readJsonSync(filePath: string) {
const content = readFileSync(filePath, 'utf-8');
return JSON.parse(content);
}
export function writeJSONSync(filePath: string, data: Record<string, any>) {
writeFileSync(filePath, JSON.stringify(data, null, 2));
}

View File

@ -1,14 +0,0 @@
import process from 'node:process';
import readline from 'node:readline';
export function clearConsole(title) {
if (process.stdout.isTTY) {
const blank = '\n'.repeat(process.stdout.rows);
console.log(blank);
readline.cursorTo(process.stdout, 0, 0);
readline.clearScreenDown(process.stdout);
if (title) {
console.log(title);
}
}
}

View File

@ -0,0 +1,17 @@
import process from 'node:process';
import { consola } from 'consola';
export function setupGlobalConsole(opts: { dev?: boolean } = {}) {
// Wrap all console logs with consola for better DX
if (opts.dev) {
consola.wrapAll();
}
else {
consola.wrapConsole();
}
process.on('unhandledRejection', err => consola.error('[unhandledRejection]', err));
process.on('uncaughtException', err => consola.error('[uncaughtException]', err));
}

View File

@ -0,0 +1,17 @@
import process from 'node:process';
import { logger } from './logger';
export async function checkEngines() {
const satisfies = await import('semver/functions/satisfies.js').then(
r => r.default || (r as any as typeof import('semver/functions/satisfies.js')),
); // npm/node-semver#381
const currentNode = process.versions.node;
const nodeRange = '>= 18.0.0';
if (!satisfies(currentNode, nodeRange)) {
logger.warn(
`Current version of Node.js (\`${currentNode}\`) is unsupported and might cause issues.\n Please upgrade to a compatible version \`${nodeRange}\`.`,
);
}
}

View File

@ -0,0 +1,49 @@
import { readFileSync, statSync } from 'node:fs';
import { join, relative } from 'node:path';
import consola from 'consola';
import { copySync, outputFileSync } from 'fs-extra/esm';
import { globSync } from 'glob';
import Mustache from 'mustache';
import { getWorkPath } from '../shared';
function copyTpl(opts: {
templatePath: string;
target: string;
context: Record<string, any>;
}): void {
const tpl = readFileSync(opts.templatePath, 'utf-8');
const content = Mustache.render(tpl, opts.context);
consola.success(`Write: ${relative(getWorkPath(), opts.target)}`);
outputFileSync(opts.target, content, 'utf-8');
}
export function copyDirectory(opts: {
path: string;
target: string;
context: Record<string, any>;
}): void {
const files = globSync('**/*', {
cwd: opts.path,
dot: true,
ignore: ['**/node_modules/**'],
});
files.forEach((file) => {
const absFile = join(opts.path, file);
if (statSync(absFile).isDirectory()) {
return;
}
if (file.endsWith('.tpl')) {
return copyTpl({
templatePath: absFile,
target: join(opts.target, file.replace(/\.tpl$/, '')),
context: opts.context,
});
}
consola.success(`Copy: ${file}`);
const absTarget = join(opts.target, file);
copySync(absFile, absTarget);
});
}

View File

@ -0,0 +1,3 @@
import { consola } from 'consola';
export const logger = consola.withTag('fes');

View File

@ -12,17 +12,18 @@
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/builder-webpack": "^3.1.0", "@fesjs/builder-webpack": "^4.0.0",
"@fesjs/fes": "^3.1.17", "@fesjs/fes": "^4.0.0",
"@fesjs/plugin-icon": "^4.0.0", "@fesjs/plugin-icon": "^5.0.0",
"@fesjs/plugin-request": "^4.0.1", "@fesjs/plugin-request": "^5.0.0",
"core-js": "^3.43.0", "core-js": "^3.43.0",
"lodash-es": "^4.17.21",
"vue": "^3.5.17" "vue": "^3.5.17"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "4.16.1", "@antfu/eslint-config": "^5.2.2",
"eslint": "9.29.0", "eslint": "^9.35.0",
"postcss-px-to-viewport-8-plugin": "^1.2.5", "postcss-px-to-viewport-8-plugin": "^1.2.5",
"typescript": "5.8.3" "typescript": "^5.9.2"
} }
} }

View File

@ -1,44 +0,0 @@
import { defineRuntimeConfig } from '@fesjs/fes';
export default defineRuntimeConfig({
request: {
// API 前缀
baseURL: '',
dataHandler(data, response) {
// 处理响应内容异常
if (data.code !== '0') {
if (data.code === '20000') {
console.log('hello world');
}
throw new Error(response);
}
// 响应数据格式化
return data?.result ? data.result : data;
},
// http 异常,和插件异常
errorHandler(error) {
if (error.response) {
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// 请求已经成功发起,但没有收到响应
// `error.request` 在浏览器中是 XMLHttpRequest 的实例,
// 而在node.js中是 http.ClientRequest 的实例
console.log(error.request);
} else if (error.type) {
// 插件异常
console.log(error.msg);
} else {
// 发送请求时出了点问题
console.log('Error', error.message);
}
console.log(error.config);
},
// 请求拦截器
requestInterceptors: [],
// 响应拦截器
responseInterceptors: [],
},
});

View File

@ -0,0 +1,42 @@
import { defineRuntimeConfig } from '@fesjs/fes'
import { isPlainObject } from 'lodash-es'
export default defineRuntimeConfig({
request: {
baseURL: '',
timeout: 10000, // 默认 10s
method: 'POST', // 默认 post
mergeRequest: false, // 是否合并请求
responseType: null, // 可选 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData',默认根据 content-type 处理
credentials: 'include', // 默认 include, 'include' | 'same-origin' | 'omit'
headers: {}, // 传给服务器的 header
cacheData: false, // 是否缓存
requestInterceptor: (config: Config) => Config,
responseInterceptor: (response: RequestResponse) => RequestResponse,
transformData(data, response) {
// 处理响应内容异常
if (isPlainObject(data)) {
if (data.code === '10000') {
return Promise.reject(data)
}
return data?.result ? data.result : data
}
return data
},
// http 异常,和插件异常
errorHandler(error) {
// 处理业务异常,例如上述 transformData 抛出的异常
if (error.code) {
console.log(error.msg)
}
else if (error.response) {
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
console.log(`服务异常:${error.response.status}`)
}
else {
// 请求异常
console.log(error.msg || error.message || `请求失败`)
}
},
},
})

View File

@ -1,64 +0,0 @@
// TODO
// 时间格式化
// js 数字精度计算
// 手机号、身份证号 等的校验
// 数字分割
export function resetContainerHeight(dom) {
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;
window.onresize = function () {
const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (resizeHeight < originalHeight) {
// 恢复内容区域高度
const container = document.querySelector(dom);
container.style.height = originalHeight;
}
};
}
export function resetInputBlur() {
const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d.]+)/i);
if (!isWechat) return;
const wechatVersion = isWechat[1];
const version = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
// 如果设备类型为iOS 12+ 和wechat 6.7.4+,恢复成原来的视口
if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) {
window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}
}
export function getQueryString(name) {
const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i');
const r = window.location.search.substr(1).match(reg);
if (r != null) {
return decodeURIComponent(r[2]);
}
return null;
}
export function simpleRequest(options) {
const xhr = new XMLHttpRequest();
xhr.timeout = 3000;
if (options.type === 'GET') {
xhr.open(options.type, options.url, options.async || true);
xhr.send(null);
} else if (options.type === 'POST') {
xhr.open(options.type, options.url, options.async || true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(options.data || {}));
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
options.successed(xhr.responseText);
} else {
options.failed && options.failed(xhr);
}
}
};
xhr.ontimeout = function () {
options.failed && options.failed(xhr);
};
}

View File

@ -0,0 +1,61 @@
export function resetContainerHeight(dom) {
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight
window.onresize = function () {
const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight
if (resizeHeight < originalHeight) {
// 恢复内容区域高度
const container = document.querySelector(dom)
container.style.height = originalHeight
}
}
}
export function resetInputBlur() {
const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d.]+)/i)
if (!isWechat)
return
const wechatVersion = isWechat[1]
const version = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/)
// 如果设备类型为iOS 12+ 和wechat 6.7.4+,恢复成原来的视口
if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) {
window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight))
}
}
export function getQueryString(name) {
const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i')
const r = window.location.search.substr(1).match(reg)
if (r != null) {
return decodeURIComponent(r[2])
}
return null
}
export function simpleRequest(options) {
const xhr = new XMLHttpRequest()
xhr.timeout = 3000
if (options.type === 'GET') {
xhr.open(options.type, options.url, options.async || true)
xhr.send(null)
}
else if (options.type === 'POST') {
xhr.open(options.type, options.url, options.async || true)
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(JSON.stringify(options.data || {}))
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
options.successed(xhr.responseText)
}
else {
options.failed && options.failed(xhr)
}
}
}
xhr.ontimeout = function () {
options.failed && options.failed(xhr)
}
}

View File

@ -1,43 +1,37 @@
<template> <script setup lang="ts">
<div class="onepiece"> import { defineRouteMeta, useRequest, useRouter } from '@fesjs/fes'
fes & 拉夫德鲁 <br /> import { onMounted, ref } from 'vue'
<fes-icon :spin="true" class="one-icon" type="smile" @click="clickIcon" />
<div v-if="loading" class="loading">loading</div>
<div v-else class="data">{{ data }}</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useRouter, useRequest, defineRouteMeta } from '@fesjs/fes';
defineRouteMeta({ defineRouteMeta({
title: '首页', title: '首页',
}); })
export default { const fes = ref('fes upgrade to vue3')
setup() { const rotate = ref(90)
const fes = ref('fes upgrade to vue3'); const router = useRouter()
const rotate = ref(90);
const router = useRouter();
onMounted(() => { onMounted(() => {
console.log(router); console.log(router)
console.log('mounted1!!'); console.log('mounted1!!')
}); })
const clickIcon = () => { function clickIcon() {
console.log('click Icon'); console.log('click Icon')
}; }
const { loading, data } = useRequest('api'); const { loading, data } = useRequest('api')
return {
loading,
data,
fes,
rotate,
clickIcon,
};
},
};
</script> </script>
<template>
<div class="onepiece">
fes & 拉夫德鲁 <br>
<fes-icon :spin="true" class="one-icon" type="smile" @click="clickIcon" />
<div v-if="loading" class="loading">
loading
</div>
<div v-else class="data">
{{ data }}
</div>
</div>
</template>
<style lang="less" scoped> <style lang="less" scoped>
@import '~@/styles/mixins/hairline'; @import '~@/styles/mixins/hairline';
@import '~@/styles/mixins/hover'; @import '~@/styles/mixins/hover';

View File

@ -1,20 +1,14 @@
<template> <script setup lang="ts">
<div>{{ fes }}</div> import { defineRouteMeta } from '@fesjs/fes'
</template> import { ref } from 'vue'
<script>
import { defineRouteMeta } from '@fesjs/fes';
import { ref } from 'vue';
defineRouteMeta({ defineRouteMeta({
title: 'one piece', title: 'one piece',
}); })
export default { const fes = ref('fes upgrade to vue3')
setup() {
const fes = ref('fes upgrade to vue3');
return {
fes,
};
},
};
</script> </script>
<template>
<div>{{ fes }}</div>
</template>

View File

@ -14,19 +14,21 @@
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/builder-webpack": "^3.1.0", "@fesjs/builder-vite": "^5.0.0",
"@fesjs/fes": "^3.1.17", "@fesjs/fes": "^4.0.0",
"@fesjs/fes-design": "^0.8.82", "@fesjs/fes-design": "^0.8.82",
"@fesjs/plugin-access": "^3.1.9", "@fesjs/plugin-access": "^4.0.0",
"@fesjs/plugin-enums": "^3.0.1", "@fesjs/plugin-enums": "^4.0.0",
"@fesjs/plugin-layout": "^5.4.6", "@fesjs/plugin-layout": "^6.0.0",
"@fesjs/plugin-model": "^3.0.3", "@fesjs/plugin-model": "^4.0.0",
"core-js": "^3.43.0", "core-js": "^3.43.0",
"lodash-es": "^4.17.21",
"vue": "^3.5.17" "vue": "^3.5.17"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "4.16.1", "@antfu/eslint-config": "^5.2.2",
"eslint": "9.29.0", "eslint": "^9.35.0",
"typescript": "5.8.3" "postcss-px-to-viewport-8-plugin": "^1.2.5",
"typescript": "^5.9.2"
} }
} }

View File

@ -1,25 +0,0 @@
import { access, defineRuntimeConfig } from '@fesjs/fes';
import PageLoading from '@/components/pageLoading.vue';
import UserCenter from '@/components/userCenter.vue';
export default defineRuntimeConfig({
beforeRender: {
loading: <PageLoading />,
action() {
const { setRole } = access;
return new Promise((resolve) => {
setTimeout(() => {
setRole('admin');
// useModel('@@initialState') @/components/UserCenter
resolve({
userName: '李雷',
});
}, 1000);
});
},
},
layout: {
renderCustom: () => <UserCenter />,
},
});

View File

@ -0,0 +1,61 @@
import { access, defineRuntimeConfig } from '@fesjs/fes'
import { isPlainObject } from 'lodash-es'
import PageLoading from '@/components/pageLoading.vue'
import UserCenter from '@/components/userCenter.vue'
export default defineRuntimeConfig({
beforeRender: {
loading: <PageLoading />,
action() {
const { setRole } = access
return new Promise((resolve) => {
setTimeout(() => {
setRole('admin')
// 初始化应用的全局状态,可以通过 useModel('@@initialState') 获取,具体用法看@/components/UserCenter 文件
resolve({
userName: '李雷',
})
}, 1000)
})
},
},
request: {
baseURL: '',
timeout: 10000, // 默认 10s
method: 'POST', // 默认 post
mergeRequest: false, // 是否合并请求
responseType: null, // 可选 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData',默认根据 content-type 处理
credentials: 'include', // 默认 include, 'include' | 'same-origin' | 'omit'
headers: {}, // 传给服务器的 header
cacheData: false, // 是否缓存
transformData(data, response) {
// 处理响应内容异常
if (isPlainObject(data)) {
if (data.code === '10000') {
return Promise.reject(data)
}
return data?.result ? data.result : data
}
return data
},
// http 异常,和插件异常
errorHandler(error) {
// 处理业务异常,例如上述 transformData 抛出的异常
if (error.code) {
console.log(error.msg)
}
else if (error.response) {
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
console.log(`服务异常:${error.response.status}`)
}
else {
// 请求异常
console.log(error.msg || error.message || `请求失败`)
}
},
},
layout: {
renderCustom: () => <UserCenter />,
},
})

View File

@ -1,20 +1,13 @@
<script setup lang="ts">
import { FSpin } from '@fesjs/fes-design'
</script>
<template> <template>
<div class="page-loading"> <div class="page-loading">
<f-spin size="large" stroke="#5384ff" /> <FSpin size="large" stroke="#5384ff" />
</div> </div>
</template> </template>
<script>
import { FSpin } from '@fesjs/fes-design';
export default {
components: {
FSpin,
},
setup() {
return {};
},
};
</script>
<style> <style>
.page-loading { .page-loading {
position: fixed; position: fixed;

View File

@ -1,18 +1,15 @@
<template> <script setup lang="ts">
<div class="right">{{ initialState.userName }}</div> import { useModel } from '@fesjs/fes'
</template>
<script>
import { useModel } from '@fesjs/fes';
export default { const initialState = useModel('@@initialState')
setup() {
const initialState = useModel('@@initialState');
return {
initialState,
};
},
};
</script> </script>
<template>
<div class="right">
{{ initialState.userName }}
</div>
</template>
<style scope> <style scope>
.right { .right {
text-align: right; text-align: right;

View File

@ -1,12 +1,14 @@
<template> <script setup lang="ts">
<div style="padding: 32px">hello world</div> import { defineRouteMeta } from '@fesjs/fes'
</template>
<script setup>
import { defineRouteMeta } from '@fesjs/fes';
defineRouteMeta({ defineRouteMeta({
name: 'index', name: 'index',
title: '首页', title: '首页',
}); })
</script> </script>
<template>
<div style="padding: 32px">
hello world
</div>
</template>

View File

@ -0,0 +1,9 @@
{
"extends": ["@fesjs/typescript-config/base.json"],
"compilerOptions": {
"rootDir": "./src",
"outDir": "./build"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@ -0,0 +1,11 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
splitting: false,
sourcemap: false,
clean: true,
dts: false,
shims: true,
format: ['esm'],
});

108
pnpm-lock.yaml generated
View File

@ -325,12 +325,31 @@ importers:
packages/create-fes-app: packages/create-fes-app:
dependencies: dependencies:
citty:
specifier: ^0.1.6
version: 0.1.6
consola:
specifier: ^3.4.2
version: 3.4.2
fs-extra: fs-extra:
specifier: ^11.3.1 specifier: ^11.3.1
version: 11.3.1 version: 11.3.1
glob:
specifier: ^11.0.3
version: 11.0.3
mustache:
specifier: ^4.2.0
version: 4.2.0
semver:
specifier: ^7.7.2
version: 7.7.2
validate-npm-package-name: validate-npm-package-name:
specifier: ^3.0.0 specifier: ^6.0.2
version: 3.0.0 version: 6.0.2
devDependencies:
'@types/validate-npm-package-name':
specifier: ^4.0.2
version: 4.0.2
packages/fes: packages/fes:
dependencies: dependencies:
@ -2016,6 +2035,14 @@ packages:
resolution: {integrity: sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==} resolution: {integrity: sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==}
engines: {node: '>= 16'} engines: {node: '>= 16'}
'@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
'@isaacs/brace-expansion@5.0.0':
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
engines: {node: 20 || >=22}
'@isaacs/cliui@8.0.2': '@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -2809,6 +2836,9 @@ packages:
'@types/unist@3.0.3': '@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
'@types/validate-npm-package-name@4.0.2':
resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==}
'@types/web-bluetooth@0.0.16': '@types/web-bluetooth@0.0.16':
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
@ -3329,9 +3359,6 @@ packages:
resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==}
engines: {node: '>=18.20'} engines: {node: '>=18.20'}
builtins@1.0.3:
resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==}
bundle-name@4.1.0: bundle-name@4.1.0:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -3444,6 +3471,9 @@ packages:
resolution: {integrity: sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==} resolution: {integrity: sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
citty@0.1.6:
resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==}
clean-css@5.3.3: clean-css@5.3.3:
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
engines: {node: '>= 10.0'} engines: {node: '>= 10.0'}
@ -4706,6 +4736,11 @@ packages:
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
hasBin: true hasBin: true
glob@11.0.3:
resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==}
engines: {node: 20 || >=22}
hasBin: true
glob@7.2.3: glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported deprecated: Glob versions prior to v9 are no longer supported
@ -5235,6 +5270,10 @@ packages:
jackspeak@3.4.3: jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
jackspeak@4.1.1:
resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==}
engines: {node: 20 || >=22}
jake@10.9.4: jake@10.9.4:
resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -5567,6 +5606,10 @@ packages:
lru-cache@10.4.3: lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-cache@11.2.1:
resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==}
engines: {node: 20 || >=22}
lru-cache@5.1.1: lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@ -5821,6 +5864,10 @@ packages:
minimalistic-assert@1.0.1: minimalistic-assert@1.0.1:
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
minimatch@10.0.3:
resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==}
engines: {node: 20 || >=22}
minimatch@3.1.2: minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@ -6218,6 +6265,10 @@ packages:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'} engines: {node: '>=16 || 14 >=14.18'}
path-scurry@2.0.0:
resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
engines: {node: 20 || >=22}
path-to-regexp@0.1.12: path-to-regexp@0.1.12:
resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}
@ -7739,8 +7790,9 @@ packages:
validate-npm-package-license@3.0.4: validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
validate-npm-package-name@3.0.0: validate-npm-package-name@6.0.2:
resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==} resolution: {integrity: sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==}
engines: {node: ^18.17.0 || >=20.5.0}
vary@1.1.2: vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
@ -9601,6 +9653,12 @@ snapshots:
'@intlify/shared@9.14.5': {} '@intlify/shared@9.14.5': {}
'@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.0':
dependencies:
'@isaacs/balanced-match': 4.0.1
'@isaacs/cliui@8.0.2': '@isaacs/cliui@8.0.2':
dependencies: dependencies:
string-width: 5.1.2 string-width: 5.1.2
@ -10367,6 +10425,8 @@ snapshots:
'@types/unist@3.0.3': {} '@types/unist@3.0.3': {}
'@types/validate-npm-package-name@4.0.2': {}
'@types/web-bluetooth@0.0.16': {} '@types/web-bluetooth@0.0.16': {}
'@types/web-bluetooth@0.0.20': {} '@types/web-bluetooth@0.0.20': {}
@ -11036,8 +11096,6 @@ snapshots:
builtin-modules@5.0.0: {} builtin-modules@5.0.0: {}
builtins@1.0.3: {}
bundle-name@4.1.0: bundle-name@4.1.0:
dependencies: dependencies:
run-applescript: 7.0.0 run-applescript: 7.0.0
@ -11168,6 +11226,10 @@ snapshots:
ci-info@4.3.0: {} ci-info@4.3.0: {}
citty@0.1.6:
dependencies:
consola: 3.4.2
clean-css@5.3.3: clean-css@5.3.3:
dependencies: dependencies:
source-map: 0.6.1 source-map: 0.6.1
@ -12685,6 +12747,15 @@ snapshots:
package-json-from-dist: 1.0.1 package-json-from-dist: 1.0.1
path-scurry: 1.11.1 path-scurry: 1.11.1
glob@11.0.3:
dependencies:
foreground-child: 3.3.1
jackspeak: 4.1.1
minimatch: 10.0.3
minipass: 7.1.2
package-json-from-dist: 1.0.1
path-scurry: 2.0.0
glob@7.2.3: glob@7.2.3:
dependencies: dependencies:
fs.realpath: 1.0.0 fs.realpath: 1.0.0
@ -13203,6 +13274,10 @@ snapshots:
optionalDependencies: optionalDependencies:
'@pkgjs/parseargs': 0.11.0 '@pkgjs/parseargs': 0.11.0
jackspeak@4.1.1:
dependencies:
'@isaacs/cliui': 8.0.2
jake@10.9.4: jake@10.9.4:
dependencies: dependencies:
async: 3.2.6 async: 3.2.6
@ -13528,6 +13603,8 @@ snapshots:
lru-cache@10.4.3: {} lru-cache@10.4.3: {}
lru-cache@11.2.1: {}
lru-cache@5.1.1: lru-cache@5.1.1:
dependencies: dependencies:
yallist: 3.1.1 yallist: 3.1.1
@ -13948,6 +14025,10 @@ snapshots:
minimalistic-assert@1.0.1: {} minimalistic-assert@1.0.1: {}
minimatch@10.0.3:
dependencies:
'@isaacs/brace-expansion': 5.0.0
minimatch@3.1.2: minimatch@3.1.2:
dependencies: dependencies:
brace-expansion: 1.1.12 brace-expansion: 1.1.12
@ -14341,6 +14422,11 @@ snapshots:
lru-cache: 10.4.3 lru-cache: 10.4.3
minipass: 7.1.2 minipass: 7.1.2
path-scurry@2.0.0:
dependencies:
lru-cache: 11.2.1
minipass: 7.1.2
path-to-regexp@0.1.12: {} path-to-regexp@0.1.12: {}
path-type@3.0.0: path-type@3.0.0:
@ -15863,9 +15949,7 @@ snapshots:
spdx-correct: 3.2.0 spdx-correct: 3.2.0
spdx-expression-parse: 3.0.1 spdx-expression-parse: 3.0.1
validate-npm-package-name@3.0.0: validate-npm-package-name@6.0.2: {}
dependencies:
builtins: 1.0.3
vary@1.1.2: {} vary@1.1.2: {}