chore: init project
This commit is contained in:
7
internal/lint-configs/commitlint-config/build.config.ts
Normal file
7
internal/lint-configs/commitlint-config/build.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index'],
|
||||
});
|
||||
42
internal/lint-configs/commitlint-config/package.json
Normal file
42
internal/lint-configs/commitlint-config/package.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@vben/commitlint-config",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/lint-configs/commitlint-config"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"stub": "pnpm unbuild --stub"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"imports": {
|
||||
"#*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"default": "./dist/index.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@commitlint/cli": "^19.3.0",
|
||||
"@commitlint/config-conventional": "^19.2.2",
|
||||
"@vben/node-utils": "workspace:*",
|
||||
"cz-git": "^1.9.1",
|
||||
"czg": "^1.9.1"
|
||||
}
|
||||
}
|
||||
145
internal/lint-configs/commitlint-config/src/index.ts
Normal file
145
internal/lint-configs/commitlint-config/src/index.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import type { UserConfig } from 'cz-git';
|
||||
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
import { getPackagesSync } from '@vben/node-utils';
|
||||
|
||||
const { packages } = getPackagesSync();
|
||||
|
||||
const pkgs = packages.map((pkg) => {
|
||||
return pkg.packageJson.name?.replace('@vben-core/', '');
|
||||
});
|
||||
|
||||
const scopes = [
|
||||
...pkgs,
|
||||
'project',
|
||||
'style',
|
||||
'lint',
|
||||
'ci',
|
||||
'dev',
|
||||
'deploy',
|
||||
'other',
|
||||
];
|
||||
|
||||
// precomputed scope
|
||||
const scopeComplete = execSync('git status --porcelain || true')
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.find((r) => ~r.indexOf('M src'))
|
||||
?.replace(/(\/)/g, '%%')
|
||||
?.match(/src%%((\w|-)*)/)?.[1]
|
||||
?.replace(/s$/, '');
|
||||
|
||||
const userConfig: UserConfig = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
prompt: {
|
||||
/** @use `pnpm commit :f` */
|
||||
alias: {
|
||||
b: 'build: bump dependencies',
|
||||
c: 'chore: update config',
|
||||
f: 'docs: fix typos',
|
||||
r: 'docs: update README',
|
||||
s: 'style: update code format',
|
||||
},
|
||||
allowCustomIssuePrefixs: false,
|
||||
// scopes: [...scopes, 'mock'],
|
||||
allowEmptyIssuePrefixs: false,
|
||||
customScopesAlign: scopeComplete ? 'bottom' : 'top',
|
||||
defaultScope: scopeComplete,
|
||||
// English
|
||||
typesAppend: [
|
||||
{ name: 'wip: work in process', value: 'wip' },
|
||||
{ name: 'workflow: workflow improvements', value: 'workflow' },
|
||||
{ name: 'types: type definition file changes', value: 'types' },
|
||||
],
|
||||
|
||||
// 中英文对照版
|
||||
// messages: {
|
||||
// type: '选择你要提交的类型 :',
|
||||
// scope: '选择一个提交范围 (可选):',
|
||||
// customScope: '请输入自定义的提交范围 :',
|
||||
// subject: '填写简短精炼的变更描述 :\n',
|
||||
// body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
|
||||
// breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
|
||||
// footerPrefixsSelect: '选择关联issue前缀 (可选):',
|
||||
// customFooterPrefixs: '输入自定义issue前缀 :',
|
||||
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
|
||||
// confirmCommit: '是否提交或修改commit ?',
|
||||
// },
|
||||
// types: [
|
||||
// { value: 'feat', name: 'feat: 新增功能' },
|
||||
// { value: 'fix', name: 'fix: 修复缺陷' },
|
||||
// { value: 'docs', name: 'docs: 文档变更' },
|
||||
// { value: 'style', name: 'style: 代码格式' },
|
||||
// { value: 'refactor', name: 'refactor: 代码重构' },
|
||||
// { value: 'perf', name: 'perf: 性能优化' },
|
||||
// { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
|
||||
// { value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },
|
||||
// { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
|
||||
// { value: 'revert', name: 'revert: 回滚 commit' },
|
||||
// { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },
|
||||
// { value: 'wip', name: 'wip: 正在开发中' },
|
||||
// { value: 'workflow', name: 'workflow: 工作流程改进' },
|
||||
// { value: 'types', name: 'types: 类型定义文件修改' },
|
||||
// ],
|
||||
// emptyScopesAlias: 'empty: 不填写',
|
||||
// customScopesAlias: 'custom: 自定义',
|
||||
},
|
||||
rules: {
|
||||
/**
|
||||
* type[scope]: [function] description
|
||||
*
|
||||
* ^^^^^^^^^^^^^^ empty line.
|
||||
* - Something here
|
||||
*/
|
||||
'body-leading-blank': [2, 'always'],
|
||||
/**
|
||||
* type[scope]: [function] description
|
||||
*
|
||||
* - something here
|
||||
*
|
||||
* ^^^^^^^^^^^^^^
|
||||
*/
|
||||
'footer-leading-blank': [1, 'always'],
|
||||
/**
|
||||
* type[scope]: [function] description [No more than 108 characters]
|
||||
* ^^^^^
|
||||
*/
|
||||
'header-max-length': [2, 'always', 108],
|
||||
/**
|
||||
* type[scope]: [function] description
|
||||
* ^^^^^
|
||||
*/
|
||||
'scope-enum': [2, 'always', scopes],
|
||||
'subject-case': [0],
|
||||
'subject-empty': [2, 'never'],
|
||||
'type-empty': [2, 'never'],
|
||||
/**
|
||||
* type[scope]: [function] description
|
||||
* ^^^^
|
||||
*/
|
||||
'type-enum': [
|
||||
2,
|
||||
'always',
|
||||
[
|
||||
'feat',
|
||||
'fix',
|
||||
'perf',
|
||||
'style',
|
||||
'docs',
|
||||
'test',
|
||||
'refactor',
|
||||
'build',
|
||||
'ci',
|
||||
'chore',
|
||||
'revert',
|
||||
'types',
|
||||
'release',
|
||||
'improvement',
|
||||
],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default userConfig;
|
||||
5
internal/lint-configs/commitlint-config/tsconfig.json
Normal file
5
internal/lint-configs/commitlint-config/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/node.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
7
internal/lint-configs/eslint-config/build.config.ts
Normal file
7
internal/lint-configs/eslint-config/build.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index'],
|
||||
});
|
||||
61
internal/lint-configs/eslint-config/package.json
Normal file
61
internal/lint-configs/eslint-config/package.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "@vben/eslint-config",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/lint-configs/eslint-config"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"stub": "pnpm unbuild --stub"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"imports": {
|
||||
"#*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-plugin-command": "^0.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.3.0",
|
||||
"@types/eslint": "^8.56.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.9.0",
|
||||
"@typescript-eslint/parser": "^7.9.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-i": "^2.29.1",
|
||||
"eslint-plugin-jsdoc": "^48.2.5",
|
||||
"eslint-plugin-jsonc": "^2.15.1",
|
||||
"eslint-plugin-n": "^17.7.0",
|
||||
"eslint-plugin-no-only-tests": "^3.1.0",
|
||||
"eslint-plugin-perfectionist": "^2.10.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-regexp": "^2.5.0",
|
||||
"eslint-plugin-unicorn": "^53.0.0",
|
||||
"eslint-plugin-unused-imports": "^3.2.0",
|
||||
"eslint-plugin-vitest": "^0.5.4",
|
||||
"eslint-plugin-vue": "^9.26.0",
|
||||
"globals": "^15.2.0",
|
||||
"jsonc-eslint-parser": "^2.4.0",
|
||||
"vue-eslint-parser": "^9.4.2"
|
||||
}
|
||||
}
|
||||
10
internal/lint-configs/eslint-config/src/configs/command.ts
Normal file
10
internal/lint-configs/eslint-config/src/configs/command.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import createCommand from 'eslint-plugin-command/config';
|
||||
|
||||
export async function command() {
|
||||
return [
|
||||
{
|
||||
// @ts-expect-error - no types
|
||||
...createCommand(),
|
||||
},
|
||||
];
|
||||
}
|
||||
22
internal/lint-configs/eslint-config/src/configs/comments.ts
Normal file
22
internal/lint-configs/eslint-config/src/configs/comments.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function comments(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginComments] = await Promise.all([
|
||||
// @ts-expect-error - no types
|
||||
import('eslint-plugin-eslint-comments'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
'eslint-comments': pluginComments,
|
||||
},
|
||||
rules: {
|
||||
'eslint-comments/no-aggregating-enable': 'error',
|
||||
'eslint-comments/no-duplicate-disable': 'error',
|
||||
'eslint-comments/no-unlimited-disable': 'error',
|
||||
'eslint-comments/no-unused-enable': 'error',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
46
internal/lint-configs/eslint-config/src/configs/ignores.ts
Normal file
46
internal/lint-configs/eslint-config/src/configs/ignores.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function ignores(): Promise<Linter.FlatConfig[]> {
|
||||
return [
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules',
|
||||
'**/dist',
|
||||
'**/.husky',
|
||||
'**/Dockerfile',
|
||||
'**/package-lock.json',
|
||||
'**/yarn.lock',
|
||||
'**/pnpm-lock.yaml',
|
||||
'**/bun.lockb',
|
||||
|
||||
'**/output',
|
||||
'**/coverage',
|
||||
'**/temp',
|
||||
'**/.temp',
|
||||
'**/tmp',
|
||||
'**/.tmp',
|
||||
'**/.history',
|
||||
'**/.vitepress/cache',
|
||||
'**/.nuxt',
|
||||
'**/.next',
|
||||
'**/.vercel',
|
||||
'**/.changeset',
|
||||
'**/.idea',
|
||||
'**/.cache',
|
||||
'**/.output',
|
||||
'**/.vite-inspect',
|
||||
|
||||
'**/CHANGELOG*.md',
|
||||
'**/*.min.*',
|
||||
'**/LICENSE*',
|
||||
'**/__snapshots__',
|
||||
'**/auto-import?(s).d.ts',
|
||||
'**/components.d.ts',
|
||||
'**/vite.config.mts.*',
|
||||
'**/*.sh',
|
||||
'**/*.ttf',
|
||||
'**/*.woff',
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
27
internal/lint-configs/eslint-config/src/configs/import.ts
Normal file
27
internal/lint-configs/eslint-config/src/configs/import.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function importPluginConfig(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginImport] = await Promise.all([
|
||||
// @ts-expect-error - no types
|
||||
import('eslint-plugin-i'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
import: pluginImport,
|
||||
},
|
||||
rules: {
|
||||
'import/first': 'error',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-duplicates': 'error',
|
||||
'import/no-mutable-exports': 'error',
|
||||
'import/no-named-default': 'error',
|
||||
'import/no-self-import': 'error',
|
||||
'import/no-unresolved': 'off',
|
||||
|
||||
'import/no-webpack-loader-syntax': 'error',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
15
internal/lint-configs/eslint-config/src/configs/index.ts
Normal file
15
internal/lint-configs/eslint-config/src/configs/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export * from './command';
|
||||
export * from './comments';
|
||||
export * from './ignores';
|
||||
export * from './import';
|
||||
export * from './javascript';
|
||||
export * from './jsdoc';
|
||||
export * from './jsonc';
|
||||
export * from './node';
|
||||
export * from './perfectionist';
|
||||
export * from './prettier';
|
||||
export * from './regexp';
|
||||
export * from './test';
|
||||
export * from './typescript';
|
||||
export * from './unicorn';
|
||||
export * from './vue';
|
||||
243
internal/lint-configs/eslint-config/src/configs/javascript.ts
Normal file
243
internal/lint-configs/eslint-config/src/configs/javascript.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
// @ts-expect-error - no types
|
||||
import js from '@eslint/js';
|
||||
// @ts-expect-error - no types
|
||||
import pluginUnusedImports from 'eslint-plugin-unused-imports';
|
||||
import globals from 'globals';
|
||||
|
||||
export async function javascript(): Promise<Linter.FlatConfig[]> {
|
||||
return [
|
||||
{
|
||||
languageOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.es2021,
|
||||
...globals.node,
|
||||
document: 'readonly',
|
||||
navigator: 'readonly',
|
||||
window: 'readonly',
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
sourceType: 'module',
|
||||
},
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: true,
|
||||
},
|
||||
plugins: {
|
||||
'unused-imports': pluginUnusedImports,
|
||||
},
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
'accessor-pairs': [
|
||||
'error',
|
||||
{ enforceForClassMembers: true, setWithoutGet: true },
|
||||
],
|
||||
'array-callback-return': 'error',
|
||||
'block-scoped-var': 'error',
|
||||
'constructor-super': 'error',
|
||||
'default-case-last': 'error',
|
||||
'dot-notation': ['error', { allowKeywords: true }],
|
||||
eqeqeq: ['error', 'always'],
|
||||
'keyword-spacing': 'off',
|
||||
|
||||
'new-cap': [
|
||||
'error',
|
||||
{ capIsNew: false, newIsCap: true, properties: true },
|
||||
],
|
||||
'no-alert': 'error',
|
||||
'no-array-constructor': 'error',
|
||||
'no-async-promise-executor': 'error',
|
||||
'no-caller': 'error',
|
||||
'no-case-declarations': 'error',
|
||||
'no-class-assign': 'error',
|
||||
'no-compare-neg-zero': 'error',
|
||||
'no-cond-assign': ['error', 'always'],
|
||||
'no-console': ['error', { allow: ['warn', 'error'] }],
|
||||
'no-const-assign': 'error',
|
||||
'no-control-regex': 'error',
|
||||
'no-debugger': 'error',
|
||||
'no-delete-var': 'error',
|
||||
'no-dupe-args': 'error',
|
||||
'no-dupe-class-members': 'error',
|
||||
'no-dupe-keys': 'error',
|
||||
'no-duplicate-case': 'error',
|
||||
'no-empty': ['error', { allowEmptyCatch: true }],
|
||||
'no-empty-character-class': 'error',
|
||||
'no-empty-function': 'off',
|
||||
'no-empty-pattern': 'error',
|
||||
'no-eval': 'error',
|
||||
'no-ex-assign': 'error',
|
||||
'no-extend-native': 'error',
|
||||
'no-extra-bind': 'error',
|
||||
'no-extra-boolean-cast': 'error',
|
||||
'no-fallthrough': 'error',
|
||||
'no-func-assign': 'error',
|
||||
'no-global-assign': 'error',
|
||||
'no-implied-eval': 'error',
|
||||
'no-import-assign': 'error',
|
||||
'no-invalid-regexp': 'error',
|
||||
'no-irregular-whitespace': 'error',
|
||||
'no-iterator': 'error',
|
||||
'no-labels': ['error', { allowLoop: false, allowSwitch: false }],
|
||||
'no-lone-blocks': 'error',
|
||||
'no-loss-of-precision': 'error',
|
||||
'no-misleading-character-class': 'error',
|
||||
'no-multi-str': 'error',
|
||||
'no-new': 'error',
|
||||
'no-new-func': 'error',
|
||||
'no-new-object': 'error',
|
||||
'no-new-symbol': 'error',
|
||||
'no-new-wrappers': 'error',
|
||||
'no-obj-calls': 'error',
|
||||
'no-octal': 'error',
|
||||
'no-octal-escape': 'error',
|
||||
'no-proto': 'error',
|
||||
'no-prototype-builtins': 'error',
|
||||
'no-redeclare': ['error', { builtinGlobals: false }],
|
||||
'no-regex-spaces': 'error',
|
||||
'no-restricted-globals': [
|
||||
'error',
|
||||
{ message: 'Use `globalThis` instead.', name: 'global' },
|
||||
{ message: 'Use `globalThis` instead.', name: 'self' },
|
||||
],
|
||||
'no-restricted-properties': [
|
||||
'error',
|
||||
{
|
||||
message:
|
||||
'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.',
|
||||
property: '__proto__',
|
||||
},
|
||||
{
|
||||
message: 'Use `Object.defineProperty` instead.',
|
||||
property: '__defineGetter__',
|
||||
},
|
||||
{
|
||||
message: 'Use `Object.defineProperty` instead.',
|
||||
property: '__defineSetter__',
|
||||
},
|
||||
{
|
||||
message: 'Use `Object.getOwnPropertyDescriptor` instead.',
|
||||
property: '__lookupGetter__',
|
||||
},
|
||||
{
|
||||
message: 'Use `Object.getOwnPropertyDescriptor` instead.',
|
||||
property: '__lookupSetter__',
|
||||
},
|
||||
],
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
'DebuggerStatement',
|
||||
'LabeledStatement',
|
||||
'WithStatement',
|
||||
'TSEnumDeclaration[const=true]',
|
||||
'TSExportAssignment',
|
||||
],
|
||||
'no-self-assign': ['error', { props: true }],
|
||||
'no-self-compare': 'error',
|
||||
'no-sequences': 'error',
|
||||
'no-shadow-restricted-names': 'error',
|
||||
'no-sparse-arrays': 'error',
|
||||
'no-template-curly-in-string': 'error',
|
||||
'no-this-before-super': 'error',
|
||||
'no-throw-literal': 'error',
|
||||
'no-undef': 'error',
|
||||
'no-undef-init': 'error',
|
||||
'no-unexpected-multiline': 'error',
|
||||
'no-unmodified-loop-condition': 'error',
|
||||
'no-unneeded-ternary': ['error', { defaultAssignment: false }],
|
||||
'no-unreachable': 'error',
|
||||
'no-unreachable-loop': 'error',
|
||||
'no-unsafe-finally': 'error',
|
||||
'no-unsafe-negation': 'error',
|
||||
'no-unused-expressions': [
|
||||
'error',
|
||||
{
|
||||
allowShortCircuit: true,
|
||||
allowTaggedTemplates: true,
|
||||
allowTernary: true,
|
||||
},
|
||||
],
|
||||
'no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
args: 'none',
|
||||
caughtErrors: 'none',
|
||||
ignoreRestSiblings: true,
|
||||
vars: 'all',
|
||||
},
|
||||
],
|
||||
'no-use-before-define': [
|
||||
'error',
|
||||
{ classes: false, functions: false, variables: true },
|
||||
],
|
||||
'no-useless-backreference': 'error',
|
||||
'no-useless-call': 'error',
|
||||
'no-useless-catch': 'error',
|
||||
'no-useless-computed-key': 'error',
|
||||
'no-useless-constructor': 'error',
|
||||
'no-useless-rename': 'error',
|
||||
'no-useless-return': 'error',
|
||||
'no-var': 'error',
|
||||
'no-with': 'error',
|
||||
'object-shorthand': [
|
||||
'error',
|
||||
'always',
|
||||
{ avoidQuotes: true, ignoreConstructors: false },
|
||||
],
|
||||
'one-var': ['error', { initialized: 'never' }],
|
||||
'prefer-arrow-callback': [
|
||||
'error',
|
||||
{
|
||||
allowNamedFunctions: false,
|
||||
allowUnboundThis: true,
|
||||
},
|
||||
],
|
||||
'prefer-const': [
|
||||
'error',
|
||||
{
|
||||
destructuring: 'all',
|
||||
ignoreReadBeforeAssign: true,
|
||||
},
|
||||
],
|
||||
'prefer-exponentiation-operator': 'error',
|
||||
|
||||
'prefer-promise-reject-errors': 'error',
|
||||
'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
|
||||
'prefer-rest-params': 'error',
|
||||
'prefer-spread': 'error',
|
||||
'prefer-template': 'error',
|
||||
'space-before-function-paren': 'off',
|
||||
'spaced-comment': 'error',
|
||||
'symbol-description': 'error',
|
||||
'unicode-bom': ['error', 'never'],
|
||||
|
||||
'unused-imports/no-unused-imports': 'error',
|
||||
'unused-imports/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
args: 'after-used',
|
||||
argsIgnorePattern: '^_',
|
||||
vars: 'all',
|
||||
varsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
'use-isnan': [
|
||||
'error',
|
||||
{ enforceForIndexOf: true, enforceForSwitchCase: true },
|
||||
],
|
||||
'valid-typeof': ['error', { requireStringLiterals: true }],
|
||||
|
||||
'vars-on-top': 'error',
|
||||
yoda: ['error', 'never'],
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
33
internal/lint-configs/eslint-config/src/configs/jsdoc.ts
Normal file
33
internal/lint-configs/eslint-config/src/configs/jsdoc.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function jsdoc(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginJsdoc] = await Promise.all([
|
||||
import('eslint-plugin-jsdoc'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
// @ts-expect-error - no types
|
||||
jsdoc: pluginJsdoc,
|
||||
},
|
||||
rules: {
|
||||
'jsdoc/check-access': 'warn',
|
||||
'jsdoc/check-param-names': 'warn',
|
||||
'jsdoc/check-property-names': 'warn',
|
||||
'jsdoc/check-types': 'warn',
|
||||
'jsdoc/empty-tags': 'warn',
|
||||
'jsdoc/implements-on-classes': 'warn',
|
||||
'jsdoc/no-defaults': 'warn',
|
||||
'jsdoc/no-multi-asterisks': 'warn',
|
||||
'jsdoc/require-param-name': 'warn',
|
||||
'jsdoc/require-property': 'warn',
|
||||
'jsdoc/require-property-description': 'warn',
|
||||
'jsdoc/require-property-name': 'warn',
|
||||
'jsdoc/require-returns-check': 'warn',
|
||||
'jsdoc/require-returns-description': 'warn',
|
||||
'jsdoc/require-yields-check': 'warn',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
257
internal/lint-configs/eslint-config/src/configs/jsonc.ts
Normal file
257
internal/lint-configs/eslint-config/src/configs/jsonc.ts
Normal file
@@ -0,0 +1,257 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function jsonc(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginJsonc, parserJsonc] = await Promise.all([
|
||||
import('eslint-plugin-jsonc'),
|
||||
import('jsonc-eslint-parser'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
files: ['**/*.json', '**/*.json5', '**/*.jsonc', '*.code-workspace'],
|
||||
languageOptions: {
|
||||
parser: parserJsonc as any,
|
||||
},
|
||||
plugins: {
|
||||
jsonc: pluginJsonc as any,
|
||||
},
|
||||
rules: {
|
||||
'jsonc/no-bigint-literals': 'error',
|
||||
'jsonc/no-binary-expression': 'error',
|
||||
'jsonc/no-binary-numeric-literals': 'error',
|
||||
'jsonc/no-dupe-keys': 'error',
|
||||
'jsonc/no-escape-sequence-in-identifier': 'error',
|
||||
'jsonc/no-floating-decimal': 'error',
|
||||
'jsonc/no-hexadecimal-numeric-literals': 'error',
|
||||
'jsonc/no-infinity': 'error',
|
||||
'jsonc/no-multi-str': 'error',
|
||||
'jsonc/no-nan': 'error',
|
||||
'jsonc/no-number-props': 'error',
|
||||
'jsonc/no-numeric-separators': 'error',
|
||||
'jsonc/no-octal': 'error',
|
||||
'jsonc/no-octal-escape': 'error',
|
||||
'jsonc/no-octal-numeric-literals': 'error',
|
||||
'jsonc/no-parenthesized': 'error',
|
||||
'jsonc/no-plus-sign': 'error',
|
||||
'jsonc/no-regexp-literals': 'error',
|
||||
'jsonc/no-sparse-arrays': 'error',
|
||||
'jsonc/no-template-literals': 'error',
|
||||
'jsonc/no-undefined-value': 'error',
|
||||
'jsonc/no-unicode-codepoint-escapes': 'error',
|
||||
'jsonc/no-useless-escape': 'error',
|
||||
'jsonc/space-unary-ops': 'error',
|
||||
'jsonc/valid-json-number': 'error',
|
||||
'jsonc/vue-custom-block/no-parsing-error': 'error',
|
||||
},
|
||||
},
|
||||
sortTsconfig(),
|
||||
sortPackageJson(),
|
||||
];
|
||||
}
|
||||
|
||||
function sortPackageJson(): Linter.FlatConfig {
|
||||
return {
|
||||
files: ['**/package.json'],
|
||||
rules: {
|
||||
'jsonc/sort-array-values': [
|
||||
'error',
|
||||
{
|
||||
order: { type: 'asc' },
|
||||
pathPattern: '^files$|^pnpm.neverBuiltDependencies$',
|
||||
},
|
||||
],
|
||||
'jsonc/sort-keys': [
|
||||
'error',
|
||||
{
|
||||
order: [
|
||||
'publisher',
|
||||
'name',
|
||||
'version',
|
||||
'private',
|
||||
'description',
|
||||
'displayName',
|
||||
'type',
|
||||
'author',
|
||||
'license',
|
||||
'funding',
|
||||
'homepage',
|
||||
'repository',
|
||||
'bugs',
|
||||
'keywords',
|
||||
'categories',
|
||||
'scripts',
|
||||
'files',
|
||||
'sideEffects',
|
||||
'bin',
|
||||
'main',
|
||||
'module',
|
||||
'unpkg',
|
||||
'jsdelivr',
|
||||
'types',
|
||||
'typesVersions',
|
||||
'imports',
|
||||
'exports',
|
||||
'publishConfig',
|
||||
'icon',
|
||||
'activationEvents',
|
||||
'contributes',
|
||||
'peerDependencies',
|
||||
'peerDependenciesMeta',
|
||||
'dependencies',
|
||||
'optionalDependencies',
|
||||
'devDependencies',
|
||||
'engines',
|
||||
'packageManager',
|
||||
'pnpm',
|
||||
'overrides',
|
||||
'resolutions',
|
||||
'husky',
|
||||
'simple-git-hooks',
|
||||
'lint-staged',
|
||||
'eslintConfig',
|
||||
],
|
||||
pathPattern: '^$',
|
||||
},
|
||||
{
|
||||
order: { type: 'asc' },
|
||||
pathPattern: '^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$',
|
||||
},
|
||||
{
|
||||
order: { type: 'asc' },
|
||||
pathPattern: '^(?:resolutions|overrides|pnpm.overrides)$',
|
||||
},
|
||||
{
|
||||
order: ['types', 'import', 'require', 'default'],
|
||||
pathPattern: '^exports.*$',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function sortTsconfig(): Linter.FlatConfig {
|
||||
return {
|
||||
files: [
|
||||
'**/tsconfig.json',
|
||||
'**/tsconfig.*.json',
|
||||
'internal/tsconfig/*.json',
|
||||
],
|
||||
rules: {
|
||||
'jsonc/sort-keys': [
|
||||
'error',
|
||||
{
|
||||
order: [
|
||||
'extends',
|
||||
'compilerOptions',
|
||||
'references',
|
||||
'files',
|
||||
'include',
|
||||
'exclude',
|
||||
],
|
||||
pathPattern: '^$',
|
||||
},
|
||||
{
|
||||
order: [
|
||||
/* Projects */
|
||||
'incremental',
|
||||
'composite',
|
||||
'tsBuildInfoFile',
|
||||
'disableSourceOfProjectReferenceRedirect',
|
||||
'disableSolutionSearching',
|
||||
'disableReferencedProjectLoad',
|
||||
/* Language and Environment */
|
||||
'target',
|
||||
'jsx',
|
||||
'jsxFactory',
|
||||
'jsxFragmentFactory',
|
||||
'jsxImportSource',
|
||||
'lib',
|
||||
'moduleDetection',
|
||||
'noLib',
|
||||
'reactNamespace',
|
||||
'useDefineForClassFields',
|
||||
'emitDecoratorMetadata',
|
||||
'experimentalDecorators',
|
||||
/* Modules */
|
||||
'baseUrl',
|
||||
'rootDir',
|
||||
'rootDirs',
|
||||
'customConditions',
|
||||
'module',
|
||||
'moduleResolution',
|
||||
'moduleSuffixes',
|
||||
'noResolve',
|
||||
'paths',
|
||||
'resolveJsonModule',
|
||||
'resolvePackageJsonExports',
|
||||
'resolvePackageJsonImports',
|
||||
'typeRoots',
|
||||
'types',
|
||||
'allowArbitraryExtensions',
|
||||
'allowImportingTsExtensions',
|
||||
'allowUmdGlobalAccess',
|
||||
/* JavaScript Support */
|
||||
'allowJs',
|
||||
'checkJs',
|
||||
'maxNodeModuleJsDepth',
|
||||
/* Type Checking */
|
||||
'strict',
|
||||
'strictBindCallApply',
|
||||
'strictFunctionTypes',
|
||||
'strictNullChecks',
|
||||
'strictPropertyInitialization',
|
||||
'allowUnreachableCode',
|
||||
'allowUnusedLabels',
|
||||
'alwaysStrict',
|
||||
'exactOptionalPropertyTypes',
|
||||
'noFallthroughCasesInSwitch',
|
||||
'noImplicitAny',
|
||||
'noImplicitOverride',
|
||||
'noImplicitReturns',
|
||||
'noImplicitThis',
|
||||
'noPropertyAccessFromIndexSignature',
|
||||
'noUncheckedIndexedAccess',
|
||||
'noUnusedLocals',
|
||||
'noUnusedParameters',
|
||||
'useUnknownInCatchVariables',
|
||||
/* Emit */
|
||||
'declaration',
|
||||
'declarationDir',
|
||||
'declarationMap',
|
||||
'downlevelIteration',
|
||||
'emitBOM',
|
||||
'emitDeclarationOnly',
|
||||
'importHelpers',
|
||||
'importsNotUsedAsValues',
|
||||
'inlineSourceMap',
|
||||
'inlineSources',
|
||||
'mapRoot',
|
||||
'newLine',
|
||||
'noEmit',
|
||||
'noEmitHelpers',
|
||||
'noEmitOnError',
|
||||
'outDir',
|
||||
'outFile',
|
||||
'preserveConstEnums',
|
||||
'preserveValueImports',
|
||||
'removeComments',
|
||||
'sourceMap',
|
||||
'sourceRoot',
|
||||
'stripInternal',
|
||||
/* Interop Constraints */
|
||||
'allowSyntheticDefaultImports',
|
||||
'esModuleInterop',
|
||||
'forceConsistentCasingInFileNames',
|
||||
'isolatedModules',
|
||||
'preserveSymlinks',
|
||||
'verbatimModuleSyntax',
|
||||
/* Completeness */
|
||||
'skipDefaultLibCheck',
|
||||
'skipLibCheck',
|
||||
],
|
||||
pathPattern: '^compilerOptions$',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
54
internal/lint-configs/eslint-config/src/configs/node.ts
Normal file
54
internal/lint-configs/eslint-config/src/configs/node.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function node(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginNode] = await Promise.all([import('eslint-plugin-n')] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
n: pluginNode,
|
||||
},
|
||||
rules: {
|
||||
'n/handle-callback-err': ['error', '^(err|error)$'],
|
||||
'n/no-deprecated-api': 'error',
|
||||
'n/no-exports-assign': 'error',
|
||||
'n/no-extraneous-import': [
|
||||
'error',
|
||||
{
|
||||
allowModules: [
|
||||
'unbuild',
|
||||
'@vben/vite-config',
|
||||
'vitest',
|
||||
'vite',
|
||||
'@vue/test-utils',
|
||||
'@vben/tailwind-config',
|
||||
],
|
||||
},
|
||||
],
|
||||
'n/no-new-require': 'error',
|
||||
'n/no-path-concat': 'error',
|
||||
// 'n/no-unpublished-import': 'off',
|
||||
'n/no-unsupported-features/es-syntax': [
|
||||
'error',
|
||||
{
|
||||
ignores: [],
|
||||
version: '>=18.0.0',
|
||||
},
|
||||
],
|
||||
'n/prefer-global/buffer': ['error', 'never'],
|
||||
// 'n/no-missing-import': 'off',
|
||||
'n/prefer-global/process': ['error', 'never'],
|
||||
'n/process-exit-as-throw': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'scripts/**/*.?([cm])[jt]s?(x)',
|
||||
'internal/**/*.?([cm])[jt]s?(x)',
|
||||
],
|
||||
rules: {
|
||||
'n/prefer-global/process': 'off',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function perfectionist(): Promise<Linter.FlatConfig[]> {
|
||||
const [perfectionistNatural] = await Promise.all([
|
||||
// @ts-expect-error - no types
|
||||
import('eslint-plugin-perfectionist/configs/recommended-natural'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
perfectionistNatural,
|
||||
{
|
||||
rules: {
|
||||
'perfectionist/sort-exports': [
|
||||
'error',
|
||||
{
|
||||
order: 'asc',
|
||||
type: 'natural',
|
||||
},
|
||||
],
|
||||
'perfectionist/sort-imports': [
|
||||
'error',
|
||||
{
|
||||
'custom-groups': {
|
||||
type: {
|
||||
vben: 'vue',
|
||||
vue: ['vue', 'vue-*', '@vue*'],
|
||||
},
|
||||
value: {
|
||||
vben: 'vben',
|
||||
vue: ['@vben-*', '@vben-core/*'],
|
||||
},
|
||||
},
|
||||
groups: [
|
||||
'side-effect',
|
||||
'type',
|
||||
'vue',
|
||||
'builtin',
|
||||
'vben',
|
||||
'external',
|
||||
'internal-type',
|
||||
'internal',
|
||||
['parent', 'sibling', 'index'],
|
||||
'style',
|
||||
'object',
|
||||
'unknown',
|
||||
'type',
|
||||
['parent-type', 'sibling-type', 'index-type'],
|
||||
],
|
||||
'internal-pattern': ['@/layouts/**', '@/router/**', '@/views/**'],
|
||||
'newlines-between': 'always',
|
||||
order: 'asc',
|
||||
type: 'natural',
|
||||
},
|
||||
],
|
||||
'perfectionist/sort-named-exports': [
|
||||
'error',
|
||||
{
|
||||
order: 'asc',
|
||||
type: 'natural',
|
||||
},
|
||||
],
|
||||
'perfectionist/sort-objects': [
|
||||
'error',
|
||||
{
|
||||
'custom-groups': {
|
||||
items: 'items',
|
||||
list: 'list',
|
||||
children: 'children',
|
||||
},
|
||||
groups: ['unknown', 'items', 'list', 'children'],
|
||||
'ignore-pattern': ['children'],
|
||||
order: 'asc',
|
||||
'partition-by-comment': 'Part:**',
|
||||
type: 'natural',
|
||||
},
|
||||
],
|
||||
'perfectionist/sort-vue-attributes': 'off',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
17
internal/lint-configs/eslint-config/src/configs/prettier.ts
Normal file
17
internal/lint-configs/eslint-config/src/configs/prettier.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function prettier(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginPrettier] = await Promise.all([
|
||||
import('eslint-plugin-prettier'),
|
||||
] as const);
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
prettier: pluginPrettier,
|
||||
},
|
||||
rules: {
|
||||
'prettier/prettier': 'error',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
18
internal/lint-configs/eslint-config/src/configs/regexp.ts
Normal file
18
internal/lint-configs/eslint-config/src/configs/regexp.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function regexp(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginRegexp] = await Promise.all([
|
||||
import('eslint-plugin-regexp'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
regexp: pluginRegexp,
|
||||
},
|
||||
rules: {
|
||||
...pluginRegexp.configs.recommended.rules,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
44
internal/lint-configs/eslint-config/src/configs/test.ts
Normal file
44
internal/lint-configs/eslint-config/src/configs/test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function test(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginTest, pluginNoOnlyTests] = await Promise.all([
|
||||
import('eslint-plugin-vitest'),
|
||||
// @ts-expect-error - no types
|
||||
import('eslint-plugin-no-only-tests'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
files: [
|
||||
`**/__tests__/**/*.?([cm])[jt]s?(x)`,
|
||||
`**/*.spec.?([cm])[jt]s?(x)`,
|
||||
`**/*.test.?([cm])[jt]s?(x)`,
|
||||
`**/*.bench.?([cm])[jt]s?(x)`,
|
||||
`**/*.benchmark.?([cm])[jt]s?(x)`,
|
||||
],
|
||||
plugins: {
|
||||
test: {
|
||||
...pluginTest,
|
||||
rules: {
|
||||
// @ts-expect-error - no types
|
||||
...pluginTest.rules,
|
||||
...pluginNoOnlyTests.rules,
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
'node/prefer-global/process': 'off',
|
||||
'test/consistent-test-it': [
|
||||
'error',
|
||||
{ fn: 'it', withinDescribe: 'it' },
|
||||
],
|
||||
'test/no-identical-title': 'error',
|
||||
'test/no-import-node-test': 'error',
|
||||
'test/no-only-tests': 'error',
|
||||
'test/prefer-hooks-in-order': 'error',
|
||||
'test/prefer-lowercase-title': 'error',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function typescript(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginTs, parserTs] = await Promise.all([
|
||||
import('@typescript-eslint/eslint-plugin'),
|
||||
// @ts-expect-error missing types
|
||||
import('@typescript-eslint/parser'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
files: ['**/*.?([cm])[jt]s?(x)'],
|
||||
languageOptions: {
|
||||
parser: parserTs,
|
||||
parserOptions: {
|
||||
createDefaultProgram: false,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 'latest',
|
||||
extraFileExtensions: ['.vue'],
|
||||
jsxPragma: 'React',
|
||||
project: './tsconfig.*?.json',
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
'@typescript-eslint': pluginTs,
|
||||
},
|
||||
rules: {
|
||||
...pluginTs.configs['eslint-recommended'].overrides?.[0].rules,
|
||||
...pluginTs.configs.strict.rules,
|
||||
'@typescript-eslint/ban-ts-comment': [
|
||||
'error',
|
||||
{
|
||||
'ts-check': false,
|
||||
'ts-expect-error': 'allow-with-description',
|
||||
'ts-ignore': 'allow-with-description',
|
||||
'ts-nocheck': 'allow-with-description',
|
||||
},
|
||||
],
|
||||
|
||||
'@typescript-eslint/ban-types': 'error',
|
||||
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/keyword-spacing': [
|
||||
'error',
|
||||
{
|
||||
after: true,
|
||||
before: true,
|
||||
overrides: {
|
||||
case: { after: true },
|
||||
return: { after: true },
|
||||
throw: { after: true },
|
||||
},
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-empty-function': [
|
||||
'error',
|
||||
{
|
||||
allow: ['arrowFunctions', 'functions', 'methods'],
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-namespace': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'error',
|
||||
'unused-imports/no-unused-vars': 'off',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
40
internal/lint-configs/eslint-config/src/configs/unicorn.ts
Normal file
40
internal/lint-configs/eslint-config/src/configs/unicorn.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function unicorn(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginUnicorn] = await Promise.all([
|
||||
// @ts-expect-error - missing types
|
||||
import('eslint-plugin-unicorn'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
unicorn: pluginUnicorn,
|
||||
},
|
||||
rules: {
|
||||
...pluginUnicorn.configs.recommended.rules,
|
||||
|
||||
'unicorn/consistent-destructuring': 'off',
|
||||
'unicorn/consistent-function-scoping': 'off',
|
||||
'unicorn/filename-case': 'off',
|
||||
'unicorn/import-style': 'off',
|
||||
'unicorn/no-array-for-each': 'off',
|
||||
'unicorn/no-null': 'off',
|
||||
'unicorn/prefer-at': 'off',
|
||||
'unicorn/prefer-dom-node-text-content': 'off',
|
||||
'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],
|
||||
'unicorn/prefer-top-level-await': 'off',
|
||||
'unicorn/prevent-abbreviations': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'scripts/**/*.?([cm])[jt]s?(x)',
|
||||
'internal/**/*.?([cm])[jt]s?(x)',
|
||||
],
|
||||
rules: {
|
||||
'unicorn/no-process-exit': 'off',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
136
internal/lint-configs/eslint-config/src/configs/vue.ts
Normal file
136
internal/lint-configs/eslint-config/src/configs/vue.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export async function vue(): Promise<Linter.FlatConfig[]> {
|
||||
const [pluginVue, parserVue, parserTs] = await Promise.all([
|
||||
// @ts-expect-error missing types
|
||||
import('eslint-plugin-vue'),
|
||||
import('vue-eslint-parser'),
|
||||
// @ts-expect-error missing types
|
||||
import('@typescript-eslint/parser'),
|
||||
] as const);
|
||||
|
||||
return [
|
||||
{
|
||||
files: ['**/*.vue'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
// TODO: 等待插件正式支持后删除
|
||||
defineModel: true,
|
||||
},
|
||||
parser: parserVue,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
extraFileExtensions: ['.vue'],
|
||||
parser: parserTs,
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
vue: pluginVue,
|
||||
},
|
||||
processor: pluginVue.processors['.vue'],
|
||||
rules: {
|
||||
...pluginVue.configs.base.rules,
|
||||
...pluginVue.configs['vue3-essential'].rules,
|
||||
...pluginVue.configs['vue3-strongly-recommended'].rules,
|
||||
...pluginVue.configs['vue3-recommended'].rules,
|
||||
|
||||
'vue/attribute-hyphenation': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
ignore: [],
|
||||
},
|
||||
],
|
||||
'vue/attributes-order': 'error',
|
||||
'vue/block-order': [
|
||||
'error',
|
||||
{
|
||||
order: ['script', 'template', 'style'],
|
||||
},
|
||||
],
|
||||
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
|
||||
'vue/component-options-name-casing': ['error', 'PascalCase'],
|
||||
'vue/custom-event-name-casing': ['error', 'camelCase'],
|
||||
'vue/define-macros-order': [
|
||||
'error',
|
||||
{
|
||||
order: [
|
||||
'defineOptions',
|
||||
'defineProps',
|
||||
'defineEmits',
|
||||
'defineSlots',
|
||||
],
|
||||
},
|
||||
],
|
||||
'vue/dot-location': ['error', 'property'],
|
||||
'vue/dot-notation': ['error', { allowKeywords: true }],
|
||||
'vue/eqeqeq': ['error', 'smart'],
|
||||
'vue/html-closing-bracket-newline': 'error',
|
||||
'vue/html-indent': 'off',
|
||||
// 'vue/html-indent': ['error', 2],
|
||||
'vue/html-quotes': ['error', 'double'],
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
component: 'always',
|
||||
normal: 'never',
|
||||
void: 'always',
|
||||
},
|
||||
math: 'always',
|
||||
svg: 'always',
|
||||
},
|
||||
],
|
||||
'vue/max-attributes-per-line': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/multiline-html-element-content-newline': 'error',
|
||||
'vue/no-empty-pattern': 'error',
|
||||
'vue/no-extra-parens': ['error', 'functions'],
|
||||
'vue/no-irregular-whitespace': 'error',
|
||||
'vue/no-loss-of-precision': 'error',
|
||||
'vue/no-reserved-component-names': 'off',
|
||||
'vue/no-restricted-syntax': [
|
||||
'error',
|
||||
'DebuggerStatement',
|
||||
'LabeledStatement',
|
||||
'WithStatement',
|
||||
],
|
||||
'vue/no-restricted-v-bind': ['error', '/^v-/'],
|
||||
'vue/no-sparse-arrays': 'error',
|
||||
'vue/no-unused-refs': 'error',
|
||||
'vue/no-useless-v-bind': 'error',
|
||||
'vue/object-shorthand': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
avoidQuotes: true,
|
||||
ignoreConstructors: false,
|
||||
},
|
||||
],
|
||||
'vue/one-component-per-file': 'error',
|
||||
'vue/prefer-import-from-vue': 'error',
|
||||
'vue/prefer-separate-static-class': 'error',
|
||||
'vue/prefer-template': 'error',
|
||||
'vue/prop-name-casing': ['error', 'camelCase'],
|
||||
'vue/require-default-prop': 'error',
|
||||
'vue/require-explicit-emits': 'error',
|
||||
'vue/require-prop-types': 'off',
|
||||
'vue/script-setup-uses-vars': 'error',
|
||||
'vue/singleline-html-element-content-newline': 'off',
|
||||
'vue/space-infix-ops': 'error',
|
||||
'vue/space-unary-ops': ['error', { nonwords: false, words: true }],
|
||||
'vue/v-on-event-hyphenation': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
autofix: true,
|
||||
ignore: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
12
internal/lint-configs/eslint-config/src/custom-config.ts
Normal file
12
internal/lint-configs/eslint-config/src/custom-config.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
const customConfig: Linter.FlatConfig[] = [
|
||||
{
|
||||
files: ['packages/@vben-core/uikit/shadcn-ui/**/**'],
|
||||
rules: {
|
||||
'vue/require-default-prop': 'off',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export { customConfig };
|
||||
56
internal/lint-configs/eslint-config/src/index.ts
Normal file
56
internal/lint-configs/eslint-config/src/index.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
import {
|
||||
command,
|
||||
comments,
|
||||
ignores,
|
||||
importPluginConfig,
|
||||
javascript,
|
||||
jsdoc,
|
||||
jsonc,
|
||||
node,
|
||||
perfectionist,
|
||||
prettier,
|
||||
regexp,
|
||||
test,
|
||||
typescript,
|
||||
unicorn,
|
||||
vue,
|
||||
} from './configs';
|
||||
import { customConfig } from './custom-config';
|
||||
|
||||
type FlatConfig = Linter.FlatConfig;
|
||||
|
||||
type FlatConfigPromise =
|
||||
| FlatConfig
|
||||
| FlatConfig[]
|
||||
| Promise<FlatConfig>
|
||||
| Promise<FlatConfig[]>;
|
||||
|
||||
async function defineConfig(config: FlatConfig[] = []) {
|
||||
const configs: FlatConfigPromise[] = [
|
||||
vue(),
|
||||
javascript(),
|
||||
ignores(),
|
||||
prettier(),
|
||||
typescript(),
|
||||
jsonc(),
|
||||
importPluginConfig(),
|
||||
node(),
|
||||
perfectionist(),
|
||||
comments(),
|
||||
jsdoc(),
|
||||
unicorn(),
|
||||
test(),
|
||||
regexp(),
|
||||
command(),
|
||||
...customConfig,
|
||||
...config,
|
||||
];
|
||||
|
||||
const resolved = await Promise.all(configs);
|
||||
|
||||
return resolved.flat();
|
||||
}
|
||||
|
||||
export { defineConfig };
|
||||
5
internal/lint-configs/eslint-config/tsconfig.json
Normal file
5
internal/lint-configs/eslint-config/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/node.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
7
internal/lint-configs/lint-staged-config/build.config.ts
Normal file
7
internal/lint-configs/lint-staged-config/build.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index'],
|
||||
});
|
||||
38
internal/lint-configs/lint-staged-config/package.json
Normal file
38
internal/lint-configs/lint-staged-config/package.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@vben/lint-staged-config",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/lint-configs/lint-staged-config"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"stub": "pnpm unbuild --stub"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"imports": {
|
||||
"#*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"default": "./dist/index.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"lint-staged": "15.2.2"
|
||||
}
|
||||
}
|
||||
16
internal/lint-configs/lint-staged-config/src/index.ts
Normal file
16
internal/lint-configs/lint-staged-config/src/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export default {
|
||||
'*.{js,jsx,ts,tsx}': [
|
||||
'prettier --cache --ignore-unknown --write',
|
||||
'eslint --cache --fix',
|
||||
],
|
||||
'*.{scss,less,styl,html,vue,css}': [
|
||||
'prettier --cache --ignore-unknown --write',
|
||||
'stylelint --fix',
|
||||
],
|
||||
'*.md': ['prettier --cache --ignore-unknown --write'],
|
||||
'*.vue': ['prettier --write', 'eslint --cache --fix', 'stylelint --fix'],
|
||||
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [
|
||||
'prettier --cache --write--parser json',
|
||||
],
|
||||
'package.json': ['prettier --cache --write'],
|
||||
};
|
||||
5
internal/lint-configs/lint-staged-config/tsconfig.json
Normal file
5
internal/lint-configs/lint-staged-config/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/node.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
7
internal/lint-configs/prettier-config/build.config.ts
Normal file
7
internal/lint-configs/prettier-config/build.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index'],
|
||||
});
|
||||
39
internal/lint-configs/prettier-config/package.json
Normal file
39
internal/lint-configs/prettier-config/package.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@vben/prettier-config",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/lint-configs/prettier-config"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"stub": "pnpm unbuild --stub"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"imports": {
|
||||
"#*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"default": "./dist/index.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-tailwindcss": "^0.5.14"
|
||||
}
|
||||
}
|
||||
24
internal/lint-configs/prettier-config/src/index.ts
Normal file
24
internal/lint-configs/prettier-config/src/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export default {
|
||||
endOfLine: 'auto',
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.json5'],
|
||||
options: {
|
||||
quoteProps: 'preserve',
|
||||
singleQuote: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.yaml', '*.yml'],
|
||||
options: {
|
||||
singleQuote: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
plugins: ['prettier-plugin-tailwindcss'],
|
||||
printWidth: 80,
|
||||
proseWrap: 'never',
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
};
|
||||
5
internal/lint-configs/prettier-config/tsconfig.json
Normal file
5
internal/lint-configs/prettier-config/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/node.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
7
internal/lint-configs/stylelint-config/build.config.ts
Normal file
7
internal/lint-configs/stylelint-config/build.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index'],
|
||||
});
|
||||
53
internal/lint-configs/stylelint-config/package.json
Normal file
53
internal/lint-configs/stylelint-config/package.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "@vben/stylelint-config",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/lint-configs/stylelint-config"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"stub": "pnpm unbuild --stub"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"imports": {
|
||||
"#*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"default": "./dist/index.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@stylistic/stylelint-plugin": "^2.1.2",
|
||||
"stylelint-config-recess-order": "^5.0.1",
|
||||
"stylelint-scss": "^6.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"postcss": "^8.4.38",
|
||||
"postcss-html": "^1.7.0",
|
||||
"postcss-scss": "^4.0.9",
|
||||
"prettier": "^3.2.5",
|
||||
"stylelint": "^16.5.0",
|
||||
"stylelint-config-recommended": "^14.0.0",
|
||||
"stylelint-config-recommended-scss": "^14.0.0",
|
||||
"stylelint-config-recommended-vue": "^1.5.0",
|
||||
"stylelint-config-standard": "^36.0.0",
|
||||
"stylelint-order": "^6.0.4",
|
||||
"stylelint-prettier": "^5.0.0"
|
||||
}
|
||||
}
|
||||
140
internal/lint-configs/stylelint-config/src/index.ts
Normal file
140
internal/lint-configs/stylelint-config/src/index.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
export default {
|
||||
extends: ['stylelint-config-standard', 'stylelint-config-recess-order'],
|
||||
ignoreFiles: [
|
||||
'**/*.js',
|
||||
'**/*.jsx',
|
||||
'**/*.tsx',
|
||||
'**/*.ts',
|
||||
'**/*.json',
|
||||
'**/*.md',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
customSyntax: 'postcss-html',
|
||||
files: ['**/*.(css|html|vue)'],
|
||||
rules: {
|
||||
'selector-pseudo-class-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignorePseudoClasses: ['global', 'deep'],
|
||||
},
|
||||
],
|
||||
'selector-pseudo-element-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
customSyntax: 'postcss-scss',
|
||||
extends: [
|
||||
'stylelint-config-recommended-scss',
|
||||
'stylelint-config-recommended-vue/scss',
|
||||
],
|
||||
files: ['*.scss', '**/*.scss'],
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
'stylelint-order',
|
||||
'@stylistic/stylelint-plugin',
|
||||
'stylelint-prettier',
|
||||
'stylelint-scss',
|
||||
],
|
||||
rules: {
|
||||
'at-rule-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignoreAtRules: [
|
||||
'extends',
|
||||
'ignores',
|
||||
'include',
|
||||
'mixin',
|
||||
'if',
|
||||
'else',
|
||||
'media',
|
||||
'for',
|
||||
'at-root',
|
||||
'tailwind',
|
||||
'apply',
|
||||
'variants',
|
||||
'responsive',
|
||||
'screen',
|
||||
'function',
|
||||
'each',
|
||||
'use',
|
||||
'forward',
|
||||
'return',
|
||||
],
|
||||
},
|
||||
],
|
||||
'font-family-no-missing-generic-family-keyword': null,
|
||||
'function-no-unknown': null,
|
||||
'import-notation': null,
|
||||
'media-feature-range-notation': null,
|
||||
'named-grid-areas-no-invalid': null,
|
||||
'no-descending-specificity': null,
|
||||
'no-empty-source': null,
|
||||
'order/order': [
|
||||
[
|
||||
'dollar-variables',
|
||||
'custom-properties',
|
||||
'at-rules',
|
||||
'declarations',
|
||||
{
|
||||
name: 'supports',
|
||||
type: 'at-rule',
|
||||
},
|
||||
{
|
||||
name: 'media',
|
||||
type: 'at-rule',
|
||||
},
|
||||
{
|
||||
name: 'include',
|
||||
type: 'at-rule',
|
||||
},
|
||||
'rules',
|
||||
],
|
||||
{ severity: 'error' },
|
||||
],
|
||||
'prettier/prettier': true,
|
||||
'rule-empty-line-before': [
|
||||
'always',
|
||||
{
|
||||
ignore: ['after-comment', 'first-nested'],
|
||||
},
|
||||
],
|
||||
'scss/at-rule-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignoreAtRules: [
|
||||
'extends',
|
||||
'ignores',
|
||||
'include',
|
||||
'mixin',
|
||||
'if',
|
||||
'else',
|
||||
'media',
|
||||
'for',
|
||||
'at-root',
|
||||
'tailwind',
|
||||
'apply',
|
||||
'variants',
|
||||
'responsive',
|
||||
'screen',
|
||||
'function',
|
||||
'each',
|
||||
'use',
|
||||
'forward',
|
||||
'return',
|
||||
],
|
||||
},
|
||||
],
|
||||
'scss/operator-no-newline-after': null,
|
||||
'selector-class-pattern':
|
||||
'^(?:(?:o|c|u|t|s|is|has|_|js|qa)-)?[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*(?:__[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:--[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:[.+])?$',
|
||||
|
||||
'selector-not-notation': null,
|
||||
},
|
||||
};
|
||||
5
internal/lint-configs/stylelint-config/tsconfig.json
Normal file
5
internal/lint-configs/stylelint-config/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/node.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
7
internal/node-utils/build.config.ts
Normal file
7
internal/node-utils/build.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index'],
|
||||
});
|
||||
45
internal/node-utils/package.json
Normal file
45
internal/node-utils/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@vben/node-utils",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/node-utils"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"stub": "pnpm unbuild --stub"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"imports": {
|
||||
"#*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"default": "./dist/index.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@changesets/git": "^3.0.0",
|
||||
"@manypkg/get-packages": "^2.2.1",
|
||||
"consola": "^3.2.3",
|
||||
"find-up": "^7.0.0",
|
||||
"pkg-types": "^1.1.1",
|
||||
"prettier": "^3.2.5",
|
||||
"rimraf": "^5.0.7",
|
||||
"zx": "^7.2.3"
|
||||
}
|
||||
}
|
||||
6
internal/node-utils/src/constants.ts
Normal file
6
internal/node-utils/src/constants.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
enum UNICODE {
|
||||
FAILURE = '\u2716', // ✖
|
||||
SUCCESS = '\u2714', // ✔
|
||||
}
|
||||
|
||||
export { UNICODE };
|
||||
48
internal/node-utils/src/find.ts
Normal file
48
internal/node-utils/src/find.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import fs from 'node:fs';
|
||||
import { dirname, extname, resolve } from 'node:path';
|
||||
|
||||
import { findUpSync } from 'find-up';
|
||||
|
||||
/**
|
||||
* 查找 package.json 文件所在的目录
|
||||
* @param pathname
|
||||
*/
|
||||
function findUpPackageDir(pathname: string = '') {
|
||||
const file = findUpSync('package.json', {
|
||||
cwd: dirname(pathname),
|
||||
type: 'file',
|
||||
});
|
||||
return dirname(file || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的扩展名数组来查找文件是否存在,并返回对应文件路径
|
||||
* @param pathname 文件路径
|
||||
* @param extensions 扩展名数组
|
||||
* @returns 对应文件路径,如果未找到则返回 null
|
||||
*/
|
||||
function findFileByExtension(
|
||||
pathname: string = '',
|
||||
extensions: string[] = ['.ts'],
|
||||
): string {
|
||||
if (extname(pathname)) {
|
||||
return pathname;
|
||||
}
|
||||
|
||||
for (const ext of extensions) {
|
||||
const fullpath = resolve(pathname);
|
||||
if (fs.existsSync(fullpath + ext) && fs.statSync(fullpath + ext).isFile()) {
|
||||
return fullpath + ext;
|
||||
}
|
||||
}
|
||||
|
||||
for (const ext of extensions) {
|
||||
const resultPath = resolve(pathname, `index${ext}`);
|
||||
if (fs.existsSync(resultPath)) {
|
||||
return resultPath;
|
||||
}
|
||||
}
|
||||
return pathname;
|
||||
}
|
||||
|
||||
export { findFileByExtension, findUpPackageDir };
|
||||
26
internal/node-utils/src/git.ts
Normal file
26
internal/node-utils/src/git.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import path from 'node:path';
|
||||
|
||||
import { $ } from 'zx';
|
||||
|
||||
export * from '@changesets/git';
|
||||
|
||||
/**
|
||||
* 获取暂存区文件
|
||||
*/
|
||||
async function getStagedFiles() {
|
||||
try {
|
||||
$.verbose = false;
|
||||
const { stdout: lines } =
|
||||
await $`git -c submodule.recurse=false diff --staged --diff-filter=ACMR --name-only --ignore-submodules -z`;
|
||||
|
||||
let changedList = lines ? lines.replace(/\0$/, '').split('\0') : [];
|
||||
changedList = changedList.map((item) => path.resolve(process.cwd(), item));
|
||||
const changedSet = new Set(changedList);
|
||||
changedSet.delete('');
|
||||
return [...changedSet];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export { getStagedFiles };
|
||||
52
internal/node-utils/src/hash.test.ts
Normal file
52
internal/node-utils/src/hash.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { generatorContentHash } from './hash';
|
||||
|
||||
describe('generatorContentHash', () => {
|
||||
it('should generate an MD5 hash for the content', () => {
|
||||
const content = 'example content';
|
||||
const expectedHash = createHash('md5')
|
||||
.update(content, 'utf8')
|
||||
.digest('hex');
|
||||
const actualHash = generatorContentHash(content);
|
||||
expect(actualHash).toBe(expectedHash);
|
||||
});
|
||||
|
||||
it('should generate an MD5 hash with specified length', () => {
|
||||
const content = 'example content';
|
||||
const hashLength = 10;
|
||||
const generatedHash = generatorContentHash(content, hashLength);
|
||||
expect(generatedHash).toHaveLength(hashLength);
|
||||
});
|
||||
|
||||
it('should correctly generate the hash with specified length', () => {
|
||||
const content = 'example content';
|
||||
const hashLength = 8;
|
||||
const expectedHash = createHash('md5')
|
||||
.update(content, 'utf8')
|
||||
.digest('hex')
|
||||
.slice(0, hashLength);
|
||||
const generatedHash = generatorContentHash(content, hashLength);
|
||||
expect(generatedHash).toBe(expectedHash);
|
||||
});
|
||||
|
||||
it('should return full hash if hash length parameter is not provided', () => {
|
||||
const content = 'example content';
|
||||
const expectedHash = createHash('md5')
|
||||
.update(content, 'utf8')
|
||||
.digest('hex');
|
||||
const actualHash = generatorContentHash(content);
|
||||
expect(actualHash).toBe(expectedHash);
|
||||
});
|
||||
|
||||
it('should handle empty content', () => {
|
||||
const content = '';
|
||||
const expectedHash = createHash('md5')
|
||||
.update(content, 'utf8')
|
||||
.digest('hex');
|
||||
const actualHash = generatorContentHash(content);
|
||||
expect(actualHash).toBe(expectedHash);
|
||||
});
|
||||
});
|
||||
18
internal/node-utils/src/hash.ts
Normal file
18
internal/node-utils/src/hash.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
|
||||
/**
|
||||
* 生产基于内容的 hash,可自定义长度
|
||||
* @param content
|
||||
* @param hashLSize
|
||||
*/
|
||||
function generatorContentHash(content: string, hashLSize?: number) {
|
||||
const hash = createHash('md5').update(content, 'utf8').digest('hex');
|
||||
|
||||
if (hashLSize) {
|
||||
return hash.slice(0, hashLSize);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
export { generatorContentHash };
|
||||
17
internal/node-utils/src/index.ts
Normal file
17
internal/node-utils/src/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export { UNICODE } from './constants';
|
||||
export { findFileByExtension, findUpPackageDir } from './find';
|
||||
export * from './git';
|
||||
export { add as gitAdd, getStagedFiles } from './git';
|
||||
export { generatorContentHash } from './hash';
|
||||
export {
|
||||
findMonorepoRoot,
|
||||
getPackage,
|
||||
getPackages,
|
||||
getPackagesSync,
|
||||
} from './monorepo';
|
||||
export { prettierFormat } from './prettier';
|
||||
export type { Package } from '@manypkg/get-packages';
|
||||
export { consola } from 'consola';
|
||||
export { readPackageJSON } from 'pkg-types';
|
||||
export { rimraf } from 'rimraf';
|
||||
export { $, chalk as colors, fs, spinner } from 'zx';
|
||||
49
internal/node-utils/src/monorepo.ts
Normal file
49
internal/node-utils/src/monorepo.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { dirname } from 'node:path';
|
||||
|
||||
import {
|
||||
getPackages as getPackagesFunc,
|
||||
getPackagesSync as getPackagesSyncFunc,
|
||||
} from '@manypkg/get-packages';
|
||||
import { findUpSync } from 'find-up';
|
||||
|
||||
/**
|
||||
* 查找大仓的根目录
|
||||
* @param cwd
|
||||
*/
|
||||
function findMonorepoRoot(cwd: string = process.cwd()) {
|
||||
const lockFile = findUpSync(
|
||||
['pnpm-lock.yaml', 'yarn.lock', 'package-lock.json'],
|
||||
{
|
||||
cwd,
|
||||
type: 'file',
|
||||
},
|
||||
);
|
||||
return dirname(lockFile || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取大仓的所有包
|
||||
*/
|
||||
function getPackagesSync() {
|
||||
const root = findMonorepoRoot();
|
||||
return getPackagesSyncFunc(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取大仓的所有包
|
||||
*/
|
||||
async function getPackages() {
|
||||
const root = findMonorepoRoot();
|
||||
|
||||
return await getPackagesFunc(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取大仓指定的包
|
||||
*/
|
||||
async function getPackage(pkgName: string) {
|
||||
const { packages } = await getPackages();
|
||||
return packages.find((pkg) => pkg.packageJson.name === pkgName);
|
||||
}
|
||||
|
||||
export { findMonorepoRoot, getPackage, getPackages, getPackagesSync };
|
||||
20
internal/node-utils/src/prettier.ts
Normal file
20
internal/node-utils/src/prettier.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { format, getFileInfo, resolveConfig } from 'prettier';
|
||||
import { fs } from 'zx';
|
||||
|
||||
async function prettierFormat(filepath: string) {
|
||||
const prettierOptions = await resolveConfig(filepath, {});
|
||||
|
||||
const fileInfo = await getFileInfo(filepath);
|
||||
|
||||
const input = await fs.readFile(filepath, 'utf8');
|
||||
const output = await format(input, {
|
||||
...prettierOptions,
|
||||
parser: fileInfo.inferredParser as any,
|
||||
});
|
||||
if (output !== input) {
|
||||
fs.writeFileSync(filepath, output, 'utf8');
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
export { prettierFormat };
|
||||
5
internal/node-utils/tsconfig.json
Normal file
5
internal/node-utils/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/node.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
11
internal/tailwind-config/build.config.ts
Normal file
11
internal/tailwind-config/build.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index', './src/postcss.config'],
|
||||
externals: ['@vben/node-utils'],
|
||||
rollup: {
|
||||
emitCJS: true,
|
||||
},
|
||||
});
|
||||
64
internal/tailwind-config/package.json
Normal file
64
internal/tailwind-config/package.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "@vben/tailwind-config",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/tailwind-config"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm unbuild",
|
||||
"stub": "pnpm unbuild --stub"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./dist/*",
|
||||
"./*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"imports": {
|
||||
"#*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"./postcss": {
|
||||
"types": "./src/postcss.config.ts",
|
||||
"default": "./dist/postcss.config.mjs"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/json": "^2.2.211",
|
||||
"@iconify/tailwind": "^1.1.1",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"cssnano": "^7.0.1",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss-antd-fixes": "^0.2.0",
|
||||
"postcss-preset-env": "^9.5.13",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vben/node-utils": "workspace:*"
|
||||
}
|
||||
}
|
||||
136
internal/tailwind-config/src/index.ts
Normal file
136
internal/tailwind-config/src/index.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import type { Config } from 'tailwindcss';
|
||||
|
||||
import path from 'node:path';
|
||||
|
||||
import { addDynamicIconSelectors } from '@iconify/tailwind';
|
||||
import formsPlugin from '@tailwindcss/forms';
|
||||
import { fs, getPackagesSync } from '@vben/node-utils';
|
||||
import animate from 'tailwindcss-animate';
|
||||
// import defaultTheme from 'tailwindcss/defaultTheme';
|
||||
|
||||
const { packages } = getPackagesSync();
|
||||
|
||||
const tailwindPackages: string[] = [];
|
||||
|
||||
packages.forEach((pkg) => {
|
||||
// apps目录下和 @vben-core/tailwind-ui 包需要使用到 tailwindcss ui
|
||||
if (fs.existsSync(path.join(pkg.dir, 'tailwind.config.mjs'))) {
|
||||
tailwindPackages.push(pkg.dir);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
content: [
|
||||
'./index.html',
|
||||
...tailwindPackages.map((item) =>
|
||||
path.join(item, 'src/**/*.{vue,js,ts,jsx,tsx,svelte,astro,html}'),
|
||||
),
|
||||
],
|
||||
darkMode: 'class',
|
||||
plugins: [animate, formsPlugin, addDynamicIconSelectors()],
|
||||
prefix: '',
|
||||
safelist: ['dark'],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: '2rem',
|
||||
screens: {
|
||||
'2xl': '1400px',
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
animation: {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
'collapsible-down': 'collapsible-down 0.2s ease-in-out',
|
||||
'collapsible-up': 'collapsible-up 0.2s ease-in-out',
|
||||
float: 'float 5s linear 0ms infinite',
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius-base)',
|
||||
md: 'calc(var(--radius-base) - 2px)',
|
||||
sm: 'calc(var(--radius-base) - 4px)',
|
||||
xl: 'calc(var(--radius-base) + 4px)',
|
||||
},
|
||||
colors: {
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--color-accent))',
|
||||
foreground: 'hsl(var(--color-accent-foreground))',
|
||||
hover: 'hsl(var(--color-accent-hover))',
|
||||
},
|
||||
background: 'hsl(var(--color-background) / <alpha-value>)',
|
||||
body: 'hsl(var(--color-body) / <alpha-value>)',
|
||||
border: 'hsl(var(--color-border))',
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--color-card))',
|
||||
foreground: 'hsl(var(--color-card-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--color-destructive))',
|
||||
foreground: 'hsl(var(--color-destructive-foreground))',
|
||||
},
|
||||
foreground: 'hsl(var(--color-foreground) / <alpha-value>)',
|
||||
heavy: {
|
||||
DEFAULT: 'hsl(var(--color-heavy) / <alpha-value>)',
|
||||
foreground: 'hsl(var(--color-heavy-foreground) / <alpha-value>)',
|
||||
},
|
||||
input: {
|
||||
DEFAULT: 'hsl(var(--color-input))',
|
||||
background: 'hsl(var(--color-input-background))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--color-muted))',
|
||||
foreground: 'hsl(var(--color-muted-foreground))',
|
||||
},
|
||||
overlay: 'hsl(var(--color-overlay))',
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--color-popover))',
|
||||
foreground: 'hsl(var(--color-popover-foreground))',
|
||||
},
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--color-primary) / <alpha-value>)',
|
||||
foreground: 'hsl(var(--color-primary-foreground) / <alpha-value>)',
|
||||
},
|
||||
ring: 'hsl(var(--color-ring))',
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--color-secondary) / <alpha-value>)',
|
||||
desc: 'hsl(var(--color-secondary-desc) / <alpha-value>)',
|
||||
foreground: 'hsl(var(--color-secondary-foreground) / <alpha-value>)',
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
sans: [
|
||||
'var(--font-geist-sans)',
|
||||
// ...defaultTheme.fontFamily.sans
|
||||
],
|
||||
},
|
||||
keyframes: {
|
||||
'accordion-down': {
|
||||
from: { height: '0' },
|
||||
to: { height: 'var(--radix-accordion-content-height)' },
|
||||
},
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: '0' },
|
||||
},
|
||||
'collapsible-down': {
|
||||
from: { height: '0' },
|
||||
to: { height: 'var(--radix-collapsible-content-height)' },
|
||||
},
|
||||
'collapsible-up': {
|
||||
from: { height: 'var(--radix-collapsible-content-height)' },
|
||||
to: { height: '0' },
|
||||
},
|
||||
float: {
|
||||
'0%': { transform: 'translateY(0)' },
|
||||
'50%': { transform: 'translateY(-20px)' },
|
||||
'100%': { transform: 'translateY(0)' },
|
||||
},
|
||||
},
|
||||
zIndex: {
|
||||
'100': '100',
|
||||
'1000': '1000',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Config;
|
||||
14
internal/tailwind-config/src/postcss.config.ts
Normal file
14
internal/tailwind-config/src/postcss.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import config from '.';
|
||||
|
||||
export default {
|
||||
plugins: {
|
||||
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
|
||||
// Specifying the config is not necessary in most cases, but it is included
|
||||
autoprefixer: {},
|
||||
// 修复 element-plus 和 ant-design-vue 的样式和tailwindcss冲突问题
|
||||
'postcss-antd-fixes': { prefixes: ['ant', 'el'] },
|
||||
'postcss-preset-env': {},
|
||||
// here to share the same config across the entire monorepo
|
||||
tailwindcss: { config },
|
||||
},
|
||||
};
|
||||
5
internal/tailwind-config/tsconfig.json
Normal file
5
internal/tailwind-config/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/node.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
37
internal/tsconfig/base.json
Normal file
37
internal/tsconfig/base.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Base",
|
||||
"compilerOptions": {
|
||||
"composite": false,
|
||||
"target": "ESNext",
|
||||
|
||||
"experimentalDecorators": true,
|
||||
|
||||
"baseUrl": ".",
|
||||
"module": "ESNext",
|
||||
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
|
||||
"inlineSources": false,
|
||||
"noEmit": true,
|
||||
"removeComments": true,
|
||||
"sourceMap": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"skipLibCheck": true,
|
||||
"preserveWatchOutput": true
|
||||
},
|
||||
"exclude": ["**/node_modules/**", "**/dist/**", "**/.turbo/**"]
|
||||
}
|
||||
13
internal/tsconfig/library.json
Normal file
13
internal/tsconfig/library.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Web Application",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve",
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"useDefineForClassFields": true,
|
||||
"moduleResolution": "bundler",
|
||||
"declaration": true,
|
||||
"noEmit": false
|
||||
}
|
||||
}
|
||||
12
internal/tsconfig/node.json
Normal file
12
internal/tsconfig/node.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Node Config",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"composite": false,
|
||||
"lib": ["ESNext"],
|
||||
"baseUrl": "./",
|
||||
"types": ["node"],
|
||||
"noImplicitAny": true
|
||||
}
|
||||
}
|
||||
27
internal/tsconfig/package.json
Normal file
27
internal/tsconfig/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@vben/tsconfig",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/tsconfig"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"files": [
|
||||
"base.json",
|
||||
"library.json",
|
||||
"node.json",
|
||||
"web-app.json",
|
||||
"web.json"
|
||||
],
|
||||
"dependencies": {
|
||||
"@vben-core/typings": "workspace:*",
|
||||
"vite": "^5.2.11"
|
||||
}
|
||||
}
|
||||
8
internal/tsconfig/web-app.json
Normal file
8
internal/tsconfig/web-app.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Web Application",
|
||||
"extends": "./web.json",
|
||||
"compilerOptions": {
|
||||
"types": ["vite/client", "@vben-core/typings/global"]
|
||||
}
|
||||
}
|
||||
14
internal/tsconfig/web.json
Normal file
14
internal/tsconfig/web.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Web Package",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "vue",
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"useDefineForClassFields": true,
|
||||
"moduleResolution": "bundler",
|
||||
"types": ["vite/client"],
|
||||
"declaration": false
|
||||
}
|
||||
}
|
||||
7
internal/vite-config/build.config.ts
Normal file
7
internal/vite-config/build.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
|
||||
export default defineBuildConfig({
|
||||
clean: true,
|
||||
declaration: true,
|
||||
entries: ['src/index'],
|
||||
});
|
||||
59
internal/vite-config/package.json
Normal file
59
internal/vite-config/package.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "@vben/vite-config",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||
"directory": "internal/vite-config"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"stub": "pnpm unbuild --stub"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"imports": {
|
||||
"#*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.mjs"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
||||
"@jspm/generator": "^2.0.1",
|
||||
"cheerio": "1.0.0-rc.12",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"resolve.exports": "^2.0.2",
|
||||
"vite-plugin-lib-inject-css": "^2.1.1",
|
||||
"vite-plugin-vue-devtools": "^7.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/html-minifier-terser": "^7.0.2",
|
||||
"@vben/node-utils": "workspace:*",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"dayjs": "^1.11.11",
|
||||
"dotenv": "^16.4.5",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"sass": "^1.77.2",
|
||||
"unplugin-turbo-console": "^1.8.6",
|
||||
"vite": "^5.2.11",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-dts": "^3.9.1",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-mock": "^3.0.2"
|
||||
}
|
||||
}
|
||||
104
internal/vite-config/src/config/application.ts
Normal file
104
internal/vite-config/src/config/application.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import type { UserConfig } from 'vite';
|
||||
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { defineConfig, mergeConfig } from 'vite';
|
||||
|
||||
import { getApplicationConditionPlugins } from '../plugins';
|
||||
import { getCommonConfig } from './common';
|
||||
|
||||
import type { DefineAppcationOptions } from '../typing';
|
||||
|
||||
function defineApplicationConfig(options: DefineAppcationOptions = {}) {
|
||||
return defineConfig(async ({ command, mode }) => {
|
||||
const { appcation = {}, vite = {} } = options;
|
||||
const root = process.cwd();
|
||||
const isBuild = command === 'build';
|
||||
// const env = loadEnv(mode, root);
|
||||
|
||||
const plugins = await getApplicationConditionPlugins({
|
||||
compress: false,
|
||||
compressTypes: ['brotli', 'gzip'],
|
||||
devtools: true,
|
||||
extraAppConfig: true,
|
||||
html: true,
|
||||
i18n: true,
|
||||
injectAppLoading: true,
|
||||
isBuild,
|
||||
mock: true,
|
||||
mode,
|
||||
turboConsole: false,
|
||||
...appcation,
|
||||
});
|
||||
|
||||
const applicationConfig: UserConfig = {
|
||||
// },
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
assetFileNames: '[ext]/[name]-[hash].[ext]',
|
||||
chunkFileNames: 'js/[name]-[hash].mjs',
|
||||
entryFileNames: 'jse/index-[name]-[hash].mjs',
|
||||
},
|
||||
},
|
||||
target: 'es2015',
|
||||
},
|
||||
// },
|
||||
esbuild: {
|
||||
drop: isBuild
|
||||
? [
|
||||
// 'console',
|
||||
'debugger',
|
||||
]
|
||||
: [],
|
||||
legalComments: 'none',
|
||||
},
|
||||
plugins,
|
||||
// css: {
|
||||
// preprocessorOptions: {
|
||||
// scss: {
|
||||
// additionalData: `@import "@vben-core/design/global";`,
|
||||
// },
|
||||
resolve: {
|
||||
alias: [
|
||||
{
|
||||
find: /@\//,
|
||||
replacement: `${resolve(root, '.', 'src')}/`,
|
||||
},
|
||||
/**
|
||||
* 确保大仓内的子包,如果通过源码方式引用,可以直接使用@别名
|
||||
*/
|
||||
// {
|
||||
// find: '@',
|
||||
// replacement: '@',
|
||||
// customResolver(source, importer) {
|
||||
// if (source[0] === '@') {
|
||||
// const realPath = source.replace(
|
||||
// /^@/,
|
||||
// resolve(findUpPackageDir(importer), 'src'),
|
||||
// );
|
||||
// return findFileByExtension(realPath);
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
// },
|
||||
],
|
||||
},
|
||||
server: {
|
||||
host: true,
|
||||
warmup: {
|
||||
// 预热文件
|
||||
clientFiles: ['./index.html', './src/{views}/*'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mergedConfig = mergeConfig(
|
||||
await getCommonConfig(),
|
||||
applicationConfig,
|
||||
);
|
||||
return mergeConfig(mergedConfig, vite);
|
||||
});
|
||||
}
|
||||
|
||||
export { defineApplicationConfig };
|
||||
13
internal/vite-config/src/config/common.ts
Normal file
13
internal/vite-config/src/config/common.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { UserConfig } from 'vite';
|
||||
|
||||
async function getCommonConfig(): Promise<UserConfig> {
|
||||
return {
|
||||
build: {
|
||||
chunkSizeWarningLimit: 1000,
|
||||
reportCompressedSize: false,
|
||||
sourcemap: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export { getCommonConfig };
|
||||
31
internal/vite-config/src/config/index.ts
Normal file
31
internal/vite-config/src/config/index.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { fs } from '@vben/node-utils';
|
||||
|
||||
import { defineApplicationConfig } from './application';
|
||||
import { defineLibraryConfig } from './library';
|
||||
|
||||
import type { DefineConfig } from '../typing';
|
||||
|
||||
export * from './application';
|
||||
export * from './library';
|
||||
|
||||
function defineConfig(options: DefineConfig = {}) {
|
||||
const { type = 'auto', ...defineOptions } = options;
|
||||
|
||||
let projectType = type;
|
||||
|
||||
// 根据包是否存在 index.html,自动判断类型
|
||||
if (type === 'auto') {
|
||||
const htmlPath = join(process.cwd(), 'index.html');
|
||||
projectType = fs.existsSync(htmlPath) ? 'appcation' : 'library';
|
||||
}
|
||||
|
||||
if (projectType === 'appcation') {
|
||||
return defineApplicationConfig(defineOptions);
|
||||
} else if (projectType === 'library') {
|
||||
return defineLibraryConfig(defineOptions);
|
||||
}
|
||||
}
|
||||
|
||||
export { defineConfig };
|
||||
51
internal/vite-config/src/config/library.ts
Normal file
51
internal/vite-config/src/config/library.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import type { UserConfig } from 'vite';
|
||||
|
||||
import { readPackageJSON } from '@vben/node-utils';
|
||||
import { defineConfig, mergeConfig } from 'vite';
|
||||
|
||||
import { getLibraryConditionPlugins } from '../plugins';
|
||||
import { getCommonConfig } from './common';
|
||||
|
||||
import type { DefineLibraryOptions } from '../typing';
|
||||
|
||||
function defineLibraryConfig(options: DefineLibraryOptions = {}) {
|
||||
return defineConfig(async ({ command, mode }) => {
|
||||
const root = process.cwd();
|
||||
const { library = {}, vite = {} } = options;
|
||||
const isBuild = command === 'build';
|
||||
|
||||
const plugins = await getLibraryConditionPlugins({
|
||||
dts: false,
|
||||
injectLibCss: true,
|
||||
isBuild,
|
||||
mode,
|
||||
...library,
|
||||
});
|
||||
|
||||
const { dependencies = {}, peerDependencies = {} } =
|
||||
await readPackageJSON(root);
|
||||
|
||||
const external = [
|
||||
...Object.keys(dependencies),
|
||||
...Object.keys(peerDependencies),
|
||||
];
|
||||
const packageConfig: UserConfig = {
|
||||
build: {
|
||||
lib: {
|
||||
entry: 'src/index.ts',
|
||||
fileName: () => 'index.mjs',
|
||||
formats: ['es'],
|
||||
},
|
||||
rollupOptions: {
|
||||
external,
|
||||
},
|
||||
},
|
||||
plugins,
|
||||
};
|
||||
const commonConfig = await getCommonConfig();
|
||||
const mergedConfig = mergeConfig(commonConfig, packageConfig);
|
||||
return mergeConfig(mergedConfig, vite);
|
||||
});
|
||||
}
|
||||
|
||||
export { defineLibraryConfig };
|
||||
2
internal/vite-config/src/index.ts
Normal file
2
internal/vite-config/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './config';
|
||||
export * from './plugins';
|
||||
97
internal/vite-config/src/plugins/extra-app-config.ts
Normal file
97
internal/vite-config/src/plugins/extra-app-config.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import {
|
||||
colors,
|
||||
generatorContentHash,
|
||||
readPackageJSON,
|
||||
} from '@vben/node-utils';
|
||||
import { type PluginOption } from 'vite';
|
||||
|
||||
import { getEnvConfig } from '../utils/env';
|
||||
|
||||
interface PluginOptions {
|
||||
isBuild: boolean;
|
||||
root: string;
|
||||
}
|
||||
|
||||
const GLOBAL_CONFIG_FILE_NAME = '_app.config.js';
|
||||
const VBEN_ADMIN_PRO_APP_CONF = '_VBEN_ADMIN_PRO_APP_CONF_';
|
||||
|
||||
/**
|
||||
* 用于将配置文件抽离出来并注入到项目中
|
||||
* @returns
|
||||
*/
|
||||
|
||||
async function viteExtraAppConfigPlugin({
|
||||
isBuild,
|
||||
root,
|
||||
}: PluginOptions): Promise<PluginOption | undefined> {
|
||||
let publicPath: string;
|
||||
let source: string;
|
||||
|
||||
if (!isBuild) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { version = '' } = await readPackageJSON(root);
|
||||
|
||||
return {
|
||||
async configResolved(config) {
|
||||
publicPath = config.base;
|
||||
source = await getConfigSource();
|
||||
},
|
||||
async generateBundle() {
|
||||
try {
|
||||
this.emitFile({
|
||||
fileName: GLOBAL_CONFIG_FILE_NAME,
|
||||
source,
|
||||
type: 'asset',
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(colors.cyan(`✨configuration file is build successfully!`));
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
colors.red(
|
||||
`configuration file configuration file failed to package:\n${error}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
name: 'vite:extra-app-config',
|
||||
async transformIndexHtml(html) {
|
||||
publicPath = publicPath.endsWith('/') ? publicPath : `${publicPath}/`;
|
||||
const hash = `v=${version}-${generatorContentHash(source, 8)}`;
|
||||
|
||||
const appConfigSrc = `${publicPath}${GLOBAL_CONFIG_FILE_NAME}?${hash}`;
|
||||
|
||||
return {
|
||||
html,
|
||||
tags: [
|
||||
{
|
||||
attrs: {
|
||||
src: appConfigSrc,
|
||||
},
|
||||
tag: 'script',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function getConfigSource() {
|
||||
const config = await getEnvConfig();
|
||||
const windowVariable = `window.${VBEN_ADMIN_PRO_APP_CONF}`;
|
||||
// 确保变量不会被修改
|
||||
let source = `${windowVariable}=${JSON.stringify(config)};`;
|
||||
source += `
|
||||
Object.freeze(${windowVariable});
|
||||
Object.defineProperty(window, "${VBEN_ADMIN_PRO_APP_CONF}", {
|
||||
configurable: false,
|
||||
writable: false,
|
||||
});
|
||||
`.replaceAll(/\s/g, '');
|
||||
return source;
|
||||
}
|
||||
|
||||
export { viteExtraAppConfigPlugin };
|
||||
243
internal/vite-config/src/plugins/importmap.ts
Normal file
243
internal/vite-config/src/plugins/importmap.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* 参考 https://github.com/jspm/vite-plugin-jspm,调整为需要的功能
|
||||
*/
|
||||
import type { GeneratorOptions } from '@jspm/generator';
|
||||
import type { Plugin } from 'vite';
|
||||
|
||||
import { Generator } from '@jspm/generator';
|
||||
import { load } from 'cheerio';
|
||||
import { minify } from 'html-minifier-terser';
|
||||
|
||||
const DEFAULT_PROVIDER = 'jspm.io';
|
||||
|
||||
type pluginOptions = {
|
||||
debug?: boolean;
|
||||
defaultProvider?: 'esm.sh' | 'jsdelivr' | 'jspm.io';
|
||||
importmap?: Array<{ name: string; range?: string }>;
|
||||
} & GeneratorOptions;
|
||||
|
||||
// async function getLatestVersionOfShims() {
|
||||
// const result = await fetch('https://ga.jspm.io/npm:es-module-shims');
|
||||
// const version = result.text();
|
||||
// return version;
|
||||
// }
|
||||
|
||||
async function getShimsUrl(provide: string) {
|
||||
// const version = await getLatestVersionOfShims();
|
||||
const version = '1.10.0';
|
||||
|
||||
const shimsSubpath = `dist/es-module-shims.js`;
|
||||
const providerShimsMap: Record<string, string> = {
|
||||
'esm.sh': `https://esm.sh/es-module-shims@${version}/${shimsSubpath}`,
|
||||
// unpkg: `https://unpkg.com/es-module-shims@${version}/${shimsSubpath}`,
|
||||
jsdelivr: `https://cdn.jsdelivr.net/npm/es-module-shims@${version}/${shimsSubpath}`,
|
||||
|
||||
// 下面两个CDN不稳定,暂时不用
|
||||
'jspm.io': `https://ga.jspm.io/npm:es-module-shims@${version}/${shimsSubpath}`,
|
||||
};
|
||||
|
||||
return providerShimsMap[provide] || providerShimsMap[DEFAULT_PROVIDER];
|
||||
}
|
||||
|
||||
let generator: Generator;
|
||||
|
||||
async function viteImportMapPlugin(
|
||||
pluginOptions?: pluginOptions,
|
||||
): Promise<Plugin[]> {
|
||||
const { importmap } = pluginOptions || {};
|
||||
|
||||
let isSSR = false;
|
||||
let isBuild = false;
|
||||
let installed = false;
|
||||
let installError: Error | null = null;
|
||||
|
||||
const options: pluginOptions = Object.assign(
|
||||
{},
|
||||
{
|
||||
debug: false,
|
||||
defaultProvider: 'jspm.io',
|
||||
env: ['production', 'browser', 'module'],
|
||||
importmap: [],
|
||||
},
|
||||
pluginOptions,
|
||||
);
|
||||
|
||||
generator = new Generator({
|
||||
...options,
|
||||
baseUrl: process.cwd(),
|
||||
});
|
||||
|
||||
if (options?.debug) {
|
||||
(async () => {
|
||||
for await (const { message, type } of generator.logStream()) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`${type}: ${message}`);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
const imports = options.inputMap?.imports ?? {};
|
||||
const scopes = options.inputMap?.scopes ?? {};
|
||||
const firstLayerKeys = Object.keys(scopes);
|
||||
const inputMapScopes: string[] = [];
|
||||
firstLayerKeys.forEach((key) => {
|
||||
inputMapScopes.push(...Object.keys(scopes[key]));
|
||||
});
|
||||
const inputMapImports = Object.keys(imports);
|
||||
|
||||
const allDepNames: string[] = [
|
||||
...(importmap?.map((item) => item.name) || []),
|
||||
...inputMapImports,
|
||||
...inputMapScopes,
|
||||
];
|
||||
const depNames = new Set<string>(allDepNames);
|
||||
|
||||
const installDeps = importmap?.map((item) => ({
|
||||
range: item.range,
|
||||
target: item.name,
|
||||
}));
|
||||
|
||||
return [
|
||||
{
|
||||
async config(_, { command, isSsrBuild }) {
|
||||
isBuild = command === 'build';
|
||||
isSSR = !!isSsrBuild;
|
||||
},
|
||||
enforce: 'pre',
|
||||
name: 'importmap:external',
|
||||
resolveId(id) {
|
||||
if (isSSR || !isBuild) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!depNames.has(id)) {
|
||||
return null;
|
||||
}
|
||||
return { external: true, id };
|
||||
},
|
||||
},
|
||||
{
|
||||
enforce: 'post',
|
||||
name: 'importmap:install',
|
||||
async resolveId() {
|
||||
if (isSSR || !isBuild || installed) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
installed = true;
|
||||
await Promise.allSettled(
|
||||
(installDeps || []).map((dep) => generator.install(dep)),
|
||||
);
|
||||
} catch (error: any) {
|
||||
installError = error;
|
||||
installed = false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
{
|
||||
buildEnd() {
|
||||
// 未生成importmap时,抛出错误,防止被turbo缓存
|
||||
if (!installed && !isSSR) {
|
||||
installError && console.error(installError);
|
||||
throw new Error('importmap install failed.');
|
||||
}
|
||||
},
|
||||
enforce: 'post',
|
||||
name: 'importmap:html',
|
||||
transformIndexHtml: {
|
||||
async handler(html) {
|
||||
if (isSSR || !isBuild) {
|
||||
return html;
|
||||
}
|
||||
|
||||
const importmapJson = generator.getMap();
|
||||
|
||||
if (!importmapJson) {
|
||||
return html;
|
||||
}
|
||||
|
||||
const esModuleShimsSrc = await getShimsUrl(
|
||||
options.defaultProvider || DEFAULT_PROVIDER,
|
||||
);
|
||||
|
||||
const resultHtml = await injectShimsToHtml(html, esModuleShimsSrc);
|
||||
html = await minify(resultHtml || html, {
|
||||
collapseWhitespace: true,
|
||||
minifyCSS: true,
|
||||
minifyJS: true,
|
||||
removeComments: false,
|
||||
});
|
||||
|
||||
return {
|
||||
html,
|
||||
tags: [
|
||||
{
|
||||
attrs: {
|
||||
type: 'importmap',
|
||||
},
|
||||
injectTo: 'head-prepend',
|
||||
tag: 'script',
|
||||
children: `${JSON.stringify(importmapJson)}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
order: 'post',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
async function injectShimsToHtml(html: string, esModuleShimUrl: string) {
|
||||
const $ = load(html);
|
||||
|
||||
const $script = $(`script[type='module']`);
|
||||
|
||||
if (!$script) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = $script.attr('src');
|
||||
|
||||
$script.removeAttr('type');
|
||||
$script.removeAttr('crossorigin');
|
||||
$script.removeAttr('src');
|
||||
$script.html(`
|
||||
if (!HTMLScriptElement.supports || !HTMLScriptElement.supports('importmap')) {
|
||||
self.importShim = function () {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
document.head.appendChild(
|
||||
Object.assign(document.createElement('script'), {
|
||||
src: '${esModuleShimUrl}',
|
||||
crossorigin: 'anonymous',
|
||||
async: true,
|
||||
onload() {
|
||||
if (!importShim.$proxy) {
|
||||
resolve(importShim);
|
||||
} else {
|
||||
reject(new Error('No globalThis.importShim found:' + esModuleShimUrl));
|
||||
}
|
||||
},
|
||||
onerror(error) {
|
||||
reject(error);
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
importShim.$proxy = true;
|
||||
return promise.then((importShim) => importShim(...arguments));
|
||||
};
|
||||
}
|
||||
|
||||
var modules = ['${entry}'];
|
||||
typeof importShim === 'function'
|
||||
? modules.forEach((moduleName) => importShim(moduleName))
|
||||
: modules.forEach((moduleName) => import(moduleName));
|
||||
`);
|
||||
$('body').after($script);
|
||||
$('head').remove(`script[type='module']`);
|
||||
return $.html();
|
||||
}
|
||||
|
||||
export { viteImportMapPlugin };
|
||||
211
internal/vite-config/src/plugins/index.ts
Normal file
211
internal/vite-config/src/plugins/index.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import type { PluginOption } from 'vite';
|
||||
|
||||
import { join } from 'node:path';
|
||||
|
||||
import viteVueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
||||
import { getPackage } from '@vben/node-utils';
|
||||
import viteVue from '@vitejs/plugin-vue';
|
||||
import viteVueJsx from '@vitejs/plugin-vue-jsx';
|
||||
import { visualizer as viteVisualizerPlugin } from 'rollup-plugin-visualizer';
|
||||
import viteTurboConsolePlugin from 'unplugin-turbo-console/vite';
|
||||
import viteCompressPlugin from 'vite-plugin-compression';
|
||||
import viteDtsPlugin from 'vite-plugin-dts';
|
||||
import { createHtmlPlugin as viteHtmlPlugin } from 'vite-plugin-html';
|
||||
import { libInjectCss as viteLibInjectCss } from 'vite-plugin-lib-inject-css';
|
||||
import { viteMockServe as viteMockPlugin } from 'vite-plugin-mock';
|
||||
import viteVueDevTools from 'vite-plugin-vue-devtools';
|
||||
|
||||
import { viteExtraAppConfigPlugin } from './extra-app-config';
|
||||
import { viteImportMapPlugin } from './importmap';
|
||||
import { viteInjectAppLoadingPlugin } from './inject-app-loading';
|
||||
|
||||
import type {
|
||||
AppcationPluginOptions,
|
||||
CommonPluginOptions,
|
||||
ConditionPlugin,
|
||||
LibraryPluginOptions,
|
||||
} from '../typing';
|
||||
|
||||
/**
|
||||
* 获取条件成立的 vite 插件
|
||||
* @param conditionPlugins
|
||||
*/
|
||||
async function getConditionEstablishedPlugins(
|
||||
conditionPlugins: ConditionPlugin[],
|
||||
) {
|
||||
const plugins: PluginOption[] = [];
|
||||
for (const conditionPlugin of conditionPlugins) {
|
||||
if (conditionPlugin.condition) {
|
||||
const realPlugins = await conditionPlugin.plugins();
|
||||
plugins.push(...realPlugins);
|
||||
}
|
||||
}
|
||||
return plugins.flat();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件获取通用的vite插件
|
||||
*/
|
||||
async function getCommonConditionPlugins(
|
||||
options: CommonPluginOptions,
|
||||
): Promise<ConditionPlugin[]> {
|
||||
const { devtools, isBuild, visualizer } = options;
|
||||
return [
|
||||
{
|
||||
condition: true,
|
||||
plugins: () => [
|
||||
viteVue({
|
||||
script: {
|
||||
defineModel: true,
|
||||
// propsDestructure: true,
|
||||
},
|
||||
}),
|
||||
viteVueJsx(),
|
||||
],
|
||||
},
|
||||
{
|
||||
condition: !isBuild && devtools,
|
||||
plugins: () => [viteVueDevTools()],
|
||||
},
|
||||
{
|
||||
condition: isBuild && !!visualizer,
|
||||
plugins: () => [<PluginOption>viteVisualizerPlugin({
|
||||
filename: './node_modules/.cache/visualizer/stats.html',
|
||||
gzipSize: true,
|
||||
open: true,
|
||||
})],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件获取应用类型的vite插件
|
||||
*/
|
||||
async function getApplicationConditionPlugins(
|
||||
options: AppcationPluginOptions,
|
||||
): Promise<PluginOption[]> {
|
||||
// 单独取,否则commonOptions拿不到
|
||||
const isBuild = options.isBuild;
|
||||
|
||||
const {
|
||||
compress,
|
||||
compressTypes,
|
||||
extraAppConfig,
|
||||
|
||||
html,
|
||||
i18n,
|
||||
importmap,
|
||||
importmapOptions,
|
||||
injectAppLoading,
|
||||
mock,
|
||||
turboConsole,
|
||||
...commonOptions
|
||||
} = options;
|
||||
|
||||
const commonPlugins = await getCommonConditionPlugins(commonOptions);
|
||||
|
||||
return await getConditionEstablishedPlugins([
|
||||
...commonPlugins,
|
||||
{
|
||||
condition: i18n,
|
||||
plugins: async () => {
|
||||
const pkg = await getPackage('@vben/locales');
|
||||
const include = `${join(pkg?.dir ?? '', isBuild ? 'dist' : 'src', 'langs')}/*.yaml`;
|
||||
return [
|
||||
viteVueI18nPlugin({
|
||||
compositionOnly: true,
|
||||
fullInstall: true,
|
||||
include,
|
||||
runtimeOnly: true,
|
||||
}),
|
||||
];
|
||||
},
|
||||
},
|
||||
{
|
||||
condition: injectAppLoading,
|
||||
plugins: async () => [await viteInjectAppLoadingPlugin()],
|
||||
},
|
||||
{
|
||||
condition: isBuild && !!compress,
|
||||
plugins: () => {
|
||||
const compressPlugins: PluginOption[] = [];
|
||||
if (compressTypes?.includes('brotli')) {
|
||||
compressPlugins.push(
|
||||
viteCompressPlugin({ deleteOriginFile: false, ext: '.br' }),
|
||||
);
|
||||
}
|
||||
if (compressTypes?.includes('gzip')) {
|
||||
compressPlugins.push(
|
||||
viteCompressPlugin({ deleteOriginFile: false, ext: '.gz' }),
|
||||
);
|
||||
}
|
||||
return compressPlugins;
|
||||
},
|
||||
},
|
||||
{
|
||||
condition: !!html,
|
||||
plugins: () => [viteHtmlPlugin({ minify: true })],
|
||||
},
|
||||
|
||||
{
|
||||
condition: isBuild && importmap,
|
||||
plugins: () => {
|
||||
return [viteImportMapPlugin(importmapOptions)];
|
||||
},
|
||||
},
|
||||
{
|
||||
condition: isBuild && extraAppConfig,
|
||||
plugins: async () => [
|
||||
await viteExtraAppConfigPlugin({ isBuild: true, root: process.cwd() }),
|
||||
],
|
||||
},
|
||||
{
|
||||
condition: !isBuild && !!turboConsole,
|
||||
plugins: () => [viteTurboConsolePlugin()],
|
||||
},
|
||||
{
|
||||
condition: !!mock,
|
||||
plugins: () => [
|
||||
viteMockPlugin({
|
||||
enable: true,
|
||||
ignore: /^_/,
|
||||
mockPath: 'mock',
|
||||
}),
|
||||
],
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件获取库类型的vite插件
|
||||
*/
|
||||
async function getLibraryConditionPlugins(
|
||||
options: LibraryPluginOptions,
|
||||
): Promise<PluginOption[]> {
|
||||
// 单独取,否则commonOptions拿不到
|
||||
const isBuild = options.isBuild;
|
||||
const { dts, injectLibCss, ...commonOptions } = options;
|
||||
const commonPlugins = await getCommonConditionPlugins(commonOptions);
|
||||
return await getConditionEstablishedPlugins([
|
||||
...commonPlugins,
|
||||
{
|
||||
condition: isBuild && !!dts,
|
||||
plugins: () => [viteDtsPlugin({ logLevel: 'error' })],
|
||||
},
|
||||
{
|
||||
condition: injectLibCss,
|
||||
plugins: () => [viteLibInjectCss()],
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
export {
|
||||
getApplicationConditionPlugins,
|
||||
getLibraryConditionPlugins,
|
||||
viteCompressPlugin,
|
||||
viteDtsPlugin,
|
||||
viteHtmlPlugin,
|
||||
viteMockPlugin,
|
||||
viteTurboConsolePlugin,
|
||||
viteVisualizerPlugin,
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
# inject-app-loading
|
||||
|
||||
用于在应用加载时显示加载动画的插件。可自行选择加载动画的样式。
|
||||
46
internal/vite-config/src/plugins/inject-app-loading/index.ts
Normal file
46
internal/vite-config/src/plugins/inject-app-loading/index.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { fs } from '@vben/node-utils';
|
||||
import { type PluginOption } from 'vite';
|
||||
|
||||
/**
|
||||
* 用于生成将loading样式注入到项目中
|
||||
* 为多app提供loading样式,无需在每个 app -> index.html单独引入
|
||||
*/
|
||||
async function viteInjectAppLoadingPlugin(): Promise<PluginOption | undefined> {
|
||||
const loadingHtml = await getLoadingRawByHtmlTemplate();
|
||||
|
||||
if (!loadingHtml) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
enforce: 'pre',
|
||||
name: 'vite:inject-app-loading',
|
||||
transformIndexHtml: {
|
||||
handler(html) {
|
||||
const re = /<div\s*id\s*=\s*"app"\s*>(\s*)<\/div>/;
|
||||
html = html.replace(re, `<div id="app">${loadingHtml}</div>`);
|
||||
return html;
|
||||
},
|
||||
order: 'pre',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于获取loading的html模板
|
||||
*/
|
||||
async function getLoadingRawByHtmlTemplate() {
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const loadingPath = join(__dirname, './loading.html');
|
||||
if (!fs.existsSync(loadingPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const htmlRaw = await fs.readFile(loadingPath, 'utf8');
|
||||
return htmlRaw;
|
||||
}
|
||||
|
||||
export { viteInjectAppLoadingPlugin };
|
||||
@@ -0,0 +1,102 @@
|
||||
<style>
|
||||
html {
|
||||
/* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.dark .loading {
|
||||
background-color: #2c344a;
|
||||
}
|
||||
|
||||
.dark .loading .title {
|
||||
color: rgb(255 255 255 / 85%);
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #f4f7f9;
|
||||
}
|
||||
|
||||
.loading .dots {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 98px;
|
||||
}
|
||||
|
||||
.loading .title {
|
||||
margin-top: 36px;
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
color: rgb(0 0 0 / 85%);
|
||||
}
|
||||
|
||||
.dot {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-top: 30px;
|
||||
font-size: 32px;
|
||||
transform: rotate(45deg);
|
||||
animation: rotate-ani 1.2s infinite linear;
|
||||
}
|
||||
|
||||
.dot i {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #0065cc;
|
||||
border-radius: 100%;
|
||||
opacity: 0.3;
|
||||
transform: scale(0.75);
|
||||
transform-origin: 50% 50%;
|
||||
animation: spin-move-ani 1s infinite linear alternate;
|
||||
}
|
||||
|
||||
.dot i:nth-child(1) {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.dot i:nth-child(2) {
|
||||
top: 0;
|
||||
right: 0;
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.dot i:nth-child(3) {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.dot i:nth-child(4) {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
@keyframes rotate-ani {
|
||||
to {
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin-move-ani {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="loading">
|
||||
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
||||
<div class="title"><%= VITE_GLOB_APP_TITLE %></div>
|
||||
</div>
|
||||
102
internal/vite-config/src/plugins/inject-app-loading/loading.html
Normal file
102
internal/vite-config/src/plugins/inject-app-loading/loading.html
Normal file
@@ -0,0 +1,102 @@
|
||||
<style>
|
||||
html {
|
||||
/* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.loading {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #f4f7f9;
|
||||
}
|
||||
|
||||
.dark .loading {
|
||||
background: #101827;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 66px;
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
color: rgb(0 0 0 / 85%);
|
||||
}
|
||||
|
||||
.dark .title {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.loader {
|
||||
position: relative;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.loader::before {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
width: 48px;
|
||||
height: 5px;
|
||||
content: '';
|
||||
background: #0065cc50;
|
||||
border-radius: 50%;
|
||||
animation: shadow-ani 0.5s linear infinite;
|
||||
}
|
||||
|
||||
.loader::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: '';
|
||||
background: #0065cc;
|
||||
border-radius: 4px;
|
||||
animation: jump-ani 0.5s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes jump-ani {
|
||||
15% {
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: translateY(9px) rotate(22.5deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
border-bottom-right-radius: 40px;
|
||||
transform: translateY(18px) scale(1, 0.9) rotate(45deg);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateY(9px) rotate(67.5deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0) rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shadow-ani {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.2, 1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="loading">
|
||||
<div class="loader"></div>
|
||||
<div class="title"><%= VITE_GLOB_APP_TITLE %></div>
|
||||
</div>
|
||||
109
internal/vite-config/src/typing.ts
Normal file
109
internal/vite-config/src/typing.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
|
||||
import type { PluginOption, UserConfig } from 'vite';
|
||||
import type { PluginOptions } from 'vite-plugin-dts';
|
||||
|
||||
import viteTurboConsolePlugin from 'unplugin-turbo-console/vite';
|
||||
|
||||
export interface IImportMap {
|
||||
imports?: Record<string, string>;
|
||||
scopes?: {
|
||||
[scope: string]: Record<string, string>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* importmap 插件配置
|
||||
*/
|
||||
interface ImportmapPluginOptions {
|
||||
/**
|
||||
* CDN 供应商
|
||||
* @default jspm.io
|
||||
*/
|
||||
defaultProvider?: 'esm.sh' | 'jspm.io';
|
||||
/** importmap 配置 */
|
||||
importmap?: Array<{ name: string; range?: string }>;
|
||||
/** 手动配置importmap */
|
||||
inputMap?: IImportMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于判断是否需要加载插件
|
||||
*/
|
||||
interface ConditionPlugin {
|
||||
// 判断条件
|
||||
condition?: boolean;
|
||||
// 插件对象
|
||||
plugins: () => PluginOption[] | PromiseLike<PluginOption[]>;
|
||||
}
|
||||
|
||||
interface CommonPluginOptions {
|
||||
/** 是否开启devtools */
|
||||
devtools?: boolean;
|
||||
/** 是否构建模式 */
|
||||
isBuild?: boolean;
|
||||
/** 构建模式 */
|
||||
mode?: string;
|
||||
/** 开启依赖分析 */
|
||||
visualizer?: PluginVisualizerOptions | boolean;
|
||||
}
|
||||
|
||||
interface AppcationPluginOptions extends CommonPluginOptions {
|
||||
/** 开启 gzip 压缩 */
|
||||
compress?: boolean;
|
||||
/** 压缩类型 */
|
||||
compressTypes?: ('brotli' | 'gzip')[];
|
||||
/** 在构建的时候抽离配置文件 */
|
||||
extraAppConfig?: boolean;
|
||||
/** html 插件配置 */
|
||||
html?: boolean;
|
||||
/** 是否开启i18n */
|
||||
i18n?: boolean;
|
||||
/** 是否开启 importmap CDN */
|
||||
importmap?: boolean;
|
||||
/** importmap 插件配置 */
|
||||
importmapOptions?: ImportmapPluginOptions;
|
||||
/** 是否注入app loading */
|
||||
injectAppLoading?: boolean;
|
||||
/** mock 插件配置 */
|
||||
mock?: boolean;
|
||||
/** turbo-console 插件配置 */
|
||||
turboConsole?: Parameters<typeof viteTurboConsolePlugin>[0] | boolean;
|
||||
}
|
||||
|
||||
interface LibraryPluginOptions extends CommonPluginOptions {
|
||||
/** 开启 dts 输出 */
|
||||
dts?: PluginOptions | boolean;
|
||||
|
||||
/** 是否注入lib css */
|
||||
injectLibCss?: boolean;
|
||||
}
|
||||
|
||||
interface AppcationOptions extends AppcationPluginOptions {}
|
||||
|
||||
interface LibraryOptions extends LibraryPluginOptions {}
|
||||
|
||||
interface DefineAppcationOptions {
|
||||
appcation?: AppcationOptions;
|
||||
vite?: UserConfig;
|
||||
}
|
||||
|
||||
interface DefineLibraryOptions {
|
||||
library?: LibraryOptions;
|
||||
vite?: UserConfig;
|
||||
}
|
||||
|
||||
type DefineConfig = {
|
||||
type?: 'appcation' | 'auto' | 'library';
|
||||
} & DefineAppcationOptions &
|
||||
DefineLibraryOptions;
|
||||
|
||||
export type {
|
||||
AppcationPluginOptions,
|
||||
CommonPluginOptions,
|
||||
ConditionPlugin,
|
||||
DefineAppcationOptions,
|
||||
DefineConfig,
|
||||
DefineLibraryOptions,
|
||||
ImportmapPluginOptions,
|
||||
LibraryPluginOptions,
|
||||
};
|
||||
49
internal/vite-config/src/utils/env.ts
Normal file
49
internal/vite-config/src/utils/env.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { fs } from '@vben/node-utils';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
/**
|
||||
* 获取当前环境下生效的配置文件名
|
||||
*/
|
||||
function getConfFiles() {
|
||||
const script = process.env.npm_lifecycle_script as string;
|
||||
const reg = /--mode ([\d_a-z]+)/;
|
||||
const result = reg.exec(script);
|
||||
if (result) {
|
||||
const mode = result[1];
|
||||
return ['.env', `.env.${mode}`];
|
||||
}
|
||||
return ['.env', '.env.production'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the environment variables starting with the specified prefix
|
||||
* @param match prefix
|
||||
* @param confFiles ext
|
||||
*/
|
||||
export async function getEnvConfig(
|
||||
match = 'VITE_GLOB_',
|
||||
confFiles = getConfFiles(),
|
||||
) {
|
||||
let envConfig = {};
|
||||
|
||||
for (const confFile of confFiles) {
|
||||
try {
|
||||
const envPath = await fs.readFile(join(process.cwd(), confFile), {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
const env = dotenv.parse(envPath);
|
||||
envConfig = { ...envConfig, ...env };
|
||||
} catch (error) {
|
||||
console.error(`Error in parsing ${confFile}`, error);
|
||||
}
|
||||
}
|
||||
const reg = new RegExp(`^(${match})`);
|
||||
Object.keys(envConfig).forEach((key) => {
|
||||
if (!reg.test(key)) {
|
||||
Reflect.deleteProperty(envConfig, key);
|
||||
}
|
||||
});
|
||||
return envConfig;
|
||||
}
|
||||
5
internal/vite-config/tsconfig.json
Normal file
5
internal/vite-config/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@vben/tsconfig/node.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in New Issue
Block a user