From d40e59205eeabf112af3dcd5780b7943d454e8d6 Mon Sep 17 00:00:00 2001
From: Rodney Chen <rodney.chen@hotmail.com>
Date: 星期二, 18 六月 2024 20:57:08 +0800
Subject: [PATCH] 干净版internal

---
 internal/vite-config/src/plugins/appConfig.ts  |  104 +++++
 internal/eslint-config/src/index.ts            |   91 ++++
 internal/vite-config/src/plugins/compress.ts   |   38 ++
 .gitignore                                     |    2 
 internal/stylelint-config/src/index.ts         |   92 ++++
 internal/eslint-config/build.config.ts         |   10 
 internal/vite-config/package.json              |   59 +++
 internal/stylelint-config/.eslintignore        |    9 
 internal/stylelint-config/build.config.ts      |   10 
 internal/vite-config/build.config.ts           |   10 
 internal/vite-config/.eslintrc.cjs             |    4 
 internal/vite-config/src/plugins/svgSprite.ts  |   17 
 internal/vite-config/src/plugins/visualizer.ts |   14 
 internal/eslint-config/package.json            |   50 ++
 internal/ts-config/node.json                   |   12 
 internal/ts-config/vue-app.json                |   10 
 internal/vite-config/src/utils/modifyVars.ts   |   47 ++
 internal/stylelint-config/package.json         |   49 ++
 internal/ts-config/node-server.json            |   18 
 internal/ts-config/package.json                |   26 +
 internal/eslint-config/tsconfig.json           |    5 
 internal/vite-config/src/utils/hash.ts         |   16 
 internal/eslint-config/.eslintignore           |    9 
 internal/vite-config/src/config/package.ts     |   42 ++
 internal/vite-config/src/plugins/index.ts      |   62 +++
 internal/ts-config/base.json                   |   27 +
 internal/stylelint-config/.eslintrc.cjs        |    4 
 internal/eslint-config/src/strict.ts           |   57 +++
 internal/vite-config/src/plugins/html.ts       |   13 
 internal/vite-config/src/utils/env.ts          |   49 ++
 internal/vite-config/src/config/application.ts |  109 +++++
 internal/stylelint-config/tsconfig.json        |    5 
 internal/eslint-config/.eslintrc.cjs           |    4 
 internal/vite-config/src/plugins/mock.ts       |   19 +
 internal/vite-config/src/index.ts              |    2 
 internal/vite-config/.eslintignore             |    9 
 internal/vite-config/src/config/common.ts      |   22 +
 internal/vite-config/tsconfig.json             |    5 
 38 files changed, 1,130 insertions(+), 1 deletions(-)

diff --git a/.gitignore b/.gitignore
index e1ca94c..5ed19af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,4 +43,4 @@
 .history
 .vscode/extensions.json
 .vscode/settings.json
-internal/
+
diff --git a/internal/eslint-config/.eslintignore b/internal/eslint-config/.eslintignore
new file mode 100644
index 0000000..cef44b3
--- /dev/null
+++ b/internal/eslint-config/.eslintignore
@@ -0,0 +1,9 @@
+
+*.sh
+node_modules
+*.md
+*.woff
+*.ttf
+.turbo
+dist
+package.json
diff --git a/internal/eslint-config/.eslintrc.cjs b/internal/eslint-config/.eslintrc.cjs
new file mode 100644
index 0000000..cd27a19
--- /dev/null
+++ b/internal/eslint-config/.eslintrc.cjs
@@ -0,0 +1,4 @@
+module.exports = {
+  root: true,
+  extends: ['@vben/eslint-config/strict'],
+};
diff --git a/internal/eslint-config/build.config.ts b/internal/eslint-config/build.config.ts
new file mode 100644
index 0000000..08301e5
--- /dev/null
+++ b/internal/eslint-config/build.config.ts
@@ -0,0 +1,10 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  entries: ['src/index', 'src/strict'],
+  declaration: true,
+  rollup: {
+    emitCJS: true,
+  },
+});
diff --git a/internal/eslint-config/package.json b/internal/eslint-config/package.json
new file mode 100644
index 0000000..2e075f8
--- /dev/null
+++ b/internal/eslint-config/package.json
@@ -0,0 +1,50 @@
+{
+  "name": "@vben/eslint-config",
+  "version": "1.0.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": {
+    "url": "https://github.com/vbenjs/vue-vben-admin/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/eslint-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "exports": {
+    ".": {
+      "types": "./dist/index.d.ts",
+      "import": "./dist/index.mjs",
+      "require": "./dist/index.cjs"
+    },
+    "./strict": {
+      "types": "./dist/strict.d.ts",
+      "import": "./dist/strict.mjs",
+      "require": "./dist/strict.cjs"
+    }
+  },
+  "main": "./dist/index.cjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
+  "files": [
+    "dist"
+  ],
+  "scripts": {
+    "clean": "pnpm rimraf .turbo node_modules dist",
+    "lint": "pnpm eslint .",
+    "stub": "pnpm unbuild --stub"
+  },
+  "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^7.0.1",
+    "@typescript-eslint/parser": "^7.0.1",
+    "eslint": "^8.56.0",
+    "eslint-config-prettier": "^9.1.0",
+    "eslint-plugin-import": "^2.29.1",
+    "eslint-plugin-prettier": "^5.1.3",
+    "eslint-plugin-simple-import-sort": "^12.0.0",
+    "eslint-plugin-vue": "^9.21.1",
+    "vue-eslint-parser": "^9.4.2"
+  }
+}
diff --git a/internal/eslint-config/src/index.ts b/internal/eslint-config/src/index.ts
new file mode 100644
index 0000000..1138bb3
--- /dev/null
+++ b/internal/eslint-config/src/index.ts
@@ -0,0 +1,91 @@
+export default {
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  parser: 'vue-eslint-parser',
+  parserOptions: {
+    parser: '@typescript-eslint/parser',
+    ecmaVersion: 2020,
+    sourceType: 'module',
+    jsxPragma: 'React',
+    ecmaFeatures: {
+      jsx: true,
+    },
+    project: './tsconfig.*?.json',
+    createDefaultProgram: false,
+    extraFileExtensions: ['.vue'],
+  },
+  plugins: ['vue', '@typescript-eslint', 'import'],
+  extends: [
+    'eslint:recommended',
+    'plugin:vue/vue3-recommended',
+    'plugin:@typescript-eslint/recommended',
+    'plugin:prettier/recommended',
+  ],
+  rules: {
+    'no-unused-vars': 'off',
+    'no-case-declarations': 'off',
+    'no-use-before-define': 'off',
+    'space-before-function-paren': 'off',
+
+    'import/first': 'error',
+    'import/newline-after-import': 'error',
+    'import/no-duplicates': 'error',
+
+    '@typescript-eslint/no-unused-vars': [
+      'error',
+      {
+        argsIgnorePattern: '^_',
+        varsIgnorePattern: '^_',
+      },
+    ],
+    '@typescript-eslint/ban-ts-ignore': 'off',
+    '@typescript-eslint/ban-ts-comment': 'off',
+    '@typescript-eslint/ban-types': 'off',
+    '@typescript-eslint/explicit-function-return-type': 'off',
+    '@typescript-eslint/no-explicit-any': 'off',
+    '@typescript-eslint/no-var-requires': 'off',
+    '@typescript-eslint/no-empty-function': 'off',
+    '@typescript-eslint/no-use-before-define': 'off',
+    '@typescript-eslint/no-non-null-assertion': 'off',
+    '@typescript-eslint/explicit-module-boundary-types': 'off',
+    'vue/script-setup-uses-vars': 'error',
+    'vue/no-reserved-component-names': 'off',
+    'vue/custom-event-name-casing': 'off',
+    'vue/attributes-order': 'off',
+    'vue/one-component-per-file': 'off',
+    'vue/html-closing-bracket-newline': 'off',
+    'vue/max-attributes-per-line': 'off',
+    'vue/multiline-html-element-content-newline': 'off',
+    'vue/singleline-html-element-content-newline': 'off',
+    'vue/attribute-hyphenation': 'off',
+    'vue/require-default-prop': 'off',
+    'vue/require-explicit-emits': 'off',
+    'vue/html-self-closing': [
+      'error',
+      {
+        html: {
+          void: 'always',
+          normal: 'never',
+          component: 'always',
+        },
+        svg: 'always',
+        math: 'always',
+      },
+    ],
+    'vue/multi-word-component-names': 'off',
+    // 'sort-imports': [
+    //   'error',
+    //   {
+    //     ignoreCase: true,
+    //     ignoreDeclarationSort: false,
+    //     ignoreMemberSort: false,
+    //     memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
+    //     allowSeparatedGroups: false,
+    //   },
+    // ],
+  },
+  globals: { defineOptions: 'readonly' },
+};
diff --git a/internal/eslint-config/src/strict.ts b/internal/eslint-config/src/strict.ts
new file mode 100644
index 0000000..5dbf5b7
--- /dev/null
+++ b/internal/eslint-config/src/strict.ts
@@ -0,0 +1,57 @@
+export default {
+  extends: ['@vben'],
+  plugins: ['simple-import-sort'],
+  rules: {
+    'simple-import-sort/imports': 'error',
+    'simple-import-sort/exports': 'error',
+
+    '@typescript-eslint/ban-ts-comment': [
+      'error',
+      {
+        'ts-expect-error': 'allow-with-description',
+        'ts-ignore': 'allow-with-description',
+        'ts-nocheck': 'allow-with-description',
+        'ts-check': false,
+      },
+    ],
+
+    /**
+     * 銆愬己鍒躲�戝叧閿瓧鍓嶅悗鏈変竴涓┖鏍�
+     * @link https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/keyword-spacing.md
+     */
+    'keyword-spacing': 'off',
+    '@typescript-eslint/keyword-spacing': [
+      'error',
+      {
+        before: true,
+        after: true,
+        overrides: {
+          return: { after: true },
+          throw: { after: true },
+          case: { after: true },
+        },
+      },
+    ],
+
+    /**
+     * 绂佹鍑虹幇绌哄嚱鏁帮紝鏅�氬嚱鏁帮紙闈� async/await/generator锛夈�佺澶村嚱鏁般�佺被涓婄殑鏂规硶闄ゅ
+     * @link https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-empty-function.md
+     */
+    'no-empty-function': 'off',
+    '@typescript-eslint/no-empty-function': [
+      'error',
+      {
+        allow: ['arrowFunctions', 'functions', 'methods'],
+      },
+    ],
+
+    /**
+     * 浼樺厛浣跨敤 interface 鑰屼笉鏄� type 瀹氫箟瀵硅薄绫诲瀷
+     * @link https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-definitions.md
+     */
+    '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
+
+    'vue/attributes-order': 'error',
+    'vue/require-default-prop': 'error',
+  },
+};
diff --git a/internal/eslint-config/tsconfig.json b/internal/eslint-config/tsconfig.json
new file mode 100644
index 0000000..cd27063
--- /dev/null
+++ b/internal/eslint-config/tsconfig.json
@@ -0,0 +1,5 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/ts-config/node.json",
+  "include": ["src"]
+}
diff --git a/internal/stylelint-config/.eslintignore b/internal/stylelint-config/.eslintignore
new file mode 100644
index 0000000..cef44b3
--- /dev/null
+++ b/internal/stylelint-config/.eslintignore
@@ -0,0 +1,9 @@
+
+*.sh
+node_modules
+*.md
+*.woff
+*.ttf
+.turbo
+dist
+package.json
diff --git a/internal/stylelint-config/.eslintrc.cjs b/internal/stylelint-config/.eslintrc.cjs
new file mode 100644
index 0000000..cd27a19
--- /dev/null
+++ b/internal/stylelint-config/.eslintrc.cjs
@@ -0,0 +1,4 @@
+module.exports = {
+  root: true,
+  extends: ['@vben/eslint-config/strict'],
+};
diff --git a/internal/stylelint-config/build.config.ts b/internal/stylelint-config/build.config.ts
new file mode 100644
index 0000000..20c8b54
--- /dev/null
+++ b/internal/stylelint-config/build.config.ts
@@ -0,0 +1,10 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  entries: ['src/index'],
+  declaration: true,
+  rollup: {
+    emitCJS: true,
+  },
+});
diff --git a/internal/stylelint-config/package.json b/internal/stylelint-config/package.json
new file mode 100644
index 0000000..18dd5d2
--- /dev/null
+++ b/internal/stylelint-config/package.json
@@ -0,0 +1,49 @@
+{
+  "name": "@vben/stylelint-config",
+  "version": "1.0.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": {
+    "url": "https://github.com/vbenjs/vue-vben-admin/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/stylelint-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "exports": {
+    ".": {
+      "types": "./dist/index.d.ts",
+      "import": "./dist/index.mjs",
+      "require": "./dist/index.cjs"
+    }
+  },
+  "main": "./dist/index.cjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
+  "files": [
+    "dist"
+  ],
+  "scripts": {
+    "clean": "pnpm rimraf .turbo node_modules dist",
+    "lint": "pnpm eslint .",
+    "stub": "pnpm unbuild --stub"
+  },
+  "devDependencies": {
+    "postcss": "^8.4.38",
+    "postcss-html": "^1.6.0",
+    "postcss-less": "^6.0.0",
+    "postcss-scss": "^4.0.9",
+    "prettier": "^3.2.5",
+    "stylelint": "^16.4.0",
+    "stylelint-config-property-sort-order-smacss": "^10.0.0",
+    "stylelint-config-recommended-scss": "^14.0.0",
+    "stylelint-config-recommended-vue": "^1.5.0",
+    "stylelint-config-standard": "^36.0.0",
+    "stylelint-config-standard-scss": "^13.1.0",
+    "stylelint-order": "^6.0.4",
+    "stylelint-prettier": "^5.0.0"
+  }
+}
diff --git a/internal/stylelint-config/src/index.ts b/internal/stylelint-config/src/index.ts
new file mode 100644
index 0000000..8b15456
--- /dev/null
+++ b/internal/stylelint-config/src/index.ts
@@ -0,0 +1,92 @@
+export default {
+  extends: ['stylelint-config-standard', 'stylelint-config-property-sort-order-smacss'],
+  plugins: ['stylelint-order', 'stylelint-prettier'],
+  // customSyntax: 'postcss-html',
+  overrides: [
+    {
+      files: ['**/*.(css|html|vue)'],
+      customSyntax: 'postcss-html',
+    },
+    {
+      files: ['*.less', '**/*.less'],
+      customSyntax: 'postcss-less',
+      extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'],
+    },
+    {
+      files: ['*.scss', '**/*.scss'],
+      customSyntax: 'postcss-scss',
+      extends: ['stylelint-config-standard-scss', 'stylelint-config-recommended-vue/scss'],
+      rule: {
+        'scss/percent-placeholder-pattern': null,
+      },
+    },
+  ],
+  rules: {
+    'prettier/prettier': true,
+    'media-feature-range-notation': null,
+    'selector-not-notation': null,
+    'import-notation': null,
+    'function-no-unknown': null,
+    'selector-class-pattern': null,
+    'selector-pseudo-class-no-unknown': [
+      true,
+      {
+        ignorePseudoClasses: ['global', 'deep'],
+      },
+    ],
+    'selector-pseudo-element-no-unknown': [
+      true,
+      {
+        ignorePseudoElements: ['v-deep'],
+      },
+    ],
+    'at-rule-no-unknown': [
+      true,
+      {
+        ignoreAtRules: [
+          'tailwind',
+          'apply',
+          'variants',
+          'responsive',
+          'screen',
+          'function',
+          'if',
+          'each',
+          'include',
+          'mixin',
+          'extend',
+        ],
+      },
+    ],
+    'no-empty-source': null,
+    'named-grid-areas-no-invalid': null,
+    'no-descending-specificity': null,
+    'font-family-no-missing-generic-family-keyword': null,
+    'rule-empty-line-before': [
+      'always',
+      {
+        ignore: ['after-comment', 'first-nested'],
+      },
+    ],
+    'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }],
+    'order/order': [
+      [
+        'dollar-variables',
+        'custom-properties',
+        'at-rules',
+        'declarations',
+        {
+          type: 'at-rule',
+          name: 'supports',
+        },
+        {
+          type: 'at-rule',
+          name: 'media',
+        },
+        'rules',
+      ],
+      { severity: 'error' },
+    ],
+  },
+  ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'],
+};
diff --git a/internal/stylelint-config/tsconfig.json b/internal/stylelint-config/tsconfig.json
new file mode 100644
index 0000000..cd27063
--- /dev/null
+++ b/internal/stylelint-config/tsconfig.json
@@ -0,0 +1,5 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/ts-config/node.json",
+  "include": ["src"]
+}
diff --git a/internal/ts-config/base.json b/internal/ts-config/base.json
new file mode 100644
index 0000000..8b90054
--- /dev/null
+++ b/internal/ts-config/base.json
@@ -0,0 +1,27 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Base",
+  "compilerOptions": {
+    "target": "ESNext",
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "strict": true,
+    "declaration": true,
+    "noImplicitOverride": true,
+    "noUnusedLocals": true,
+    "esModuleInterop": true,
+    "useUnknownInCatchVariables": false,
+    "composite": false,
+    "declarationMap": false,
+    "forceConsistentCasingInFileNames": true,
+    "inlineSources": false,
+    "isolatedModules": true,
+    "skipLibCheck": true,
+    "noUnusedParameters": false,
+    "preserveWatchOutput": true,
+    "experimentalDecorators": true,
+    "resolveJsonModule": true,
+    "removeComments": true
+  },
+  "exclude": ["**/node_modules/**", "**/dist/**"]
+}
diff --git a/internal/ts-config/node-server.json b/internal/ts-config/node-server.json
new file mode 100644
index 0000000..e27374a
--- /dev/null
+++ b/internal/ts-config/node-server.json
@@ -0,0 +1,18 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Node Server  Config",
+  "extends": "./base.json",
+  "compilerOptions": {
+    "module": "commonjs",
+    "declaration": false,
+    "removeComments": true,
+    "emitDecoratorMetadata": true,
+    "experimentalDecorators": true,
+    "target": "es6",
+    "sourceMap": false,
+    "esModuleInterop": true,
+    "outDir": "./dist",
+    "baseUrl": "./"
+  },
+  "exclude": ["node_modules"]
+}
diff --git a/internal/ts-config/node.json b/internal/ts-config/node.json
new file mode 100644
index 0000000..cdd365f
--- /dev/null
+++ b/internal/ts-config/node.json
@@ -0,0 +1,12 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Node Config",
+  "extends": "./base.json",
+  "compilerOptions": {
+    "lib": ["ESNext"],
+    "noImplicitAny": true,
+    "sourceMap": true,
+    "noEmit": true,
+    "baseUrl": "./"
+  }
+}
diff --git a/internal/ts-config/package.json b/internal/ts-config/package.json
new file mode 100644
index 0000000..dd968c8
--- /dev/null
+++ b/internal/ts-config/package.json
@@ -0,0 +1,26 @@
+{
+  "name": "@vben/ts-config",
+  "version": "1.0.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": {
+    "url": "https://github.com/vbenjs/vue-vben-admin/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/ts-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "files": [
+    "base.json",
+    "node.json",
+    "vue-app.json",
+    "node-server.json"
+  ],
+  "dependencies": {
+    "@types/node": "^20.12.7",
+    "vite": "^5.2.10"
+  }
+}
diff --git a/internal/ts-config/vue-app.json b/internal/ts-config/vue-app.json
new file mode 100644
index 0000000..02f3fd2
--- /dev/null
+++ b/internal/ts-config/vue-app.json
@@ -0,0 +1,10 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Vue Application",
+  "extends": "./base.json",
+  "compilerOptions": {
+    "jsx": "preserve",
+    "lib": ["ESNext", "DOM"],
+    "noImplicitAny": false
+  }
+}
diff --git a/internal/vite-config/.eslintignore b/internal/vite-config/.eslintignore
new file mode 100644
index 0000000..cef44b3
--- /dev/null
+++ b/internal/vite-config/.eslintignore
@@ -0,0 +1,9 @@
+
+*.sh
+node_modules
+*.md
+*.woff
+*.ttf
+.turbo
+dist
+package.json
diff --git a/internal/vite-config/.eslintrc.cjs b/internal/vite-config/.eslintrc.cjs
new file mode 100644
index 0000000..cd27a19
--- /dev/null
+++ b/internal/vite-config/.eslintrc.cjs
@@ -0,0 +1,4 @@
+module.exports = {
+  root: true,
+  extends: ['@vben/eslint-config/strict'],
+};
diff --git a/internal/vite-config/build.config.ts b/internal/vite-config/build.config.ts
new file mode 100644
index 0000000..20c8b54
--- /dev/null
+++ b/internal/vite-config/build.config.ts
@@ -0,0 +1,10 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  entries: ['src/index'],
+  declaration: true,
+  rollup: {
+    emitCJS: true,
+  },
+});
diff --git a/internal/vite-config/package.json b/internal/vite-config/package.json
new file mode 100644
index 0000000..86d44e2
--- /dev/null
+++ b/internal/vite-config/package.json
@@ -0,0 +1,59 @@
+{
+  "name": "@vben/vite-config",
+  "version": "1.0.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": {
+    "url": "https://github.com/vbenjs/vue-vben-admin/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/vite-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "exports": {
+    ".": {
+      "types": "./dist/index.d.ts",
+      "import": "./dist/index.mjs",
+      "require": "./dist/index.cjs"
+    }
+  },
+  "main": "./dist/index.cjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
+  "files": [
+    "dist"
+  ],
+  "scripts": {
+    "clean": "pnpm rimraf .turbo node_modules dist",
+    "lint": "pnpm eslint .",
+    "stub": "pnpm unbuild --stub"
+  },
+  "dependencies": {
+    "@ant-design/colors": "^7.0.2",
+    "vite": "^5.2.10"
+  },
+  "devDependencies": {
+    "@types/fs-extra": "^11.0.4",
+    "@vitejs/plugin-vue": "^5.0.4",
+    "@vitejs/plugin-vue-jsx": "^3.1.0",
+    "ant-design-vue": "^4.2.1",
+    "dayjs": "^1.11.10",
+    "dotenv": "^16.4.5",
+    "fs-extra": "^11.2.0",
+    "less": "^4.2.0",
+    "picocolors": "^1.0.0",
+    "pkg-types": "^1.1.0",
+    "rollup-plugin-visualizer": "^5.12.0",
+    "sass": "^1.75.0",
+    "unocss": "0.59.4",
+    "vite-plugin-compression": "^0.5.1",
+    "vite-plugin-dts": "^3.9.0",
+    "vite-plugin-html": "^3.2.2",
+    "vite-plugin-mock": "^2.9.6",
+    "vite-plugin-purge-icons": "^0.10.0",
+    "vite-plugin-svg-icons": "^2.0.1"
+  }
+}
diff --git a/internal/vite-config/src/config/application.ts b/internal/vite-config/src/config/application.ts
new file mode 100644
index 0000000..7ee5ef1
--- /dev/null
+++ b/internal/vite-config/src/config/application.ts
@@ -0,0 +1,109 @@
+import { resolve } from 'node:path';
+
+import dayjs from 'dayjs';
+import { readPackageJSON } from 'pkg-types';
+import { defineConfig, loadEnv, mergeConfig, type UserConfig } from 'vite';
+
+import { createPlugins } from '../plugins';
+import { generateModifyVars } from '../utils/modifyVars';
+import { commonConfig } from './common';
+
+interface DefineOptions {
+  overrides?: UserConfig;
+  options?: {
+    //
+  };
+}
+
+function defineApplicationConfig(defineOptions: DefineOptions = {}) {
+  const { overrides = {} } = defineOptions;
+
+  return defineConfig(async ({ command, mode }) => {
+    const root = process.cwd();
+    const isBuild = command === 'build';
+    const { VITE_PUBLIC_PATH, VITE_USE_MOCK, VITE_BUILD_COMPRESS, VITE_ENABLE_ANALYZE } = loadEnv(
+      mode,
+      root,
+    );
+
+    const defineData = await createDefineData(root);
+    const plugins = await createPlugins({
+      isBuild,
+      root,
+      enableAnalyze: VITE_ENABLE_ANALYZE === 'true',
+      enableMock: VITE_USE_MOCK === 'true',
+      compress: VITE_BUILD_COMPRESS,
+    });
+
+    const pathResolve = (pathname: string) => resolve(root, '.', pathname);
+
+    const applicationConfig: UserConfig = {
+      base: VITE_PUBLIC_PATH,
+      resolve: {
+        alias: [
+          {
+            find: 'vue-i18n',
+            replacement: 'vue-i18n/dist/vue-i18n.cjs.js',
+          },
+          // @/xxxx => src/xxxx
+          {
+            find: /@\//,
+            replacement: pathResolve('src') + '/',
+          },
+          // #/xxxx => types/xxxx
+          {
+            find: /#\//,
+            replacement: pathResolve('types') + '/',
+          },
+        ],
+      },
+      define: defineData,
+      build: {
+        target: 'es2015',
+        cssTarget: 'chrome80',
+        rollupOptions: {
+          output: {
+            // 鍏ュ彛鏂囦欢鍚�
+            entryFileNames: 'assets/entry/[name]-[hash].js',
+            manualChunks: {
+              vue: ['vue', 'pinia', 'vue-router'],
+              antd: ['ant-design-vue', '@ant-design/icons-vue'],
+            },
+          },
+        },
+      },
+      css: {
+        preprocessorOptions: {
+          less: {
+            modifyVars: generateModifyVars(),
+            javascriptEnabled: true,
+          },
+        },
+      },
+      plugins,
+    };
+
+    const mergedConfig = mergeConfig(commonConfig(mode), applicationConfig);
+
+    return mergeConfig(mergedConfig, overrides);
+  });
+}
+
+async function createDefineData(root: string) {
+  try {
+    const pkgJson = await readPackageJSON(root);
+    const { dependencies, devDependencies, name, version } = pkgJson;
+
+    const __APP_INFO__ = {
+      pkg: { dependencies, devDependencies, name, version },
+      lastBuildTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+    };
+    return {
+      __APP_INFO__: JSON.stringify(__APP_INFO__),
+    };
+  } catch (error) {
+    return {};
+  }
+}
+
+export { defineApplicationConfig };
diff --git a/internal/vite-config/src/config/common.ts b/internal/vite-config/src/config/common.ts
new file mode 100644
index 0000000..559896e
--- /dev/null
+++ b/internal/vite-config/src/config/common.ts
@@ -0,0 +1,22 @@
+import UnoCSS from 'unocss/vite';
+import { type UserConfig } from 'vite';
+
+const commonConfig: (mode: string) => UserConfig = (mode) => ({
+  server: {
+    host: true,
+  },
+  esbuild: {
+    drop: mode === 'production' ? ['console', 'debugger'] : [],
+  },
+  build: {
+    reportCompressedSize: false,
+    chunkSizeWarningLimit: 1500,
+    rollupOptions: {
+      // TODO: Prevent memory overflow
+      maxParallelFileOps: 3,
+    },
+  },
+  plugins: [UnoCSS()],
+});
+
+export { commonConfig };
diff --git a/internal/vite-config/src/config/package.ts b/internal/vite-config/src/config/package.ts
new file mode 100644
index 0000000..ab83852
--- /dev/null
+++ b/internal/vite-config/src/config/package.ts
@@ -0,0 +1,42 @@
+import { readPackageJSON } from 'pkg-types';
+import { defineConfig, mergeConfig, type UserConfig } from 'vite';
+import dts from 'vite-plugin-dts';
+
+import { commonConfig } from './common';
+
+interface DefineOptions {
+  overrides?: UserConfig;
+  options?: {
+    //
+  };
+}
+
+function definePackageConfig(defineOptions: DefineOptions = {}) {
+  const { overrides = {} } = defineOptions;
+  const root = process.cwd();
+  return defineConfig(async ({ mode }) => {
+    const { dependencies = {}, peerDependencies = {} } = await readPackageJSON(root);
+    const packageConfig: UserConfig = {
+      build: {
+        lib: {
+          entry: 'src/index.ts',
+          formats: ['es'],
+          fileName: () => 'index.mjs',
+        },
+        rollupOptions: {
+          external: [...Object.keys(dependencies), ...Object.keys(peerDependencies)],
+        },
+      },
+      plugins: [
+        dts({
+          logLevel: 'error',
+        }),
+      ],
+    };
+    const mergedConfig = mergeConfig(commonConfig(mode), packageConfig);
+
+    return mergeConfig(mergedConfig, overrides);
+  });
+}
+
+export { definePackageConfig };
diff --git a/internal/vite-config/src/index.ts b/internal/vite-config/src/index.ts
new file mode 100644
index 0000000..9ef1e80
--- /dev/null
+++ b/internal/vite-config/src/index.ts
@@ -0,0 +1,2 @@
+export * from './config/application';
+export * from './config/package';
diff --git a/internal/vite-config/src/plugins/appConfig.ts b/internal/vite-config/src/plugins/appConfig.ts
new file mode 100644
index 0000000..7d50662
--- /dev/null
+++ b/internal/vite-config/src/plugins/appConfig.ts
@@ -0,0 +1,104 @@
+import colors from 'picocolors';
+import { readPackageJSON } from 'pkg-types';
+import { type PluginOption } from 'vite';
+
+import { getEnvConfig } from '../utils/env';
+import { createContentHash } from '../utils/hash';
+
+const GLOBAL_CONFIG_FILE_NAME = '_app.config.js';
+const PLUGIN_NAME = 'app-config';
+
+async function createAppConfigPlugin({
+  root,
+  isBuild,
+}: {
+  root: string;
+  isBuild: boolean;
+}): Promise<PluginOption> {
+  let publicPath: string;
+  let source: string;
+  if (!isBuild) {
+    return {
+      name: PLUGIN_NAME,
+    };
+  }
+  const { version = '' } = await readPackageJSON(root);
+
+  return {
+    name: PLUGIN_NAME,
+    async configResolved(_config) {
+      const appTitle = _config?.env?.VITE_GLOB_APP_TITLE ?? '';
+      // appTitle = appTitle.replace(/\s/g, '_').replace(/-/g, '_');
+      publicPath = _config.base;
+      source = await getConfigSource(appTitle);
+    },
+    async transformIndexHtml(html) {
+      publicPath = publicPath.endsWith('/') ? publicPath : `${publicPath}/`;
+
+      const appConfigSrc = `${
+        publicPath || '/'
+      }${GLOBAL_CONFIG_FILE_NAME}?v=${version}-${createContentHash(source)}`;
+
+      return {
+        html,
+        tags: [
+          {
+            tag: 'script',
+            attrs: {
+              src: appConfigSrc,
+            },
+          },
+        ],
+      };
+    },
+    async generateBundle() {
+      try {
+        this.emitFile({
+          type: 'asset',
+          fileName: GLOBAL_CONFIG_FILE_NAME,
+          source,
+        });
+
+        console.log(colors.cyan(`鉁╟onfiguration file is build successfully!`));
+      } catch (error) {
+        console.log(
+          colors.red('configuration file configuration file failed to package:\n' + error),
+        );
+      }
+    },
+  };
+}
+
+/**
+ * Get the configuration file variable name
+ * @param env
+ */
+const getVariableName = (title: string) => {
+  function strToHex(str: string) {
+    const result: string[] = [];
+    for (let i = 0; i < str.length; ++i) {
+      const hex = str.charCodeAt(i).toString(16);
+      result.push(('000' + hex).slice(-4));
+    }
+    return result.join('').toUpperCase();
+  }
+  return `__PRODUCTION__${strToHex(title) || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, '');
+};
+
+async function getConfigSource(appTitle: string) {
+  const config = await getEnvConfig();
+  const variableName = getVariableName(appTitle);
+  const windowVariable = `window.${variableName}`;
+  // Ensure that the variable will not be modified
+  let source = `${windowVariable}=${JSON.stringify(config)};`;
+  source += `
+    Object.freeze(${windowVariable});
+    Object.defineProperty(window, "${variableName}", {
+      configurable: false,
+      writable: false,
+    });
+  `.replace(/\s/g, '');
+  return source;
+}
+
+export { createAppConfigPlugin };
diff --git a/internal/vite-config/src/plugins/compress.ts b/internal/vite-config/src/plugins/compress.ts
new file mode 100644
index 0000000..8fc1397
--- /dev/null
+++ b/internal/vite-config/src/plugins/compress.ts
@@ -0,0 +1,38 @@
+/**
+ * Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated
+ * https://github.com/anncwb/vite-plugin-compression
+ */
+import type { PluginOption } from 'vite';
+import compressPlugin from 'vite-plugin-compression';
+
+export function configCompressPlugin({
+  compress,
+  deleteOriginFile = false,
+}: {
+  compress: string;
+  deleteOriginFile?: boolean;
+}): PluginOption[] {
+  const compressList = compress.split(',');
+
+  const plugins: PluginOption[] = [];
+
+  if (compressList.includes('gzip')) {
+    plugins.push(
+      compressPlugin({
+        ext: '.gz',
+        deleteOriginFile,
+      }),
+    );
+  }
+
+  if (compressList.includes('brotli')) {
+    plugins.push(
+      compressPlugin({
+        ext: '.br',
+        algorithm: 'brotliCompress',
+        deleteOriginFile,
+      }),
+    );
+  }
+  return plugins;
+}
diff --git a/internal/vite-config/src/plugins/html.ts b/internal/vite-config/src/plugins/html.ts
new file mode 100644
index 0000000..a01b43a
--- /dev/null
+++ b/internal/vite-config/src/plugins/html.ts
@@ -0,0 +1,13 @@
+/**
+ * Plugin to minimize and use ejs template syntax in index.html.
+ * https://github.com/anncwb/vite-plugin-html
+ */
+import type { PluginOption } from 'vite';
+import { createHtmlPlugin } from 'vite-plugin-html';
+
+export function configHtmlPlugin({ isBuild }: { isBuild: boolean }) {
+  const htmlPlugin: PluginOption[] = createHtmlPlugin({
+    minify: isBuild,
+  });
+  return htmlPlugin;
+}
diff --git a/internal/vite-config/src/plugins/index.ts b/internal/vite-config/src/plugins/index.ts
new file mode 100644
index 0000000..77b7466
--- /dev/null
+++ b/internal/vite-config/src/plugins/index.ts
@@ -0,0 +1,62 @@
+import vue from '@vitejs/plugin-vue';
+import vueJsx from '@vitejs/plugin-vue-jsx';
+import { type PluginOption } from 'vite';
+import purgeIcons from 'vite-plugin-purge-icons';
+import DevTools from 'vite-plugin-vue-devtools';
+
+import { createAppConfigPlugin } from './appConfig';
+import { configCompressPlugin } from './compress';
+import { configHtmlPlugin } from './html';
+import { configMockPlugin } from './mock';
+import { configSvgIconsPlugin } from './svgSprite';
+import { configVisualizerConfig } from './visualizer';
+
+interface Options {
+  isBuild: boolean;
+  root: string;
+  compress: string;
+  enableMock?: boolean;
+  enableAnalyze?: boolean;
+}
+
+async function createPlugins({ isBuild, root, enableMock, compress, enableAnalyze }: Options) {
+  const vitePlugins: (PluginOption | PluginOption[])[] = [vue(), vueJsx()];
+
+  const appConfigPlugin = await createAppConfigPlugin({ root, isBuild });
+  vitePlugins.push(appConfigPlugin);
+
+  vitePlugins.push(DevTools());
+
+  // vite-plugin-html
+  vitePlugins.push(configHtmlPlugin({ isBuild }));
+
+  // vite-plugin-svg-icons
+  vitePlugins.push(configSvgIconsPlugin({ isBuild }));
+
+  // vite-plugin-purge-icons
+  vitePlugins.push(purgeIcons());
+
+  // The following plugins only work in the production environment
+  if (isBuild) {
+    // rollup-plugin-gzip
+    vitePlugins.push(
+      configCompressPlugin({
+        compress,
+      }),
+    );
+  }
+
+  // rollup-plugin-visualizer
+  if (enableAnalyze) {
+    vitePlugins.push(configVisualizerConfig());
+  }
+
+  // vite-plugin-mock
+  if (enableMock) {
+    vitePlugins.push(configMockPlugin({ isBuild }));
+  }
+
+  return vitePlugins;
+}
+
+export { createPlugins };
diff --git a/internal/vite-config/src/plugins/mock.ts b/internal/vite-config/src/plugins/mock.ts
new file mode 100644
index 0000000..b47899c
--- /dev/null
+++ b/internal/vite-config/src/plugins/mock.ts
@@ -0,0 +1,19 @@
+/**
+ * Mock plugin for development and production.
+ * https://github.com/anncwb/vite-plugin-mock
+ */
+import { viteMockServe } from 'vite-plugin-mock';
+
+export function configMockPlugin({ isBuild }: { isBuild: boolean }) {
+  return viteMockServe({
+    ignore: /^_/,
+    mockPath: 'mock',
+    localEnabled: !isBuild,
+    prodEnabled: isBuild,
+    injectCode: `
+      import { setupProdMockServer } from '../mock/_createProductionServer';
+
+      setupProdMockServer();
+      `,
+  });
+}
diff --git a/internal/vite-config/src/plugins/svgSprite.ts b/internal/vite-config/src/plugins/svgSprite.ts
new file mode 100644
index 0000000..659e5af
--- /dev/null
+++ b/internal/vite-config/src/plugins/svgSprite.ts
@@ -0,0 +1,17 @@
+/**
+ *  Vite Plugin for fast creating SVG sprites.
+ * https://github.com/anncwb/vite-plugin-svg-icons
+ */
+
+import { resolve } from 'node:path';
+
+import type { PluginOption } from 'vite';
+import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
+
+export function configSvgIconsPlugin({ isBuild }: { isBuild: boolean }) {
+  const svgIconsPlugin = createSvgIconsPlugin({
+    iconDirs: [resolve(process.cwd(), 'src/assets/icons')],
+    svgoOptions: isBuild,
+  });
+  return svgIconsPlugin as PluginOption;
+}
diff --git a/internal/vite-config/src/plugins/visualizer.ts b/internal/vite-config/src/plugins/visualizer.ts
new file mode 100644
index 0000000..0b6ba62
--- /dev/null
+++ b/internal/vite-config/src/plugins/visualizer.ts
@@ -0,0 +1,14 @@
+/**
+ * Package file volume analysis
+ */
+import visualizer from 'rollup-plugin-visualizer';
+import { type PluginOption } from 'vite';
+
+export function configVisualizerConfig() {
+  return visualizer({
+    filename: './node_modules/.cache/visualizer/stats.html',
+    open: true,
+    gzipSize: true,
+    brotliSize: true,
+  }) as PluginOption;
+}
diff --git a/internal/vite-config/src/utils/env.ts b/internal/vite-config/src/utils/env.ts
new file mode 100644
index 0000000..c84ea94
--- /dev/null
+++ b/internal/vite-config/src/utils/env.ts
@@ -0,0 +1,49 @@
+import { join } from 'node:path';
+
+import dotenv from 'dotenv';
+import { readFile } from 'fs-extra';
+
+/**
+ * 鑾峰彇褰撳墠鐜涓嬬敓鏁堢殑閰嶇疆鏂囦欢鍚�
+ */
+function getConfFiles() {
+  const script = process.env.npm_lifecycle_script as string;
+  const reg = new RegExp('--mode ([a-z_\\d]+)');
+  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(),
+): Promise<{
+  [key: string]: string;
+}> {
+  let envConfig = {};
+
+  for (const confFile of confFiles) {
+    try {
+      const envPath = await readFile(join(process.cwd(), confFile), { encoding: 'utf8' });
+      const env = dotenv.parse(envPath);
+      envConfig = { ...envConfig, ...env };
+    } catch (e) {
+      console.error(`Error in parsing ${confFile}`, e);
+    }
+  }
+  const reg = new RegExp(`^(${match})`);
+  Object.keys(envConfig).forEach((key) => {
+    if (!reg.test(key)) {
+      Reflect.deleteProperty(envConfig, key);
+    }
+  });
+  return envConfig;
+}
diff --git a/internal/vite-config/src/utils/hash.ts b/internal/vite-config/src/utils/hash.ts
new file mode 100644
index 0000000..0b5a7c9
--- /dev/null
+++ b/internal/vite-config/src/utils/hash.ts
@@ -0,0 +1,16 @@
+import { createHash } from 'node:crypto';
+
+function createContentHash(content: string, hashLSize = 12) {
+  const hash = createHash('sha256').update(content);
+  return hash.digest('hex').slice(0, hashLSize);
+}
+function strToHex(str: string) {
+  const result: string[] = [];
+  for (let i = 0; i < str.length; ++i) {
+    const hex = str.charCodeAt(i).toString(16);
+    result.push(('000' + hex).slice(-4));
+  }
+  return result.join('').toUpperCase();
+}
+
+export { createContentHash, strToHex };
diff --git a/internal/vite-config/src/utils/modifyVars.ts b/internal/vite-config/src/utils/modifyVars.ts
new file mode 100644
index 0000000..0554343
--- /dev/null
+++ b/internal/vite-config/src/utils/modifyVars.ts
@@ -0,0 +1,47 @@
+import { resolve } from 'node:path';
+
+import { generate } from '@ant-design/colors';
+// @ts-ignore: typo
+/* import { getThemeVariables } from 'ant-design-vue/dist/theme'; */
+import { theme } from 'ant-design-vue/lib';
+import convertLegacyToken from 'ant-design-vue/lib/theme/convertLegacyToken';
+
+const { defaultAlgorithm, defaultSeed } = theme;
+const primaryColor = '#0960bd';
+
+function generateAntColors(color: string, theme: 'default' | 'dark' = 'default') {
+  return generate(color, {
+    theme,
+  });
+}
+
+/**
+ * less global variable
+ */
+export function generateModifyVars() {
+  const palettes = generateAntColors(primaryColor);
+  const primary = palettes[5];
+  const primaryColorObj: Record<string, string> = {};
+
+  for (let index = 0; index < 10; index++) {
+    primaryColorObj[`primary-${index + 1}`] = palettes[index];
+  }
+  // const modifyVars = getThemeVariables();
+  const mapToken = defaultAlgorithm(defaultSeed);
+  const v3Token = convertLegacyToken(mapToken);
+  return {
+    ...v3Token,
+    // reference:  Avoid repeated references
+    hack: `true; @import (reference) "${resolve('src/design/config.less')}";`,
+    'primary-color': primary,
+    ...primaryColorObj,
+    'info-color': primary,
+    'processing-color': primary,
+    'success-color': '#55D187', //  Success color
+    'error-color': '#ED6F6F', //  False color
+    'warning-color': '#EFBD47', //   Warning color
+    'font-size-base': '14px', //  Main font size
+    'border-radius-base': '2px', //  Component/float fillet
+    'link-color': primary, //   Link color
+  };
+}
diff --git a/internal/vite-config/tsconfig.json b/internal/vite-config/tsconfig.json
new file mode 100644
index 0000000..cd27063
--- /dev/null
+++ b/internal/vite-config/tsconfig.json
@@ -0,0 +1,5 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/ts-config/node.json",
+  "include": ["src"]
+}

--
Gitblit v1.9.3