Browse Source

wip: support vite

vben 4 years ago
parent
commit
99ac309fa9
100 changed files with 397 additions and 1129 deletions
  1. 2 2
      .env.production
  2. 0 26
      build/script/changelog.ts
  3. 0 3
      build/script/postBuild.ts
  4. 4 9
      build/utils.ts
  5. 0 12
      build/vite/hm.ts
  6. 12 0
      build/vite/plugin/gzip.ts
  7. 0 35
      build/vite/plugin/gzip/compress.ts
  8. 0 196
      build/vite/plugin/gzip/index.ts
  9. 0 56
      build/vite/plugin/gzip/types.ts
  10. 22 27
      build/vite/plugin/html.ts
  11. 12 0
      build/vite/plugin/importContext.ts
  12. 22 25
      build/vite/plugin/index.ts
  13. 7 12
      build/vite/plugin/mock.ts
  14. 25 29
      build/vite/plugin/pwa.ts
  15. 0 54
      build/vite/plugin/transform/dynamic-import/index.ts
  16. 0 222
      build/vite/plugin/transform/globby/index.ts
  17. 5 9
      build/vite/proxy.ts
  18. 3 9
      index.html
  19. 24 21
      package.json
  20. 4 2
      src/App.vue
  21. 1 2
      src/components/Application/src/AppLocalePicker.vue
  22. 0 1
      src/components/Application/src/AppLogo.vue
  23. 0 1
      src/components/Application/src/search/AppSearch.vue
  24. 0 1
      src/components/Application/src/search/AppSearchFooter.vue
  25. 0 1
      src/components/Application/src/search/AppSearchModal.vue
  26. 0 1
      src/components/Basic/src/BasicArrow.vue
  27. 0 1
      src/components/Basic/src/BasicHelp.vue
  28. 0 1
      src/components/Basic/src/BasicTitle.vue
  29. 0 1
      src/components/Container/src/LazyContainer.vue
  30. 1 1
      src/components/Container/src/ScrollContainer.vue
  31. 0 1
      src/components/Container/src/collapse/CollapseContainer.vue
  32. 0 2
      src/components/ContextMenu/src/index.less
  33. 2 4
      src/components/ContextMenu/src/index.tsx
  34. 1 1
      src/components/Description/src/index.tsx
  35. 0 1
      src/components/Drawer/src/BasicDrawer.vue
  36. 0 1
      src/components/Drawer/src/components/DrawerFooter.vue
  37. 0 1
      src/components/Drawer/src/components/DrawerHeader.vue
  38. 0 1
      src/components/Form/src/BasicForm.vue
  39. 7 8
      src/components/Form/src/components/FormItem.tsx
  40. 0 2
      src/components/Icon/src/index.vue
  41. 1 1
      src/components/Markdown/src/index.vue
  42. 0 2
      src/components/Menu/src/index.less
  43. 0 1
      src/components/Modal/src/components/ModalClose.vue
  44. 1 3
      src/components/Modal/src/index.less
  45. 7 3
      src/components/Preview/index.ts
  46. 0 2
      src/components/Preview/src/index.less
  47. 0 1
      src/components/Preview/src/index.vue
  48. 1 1
      src/components/Scrollbar/src/index.vue
  49. 0 1
      src/components/StrengthMeter/src/index.vue
  50. 0 2
      src/components/Upload/src/FileList.less
  51. 0 2
      src/components/Verify/src/DragVerify.less
  52. 0 2
      src/components/Verify/src/ImgRotate.less
  53. 4 8
      src/components/registerGlobComp.ts
  54. 1 1
      src/hooks/setting/useLocaleSetting.ts
  55. 8 7
      src/hooks/web/useI18n.ts
  56. 1 1
      src/hooks/web/useMessage.tsx
  57. 1 2
      src/layouts/default/content/index.vue
  58. 0 1
      src/layouts/default/footer/index.vue
  59. 0 1
      src/layouts/default/header/MultipleHeader.vue
  60. 0 1
      src/layouts/default/header/components/Breadcrumb.vue
  61. 0 1
      src/layouts/default/header/components/lock/LockModal.vue
  62. 0 1
      src/layouts/default/header/components/notify/NoticeList.vue
  63. 0 1
      src/layouts/default/header/components/notify/index.vue
  64. 0 1
      src/layouts/default/header/components/user-dropdown/index.vue
  65. 0 1
      src/layouts/default/header/index.less
  66. 0 7
      src/layouts/default/index.vue
  67. 0 2
      src/layouts/default/menu/index.less
  68. 14 20
      src/layouts/default/setting/SettingDrawer.tsx
  69. 0 1
      src/layouts/default/setting/components/InputNumberItem.vue
  70. 0 1
      src/layouts/default/setting/components/SelectItem.vue
  71. 0 1
      src/layouts/default/setting/components/SettingFooter.vue
  72. 0 1
      src/layouts/default/setting/components/SwitchItem.vue
  73. 0 1
      src/layouts/default/setting/components/ThemePicker.vue
  74. 0 1
      src/layouts/default/setting/components/TypePicker.vue
  75. 0 1
      src/layouts/default/setting/index.vue
  76. 0 1
      src/layouts/default/sider/DragBar.vue
  77. 0 1
      src/layouts/default/sider/LayoutSider.vue
  78. 0 1
      src/layouts/default/sider/MixSider.vue
  79. 0 1
      src/layouts/default/sider/index.vue
  80. 0 1
      src/layouts/default/tabs/index.less
  81. 0 72
      src/layouts/page/index.tsx
  82. 72 0
      src/layouts/page/index.vue
  83. 0 3
      src/locales/constant.ts
  84. 4 0
      src/locales/getMessage.ts
  85. 20 0
      src/locales/helper.ts
  86. 9 12
      src/locales/setupI18n.ts
  87. 9 7
      src/locales/useLocale.ts
  88. 5 6
      src/main.ts
  89. 0 5
      src/router/helper/dynamicImport.ts
  90. 28 2
      src/router/helper/routeHelper.ts
  91. 6 6
      src/router/menus/index.ts
  92. 5 4
      src/router/routes/index.ts
  93. 44 44
      src/router/routes/modules/demo/feat.ts
  94. 1 1
      src/settings/projectSetting.ts
  95. 0 12
      src/setup/App.ts
  96. 0 78
      src/types/vue-app-env.d.ts
  97. 1 0
      src/types/window.d.ts
  98. 0 2
      src/views/dashboard/analysis/components/GrowCard.vue
  99. 0 2
      src/views/dashboard/analysis/index.vue
  100. 0 2
      src/views/dashboard/house/index.less

+ 2 - 2
.env.production

@@ -23,5 +23,5 @@ VITE_GLOB_API_URL_PREFIX=
 # use pwa
 VITE_USE_PWA = false
 
-# TODO use Cdn
-VITE_USE_CDN = true
+# Is it compatible with older browsers
+VITE_LEGACY = false

+ 0 - 26
build/script/changelog.ts

@@ -1,26 +0,0 @@
-// #!/usr/bin/env node
-
-import { sh } from 'tasksfile';
-import { errorConsole, successConsole } from '../utils';
-
-export const runChangeLog = async () => {
-  try {
-    let cmd = `conventional-changelog -p custom-config -i CHANGELOG.md -s -r 0 `;
-
-    await sh(cmd, {
-      async: true,
-      nopipe: true,
-    });
-    await sh('prettier --write **/CHANGELOG.md ', {
-      async: true,
-      nopipe: true,
-    });
-    successConsole('CHANGE_LOG.md generated successfully!');
-  } catch (error) {
-    errorConsole('CHANGE_LOG.md generated error\n' + error);
-
-    process.exit(1);
-  }
-};
-
-runChangeLog();

+ 0 - 3
build/script/postBuild.ts

@@ -3,7 +3,6 @@
 import { argv } from 'yargs';
 import { runBuildConfig } from './buildConf';
 import { errorConsole, successConsole } from '../utils';
-import { startGzipStyle } from '../vite/plugin/gzip/compress';
 
 export const runBuild = async () => {
   try {
@@ -13,8 +12,6 @@ export const runBuild = async () => {
     if (!argvList.includes('no-conf')) {
       await runBuildConfig();
     }
-    // await runUpdateHtml();
-    await startGzipStyle();
     successConsole('Vite Build successfully!');
   } catch (error) {
     errorConsole('Vite Build Error\n' + error);

+ 4 - 9
build/utils.ts

@@ -63,11 +63,11 @@ export function getIPAddress() {
   return '';
 }
 
-export function isDevFn(mode: 'development' | 'production'): boolean {
+export function isDevFn(mode: string): boolean {
   return mode === 'development';
 }
 
-export function isProdFn(mode: 'development' | 'production'): boolean {
+export function isProdFn(mode: string): boolean {
   return mode === 'production';
 }
 
@@ -85,13 +85,6 @@ export function isBuildGzip(): boolean {
   return process.env.VITE_BUILD_GZIP === 'true';
 }
 
-/**
- *  Whether to generate package site
- */
-export function isSiteMode(): boolean {
-  return process.env.SITE === 'true';
-}
-
 export interface ViteEnv {
   VITE_PORT: number;
   VITE_USE_MOCK: boolean;
@@ -99,10 +92,12 @@ export interface ViteEnv {
   VITE_PUBLIC_PATH: string;
   VITE_PROXY: [string, string][];
   VITE_GLOB_APP_TITLE: string;
+  VITE_GLOB_APP_SHORT_NAME: string;
   VITE_USE_CDN: boolean;
   VITE_DROP_CONSOLE: boolean;
   VITE_BUILD_GZIP: boolean;
   VITE_DYNAMIC_IMPORT: boolean;
+  VITE_LEGACY: boolean;
 }
 
 // Read all environment variable configuration files to process.env

+ 0 - 12
build/vite/hm.ts

@@ -1,12 +0,0 @@
-// Baidu statistics code for site deployment
-// Only open in build:site
-export const hmScript = `<script>
-var _hmt = _hmt || [];
-(function() {
-  var hm = document.createElement("script");
-  hm.src = "https://hm.baidu.com/hm.js?384d6046e02f6ac4ea075357bd0e9b43";
-  var s = document.getElementsByTagName("script")[0];
-  s.parentNode.insertBefore(hm, s);
-})();
-</script>
-`;

+ 12 - 0
build/vite/plugin/gzip.ts

@@ -0,0 +1,12 @@
+import gzipPlugin from 'rollup-plugin-gzip';
+import { isBuildGzip } from '../../utils';
+import { Plugin } from 'vite';
+export function configGzipPlugin(isBuild: boolean): Plugin | Plugin[] {
+  const useGzip = isBuild && isBuildGzip;
+
+  if (useGzip) {
+    return gzipPlugin();
+  }
+
+  return [];
+}

+ 0 - 35
build/vite/plugin/gzip/compress.ts

@@ -1,35 +0,0 @@
-import { gzip } from 'zlib';
-import { readFileSync, writeFileSync } from 'fs';
-import { GzipPluginOptions } from './types';
-import { readAllFile, getCwdPath, isBuildGzip, isSiteMode } from '../../../utils';
-
-export function startGzip(
-  fileContent: string | Buffer,
-  options: GzipPluginOptions = {}
-): Promise<Buffer> {
-  return new Promise((resolve, reject) => {
-    gzip(fileContent, options.gzipOptions || {}, (err, result) => {
-      if (err) {
-        reject(err);
-      } else {
-        resolve(result);
-      }
-    });
-  });
-}
-
-// 手动压缩css
-export async function startGzipStyle() {
-  if (isBuildGzip() || isSiteMode()) {
-    const outDir = 'dist';
-    const assets = '_assets';
-    const allCssFile = readAllFile(getCwdPath(outDir, assets), /\.(css)$/);
-    for (const path of allCssFile) {
-      const source = readFileSync(path);
-      const content = await startGzip(source);
-      const ds = path.split('/');
-      const fileName = ds[ds.length - 1];
-      writeFileSync(getCwdPath(outDir, assets, `${fileName}.gz`), content);
-    }
-  }
-}

+ 0 - 196
build/vite/plugin/gzip/index.ts

@@ -1,196 +0,0 @@
-// 修改自https://github.com/kryops/rollup-plugin-gzip
-// 因为rollup-plugin-gzip不支持vite
-// vite对css打包独立的。所以不能在打包的时候顺带打包css
-// TODO rc.9会支持 configurBuild 配置项。到时候重新修改
-
-import { readFile, writeFile } from 'fs';
-import { basename } from 'path';
-import { promisify } from 'util';
-import { gzip } from 'zlib';
-
-import { OutputAsset, OutputChunk, OutputOptions, Plugin } from 'rollup';
-import { GzipPluginOptions } from './types';
-
-const isFunction = (arg: unknown): arg is (...args: any[]) => any => typeof arg === 'function';
-const isRegExp = (arg: unknown): arg is RegExp =>
-  Object.prototype.toString.call(arg) === '[object RegExp]';
-
-export type StringMappingOption = (originalString: string) => string;
-export type CustomCompressionOption = (
-  content: string | Buffer
-) => string | Buffer | Promise<string | Buffer>;
-
-const readFilePromise = promisify(readFile);
-const writeFilePromise = promisify(writeFile);
-
-// functionality partially copied from rollup
-
-/**
- * copied from https://github.com/rollup/rollup/blob/master/src/rollup/index.ts#L450
- */
-function isOutputChunk(file: OutputAsset | OutputChunk): file is OutputChunk {
-  return typeof (file as OutputChunk).code === 'string';
-}
-
-/**
- * Gets the string/buffer content from a file object.
- * Important for adding source map comments
- *
- * Copied partially from rollup.writeOutputFile
- * https://github.com/rollup/rollup/blob/master/src/rollup/index.ts#L454
- */
-function getOutputFileContent(
-  outputFileName: string,
-  outputFile: OutputAsset | OutputChunk,
-  outputOptions: OutputOptions
-): string | Buffer {
-  if (isOutputChunk(outputFile)) {
-    let source: string | Buffer;
-    source = outputFile.code;
-    if (outputOptions.sourcemap && outputFile.map) {
-      const url =
-        outputOptions.sourcemap === 'inline'
-          ? outputFile.map.toUrl()
-          : `${basename(outputFileName)}.map`;
-
-      // https://github.com/rollup/rollup/blob/master/src/utils/sourceMappingURL.ts#L1
-      source += `//# source` + `MappingURL=${url}\n`;
-    }
-    return source;
-  } else {
-    return typeof outputFile.source === 'string'
-      ? outputFile.source
-      : // just to be sure, as it is typed string | Uint8Array in rollup 2.0.0
-        Buffer.from(outputFile.source);
-  }
-}
-
-// actual plugin code
-
-function gzipPlugin(options: GzipPluginOptions = {}): Plugin {
-  // check for old options
-  if ('algorithm' in options) {
-    console.warn(
-      '[rollup-plugin-gzip] The "algorithm" option is not supported any more! ' +
-        'Use "customCompression" instead to specify a different compression algorithm.'
-    );
-  }
-  if ('options' in options) {
-    console.warn('[rollup-plugin-gzip] The "options" option was renamed to "gzipOptions"!');
-  }
-  if ('additional' in options) {
-    console.warn('[rollup-plugin-gzip] The "additional" option was renamed to "additionalFiles"!');
-  }
-  if ('delay' in options) {
-    console.warn('[rollup-plugin-gzip] The "delay" option was renamed to "additionalFilesDelay"!');
-  }
-
-  const compressGzip: CustomCompressionOption = (fileContent) => {
-    return new Promise((resolve, reject) => {
-      gzip(fileContent, options.gzipOptions || {}, (err, result) => {
-        if (err) {
-          reject(err);
-        } else {
-          resolve(result);
-        }
-      });
-    });
-  };
-
-  const doCompress = options.customCompression || compressGzip;
-
-  const mapFileName: StringMappingOption = isFunction(options.fileName)
-    ? (options.fileName as StringMappingOption)
-    : (fileName: string) => fileName + (options.fileName || '.gz');
-
-  const plugin: Plugin = {
-    name: 'gzip',
-
-    generateBundle(outputOptions, bundle) {
-      return Promise.all(
-        Object.keys(bundle)
-          .map((fileName) => {
-            const fileEntry = bundle[fileName];
-
-            // file name filter option check
-
-            const fileNameFilter = options.filter || /\.(js|mjs|json|css|html)$/;
-
-            if (isRegExp(fileNameFilter) && !fileName.match(fileNameFilter)) {
-              return Promise.resolve();
-            }
-
-            if (
-              isFunction(fileNameFilter) &&
-              !(fileNameFilter as (x: string) => boolean)(fileName)
-            ) {
-              return Promise.resolve();
-            }
-
-            const fileContent = getOutputFileContent(fileName, fileEntry, outputOptions);
-
-            // minSize option check
-            if (options.minSize && options.minSize > fileContent.length) {
-              return Promise.resolve();
-            }
-
-            return Promise.resolve(doCompress(fileContent))
-              .then((compressedContent) => {
-                const compressedFileName = mapFileName(fileName);
-                bundle[compressedFileName] = {
-                  type: 'asset', // Rollup >= 1.21
-                  name: compressedFileName,
-                  fileName: compressedFileName,
-                  isAsset: true, // Rollup < 1.21
-                  source: compressedContent,
-                };
-              })
-              .catch((err: any) => {
-                console.error(err);
-                return Promise.reject('[rollup-plugin-gzip] Error compressing file ' + fileName);
-              });
-          })
-          .concat([
-            (() => {
-              if (!options.additionalFiles || !options.additionalFiles.length)
-                return Promise.resolve();
-
-              const compressAdditionalFiles = () =>
-                Promise.all(
-                  options.additionalFiles!.map((filePath) =>
-                    readFilePromise(filePath)
-                      .then((fileContent) => doCompress(fileContent))
-                      .then((compressedContent) => {
-                        return writeFilePromise(mapFileName(filePath), compressedContent);
-                      })
-                      .catch(() => {
-                        return Promise.reject(
-                          '[rollup-plugin-gzip] Error compressing additional file ' +
-                            filePath +
-                            '. Please check the spelling of your configured additionalFiles. ' +
-                            'You might also have to increase the value of the additionalFilesDelay option.'
-                        );
-                      })
-                  )
-                ) as Promise<any>;
-
-              // additional files can be processed outside of rollup after a delay
-              // for older plugins or plugins that write to disk (curcumventing rollup) without awaiting
-              const additionalFilesDelay = options.additionalFilesDelay || 0;
-
-              if (additionalFilesDelay) {
-                setTimeout(compressAdditionalFiles, additionalFilesDelay);
-                return Promise.resolve();
-              } else {
-                return compressAdditionalFiles();
-              }
-            })(),
-          ])
-      ) as Promise<any>;
-    },
-  };
-
-  return plugin;
-}
-
-export default gzipPlugin;

+ 0 - 56
build/vite/plugin/gzip/types.ts

@@ -1,56 +0,0 @@
-import type { ZlibOptions } from 'zlib';
-
-export type StringMappingOption = (originalString: string) => string;
-export type CustomCompressionOption = (
-  content: string | Buffer
-) => string | Buffer | Promise<string | Buffer>;
-
-export interface GzipPluginOptions {
-  /**
-   * Control which of the output files to compress
-   *
-   * Defaults to `/\.(js|mjs|json|css|html)$/`
-   */
-  filter?: RegExp | ((fileName: string) => boolean);
-
-  /**
-   * GZIP compression options, see https://nodejs.org/api/zlib.html#zlib_class_options
-   */
-  gzipOptions?: ZlibOptions;
-
-  /**
-   * Specified the minimum size in Bytes for a file to get compressed.
-   * Files that are smaller than this threshold will not be compressed.
-   * This does not apply to the files specified through `additionalFiles`!
-   */
-  minSize?: number;
-
-  /**
-   * This option allows you to compress additional files outside of the main rollup bundling process.
-   * The processing is delayed to make sure the files are written on disk; the delay is controlled
-   * through `additionalFilesDelay`.
-   */
-  additionalFiles?: string[];
-
-  /**
-   * This options sets a delay (ms) before the plugin compresses the files specified through `additionalFiles`.
-   * Increase this value if your artifacts take a long time to generate.
-   *
-   * Defaults to `2000`
-   */
-  additionalFilesDelay?: number;
-
-  /**
-   * Set a custom compression algorithm. The function can either return the compressed contents synchronously,
-   * or otherwise return a promise for asynchronous processing.
-   */
-  customCompression?: CustomCompressionOption;
-
-  /**
-   * Set a custom file name convention for the compressed files. Can be a suffix string or a function
-   * returning the file name.
-   *
-   * Defaults to `.gz`
-   */
-  fileName?: string | StringMappingOption;
-}

+ 22 - 27
build/vite/plugin/html.ts

@@ -1,37 +1,32 @@
 import type { Plugin } from 'vite';
-import ViteHtmlPlugin from 'vite-plugin-html';
-import { isProdFn, isSiteMode, ViteEnv } from '../../utils';
+import html from 'vite-plugin-html';
+import { ViteEnv } from '../../utils';
 
-import { hmScript } from '../hm';
 // @ts-ignore
 import pkg from '../../../package.json';
 import { GLOB_CONFIG_FILE_NAME } from '../../constant';
 
-export function setupHtmlPlugin(
-  plugins: Plugin[],
-  env: ViteEnv,
-  mode: 'development' | 'production'
-) {
+export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
   const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env;
-
-  const htmlPlugin = ViteHtmlPlugin({
-    // html title
-    title: VITE_GLOB_APP_TITLE,
-    minify: isProdFn(mode),
-    options: {
-      publicPath: VITE_PUBLIC_PATH,
-      // Package and insert additional configuration files
-      injectConfig: isProdFn(mode)
-        ? `<script src='${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
-            pkg.version
-          }-${new Date().getTime()}'></script>`
-        : '',
-      // Insert Baidu statistics code
-      hmScript: isSiteMode() ? hmScript : '',
-      title: VITE_GLOB_APP_TITLE,
+  const htmlPlugin: Plugin[] = html({
+    minify: isBuild,
+    inject: {
+      injectData: {
+        title: VITE_GLOB_APP_TITLE,
+      },
+      tags: isBuild
+        ? [
+            {
+              tag: 'script',
+              attrs: {
+                src: `${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
+                  pkg.version
+                }-${new Date().getTime()}`,
+              },
+            },
+          ]
+        : [],
     },
   });
-
-  plugins.push(htmlPlugin);
-  return plugins;
+  return htmlPlugin;
 }

+ 12 - 0
build/vite/plugin/importContext.ts

@@ -0,0 +1,12 @@
+import dynamicImport from 'vite-plugin-import-context';
+import type { ViteEnv } from '../../utils';
+import type { Plugin } from 'vite';
+
+export function configDynamicImport(env: ViteEnv) {
+  const { VITE_DYNAMIC_IMPORT } = env;
+  const dynamicImportPlugin: Plugin = dynamicImport({
+    include: ['**/*.ts'],
+    autoImportRoute: VITE_DYNAMIC_IMPORT,
+  });
+  return dynamicImportPlugin;
+}

+ 22 - 25
build/vite/plugin/index.ts

@@ -1,47 +1,44 @@
-import type { Plugin as VitePlugin } from 'vite';
-import type { Plugin as rollupPlugin } from 'rollup';
+import type { Plugin } from 'vite';
 
 import PurgeIcons from 'vite-plugin-purge-icons';
 
 import visualizer from 'rollup-plugin-visualizer';
-import gzipPlugin from './gzip/index';
 
 // @ts-ignore
 import pkg from '../../../package.json';
-import { isSiteMode, ViteEnv, isReportMode, isBuildGzip } from '../../utils';
-import { setupHtmlPlugin } from './html';
-import { setupPwaPlugin } from './pwa';
-import { setupMockPlugin } from './mock';
+import { ViteEnv, isReportMode } from '../../utils';
+import { configHtmlPlugin } from './html';
+import { configPwaConfig } from './pwa';
+import { configMockPlugin } from './mock';
+import { configDynamicImport } from './importContext';
+import { configGzipPlugin } from './gzip';
 
 // gen vite plugins
-export function createVitePlugins(viteEnv: ViteEnv, mode: 'development' | 'production') {
-  const vitePlugins: VitePlugin[] = [];
+export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean, mode: string) {
+  const vitePlugins: (Plugin | Plugin[])[] = [];
 
   // vite-plugin-html
-  setupHtmlPlugin(vitePlugins, viteEnv, mode);
+  vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
+
   // vite-plugin-pwa
-  setupPwaPlugin(vitePlugins, viteEnv, mode);
+  vitePlugins.push(configPwaConfig(viteEnv, isBuild));
+
   // vite-plugin-mock
-  setupMockPlugin(vitePlugins, viteEnv, mode);
+  vitePlugins.push(configMockPlugin(viteEnv, isBuild));
+
+  // vite-plugin-import-context
+  vitePlugins.push(configDynamicImport(viteEnv));
 
   // vite-plugin-purge-icons
   vitePlugins.push(PurgeIcons());
 
-  return vitePlugins;
-}
-
-// gen rollup plugins
-export function createRollupPlugin() {
-  const rollupPlugins: rollupPlugin[] = [];
+  // rollup-plugin-gzip
+  vitePlugins.push(configGzipPlugin(isBuild));
 
+  // rollup-plugin-visualizer
   if (isReportMode()) {
-    // rollup-plugin-visualizer
-    rollupPlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
-  }
-  if (isBuildGzip() || isSiteMode()) {
-    // rollup-plugin-gizp
-    rollupPlugins.push(gzipPlugin());
+    vitePlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
   }
 
-  return rollupPlugins;
+  return vitePlugins;
 }

+ 7 - 12
build/vite/plugin/mock.ts

@@ -1,24 +1,19 @@
-import { createMockServer } from 'vite-plugin-mock';
-import type { Plugin } from 'vite';
-import { isDevFn, ViteEnv } from '../../utils';
+import { viteMockServe } from 'vite-plugin-mock';
+import { ViteEnv } from '../../utils';
 
-export function setupMockPlugin(
-  plugins: Plugin[],
-  env: ViteEnv,
-  mode: 'development' | 'production'
-) {
+export function configMockPlugin(env: ViteEnv, isBuild: boolean) {
   const { VITE_USE_MOCK } = env;
 
-  const useMock = isDevFn(mode) && VITE_USE_MOCK;
+  const useMock = !isBuild && VITE_USE_MOCK;
 
   if (useMock) {
-    const mockPlugin = createMockServer({
+    const mockPlugin = viteMockServe({
       ignore: /^\_/,
       mockPath: 'mock',
       showTime: true,
       localEnabled: useMock,
     });
-    plugins.push(mockPlugin);
+    return mockPlugin;
   }
-  return plugins;
+  return [];
 }

+ 25 - 29
build/vite/plugin/pwa.ts

@@ -1,35 +1,31 @@
 import { VitePWA } from 'vite-plugin-pwa';
-import type { Plugin } from 'vite';
+
 import { ViteEnv } from '../../utils';
 
-export function setupPwaPlugin(
-  plugins: Plugin[],
-  env: ViteEnv,
-  // @ts-ignore
-  mode: 'development' | 'production'
-) {
-  const { VITE_USE_PWA } = env;
+export function configPwaConfig(env: ViteEnv, isBulid: boolean) {
+  const { VITE_USE_PWA, VITE_GLOB_APP_TITLE, VITE_GLOB_APP_SHORT_NAME } = env;
 
-  const pwaPlugin = VitePWA({
-    manifest: {
-      name: 'Vben Admin',
-      short_name: 'vben_admin',
-      icons: [
-        {
-          src: './resource/img/pwa-192x192.png',
-          sizes: '192x192',
-          type: 'image/png',
-        },
-        {
-          src: './resource/img/pwa-512x512.png',
-          sizes: '512x512',
-          type: 'image/png',
-        },
-      ],
-    },
-  });
-  if (VITE_USE_PWA) {
-    plugins.push(pwaPlugin);
+  if (VITE_USE_PWA && isBulid) {
+    // vite-plugin-pwa
+    const pwaPlugin = VitePWA({
+      manifest: {
+        name: VITE_GLOB_APP_TITLE,
+        short_name: VITE_GLOB_APP_SHORT_NAME,
+        icons: [
+          {
+            src: './resource/img/pwa-192x192.png',
+            sizes: '192x192',
+            type: 'image/png',
+          },
+          {
+            src: './resource/img/pwa-512x512.png',
+            sizes: '512x512',
+            type: 'image/png',
+          },
+        ],
+      },
+    });
+    return pwaPlugin;
   }
-  return plugins;
+  return [];
 }

+ 0 - 54
build/vite/plugin/transform/dynamic-import/index.ts

@@ -1,54 +0,0 @@
-// Used to import all files under `src/views`
-// The built-in dynamic import of vite cannot meet the needs of importing all files under views
-// Special usage ,Only for this project
-import glob from 'glob';
-import { Transform } from 'vite/dist/node/transform.js';
-
-function getPath(path: string) {
-  const lastIndex = path.lastIndexOf('.');
-  if (lastIndex !== -1) {
-    path = path.substring(0, lastIndex);
-  }
-  return path.replace('src/views', '');
-}
-
-const dynamicImportTransform = function (enableDynamicImport: boolean): Transform {
-  return {
-    test({ path }) {
-      // Only convert the file
-      return (
-        path.includes('/src/router/helper/dynamicImport.ts') ||
-        path.includes(`\\src\\router\\helper\\dynamicImport.ts`)
-      );
-    },
-    transform({ code }) {
-      if (!enableDynamicImport) {
-        return code;
-      }
-
-      // Only convert the dir
-      try {
-        const files = glob.sync('src/views/**/**.{vue,tsx}', { cwd: process.cwd() });
-
-        return `
-        export default function (id) {
-           switch (id) {
-          ${files
-            .map((p) =>
-              `   case '${getPath(p)}': return  () => import('${p
-                .replace('src/views', '/@/views')
-                .replace(/\/\//g, '/')}');`.replace('.tsx', '')
-            )
-            .join('\n  ')}
-          default: return Promise.reject(new Error("Unknown variable dynamic import: " + id));
-           }
-    }\n\n
-    `;
-      } catch (error) {
-        console.error(error);
-        return code;
-      }
-    },
-  };
-};
-export default dynamicImportTransform;

+ 0 - 222
build/vite/plugin/transform/globby/index.ts

@@ -1,222 +0,0 @@
-// Modified from
-// https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts
-
-// TODO Deleting files requires re-running the project
-import { join } from 'path';
-import { lstatSync } from 'fs';
-import glob from 'glob';
-import globrex from 'globrex';
-import dotProp from 'dot-prop';
-import { createResolver, Resolver } from 'vite/dist/node/resolver.js';
-import { Transform } from 'vite/dist/node/transform.js';
-
-const modulesDir: string = join(process.cwd(), '/node_modules/');
-
-interface SharedConfig {
-  root?: string;
-  alias?: Record<string, string>;
-  resolvers?: Resolver[];
-
-  includes?: string[];
-}
-
-function template(template: string) {
-  return (data: { [x: string]: any }) => {
-    return template.replace(/#([^#]+)#/g, (_, g1) => data[g1] || g1);
-  };
-}
-
-// TODO support hmr
-function hmr(isBuild = false) {
-  if (isBuild) return '';
-  return `
-  if (import.meta.hot) {
-    import.meta.hot.accept();
-  }`;
-}
-
-// handle includes
-function fileInclude(includes: string | string[] | undefined, filePath: string) {
-  return !includes || !Array.isArray(includes)
-    ? true
-    : includes.some((item) => filePath.startsWith(item));
-}
-
-// Bare exporter
-function compareString(modify: any, data: string[][]) {
-  return modify ? '\n' + data.map((v) => `${v[0]}._path = ${v[1]}`).join('\n') : '';
-}
-
-function varTemplate(data: string[][], name: string) {
-  //prepare deep data (for locales)
-  let deepData: Record<string, object | string> = {};
-  let hasDeepData = false;
-
-  //data modify
-  data.map((v) => {
-    //check for has deep data
-    if (v[0].includes('/')) {
-      hasDeepData = true;
-    }
-
-    // lastKey is a data
-    let pathValue = v[0].replace(/\//g, '.').split('.');
-    // let scopeKey = '';
-    //   const len=pathValue.length
-    //   const scope=pathValue[len-2]
-    let lastKey: string | undefined = pathValue.pop();
-
-    let deepValue: Record<any, any> = {};
-    if (lastKey) {
-      // Solve the problem of files with the same name in different folders
-      const lastKeyList = lastKey.replace('_' + pathValue[0], '').split('_');
-      const key = lastKeyList.pop();
-      if (key) {
-        deepValue[key] = lastKey;
-      }
-    }
-    // Set Deep Value
-    deepValue = Object.assign(deepValue, dotProp.get(deepData, pathValue.join('.')));
-    dotProp.set(deepData, pathValue.join('.'), deepValue);
-  });
-
-  if (hasDeepData) {
-    return `const ${name} = ` + JSON.stringify(deepData).replace(/\"|\'/g, '');
-  }
-
-  return `const ${name} = { ${data.map((v) => v[0]).join(',')} }`;
-}
-
-const globTransform = function (config: SharedConfig): Transform {
-  const resolver = createResolver(
-    config.root || process.cwd(),
-    config.resolvers || [],
-    config.alias || {}
-  );
-  const { includes } = config;
-  const cache = new Map();
-  const urlMap = new Map();
-  return {
-    test({ path }) {
-      const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
-
-      try {
-        return (
-          !filePath.startsWith(modulesDir) &&
-          /\.(vue|js|jsx|ts|tsx)$/.test(filePath) &&
-          fileInclude(includes, filePath) &&
-          lstatSync(filePath).isFile()
-        );
-      } catch {
-        return false;
-      }
-    },
-    transform({ code, path, isBuild }) {
-      let result = cache.get(path);
-      if (!result) {
-        const reg = /import\s+([\w\s{}*]+)\s+from\s+(['"])globby(\?locale)?(\?path)?!([^'"]+)\2/g;
-        const match = code.match(reg);
-        if (!match) return code;
-        const lastImport = urlMap.get(path);
-        if (lastImport && match) {
-          code = code.replace(lastImport, match[0]);
-        }
-        result = code.replace(
-          reg,
-          (
-            _,
-            // variable to export
-            exportName,
-            // bare export or not
-            bareExporter,
-            // is locale import
-            isLocale,
-            // inject _path attr
-            injectPath,
-            // path export
-            globPath
-          ) => {
-            const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
-            // resolve path
-
-            const resolvedFilePath = globPath.startsWith('.')
-              ? resolver.resolveRelativeRequest(filePath, globPath)
-              : { pathname: resolver.requestToFile(globPath) };
-
-            const files = glob.sync(resolvedFilePath.pathname, { dot: true });
-
-            let templateStr = 'import #name# from #file#'; // import default
-            let name = exportName;
-            const m = exportName.match(/\{\s*(\w+)(\s+as\s+(\w+))?\s*\}/); // import module
-            const m2 = exportName.match(/\*\s+as\s+(\w+)/); // import * as all module
-            if (m) {
-              templateStr = `import { ${m[1]} as #name# } from #file#`;
-              name = m[3] || m[1];
-            } else if (m2) {
-              templateStr = 'import * as #name# from #file#';
-              name = m2[1];
-            }
-
-            const templateRender = template(templateStr);
-
-            const groups: Array<string>[] = [];
-            const replaceFiles = files.map((f, i) => {
-              const filePath = resolver.fileToRequest(f);
-              const file = bareExporter + filePath + bareExporter;
-
-              if (isLocale) {
-                const globrexRes = globrex(globPath, { extended: true, globstar: true });
-
-                // Get segments for files like an en/system ch/modules for:
-                // ['en', 'system'] ['ch', 'modules']
-
-                // TODO The window system and mac system path are inconsistent?
-                const fileNameWithAlias = filePath.replace(/^(\/src\/)/, '/@/');
-                const matchedGroups = globrexRes.regex.exec(fileNameWithAlias);
-
-                if (matchedGroups && matchedGroups.length) {
-                  const matchedSegments = matchedGroups[1]; //first everytime "Full Match"
-                  const matchList = matchedSegments.split('/').filter(Boolean);
-                  const lang = matchList.shift();
-                  const scope = matchList.pop();
-
-                  // Solve the problem of files with the same name in different folders
-                  const scopeKey = scope ? `${scope}_` : '';
-                  const fileName = matchedGroups[2];
-                  const name = scopeKey + fileName + '_' + lang;
-
-                  //send deep way like an (en/modules/system/dashboard) into groups
-                  groups.push([matchedSegments + name, file]);
-                  return templateRender({
-                    name,
-                    file,
-                  });
-                }
-              } else {
-                groups.push([name + i, file]);
-                return templateRender({ name: name + i, file });
-              }
-            });
-            // save in memory used result
-            const filesJoined = replaceFiles.join('\n');
-
-            urlMap.set(path, filesJoined);
-
-            // console.log('======================');
-            // console.log(filesJoined, varTemplate(groups, name));
-            // console.log('======================');
-            return [
-              filesJoined,
-              compareString(injectPath, groups),
-              varTemplate(groups, name),
-              '',
-            ].join('\n');
-          }
-        );
-        if (isBuild) cache.set(path, result);
-      }
-      return `${result}${hmr(isBuild)}`;
-    },
-  };
-};
-export default globTransform;

+ 5 - 9
build/vite/proxy.ts

@@ -1,16 +1,10 @@
+import type { ServerOptions } from 'http-proxy';
+
 type ProxyItem = [string, string];
 
 type ProxyList = ProxyItem[];
 
-type ProxyTargetList = Record<
-  string,
-  {
-    target: string;
-    changeOrigin: boolean;
-    rewrite: (path: string) => any;
-    secure?: boolean;
-  }
->;
+type ProxyTargetList = Record<string, ServerOptions & { rewrite: (path: string) => string }>;
 
 const httpsRE = /^https:\/\//;
 
@@ -23,9 +17,11 @@ export function createProxy(list: ProxyList = []) {
   for (const [prefix, target] of list) {
     const isHttps = httpsRE.test(target);
 
+    // https://github.com/http-party/node-http-proxy#options
     ret[prefix] = {
       target: target,
       changeOrigin: true,
+      ws: true,
       rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
       // https is require secure=false
       ...(isHttps ? { secure: false } : {}),

+ 3 - 9
index.html

@@ -1,7 +1,6 @@
 <!DOCTYPE html>
 <html lang="en">
   <head>
-    <%= viteHtmlPluginOptions.hmScript %>
     <meta charset="UTF-8" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
     <meta name="renderer" content="webkit" />
@@ -10,9 +9,8 @@
       content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
     />
 
-    <title></title>
+    <title><%= title %></title>
     <link rel="icon" href="/favicon.ico" />
-    <%= viteHtmlPluginOptions.injectConfig %>
   </head>
   <body>
     <div id="app">
@@ -137,15 +135,11 @@
       </style>
       <div class="app-loading">
         <div class="app-loading-wrap">
-          <img
-            src="<%= viteHtmlPluginOptions.publicPath %>resource/img/logo.png"
-            class="app-loading-logo"
-            alt="Logo"
-          />
+          <img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" />
           <div class="app-loading-dots">
             <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
           </div>
-          <div class="app-loading-title"><%= viteHtmlPluginOptions.title %></div>
+          <div class="app-loading-title"><%= title %></div>
         </div>
       </div>
     </div>

+ 24 - 21
package.json

@@ -1,20 +1,17 @@
 {
   "name": "vben-admin",
-  "version": "2.0.0-rc.15",
+  "version": "2.0.0-rc.16",
   "scripts": {
     "bootstrap": "yarn install",
-    "serve": "cross-env  vite --mode=development",
-    "build": "cross-env  vite build --mode=production && esno ./build/script/postBuild.ts",
-    "build:site": "cross-env SITE=true npm run build ",
+    "serve": "cross-env  vite ",
+    "build": "cross-env  vite build && esno ./build/script/postBuild.ts",
     "build:no-cache": "yarn  clean:cache && npm run build",
-    "typecheck": "vuedx-typecheck .",
     "report": "cross-env REPORT=true npm run build ",
     "preview": "npm run build && esno ./build/script/preview.ts",
     "preview:dist": "esno ./build/script/preview.ts",
-    "log": "esno ./build/script/changelog.ts",
+    "log": "conventional-changelog -p custom-config -i CHANGELOG.md -s -r 0",
     "clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite_opt_cache",
     "clean:lib": "npx rimraf node_modules",
-    "ls-lint": "npx ls-lint",
     "lint:eslint": "eslint --fix --ext \"src/**/*.{vue,less,css,scss}\"",
     "lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
     "lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
@@ -22,7 +19,7 @@
   },
   "dependencies": {
     "@iconify/iconify": "^2.0.0-rc.5",
-    "@vueuse/core": "^4.0.2",
+    "@vueuse/core": "^4.0.5",
     "ant-design-vue": "^2.0.0-rc.8",
     "apexcharts": "^3.23.1",
     "axios": "^0.21.1",
@@ -34,26 +31,27 @@
     "nprogress": "^0.2.0",
     "path-to-regexp": "^6.2.0",
     "qrcode": "^1.4.4",
-    "sortablejs": "^1.12.0",
+    "sortablejs": "^1.13.0",
     "vditor": "^3.7.5",
     "vue": "^3.0.5",
-    "vue-i18n": "9.0.0-beta.14",
+    "vue-i18n": "^9.0.0-rc.1",
     "vue-router": "^4.0.2",
     "vue-types": "^3.0.1",
     "vuex": "^4.0.0-rc.2",
     "vuex-module-decorators": "^1.0.1",
-    "xlsx": "^0.16.9",
     "zxcvbn": "^4.4.2"
   },
   "devDependencies": {
+    "@babel/core": "^7.12.10",
     "@commitlint/cli": "^11.0.0",
     "@commitlint/config-conventional": "^11.0.0",
-    "@iconify/json": "^1.1.282",
+    "@iconify/json": "^1.1.283",
     "@ls-lint/ls-lint": "^1.9.2",
-    "@purge-icons/generated": "^0.4.1",
+    "@purge-icons/generated": "^0.5.0",
     "@types/echarts": "^4.9.3",
     "@types/fs-extra": "^9.0.6",
     "@types/globrex": "^0.1.0",
+    "@types/http-proxy": "^1.17.4",
     "@types/koa-static": "^4.0.1",
     "@types/lodash-es": "^4.17.4",
     "@types/mockjs": "^1.0.3",
@@ -65,10 +63,13 @@
     "@types/zxcvbn": "^4.4.0",
     "@typescript-eslint/eslint-plugin": "^4.12.0",
     "@typescript-eslint/parser": "^4.12.0",
+    "@vitejs/plugin-legacy": "^1.1.0",
+    "@vitejs/plugin-vue": "^1.0.4",
+    "@vitejs/plugin-vue-jsx": "^1.0.1",
     "@vue/compiler-sfc": "^3.0.5",
     "@vuedx/typecheck": "^0.4.1",
     "@vuedx/typescript-plugin-vue": "^0.4.1",
-    "autoprefixer": "^9.8.6",
+    "autoprefixer": "^10.2.1",
     "commitizen": "^4.2.2",
     "conventional-changelog-cli": "^2.1.1",
     "conventional-changelog-custom-config": "^0.3.1",
@@ -82,14 +83,15 @@
     "esno": "^0.4.0",
     "fs-extra": "^9.0.1",
     "globrex": "^0.1.2",
-    "husky": "^4.3.6",
+    "husky": "^4.3.7",
     "koa-static": "^5.0.0",
     "less": "^4.0.0",
     "lint-staged": "^10.5.3",
     "portfinder": "^1.0.28",
-    "postcss-import": "^12.0.1",
+    "postcss-import": "^14.0.0",
     "prettier": "^2.2.1",
     "rimraf": "^3.0.2",
+    "rollup-plugin-gzip": "^2.5.0",
     "rollup-plugin-visualizer": "^4.1.2",
     "stylelint": "^13.8.0",
     "stylelint-config-prettier": "^8.0.2",
@@ -98,11 +100,12 @@
     "tasksfile": "^5.1.1",
     "ts-node": "^9.1.0",
     "typescript": "^4.1.3",
-    "vite": "^1.0.0-rc.13",
-    "vite-plugin-html": "^1.0.0-beta.2",
-    "vite-plugin-mock": "^1.0.9",
-    "vite-plugin-purge-icons": "^0.4.5",
-    "vite-plugin-pwa": "^0.2.1",
+    "vite": "^2.0.0-beta.15",
+    "vite-plugin-html": "^2.0.0-beta.5",
+    "vite-plugin-import-context": "^1.0.0-rc.1",
+    "vite-plugin-mock": "^2.0.0-beta.1",
+    "vite-plugin-purge-icons": "^0.5.0",
+    "vite-plugin-pwa": "^0.3.2",
     "vue-eslint-parser": "^7.3.0",
     "yargs": "^16.2.0"
   },

+ 4 - 2
src/App.vue

@@ -13,7 +13,7 @@
   import { initAppConfigStore } from '/@/setup/App';
 
   import { useLockPage } from '/@/hooks/web/useLockPage';
-  import { useLocale } from '/@/hooks/web/useLocale';
+  import { useLocale } from '/@/locales/useLocale';
 
   import { AppProvider } from '/@/components/Application';
 
@@ -21,6 +21,9 @@
     name: 'App',
     components: { ConfigProvider, AppProvider },
     setup() {
+      const { antConfigLocale, setLocale } = useLocale();
+      setLocale();
+
       // Initialize vuex internal system configuration
       initAppConfigStore();
 
@@ -28,7 +31,6 @@
       const lockEvent = useLockPage();
 
       // support Multi-language
-      const { antConfigLocale } = useLocale();
 
       return {
         antConfigLocale,

+ 1 - 2
src/components/Application/src/AppLocalePicker.vue

@@ -22,7 +22,7 @@
   import { Dropdown, DropMenu } from '/@/components/Dropdown';
   import { GlobalOutlined } from '@ant-design/icons-vue';
 
-  import { useLocale } from '/@/hooks/web/useLocale';
+  import { useLocale } from '/@/locales/useLocale';
   import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
 
   import { LocaleType } from '/@/locales/types';
@@ -75,7 +75,6 @@
 </script>
 
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-app-locale-picker';
 
   :global(.@{prefix-cls}-overlay) {

+ 0 - 1
src/components/Application/src/AppLogo.vue

@@ -59,7 +59,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-app-logo';
 
   .@{prefix-cls} {

+ 0 - 1
src/components/Application/src/search/AppSearch.vue

@@ -44,7 +44,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-app-search';
 
   .@{prefix-cls} {

+ 0 - 1
src/components/Application/src/search/AppSearchFooter.vue

@@ -37,7 +37,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-app-search-footer';
 
   .@{prefix-cls} {

+ 0 - 1
src/components/Application/src/search/AppSearchModal.vue

@@ -123,7 +123,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-app-search-modal';
   @footer-prefix-cls: ~'@{namespace}-app-search-footer';
   .@{prefix-cls} {

+ 0 - 1
src/components/Basic/src/BasicArrow.vue

@@ -46,7 +46,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-basic-arrow';
 
   .@{prefix-cls} {

+ 0 - 1
src/components/Basic/src/BasicHelp.vue

@@ -112,7 +112,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-basic-help';
 
   .@{prefix-cls} {

+ 0 - 1
src/components/Basic/src/BasicTitle.vue

@@ -30,7 +30,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-basic-title';
 
   .@{prefix-cls} {

+ 0 - 1
src/components/Container/src/LazyContainer.vue

@@ -140,7 +140,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-lazy-container';
 
   .@{prefix-cls} {

+ 1 - 1
src/components/Container/src/ScrollContainer.vue

@@ -12,7 +12,7 @@
 
   export default defineComponent({
     name: 'ScrollContainer',
-    inheritAttrs: false,
+    // inheritAttrs: false,
     components: { Scrollbar },
     setup() {
       const scrollbarRef = ref<Nullable<ScrollbarType>>(null);

+ 0 - 1
src/components/Container/src/collapse/CollapseContainer.vue

@@ -87,7 +87,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-collapse-container';
 
   .@{prefix-cls} {

+ 0 - 2
src/components/ContextMenu/src/index.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 @default-height: 42px !important;
 
 @small-height: 36px !important;

+ 2 - 4
src/components/ContextMenu/src/index.tsx

@@ -76,9 +76,7 @@ export default defineComponent({
           return (
             <>
               <Menu.Item disabled={disabled} class={`${prefixCls}__item`} key={label}>
-                {() => [
-                  <ItemContent showIcon={props.showIcon} item={item} handler={handleAction} />,
-                ]}
+                <ItemContent showIcon={props.showIcon} item={item} handler={handleAction} />
               </Menu.Item>
               {DividerComp}
             </>
@@ -109,7 +107,7 @@ export default defineComponent({
           ref={wrapRef}
           style={unref(getStyle)}
         >
-          {() => renderMenuItem(items)}
+          {renderMenuItem(items)}
         </Menu>
       );
     };

+ 1 - 1
src/components/Description/src/index.tsx

@@ -114,7 +114,7 @@ export default defineComponent({
     const renderDesc = () => {
       return (
         <Descriptions class={`${prefixCls}`} {...(unref(getDescriptionsProps) as any)}>
-          {() => renderItem()}
+          {renderItem()}
         </Descriptions>
       );
     };

+ 0 - 1
src/components/Drawer/src/BasicDrawer.vue

@@ -199,7 +199,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @header-height: 60px;
   @detail-header-height: 40px;
   @prefix-cls: ~'@{namespace}-basic-drawer';

+ 0 - 1
src/components/Drawer/src/components/DrawerFooter.vue

@@ -66,7 +66,6 @@
 </script>
 
 <style lang="less">
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-basic-drawer-footer';
   @footer-height: 60px;
   .@{prefix-cls} {

+ 0 - 1
src/components/Drawer/src/components/DrawerHeader.vue

@@ -45,7 +45,6 @@
 </script>
 
 <style lang="less">
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-basic-drawer-header';
   @footer-height: 60px;
   .@{prefix-cls} {

+ 0 - 1
src/components/Form/src/BasicForm.vue

@@ -247,7 +247,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-basic-form';
 
   .@{prefix-cls} {

+ 7 - 8
src/components/Form/src/components/FormItem.tsx

@@ -173,7 +173,8 @@ export default defineComponent({
       const characterInx = rules.findIndex((val) => val.max);
       if (characterInx !== -1 && !rules[characterInx].validator) {
         rules[characterInx].message =
-          rules[characterInx].message || t('component.form.maxTip', [rules[characterInx].max]);
+          rules[characterInx].message ||
+          t('component.form.maxTip', [rules[characterInx].max] as Recordable);
       }
       return rules;
     }
@@ -294,12 +295,10 @@ export default defineComponent({
           labelCol={labelCol}
           wrapperCol={wrapperCol}
         >
-          {() => (
-            <>
-              {getContent()}
-              {showSuffix && <span class="suffix">{getSuffix}</span>}
-            </>
-          )}
+          <>
+            {getContent()}
+            {showSuffix && <span class="suffix">{getSuffix}</span>}
+          </>
         </Form.Item>
       );
     }
@@ -323,7 +322,7 @@ export default defineComponent({
       return (
         isIfShow && (
           <Col {...realColProps} class={{ hidden: !isShow }}>
-            {() => getContent()}
+            {getContent()}
           </Col>
         )
       );

+ 0 - 2
src/components/Icon/src/index.vue

@@ -83,8 +83,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
-
   .app-iconify {
     display: inline-block;
     vertical-align: middle;

+ 1 - 1
src/components/Markdown/src/index.vue

@@ -7,7 +7,7 @@
   import 'vditor/dist/index.css';
 
   import { propTypes } from '/@/utils/propTypes';
-  import { useLocale } from '/@/hooks/web/useLocale';
+  import { useLocale } from '/@/locales/useLocale';
   import { useModalContext } from '../../Modal';
 
   type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;

+ 0 - 2
src/components/Menu/src/index.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 @basic-menu-prefix-cls: ~'@{namespace}-basic-menu';
 @basic-menu-content-prefix-cls: ~'@{namespace}-basic-menu-item-content';
 @basic-menu-tag-prefix-cls: ~'@{namespace}-basic-menu-item-tag';

+ 0 - 1
src/components/Modal/src/components/ModalClose.vue

@@ -54,7 +54,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-basic-modal-close';
   .@{prefix-cls} {
     display: flex;

+ 1 - 3
src/components/Modal/src/index.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 .fullscreen-modal {
   overflow: hidden;
 
@@ -79,7 +77,7 @@
 
   &-confirm-body {
     .ant-modal-confirm-content {
-      color: #fff;
+      // color: #fff;
 
       > * {
         color: @text-color-help-dark;

+ 7 - 3
src/components/Preview/index.ts

@@ -1,4 +1,8 @@
-export { createImgPreview } from './src/functional';
+// export { createImgPreview } from './src/functional';
 
-import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
-export const ImagePreview = createAsyncComponent(() => import('./src/index.vue'));
+export const createImgPreview = () => {};
+
+// import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+// export const ImagePreview = createAsyncComponent(() => import('./src/index.vue'));
+
+export { default as ImagePreview } from './src/index.vue';

+ 0 - 2
src/components/Preview/src/index.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 .img-preview {
   position: fixed;
   top: 0;

+ 0 - 1
src/components/Preview/src/index.vue

@@ -58,7 +58,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-image-preview';
 
   .@{prefix-cls} {

+ 1 - 1
src/components/Scrollbar/src/index.vue

@@ -34,7 +34,7 @@
 
   export default defineComponent({
     name: 'Scrollbar',
-    inheritAttrs: false,
+    // inheritAttrs: false,
     components: { Bar },
     props: {
       native: {

+ 0 - 1
src/components/StrengthMeter/src/index.vue

@@ -83,7 +83,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-strength-meter';
 
   .@{prefix-cls} {

+ 0 - 2
src/components/Upload/src/FileList.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 .file-table {
   width: 100%;
   border-collapse: collapse;

+ 0 - 2
src/components/Verify/src/DragVerify.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 @radius: 4px;
 
 .darg-verify {

+ 0 - 2
src/components/Verify/src/ImgRotate.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 .ir-dv {
   position: relative;
   display: flex;

+ 4 - 8
src/components/registerGlobComp.ts

@@ -35,25 +35,21 @@ import {
   Menu,
   Breadcrumb,
 } from 'ant-design-vue';
-import { getApp } from '/@/setup/App';
+import { App } from 'vue';
 
 const compList = [Icon, Button, AntButton.Group];
 
 // Fix hmr multiple registered components
-let registered = false;
-export function registerGlobComp() {
-  if (registered) return;
+export function registerGlobComp(app: App) {
   compList.forEach((comp: any) => {
-    getApp().component(comp.name, comp);
+    app.component(comp.name, comp);
   });
 
-  registered = true;
-
   // Optional
   // Why register here: The main reason for registering here is not to increase the size of the first screen code
   // If you need to customize global components, you can write here
   // If you don’t need it, you can delete it
-  getApp()
+  app
     .use(Select)
     .use(Alert)
     .use(Breadcrumb)

+ 1 - 1
src/hooks/setting/useLocaleSetting.ts

@@ -4,7 +4,7 @@ import { computed, unref } from 'vue';
 import { appStore } from '/@/store/modules/app';
 
 import getProjectSetting from '/@/settings/projectSetting';
-import { localeList } from '/@/locales';
+import { localeList } from '/@/locales/constant';
 
 // Get locale configuration
 const getLocale = computed(() => appStore.getProjectConfig.locale || getProjectSetting.locale);

+ 8 - 7
src/hooks/web/useI18n.ts

@@ -1,4 +1,4 @@
-import { getI18n } from '/@/setup/i18n';
+import { i18n } from '/@/locales/setupI18n';
 
 export function useI18n(namespace?: string) {
   function getKey(key: string) {
@@ -16,18 +16,19 @@ export function useI18n(namespace?: string) {
     },
   };
 
-  if (!getI18n()) {
+  if (!i18n) {
     return normalFn;
   }
 
-  const { t, ...methods } = getI18n().global;
+  const { t, ...methods } = i18n.global;
 
+  const tFn = function (...arg: Parameters<typeof t>) {
+    if (!arg[0]) return '';
+    return t(getKey(arg[0]), ...(arg as Parameters<typeof t>));
+  };
   return {
     ...methods,
-    t: (key: string, ...arg: any): string => {
-      if (!key) return '';
-      return t(getKey(key), ...(arg as Parameters<typeof t>));
-    },
+    t: tFn,
   };
 }
 

+ 1 - 1
src/hooks/web/useMessage.tsx

@@ -59,7 +59,7 @@ function createConfirm(options: ModalOptionsEx): ConfirmOptions {
     icon: getIcon(iconType),
     ...options,
   };
-  return Modal.confirm(opt) as any;
+  return (Modal.confirm(opt) as unknown) as ConfirmOptions;
 }
 
 const baseOptions = {

+ 1 - 2
src/layouts/default/content/index.vue

@@ -18,7 +18,7 @@
   import { useDesign } from '/@/hooks/web/useDesign';
   import { useRootSetting } from '/@/hooks/setting/useRootSetting';
   import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
-  import PageLayout from '/@/layouts/page/index';
+  import PageLayout from '/@/layouts/page/index.vue';
   import { useContentViewHeight } from './useContentViewHeight';
   import { Loading } from '/@/components/Loading';
 
@@ -41,7 +41,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-layout-content';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/footer/index.vue

@@ -40,7 +40,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-layout-footer';
 
   @normal-color: rgba(0, 0, 0, 0.45);

+ 0 - 1
src/layouts/default/header/MultipleHeader.vue

@@ -109,7 +109,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-layout-multiple-header';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/header/components/Breadcrumb.vue

@@ -147,7 +147,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-layout-breadcrumb';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/header/components/lock/LockModal.vue

@@ -80,7 +80,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-header-lock-modal';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/header/components/notify/NoticeList.vue

@@ -49,7 +49,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-header-notify-list';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/header/components/notify/index.vue

@@ -49,7 +49,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-header-notify';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/header/components/user-dropdown/index.vue

@@ -99,7 +99,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-header-user-dropdown';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/header/index.less

@@ -1,4 +1,3 @@
-@import (reference) '../../../design/index.less';
 @header-trigger-prefix-cls: ~'@{namespace}-layout-header-trigger';
 @header-prefix-cls: ~'@{namespace}-layout-header';
 @locale-prefix-cls: ~'@{namespace}-app-locale-picker';

+ 0 - 7
src/layouts/default/index.vue

@@ -31,7 +31,6 @@
   import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
   import { useDesign } from '/@/hooks/web/useDesign';
 
-  import { registerGlobComp } from '/@/components/registerGlobComp';
   import { useAppInject } from '/@/hooks/web/useAppInject';
 
   export default defineComponent({
@@ -46,11 +45,6 @@
       Layout,
     },
     setup() {
-      // ! Only register global components here
-      // ! Can reduce the size of the first screen code
-      // default layout It is loaded after login. So it won’t be packaged to the first screen
-      registerGlobComp();
-
       const { prefixCls } = useDesign('default-layout');
 
       const { getIsMobile } = useAppInject();
@@ -70,7 +64,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../design/index.less';
   @prefix-cls: ~'@{namespace}-default-layout';
 
   .@{prefix-cls} {

+ 0 - 2
src/layouts/default/menu/index.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 @prefix-cls: ~'@{namespace}-layout-menu';
 @logo-prefix-cls: ~'@{namespace}-app-logo';
 

+ 14 - 20
src/layouts/default/setting/SettingDrawer.tsx

@@ -389,26 +389,20 @@ export default defineComponent({
         width={330}
         wrapClassName="setting-drawer"
       >
-        {{
-          default: () => (
-            <>
-              <Divider>{() => t('layout.setting.navMode')}</Divider>
-              {renderSidebar()}
-              <Divider>{() => t('layout.setting.headerTheme')}</Divider>
-              {renderHeaderTheme()}
-              <Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
-              {renderSiderTheme()}
-              <Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
-              {renderFeatures()}
-              <Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
-              {renderContent()}
-              <Divider>{() => t('layout.setting.animation')}</Divider>
-              {renderTransition()}
-              <Divider />
-              <SettingFooter />
-            </>
-          ),
-        }}
+        <Divider>{() => t('layout.setting.navMode')}</Divider>
+        {renderSidebar()}
+        <Divider>{() => t('layout.setting.headerTheme')}</Divider>
+        {renderHeaderTheme()}
+        <Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
+        {renderSiderTheme()}
+        <Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
+        {renderFeatures()}
+        <Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
+        {renderContent()}
+        <Divider>{() => t('layout.setting.animation')}</Divider>
+        {renderTransition()}
+        <Divider />
+        <SettingFooter />
       </BasicDrawer>
     );
   },

+ 0 - 1
src/layouts/default/setting/components/InputNumberItem.vue

@@ -43,7 +43,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-setting-input-number-item';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/setting/components/SelectItem.vue

@@ -62,7 +62,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-setting-select-item';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/setting/components/SettingFooter.vue

@@ -75,7 +75,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-setting-footer';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/setting/components/SwitchItem.vue

@@ -57,7 +57,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-setting-switch-item';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/setting/components/ThemePicker.vue

@@ -55,7 +55,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-setting-theme-picker';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/setting/components/TypePicker.vue

@@ -51,7 +51,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../../design/index.less';
   @prefix-cls: ~'@{namespace}-setting-menu-type-picker';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/setting/index.vue

@@ -28,7 +28,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-setting-button';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/sider/DragBar.vue

@@ -41,7 +41,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-darg-bar';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/sider/LayoutSider.vue

@@ -128,7 +128,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-layout-sideBar';
 
   .@{prefix-cls} {

+ 0 - 1
src/layouts/default/sider/MixSider.vue

@@ -333,7 +333,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-layout-mix-sider';
   @tag-prefix-cls: ~'@{namespace}-basic-menu-item-tag';
   @width: 80px;

+ 0 - 1
src/layouts/default/sider/index.vue

@@ -41,7 +41,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../design/index.less';
   @prefix-cls: ~'@{namespace}-layout-sider-wrapper';
   .@{prefix-cls} {
     .ant-drawer-body {

+ 0 - 1
src/layouts/default/tabs/index.less

@@ -1,4 +1,3 @@
-@import (reference) '../../../design/index.less';
 @prefix-cls: ~'@{namespace}-multiple-tabs';
 
 .@{prefix-cls} {

+ 0 - 72
src/layouts/page/index.tsx

@@ -1,72 +0,0 @@
-import type { DefaultContext } from './transition';
-
-import { computed, defineComponent, unref, Transition, KeepAlive } from 'vue';
-import { RouterView } from 'vue-router';
-
-import FrameLayout from '/@/layouts/iframe/index.vue';
-
-import { useRootSetting } from '/@/hooks/setting/useRootSetting';
-
-import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
-import { useCache } from './useCache';
-import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
-import { getTransitionName } from './transition';
-
-export default defineComponent({
-  name: 'PageLayout',
-  setup() {
-    const { getCaches } = useCache(true);
-    const { getShowMultipleTab } = useMultipleTabSetting();
-
-    const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
-
-    const { getBasicTransition, getEnableTransition } = useTransitionSetting();
-
-    const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
-
-    return () => {
-      return (
-        <>
-          <RouterView>
-            {{
-              default: ({ Component, route }: DefaultContext) => {
-                // No longer show animations that are already in the tab
-                const cacheTabs = unref(getCaches);
-
-                const name = getTransitionName({
-                  route,
-                  openCache: unref(openCache),
-                  enableTransition: unref(getEnableTransition),
-                  cacheTabs,
-                  def: unref(getBasicTransition),
-                });
-
-                // When the child element is the parentView, adding the key will cause the component to be executed multiple times. When it is not parentView, you need to add a key, because it needs to be compatible with the same route carrying different parameters
-                const isParentView = Component?.type.parentView;
-                const componentKey = isParentView ? {} : { key: route.fullPath };
-
-                const renderComp = () => <Component {...componentKey} />;
-
-                const PageContent = unref(openCache) ? (
-                  <KeepAlive include={cacheTabs}>{renderComp()}</KeepAlive>
-                ) : (
-                  renderComp()
-                );
-
-                if (!unref(getEnableTransition)) {
-                  return PageContent;
-                }
-                return (
-                  <Transition name={name} mode="out-in" appear={true}>
-                    {() => PageContent}
-                  </Transition>
-                );
-              },
-            }}
-          </RouterView>
-          {unref(getCanEmbedIFramePage) && <FrameLayout />}
-        </>
-      );
-    };
-  },
-});

+ 72 - 0
src/layouts/page/index.vue

@@ -0,0 +1,72 @@
+<template>
+  <div>
+    <router-view>
+      <template v-slot="{ Component, route }">
+        <transition
+          :name="
+            getTransitionName({
+              route,
+              openCache,
+              enableTransition: getEnableTransition,
+              cacheTabs: getCaches,
+              def: getBasicTransition,
+            })
+          "
+          mode="out-in"
+          appear
+        >
+          <keep-alive v-if="openCache" :include="getCaches">
+            <component :is="Component" v-bind="getKey(Component, route)" />
+          </keep-alive>
+          <component v-else :is="Component" v-bind="getKey(Component, route)" />
+        </transition>
+      </template>
+    </router-view>
+    <FrameLayout v-if="getCanEmbedIFramePage" />
+  </div>
+</template>
+
+<script lang="ts">
+  import type { FunctionalComponent } from 'vue';
+  import type { RouteLocation } from 'vue-router';
+
+  import { computed, defineComponent, unref } from 'vue';
+
+  import FrameLayout from '/@/layouts/iframe/index.vue';
+
+  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
+
+  import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
+  import { useCache } from './useCache';
+  import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
+  import { getTransitionName } from './transition';
+
+  export default defineComponent({
+    name: 'PageLayout',
+    components: { FrameLayout },
+    setup() {
+      const { getCaches } = useCache(true);
+      const { getShowMultipleTab } = useMultipleTabSetting();
+
+      const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
+
+      const { getBasicTransition, getEnableTransition } = useTransitionSetting();
+
+      const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
+
+      function getKey(component: FunctionalComponent & { type: Indexable }, route: RouteLocation) {
+        return !!component?.type.parentView ? {} : { key: route.fullPath };
+      }
+
+      return {
+        getTransitionName,
+        openCache,
+        getEnableTransition,
+        getBasicTransition,
+        getCaches,
+        getCanEmbedIFramePage,
+        getKey,
+      };
+    },
+  });
+</script>

+ 0 - 3
src/locales/index.ts → src/locales/constant.ts

@@ -1,5 +1,3 @@
-import messages from 'globby?locale!/@/locales/lang/**/*.@(ts)';
-
 import type { DropMenu } from '/@/components/Dropdown';
 
 // locale list
@@ -13,4 +11,3 @@ export const localeList: DropMenu[] = [
     event: 'en',
   },
 ];
-export default messages;

+ 4 - 0
src/locales/getMessage.ts

@@ -0,0 +1,4 @@
+import { genMessage } from './helper';
+import modules from 'glob:./lang/**/*.ts';
+
+export default genMessage(modules);

+ 20 - 0
src/locales/helper.ts

@@ -0,0 +1,20 @@
+import { set } from 'lodash-es';
+
+export function genMessage(langs: Record<string, Record<string, any>>, prefix = 'lang') {
+  const obj: Recordable = {};
+
+  Object.keys(langs).forEach((key) => {
+    const mod = langs[key].default;
+    let k = key.replace(`./${prefix}/`, '').replace(/^\.\//, '');
+    const lastIndex = k.lastIndexOf('.');
+    k = k.substring(0, lastIndex);
+    const keyList = k.split('/');
+    const lang = keyList.shift();
+    const objKey = keyList.join('.');
+    if (lang) {
+      set(obj, lang, obj[lang] || {});
+      set(obj[lang], objKey, mod);
+    }
+  });
+  return obj;
+}

+ 9 - 12
src/setup/i18n/index.ts → src/locales/setupI18n.ts

@@ -1,34 +1,31 @@
-import { App } from 'vue';
+import type { App } from 'vue';
 import type { I18n, I18nOptions } from 'vue-i18n';
 
 import { createI18n } from 'vue-i18n';
-import localeMessages from '/@/locales';
-import { useLocale } from '/@/hooks/web/useLocale';
+
+import 'moment/dist/locale/zh-cn';
+
 import projectSetting from '/@/settings/projectSetting';
-const { setupLocale } = useLocale();
+
+import messages from './getMessage';
 
 const { lang, availableLocales, fallback } = projectSetting?.locale;
+
 const localeData: I18nOptions = {
   legacy: false,
   locale: lang,
   fallbackLocale: fallback,
-  messages: localeMessages,
+  messages,
   availableLocales: availableLocales,
   sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false.
   silentTranslationWarn: true, // true - warning off
   missingWarn: false,
   silentFallbackWarn: true,
 };
-
-let i18n: I18n;
+export let i18n: I18n;
 
 // setup i18n instance with glob
 export function setupI18n(app: App) {
   i18n = createI18n(localeData) as I18n;
-  setupLocale();
   app.use(i18n);
 }
-
-export function getI18n(): I18n {
-  return i18n;
-}

+ 9 - 7
src/hooks/web/useLocale.ts → src/locales/useLocale.ts

@@ -2,18 +2,16 @@
  * Multi-language related operations
  */
 import type { LocaleType } from '/@/locales/types';
+import type { Ref } from 'vue';
 
 import { unref, ref } from 'vue';
-
-import { getI18n } from '/@/setup/i18n';
-
 import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
 
 import moment from 'moment';
 
 import 'moment/dist/locale/zh-cn';
 
-moment.locale('zh-cn');
+import { i18n } from './setupI18n';
 
 const antConfigLocaleRef = ref<any>(null);
 
@@ -23,7 +21,11 @@ export function useLocale() {
   // Switching the language will change the locale of useI18n
   // And submit to configuration modification
   function changeLocale(lang: LocaleType): void {
-    (getI18n().global.locale as any).value = lang;
+    if (i18n.mode === 'legacy') {
+      i18n.global.locale = lang;
+    } else {
+      ((i18n.global.locale as unknown) as Ref<string>).value = lang;
+    }
     setLocalSetting({ lang });
     // i18n.global.setLocaleMessage(locale, messages);
 
@@ -51,13 +53,13 @@ export function useLocale() {
   }
 
   // initialization
-  function setupLocale() {
+  function setLocale() {
     const lang = unref(getLang);
     lang && changeLocale(lang);
   }
 
   return {
-    setupLocale,
+    setLocale,
     getLocale,
     getLang,
     changeLocale,

+ 5 - 6
src/main.ts

@@ -6,18 +6,19 @@ import { setupStore } from '/@/store';
 import { setupAntd } from '/@/setup/ant-design-vue';
 import { setupErrorHandle } from '/@/setup/error-handle';
 import { setupGlobDirectives } from '/@/directives';
-import { setupI18n } from '/@/setup/i18n';
+import { setupI18n } from '/@/locales/setupI18n';
 import { setupProdMockServer } from '../mock/_createProductionServer';
-import { setApp } from '/@/setup/App';
+
+import { registerGlobComp } from '/@/components/registerGlobComp';
 
 import { isDevMode, isProdMode, isUseMock } from '/@/utils/env';
 
 import '/@/design/index.less';
 
-import '/@/locales/index';
-
 const app = createApp(App);
 
+registerGlobComp(app);
+
 // Configure component library
 setupAntd(app);
 
@@ -51,5 +52,3 @@ if (isDevMode()) {
 if (isProdMode() && isUseMock()) {
   setupProdMockServer();
 }
-// Used to share app instances in other modules
-setApp(app);

+ 0 - 5
src/router/helper/dynamicImport.ts

@@ -1,5 +0,0 @@
-// The content here is just for type approval. The actual file content is overwritten by transform
-// For specific coverage, see build/vite/plugin/transform/dynamic-import/index.ts
-export default function (name: string) {
-  return name as any;
-}

+ 28 - 2
src/router/helper/routeHelper.ts

@@ -2,8 +2,8 @@ import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
 import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
 
 import { getParentLayout, LAYOUT } from '/@/router/constant';
-import dynamicImport from './dynamicImport';
 import { cloneDeep } from 'lodash-es';
+import { warn } from '/@/utils/log';
 
 export type LayoutMapKey = 'LAYOUT';
 
@@ -11,12 +11,20 @@ const LayoutMap = new Map<LayoutMapKey, () => Promise<typeof import('*.vue')>>()
 
 // 动态引入
 function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
+  // TODO Because xlsx does not support vite2.0 temporarily. So filter the excel example first
+  const dynamicViewsModules = importContext({
+    dir: '/@/views',
+    deep: true,
+    regexp: /^(?!.*\/demo\/excel).*\.(tsx?|vue)$/,
+    dynamicImport: true,
+    dynamicEnabled: 'autoImportRoute',
+  });
   if (!routes) return;
   routes.forEach((item) => {
     const { component, name } = item;
     const { children } = item;
     if (component) {
-      item.component = dynamicImport(component as string);
+      item.component = dynamicImport(dynamicViewsModules, component as string);
     } else if (name) {
       item.component = getParentLayout(name);
     }
@@ -24,6 +32,24 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
   });
 }
 
+function dynamicImport(dynamicViewsModules: DynamicImportContextResult, component: string) {
+  const keys = dynamicViewsModules.keys();
+  const matchKeys = keys.filter((key) => {
+    const k = key.substr(1);
+    return k.startsWith(component) || k.startsWith(`/${component}`);
+  });
+  if (matchKeys?.length === 1) {
+    const matchKey = matchKeys[0];
+    return dynamicViewsModules(matchKey);
+  }
+  if (matchKeys?.length > 1) {
+    warn(
+      'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure'
+    );
+    return;
+  }
+}
+
 // Turn background objects into routing objects
 export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
   LayoutMap.set('LAYOUT', LAYOUT);

+ 6 - 6
src/router/menus/index.ts

@@ -9,18 +9,18 @@ import router from '/@/router';
 import { PermissionModeEnum } from '/@/enums/appEnum';
 import { pathToRegexp } from 'path-to-regexp';
 
-import modules from 'globby!/@/router/menus/modules/**/*.@(ts)';
-
-const reg = /(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
+import modules from 'glob:./modules/**/*.ts';
 
 const menuModules: MenuModule[] = [];
 
 Object.keys(modules).forEach((key) => {
-  const moduleItem = modules[key];
-  const menuModule = Array.isArray(moduleItem) ? [...moduleItem] : [moduleItem];
-  menuModules.push(...menuModule);
+  const mod = modules[key].default || {};
+  const modList = Array.isArray(mod) ? [...mod] : [mod];
+  menuModules.push(...modList);
 });
 
+const reg = /(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
+
 // ===========================
 // ==========Helper===========
 // ===========================

+ 5 - 4
src/router/routes/index.ts

@@ -2,17 +2,18 @@ import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
 
 import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant';
 
-import modules from 'globby!/@/router/routes/modules/**/*.@(ts)';
 import { mainOutRoutes } from './mainOut';
 import { PageEnum } from '/@/enums/pageEnum';
-
 import { t } from '/@/hooks/web/useI18n';
 
+import modules from 'glob:./modules/**/*.ts';
+
 const routeModuleList: AppRouteModule[] = [];
 
 Object.keys(modules).forEach((key) => {
-  const mod = Array.isArray(modules[key]) ? [...modules[key]] : [modules[key]];
-  routeModuleList.push(...mod);
+  const mod = modules[key].default || {};
+  const modList = Array.isArray(mod) ? [...mod] : [mod];
+  routeModuleList.push(...modList);
 });
 
 export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];

+ 44 - 44
src/router/routes/modules/demo/feat.ts

@@ -172,51 +172,51 @@ const feat: AppRouteModule = {
         title: t('routes.demo.feat.errorLog'),
       },
     },
-    {
-      path: 'excel',
-      name: 'Excel',
-      redirect: '/feat/excel/customExport',
-      component: getParentLayout('Excel'),
-      meta: {
-        // icon: 'mdi:microsoft-excel',
-        title: t('routes.demo.excel.excel'),
-      },
+    // {
+    //   path: 'excel',
+    //   name: 'Excel',
+    //   redirect: '/feat/excel/customExport',
+    //   component: getParentLayout('Excel'),
+    //   meta: {
+    //     // icon: 'mdi:microsoft-excel',
+    //     title: t('routes.demo.excel.excel'),
+    //   },
 
-      children: [
-        {
-          path: 'customExport',
-          name: 'CustomExport',
-          component: () => import('/@/views/demo/excel/CustomExport.vue'),
-          meta: {
-            title: t('routes.demo.excel.customExport'),
-          },
-        },
-        {
-          path: 'jsonExport',
-          name: 'JsonExport',
-          component: () => import('/@/views/demo/excel/JsonExport.vue'),
-          meta: {
-            title: t('routes.demo.excel.jsonExport'),
-          },
-        },
-        {
-          path: 'arrayExport',
-          name: 'ArrayExport',
-          component: () => import('/@/views/demo/excel/ArrayExport.vue'),
-          meta: {
-            title: t('routes.demo.excel.arrayExport'),
-          },
-        },
-        {
-          path: 'importExcel',
-          name: 'ImportExcel',
-          component: () => import('/@/views/demo/excel/ImportExcel.vue'),
-          meta: {
-            title: t('routes.demo.excel.importExcel'),
-          },
-        },
-      ],
-    },
+    //   children: [
+    //     {
+    //       path: 'customExport',
+    //       name: 'CustomExport',
+    //       component: () => import('/@/views/demo/excel/CustomExport.vue'),
+    //       meta: {
+    //         title: t('routes.demo.excel.customExport'),
+    //       },
+    //     },
+    //     {
+    //       path: 'jsonExport',
+    //       name: 'JsonExport',
+    //       component: () => import('/@/views/demo/excel/JsonExport.vue'),
+    //       meta: {
+    //         title: t('routes.demo.excel.jsonExport'),
+    //       },
+    //     },
+    //     {
+    //       path: 'arrayExport',
+    //       name: 'ArrayExport',
+    //       component: () => import('/@/views/demo/excel/ArrayExport.vue'),
+    //       meta: {
+    //         title: t('routes.demo.excel.arrayExport'),
+    //       },
+    //     },
+    //     {
+    //       path: 'importExcel',
+    //       name: 'ImportExcel',
+    //       component: () => import('/@/views/demo/excel/ImportExcel.vue'),
+    //       meta: {
+    //         title: t('routes.demo.excel.importExcel'),
+    //       },
+    //     },
+    //   ],
+    // },
     {
       path: 'testTab/:id',
       name: 'TestTab',

+ 1 - 1
src/settings/projectSetting.ts

@@ -172,7 +172,7 @@ const setting: ProjectConfig = {
 
   // Whether to cancel the http request that has been sent but not responded when switching the interface.
   // If it is enabled, I want to overwrite a single interface. Can be set in a separate interface
-  removeAllHttpPending: true,
+  removeAllHttpPending: false,
 };
 
 export default setting;

+ 0 - 12
src/setup/App.ts

@@ -3,7 +3,6 @@
  */
 
 import type { ProjectConfig } from '/@/types/config';
-import type { App } from 'vue';
 import { computed, ref } from 'vue';
 
 import { ThemeModeEnum } from '/@/enums/appEnum';
@@ -21,17 +20,6 @@ import {
 import { appStore } from '/@/store/modules/app';
 import { deepMerge } from '/@/utils';
 
-// Used to share global app instances
-let app: App;
-
-export function setApp(_app: App): void {
-  app = _app;
-}
-
-export function getApp(): App {
-  return app;
-}
-
 // TODO Theme switching
 export function useThemeMode(mode: ThemeModeEnum) {
   const modeRef = ref(mode);

+ 0 - 78
src/types/vue-app-env.d.ts

@@ -23,81 +23,3 @@ declare namespace NodeJS {
 }
 
 declare let process: NodeJS.Process;
-
-declare module '*.bmp' {
-  const src: string;
-  export default src;
-}
-
-declare module '*.gif' {
-  const src: string;
-  export default src;
-}
-
-declare module '*.jpg' {
-  const src: string;
-  export default src;
-}
-
-declare module '*.jpeg' {
-  const src: string;
-  export default src;
-}
-
-declare module '*.png' {
-  const src: string;
-  export default src;
-}
-
-declare module '*.webp' {
-  const src: string;
-  export default src;
-}
-
-declare module '*.svg' {
-  const src: string;
-  export default src;
-}
-
-declare module '*.json' {
-  const content: any | any[];
-  export default content;
-}
-
-declare module '*.scss' {
-  const content: {
-    readonly [className: string]: string;
-  };
-  export default content;
-}
-declare module '*.less' {
-  const content: {
-    readonly [className: string]: string;
-  };
-  export default content;
-}
-declare module '*.styl' {
-  const content: {
-    readonly [className: string]: string;
-  };
-  export default content;
-}
-declare module '*.css' {
-  const content: any;
-  export default content;
-}
-
-declare module '*.module.css' {
-  const classes: { readonly [key: string]: string };
-  export default classes;
-}
-
-declare module '*.module.scss' {
-  const classes: { readonly [key: string]: string };
-  export default classes;
-}
-
-declare module '*.module.sass' {
-  const classes: { readonly [key: string]: string };
-  export default classes;
-}

+ 1 - 0
src/types/window.d.ts

@@ -4,5 +4,6 @@ declare global {
   declare interface Window {
     // Global vue app instance
     __APP__: App<Element>;
+    __VERSION__: string;
   }
 }

+ 0 - 2
src/views/dashboard/analysis/components/GrowCard.vue

@@ -41,8 +41,6 @@
   });
 </script>
 <style lang="less">
-  @import (reference) '../../../../design/index.less';
-
   .grow-card {
     display: flex;
     width: calc(100% - 12px);

+ 0 - 2
src/views/dashboard/analysis/index.vue

@@ -68,8 +68,6 @@
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
-
   .analysis {
     width: 100%;
 

+ 0 - 2
src/views/dashboard/house/index.less

@@ -1,5 +1,3 @@
-@import (reference) '../../../design/index.less';
-
 .house-wrap {
   position: relative;
   width: 600px;

Some files were not shown because too many files changed in this diff