Commit 99ac309fa9eed36f8444b8bbab7b18275c5aa5aa

Authored by vben
1 parent 1d3007f0

wip: support vite

Showing 100 changed files with 397 additions and 1129 deletions

Too many changes to show.

To preserve performance only 100 of 105 files are displayed.

.env.production
... ... @@ -23,5 +23,5 @@ VITE_GLOB_API_URL_PREFIX=
23 23 # use pwa
24 24 VITE_USE_PWA = false
25 25  
26   -# TODO use Cdn
27   -VITE_USE_CDN = true
  26 +# Is it compatible with older browsers
  27 +VITE_LEGACY = false
... ...
build/script/changelog.ts deleted 100644 → 0
1   -// #!/usr/bin/env node
2   -
3   -import { sh } from 'tasksfile';
4   -import { errorConsole, successConsole } from '../utils';
5   -
6   -export const runChangeLog = async () => {
7   - try {
8   - let cmd = `conventional-changelog -p custom-config -i CHANGELOG.md -s -r 0 `;
9   -
10   - await sh(cmd, {
11   - async: true,
12   - nopipe: true,
13   - });
14   - await sh('prettier --write **/CHANGELOG.md ', {
15   - async: true,
16   - nopipe: true,
17   - });
18   - successConsole('CHANGE_LOG.md generated successfully!');
19   - } catch (error) {
20   - errorConsole('CHANGE_LOG.md generated error\n' + error);
21   -
22   - process.exit(1);
23   - }
24   -};
25   -
26   -runChangeLog();
build/script/postBuild.ts
... ... @@ -3,7 +3,6 @@
3 3 import { argv } from 'yargs';
4 4 import { runBuildConfig } from './buildConf';
5 5 import { errorConsole, successConsole } from '../utils';
6   -import { startGzipStyle } from '../vite/plugin/gzip/compress';
7 6  
8 7 export const runBuild = async () => {
9 8 try {
... ... @@ -13,8 +12,6 @@ export const runBuild = async () => {
13 12 if (!argvList.includes('no-conf')) {
14 13 await runBuildConfig();
15 14 }
16   - // await runUpdateHtml();
17   - await startGzipStyle();
18 15 successConsole('Vite Build successfully!');
19 16 } catch (error) {
20 17 errorConsole('Vite Build Error\n' + error);
... ...
build/utils.ts
... ... @@ -63,11 +63,11 @@ export function getIPAddress() {
63 63 return '';
64 64 }
65 65  
66   -export function isDevFn(mode: 'development' | 'production'): boolean {
  66 +export function isDevFn(mode: string): boolean {
67 67 return mode === 'development';
68 68 }
69 69  
70   -export function isProdFn(mode: 'development' | 'production'): boolean {
  70 +export function isProdFn(mode: string): boolean {
71 71 return mode === 'production';
72 72 }
73 73  
... ... @@ -85,13 +85,6 @@ export function isBuildGzip(): boolean {
85 85 return process.env.VITE_BUILD_GZIP === 'true';
86 86 }
87 87  
88   -/**
89   - * Whether to generate package site
90   - */
91   -export function isSiteMode(): boolean {
92   - return process.env.SITE === 'true';
93   -}
94   -
95 88 export interface ViteEnv {
96 89 VITE_PORT: number;
97 90 VITE_USE_MOCK: boolean;
... ... @@ -99,10 +92,12 @@ export interface ViteEnv {
99 92 VITE_PUBLIC_PATH: string;
100 93 VITE_PROXY: [string, string][];
101 94 VITE_GLOB_APP_TITLE: string;
  95 + VITE_GLOB_APP_SHORT_NAME: string;
102 96 VITE_USE_CDN: boolean;
103 97 VITE_DROP_CONSOLE: boolean;
104 98 VITE_BUILD_GZIP: boolean;
105 99 VITE_DYNAMIC_IMPORT: boolean;
  100 + VITE_LEGACY: boolean;
106 101 }
107 102  
108 103 // Read all environment variable configuration files to process.env
... ...
build/vite/hm.ts deleted 100644 → 0
1   -// Baidu statistics code for site deployment
2   -// Only open in build:site
3   -export const hmScript = `<script>
4   -var _hmt = _hmt || [];
5   -(function() {
6   - var hm = document.createElement("script");
7   - hm.src = "https://hm.baidu.com/hm.js?384d6046e02f6ac4ea075357bd0e9b43";
8   - var s = document.getElementsByTagName("script")[0];
9   - s.parentNode.insertBefore(hm, s);
10   -})();
11   -</script>
12   -`;
build/vite/plugin/gzip.ts 0 → 100644
  1 +import gzipPlugin from 'rollup-plugin-gzip';
  2 +import { isBuildGzip } from '../../utils';
  3 +import { Plugin } from 'vite';
  4 +export function configGzipPlugin(isBuild: boolean): Plugin | Plugin[] {
  5 + const useGzip = isBuild && isBuildGzip;
  6 +
  7 + if (useGzip) {
  8 + return gzipPlugin();
  9 + }
  10 +
  11 + return [];
  12 +}
... ...
build/vite/plugin/gzip/compress.ts deleted 100644 → 0
1   -import { gzip } from 'zlib';
2   -import { readFileSync, writeFileSync } from 'fs';
3   -import { GzipPluginOptions } from './types';
4   -import { readAllFile, getCwdPath, isBuildGzip, isSiteMode } from '../../../utils';
5   -
6   -export function startGzip(
7   - fileContent: string | Buffer,
8   - options: GzipPluginOptions = {}
9   -): Promise<Buffer> {
10   - return new Promise((resolve, reject) => {
11   - gzip(fileContent, options.gzipOptions || {}, (err, result) => {
12   - if (err) {
13   - reject(err);
14   - } else {
15   - resolve(result);
16   - }
17   - });
18   - });
19   -}
20   -
21   -// 手动压缩css
22   -export async function startGzipStyle() {
23   - if (isBuildGzip() || isSiteMode()) {
24   - const outDir = 'dist';
25   - const assets = '_assets';
26   - const allCssFile = readAllFile(getCwdPath(outDir, assets), /\.(css)$/);
27   - for (const path of allCssFile) {
28   - const source = readFileSync(path);
29   - const content = await startGzip(source);
30   - const ds = path.split('/');
31   - const fileName = ds[ds.length - 1];
32   - writeFileSync(getCwdPath(outDir, assets, `${fileName}.gz`), content);
33   - }
34   - }
35   -}
build/vite/plugin/gzip/index.ts deleted 100644 → 0
1   -// 修改自https://github.com/kryops/rollup-plugin-gzip
2   -// 因为rollup-plugin-gzip不支持vite
3   -// vite对css打包独立的。所以不能在打包的时候顺带打包css
4   -// TODO rc.9会支持 configurBuild 配置项。到时候重新修改
5   -
6   -import { readFile, writeFile } from 'fs';
7   -import { basename } from 'path';
8   -import { promisify } from 'util';
9   -import { gzip } from 'zlib';
10   -
11   -import { OutputAsset, OutputChunk, OutputOptions, Plugin } from 'rollup';
12   -import { GzipPluginOptions } from './types';
13   -
14   -const isFunction = (arg: unknown): arg is (...args: any[]) => any => typeof arg === 'function';
15   -const isRegExp = (arg: unknown): arg is RegExp =>
16   - Object.prototype.toString.call(arg) === '[object RegExp]';
17   -
18   -export type StringMappingOption = (originalString: string) => string;
19   -export type CustomCompressionOption = (
20   - content: string | Buffer
21   -) => string | Buffer | Promise<string | Buffer>;
22   -
23   -const readFilePromise = promisify(readFile);
24   -const writeFilePromise = promisify(writeFile);
25   -
26   -// functionality partially copied from rollup
27   -
28   -/**
29   - * copied from https://github.com/rollup/rollup/blob/master/src/rollup/index.ts#L450
30   - */
31   -function isOutputChunk(file: OutputAsset | OutputChunk): file is OutputChunk {
32   - return typeof (file as OutputChunk).code === 'string';
33   -}
34   -
35   -/**
36   - * Gets the string/buffer content from a file object.
37   - * Important for adding source map comments
38   - *
39   - * Copied partially from rollup.writeOutputFile
40   - * https://github.com/rollup/rollup/blob/master/src/rollup/index.ts#L454
41   - */
42   -function getOutputFileContent(
43   - outputFileName: string,
44   - outputFile: OutputAsset | OutputChunk,
45   - outputOptions: OutputOptions
46   -): string | Buffer {
47   - if (isOutputChunk(outputFile)) {
48   - let source: string | Buffer;
49   - source = outputFile.code;
50   - if (outputOptions.sourcemap && outputFile.map) {
51   - const url =
52   - outputOptions.sourcemap === 'inline'
53   - ? outputFile.map.toUrl()
54   - : `${basename(outputFileName)}.map`;
55   -
56   - // https://github.com/rollup/rollup/blob/master/src/utils/sourceMappingURL.ts#L1
57   - source += `//# source` + `MappingURL=${url}\n`;
58   - }
59   - return source;
60   - } else {
61   - return typeof outputFile.source === 'string'
62   - ? outputFile.source
63   - : // just to be sure, as it is typed string | Uint8Array in rollup 2.0.0
64   - Buffer.from(outputFile.source);
65   - }
66   -}
67   -
68   -// actual plugin code
69   -
70   -function gzipPlugin(options: GzipPluginOptions = {}): Plugin {
71   - // check for old options
72   - if ('algorithm' in options) {
73   - console.warn(
74   - '[rollup-plugin-gzip] The "algorithm" option is not supported any more! ' +
75   - 'Use "customCompression" instead to specify a different compression algorithm.'
76   - );
77   - }
78   - if ('options' in options) {
79   - console.warn('[rollup-plugin-gzip] The "options" option was renamed to "gzipOptions"!');
80   - }
81   - if ('additional' in options) {
82   - console.warn('[rollup-plugin-gzip] The "additional" option was renamed to "additionalFiles"!');
83   - }
84   - if ('delay' in options) {
85   - console.warn('[rollup-plugin-gzip] The "delay" option was renamed to "additionalFilesDelay"!');
86   - }
87   -
88   - const compressGzip: CustomCompressionOption = (fileContent) => {
89   - return new Promise((resolve, reject) => {
90   - gzip(fileContent, options.gzipOptions || {}, (err, result) => {
91   - if (err) {
92   - reject(err);
93   - } else {
94   - resolve(result);
95   - }
96   - });
97   - });
98   - };
99   -
100   - const doCompress = options.customCompression || compressGzip;
101   -
102   - const mapFileName: StringMappingOption = isFunction(options.fileName)
103   - ? (options.fileName as StringMappingOption)
104   - : (fileName: string) => fileName + (options.fileName || '.gz');
105   -
106   - const plugin: Plugin = {
107   - name: 'gzip',
108   -
109   - generateBundle(outputOptions, bundle) {
110   - return Promise.all(
111   - Object.keys(bundle)
112   - .map((fileName) => {
113   - const fileEntry = bundle[fileName];
114   -
115   - // file name filter option check
116   -
117   - const fileNameFilter = options.filter || /\.(js|mjs|json|css|html)$/;
118   -
119   - if (isRegExp(fileNameFilter) && !fileName.match(fileNameFilter)) {
120   - return Promise.resolve();
121   - }
122   -
123   - if (
124   - isFunction(fileNameFilter) &&
125   - !(fileNameFilter as (x: string) => boolean)(fileName)
126   - ) {
127   - return Promise.resolve();
128   - }
129   -
130   - const fileContent = getOutputFileContent(fileName, fileEntry, outputOptions);
131   -
132   - // minSize option check
133   - if (options.minSize && options.minSize > fileContent.length) {
134   - return Promise.resolve();
135   - }
136   -
137   - return Promise.resolve(doCompress(fileContent))
138   - .then((compressedContent) => {
139   - const compressedFileName = mapFileName(fileName);
140   - bundle[compressedFileName] = {
141   - type: 'asset', // Rollup >= 1.21
142   - name: compressedFileName,
143   - fileName: compressedFileName,
144   - isAsset: true, // Rollup < 1.21
145   - source: compressedContent,
146   - };
147   - })
148   - .catch((err: any) => {
149   - console.error(err);
150   - return Promise.reject('[rollup-plugin-gzip] Error compressing file ' + fileName);
151   - });
152   - })
153   - .concat([
154   - (() => {
155   - if (!options.additionalFiles || !options.additionalFiles.length)
156   - return Promise.resolve();
157   -
158   - const compressAdditionalFiles = () =>
159   - Promise.all(
160   - options.additionalFiles!.map((filePath) =>
161   - readFilePromise(filePath)
162   - .then((fileContent) => doCompress(fileContent))
163   - .then((compressedContent) => {
164   - return writeFilePromise(mapFileName(filePath), compressedContent);
165   - })
166   - .catch(() => {
167   - return Promise.reject(
168   - '[rollup-plugin-gzip] Error compressing additional file ' +
169   - filePath +
170   - '. Please check the spelling of your configured additionalFiles. ' +
171   - 'You might also have to increase the value of the additionalFilesDelay option.'
172   - );
173   - })
174   - )
175   - ) as Promise<any>;
176   -
177   - // additional files can be processed outside of rollup after a delay
178   - // for older plugins or plugins that write to disk (curcumventing rollup) without awaiting
179   - const additionalFilesDelay = options.additionalFilesDelay || 0;
180   -
181   - if (additionalFilesDelay) {
182   - setTimeout(compressAdditionalFiles, additionalFilesDelay);
183   - return Promise.resolve();
184   - } else {
185   - return compressAdditionalFiles();
186   - }
187   - })(),
188   - ])
189   - ) as Promise<any>;
190   - },
191   - };
192   -
193   - return plugin;
194   -}
195   -
196   -export default gzipPlugin;
build/vite/plugin/gzip/types.ts deleted 100644 → 0
1   -import type { ZlibOptions } from 'zlib';
2   -
3   -export type StringMappingOption = (originalString: string) => string;
4   -export type CustomCompressionOption = (
5   - content: string | Buffer
6   -) => string | Buffer | Promise<string | Buffer>;
7   -
8   -export interface GzipPluginOptions {
9   - /**
10   - * Control which of the output files to compress
11   - *
12   - * Defaults to `/\.(js|mjs|json|css|html)$/`
13   - */
14   - filter?: RegExp | ((fileName: string) => boolean);
15   -
16   - /**
17   - * GZIP compression options, see https://nodejs.org/api/zlib.html#zlib_class_options
18   - */
19   - gzipOptions?: ZlibOptions;
20   -
21   - /**
22   - * Specified the minimum size in Bytes for a file to get compressed.
23   - * Files that are smaller than this threshold will not be compressed.
24   - * This does not apply to the files specified through `additionalFiles`!
25   - */
26   - minSize?: number;
27   -
28   - /**
29   - * This option allows you to compress additional files outside of the main rollup bundling process.
30   - * The processing is delayed to make sure the files are written on disk; the delay is controlled
31   - * through `additionalFilesDelay`.
32   - */
33   - additionalFiles?: string[];
34   -
35   - /**
36   - * This options sets a delay (ms) before the plugin compresses the files specified through `additionalFiles`.
37   - * Increase this value if your artifacts take a long time to generate.
38   - *
39   - * Defaults to `2000`
40   - */
41   - additionalFilesDelay?: number;
42   -
43   - /**
44   - * Set a custom compression algorithm. The function can either return the compressed contents synchronously,
45   - * or otherwise return a promise for asynchronous processing.
46   - */
47   - customCompression?: CustomCompressionOption;
48   -
49   - /**
50   - * Set a custom file name convention for the compressed files. Can be a suffix string or a function
51   - * returning the file name.
52   - *
53   - * Defaults to `.gz`
54   - */
55   - fileName?: string | StringMappingOption;
56   -}
build/vite/plugin/html.ts
1 1 import type { Plugin } from 'vite';
2   -import ViteHtmlPlugin from 'vite-plugin-html';
3   -import { isProdFn, isSiteMode, ViteEnv } from '../../utils';
  2 +import html from 'vite-plugin-html';
  3 +import { ViteEnv } from '../../utils';
4 4  
5   -import { hmScript } from '../hm';
6 5 // @ts-ignore
7 6 import pkg from '../../../package.json';
8 7 import { GLOB_CONFIG_FILE_NAME } from '../../constant';
9 8  
10   -export function setupHtmlPlugin(
11   - plugins: Plugin[],
12   - env: ViteEnv,
13   - mode: 'development' | 'production'
14   -) {
  9 +export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
15 10 const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env;
16   -
17   - const htmlPlugin = ViteHtmlPlugin({
18   - // html title
19   - title: VITE_GLOB_APP_TITLE,
20   - minify: isProdFn(mode),
21   - options: {
22   - publicPath: VITE_PUBLIC_PATH,
23   - // Package and insert additional configuration files
24   - injectConfig: isProdFn(mode)
25   - ? `<script src='${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
26   - pkg.version
27   - }-${new Date().getTime()}'></script>`
28   - : '',
29   - // Insert Baidu statistics code
30   - hmScript: isSiteMode() ? hmScript : '',
31   - title: VITE_GLOB_APP_TITLE,
  11 + const htmlPlugin: Plugin[] = html({
  12 + minify: isBuild,
  13 + inject: {
  14 + injectData: {
  15 + title: VITE_GLOB_APP_TITLE,
  16 + },
  17 + tags: isBuild
  18 + ? [
  19 + {
  20 + tag: 'script',
  21 + attrs: {
  22 + src: `${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
  23 + pkg.version
  24 + }-${new Date().getTime()}`,
  25 + },
  26 + },
  27 + ]
  28 + : [],
32 29 },
33 30 });
34   -
35   - plugins.push(htmlPlugin);
36   - return plugins;
  31 + return htmlPlugin;
37 32 }
... ...
build/vite/plugin/importContext.ts 0 → 100644
  1 +import dynamicImport from 'vite-plugin-import-context';
  2 +import type { ViteEnv } from '../../utils';
  3 +import type { Plugin } from 'vite';
  4 +
  5 +export function configDynamicImport(env: ViteEnv) {
  6 + const { VITE_DYNAMIC_IMPORT } = env;
  7 + const dynamicImportPlugin: Plugin = dynamicImport({
  8 + include: ['**/*.ts'],
  9 + autoImportRoute: VITE_DYNAMIC_IMPORT,
  10 + });
  11 + return dynamicImportPlugin;
  12 +}
... ...
build/vite/plugin/index.ts
1   -import type { Plugin as VitePlugin } from 'vite';
2   -import type { Plugin as rollupPlugin } from 'rollup';
  1 +import type { Plugin } from 'vite';
3 2  
4 3 import PurgeIcons from 'vite-plugin-purge-icons';
5 4  
6 5 import visualizer from 'rollup-plugin-visualizer';
7   -import gzipPlugin from './gzip/index';
8 6  
9 7 // @ts-ignore
10 8 import pkg from '../../../package.json';
11   -import { isSiteMode, ViteEnv, isReportMode, isBuildGzip } from '../../utils';
12   -import { setupHtmlPlugin } from './html';
13   -import { setupPwaPlugin } from './pwa';
14   -import { setupMockPlugin } from './mock';
  9 +import { ViteEnv, isReportMode } from '../../utils';
  10 +import { configHtmlPlugin } from './html';
  11 +import { configPwaConfig } from './pwa';
  12 +import { configMockPlugin } from './mock';
  13 +import { configDynamicImport } from './importContext';
  14 +import { configGzipPlugin } from './gzip';
15 15  
16 16 // gen vite plugins
17   -export function createVitePlugins(viteEnv: ViteEnv, mode: 'development' | 'production') {
18   - const vitePlugins: VitePlugin[] = [];
  17 +export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean, mode: string) {
  18 + const vitePlugins: (Plugin | Plugin[])[] = [];
19 19  
20 20 // vite-plugin-html
21   - setupHtmlPlugin(vitePlugins, viteEnv, mode);
  21 + vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
  22 +
22 23 // vite-plugin-pwa
23   - setupPwaPlugin(vitePlugins, viteEnv, mode);
  24 + vitePlugins.push(configPwaConfig(viteEnv, isBuild));
  25 +
24 26 // vite-plugin-mock
25   - setupMockPlugin(vitePlugins, viteEnv, mode);
  27 + vitePlugins.push(configMockPlugin(viteEnv, isBuild));
  28 +
  29 + // vite-plugin-import-context
  30 + vitePlugins.push(configDynamicImport(viteEnv));
26 31  
27 32 // vite-plugin-purge-icons
28 33 vitePlugins.push(PurgeIcons());
29 34  
30   - return vitePlugins;
31   -}
32   -
33   -// gen rollup plugins
34   -export function createRollupPlugin() {
35   - const rollupPlugins: rollupPlugin[] = [];
  35 + // rollup-plugin-gzip
  36 + vitePlugins.push(configGzipPlugin(isBuild));
36 37  
  38 + // rollup-plugin-visualizer
37 39 if (isReportMode()) {
38   - // rollup-plugin-visualizer
39   - rollupPlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
40   - }
41   - if (isBuildGzip() || isSiteMode()) {
42   - // rollup-plugin-gizp
43   - rollupPlugins.push(gzipPlugin());
  40 + vitePlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
44 41 }
45 42  
46   - return rollupPlugins;
  43 + return vitePlugins;
47 44 }
... ...
build/vite/plugin/mock.ts
1   -import { createMockServer } from 'vite-plugin-mock';
2   -import type { Plugin } from 'vite';
3   -import { isDevFn, ViteEnv } from '../../utils';
  1 +import { viteMockServe } from 'vite-plugin-mock';
  2 +import { ViteEnv } from '../../utils';
4 3  
5   -export function setupMockPlugin(
6   - plugins: Plugin[],
7   - env: ViteEnv,
8   - mode: 'development' | 'production'
9   -) {
  4 +export function configMockPlugin(env: ViteEnv, isBuild: boolean) {
10 5 const { VITE_USE_MOCK } = env;
11 6  
12   - const useMock = isDevFn(mode) && VITE_USE_MOCK;
  7 + const useMock = !isBuild && VITE_USE_MOCK;
13 8  
14 9 if (useMock) {
15   - const mockPlugin = createMockServer({
  10 + const mockPlugin = viteMockServe({
16 11 ignore: /^\_/,
17 12 mockPath: 'mock',
18 13 showTime: true,
19 14 localEnabled: useMock,
20 15 });
21   - plugins.push(mockPlugin);
  16 + return mockPlugin;
22 17 }
23   - return plugins;
  18 + return [];
24 19 }
... ...
build/vite/plugin/pwa.ts
1 1 import { VitePWA } from 'vite-plugin-pwa';
2   -import type { Plugin } from 'vite';
  2 +
3 3 import { ViteEnv } from '../../utils';
4 4  
5   -export function setupPwaPlugin(
6   - plugins: Plugin[],
7   - env: ViteEnv,
8   - // @ts-ignore
9   - mode: 'development' | 'production'
10   -) {
11   - const { VITE_USE_PWA } = env;
  5 +export function configPwaConfig(env: ViteEnv, isBulid: boolean) {
  6 + const { VITE_USE_PWA, VITE_GLOB_APP_TITLE, VITE_GLOB_APP_SHORT_NAME } = env;
12 7  
13   - const pwaPlugin = VitePWA({
14   - manifest: {
15   - name: 'Vben Admin',
16   - short_name: 'vben_admin',
17   - icons: [
18   - {
19   - src: './resource/img/pwa-192x192.png',
20   - sizes: '192x192',
21   - type: 'image/png',
22   - },
23   - {
24   - src: './resource/img/pwa-512x512.png',
25   - sizes: '512x512',
26   - type: 'image/png',
27   - },
28   - ],
29   - },
30   - });
31   - if (VITE_USE_PWA) {
32   - plugins.push(pwaPlugin);
  8 + if (VITE_USE_PWA && isBulid) {
  9 + // vite-plugin-pwa
  10 + const pwaPlugin = VitePWA({
  11 + manifest: {
  12 + name: VITE_GLOB_APP_TITLE,
  13 + short_name: VITE_GLOB_APP_SHORT_NAME,
  14 + icons: [
  15 + {
  16 + src: './resource/img/pwa-192x192.png',
  17 + sizes: '192x192',
  18 + type: 'image/png',
  19 + },
  20 + {
  21 + src: './resource/img/pwa-512x512.png',
  22 + sizes: '512x512',
  23 + type: 'image/png',
  24 + },
  25 + ],
  26 + },
  27 + });
  28 + return pwaPlugin;
33 29 }
34   - return plugins;
  30 + return [];
35 31 }
... ...
build/vite/plugin/transform/dynamic-import/index.ts deleted 100644 → 0
1   -// Used to import all files under `src/views`
2   -// The built-in dynamic import of vite cannot meet the needs of importing all files under views
3   -// Special usage ,Only for this project
4   -import glob from 'glob';
5   -import { Transform } from 'vite/dist/node/transform.js';
6   -
7   -function getPath(path: string) {
8   - const lastIndex = path.lastIndexOf('.');
9   - if (lastIndex !== -1) {
10   - path = path.substring(0, lastIndex);
11   - }
12   - return path.replace('src/views', '');
13   -}
14   -
15   -const dynamicImportTransform = function (enableDynamicImport: boolean): Transform {
16   - return {
17   - test({ path }) {
18   - // Only convert the file
19   - return (
20   - path.includes('/src/router/helper/dynamicImport.ts') ||
21   - path.includes(`\\src\\router\\helper\\dynamicImport.ts`)
22   - );
23   - },
24   - transform({ code }) {
25   - if (!enableDynamicImport) {
26   - return code;
27   - }
28   -
29   - // Only convert the dir
30   - try {
31   - const files = glob.sync('src/views/**/**.{vue,tsx}', { cwd: process.cwd() });
32   -
33   - return `
34   - export default function (id) {
35   - switch (id) {
36   - ${files
37   - .map((p) =>
38   - ` case '${getPath(p)}': return () => import('${p
39   - .replace('src/views', '/@/views')
40   - .replace(/\/\//g, '/')}');`.replace('.tsx', '')
41   - )
42   - .join('\n ')}
43   - default: return Promise.reject(new Error("Unknown variable dynamic import: " + id));
44   - }
45   - }\n\n
46   - `;
47   - } catch (error) {
48   - console.error(error);
49   - return code;
50   - }
51   - },
52   - };
53   -};
54   -export default dynamicImportTransform;
build/vite/plugin/transform/globby/index.ts deleted 100644 → 0
1   -// Modified from
2   -// https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts
3   -
4   -// TODO Deleting files requires re-running the project
5   -import { join } from 'path';
6   -import { lstatSync } from 'fs';
7   -import glob from 'glob';
8   -import globrex from 'globrex';
9   -import dotProp from 'dot-prop';
10   -import { createResolver, Resolver } from 'vite/dist/node/resolver.js';
11   -import { Transform } from 'vite/dist/node/transform.js';
12   -
13   -const modulesDir: string = join(process.cwd(), '/node_modules/');
14   -
15   -interface SharedConfig {
16   - root?: string;
17   - alias?: Record<string, string>;
18   - resolvers?: Resolver[];
19   -
20   - includes?: string[];
21   -}
22   -
23   -function template(template: string) {
24   - return (data: { [x: string]: any }) => {
25   - return template.replace(/#([^#]+)#/g, (_, g1) => data[g1] || g1);
26   - };
27   -}
28   -
29   -// TODO support hmr
30   -function hmr(isBuild = false) {
31   - if (isBuild) return '';
32   - return `
33   - if (import.meta.hot) {
34   - import.meta.hot.accept();
35   - }`;
36   -}
37   -
38   -// handle includes
39   -function fileInclude(includes: string | string[] | undefined, filePath: string) {
40   - return !includes || !Array.isArray(includes)
41   - ? true
42   - : includes.some((item) => filePath.startsWith(item));
43   -}
44   -
45   -// Bare exporter
46   -function compareString(modify: any, data: string[][]) {
47   - return modify ? '\n' + data.map((v) => `${v[0]}._path = ${v[1]}`).join('\n') : '';
48   -}
49   -
50   -function varTemplate(data: string[][], name: string) {
51   - //prepare deep data (for locales)
52   - let deepData: Record<string, object | string> = {};
53   - let hasDeepData = false;
54   -
55   - //data modify
56   - data.map((v) => {
57   - //check for has deep data
58   - if (v[0].includes('/')) {
59   - hasDeepData = true;
60   - }
61   -
62   - // lastKey is a data
63   - let pathValue = v[0].replace(/\//g, '.').split('.');
64   - // let scopeKey = '';
65   - // const len=pathValue.length
66   - // const scope=pathValue[len-2]
67   - let lastKey: string | undefined = pathValue.pop();
68   -
69   - let deepValue: Record<any, any> = {};
70   - if (lastKey) {
71   - // Solve the problem of files with the same name in different folders
72   - const lastKeyList = lastKey.replace('_' + pathValue[0], '').split('_');
73   - const key = lastKeyList.pop();
74   - if (key) {
75   - deepValue[key] = lastKey;
76   - }
77   - }
78   - // Set Deep Value
79   - deepValue = Object.assign(deepValue, dotProp.get(deepData, pathValue.join('.')));
80   - dotProp.set(deepData, pathValue.join('.'), deepValue);
81   - });
82   -
83   - if (hasDeepData) {
84   - return `const ${name} = ` + JSON.stringify(deepData).replace(/\"|\'/g, '');
85   - }
86   -
87   - return `const ${name} = { ${data.map((v) => v[0]).join(',')} }`;
88   -}
89   -
90   -const globTransform = function (config: SharedConfig): Transform {
91   - const resolver = createResolver(
92   - config.root || process.cwd(),
93   - config.resolvers || [],
94   - config.alias || {}
95   - );
96   - const { includes } = config;
97   - const cache = new Map();
98   - const urlMap = new Map();
99   - return {
100   - test({ path }) {
101   - const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
102   -
103   - try {
104   - return (
105   - !filePath.startsWith(modulesDir) &&
106   - /\.(vue|js|jsx|ts|tsx)$/.test(filePath) &&
107   - fileInclude(includes, filePath) &&
108   - lstatSync(filePath).isFile()
109   - );
110   - } catch {
111   - return false;
112   - }
113   - },
114   - transform({ code, path, isBuild }) {
115   - let result = cache.get(path);
116   - if (!result) {
117   - const reg = /import\s+([\w\s{}*]+)\s+from\s+(['"])globby(\?locale)?(\?path)?!([^'"]+)\2/g;
118   - const match = code.match(reg);
119   - if (!match) return code;
120   - const lastImport = urlMap.get(path);
121   - if (lastImport && match) {
122   - code = code.replace(lastImport, match[0]);
123   - }
124   - result = code.replace(
125   - reg,
126   - (
127   - _,
128   - // variable to export
129   - exportName,
130   - // bare export or not
131   - bareExporter,
132   - // is locale import
133   - isLocale,
134   - // inject _path attr
135   - injectPath,
136   - // path export
137   - globPath
138   - ) => {
139   - const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
140   - // resolve path
141   -
142   - const resolvedFilePath = globPath.startsWith('.')
143   - ? resolver.resolveRelativeRequest(filePath, globPath)
144   - : { pathname: resolver.requestToFile(globPath) };
145   -
146   - const files = glob.sync(resolvedFilePath.pathname, { dot: true });
147   -
148   - let templateStr = 'import #name# from #file#'; // import default
149   - let name = exportName;
150   - const m = exportName.match(/\{\s*(\w+)(\s+as\s+(\w+))?\s*\}/); // import module
151   - const m2 = exportName.match(/\*\s+as\s+(\w+)/); // import * as all module
152   - if (m) {
153   - templateStr = `import { ${m[1]} as #name# } from #file#`;
154   - name = m[3] || m[1];
155   - } else if (m2) {
156   - templateStr = 'import * as #name# from #file#';
157   - name = m2[1];
158   - }
159   -
160   - const templateRender = template(templateStr);
161   -
162   - const groups: Array<string>[] = [];
163   - const replaceFiles = files.map((f, i) => {
164   - const filePath = resolver.fileToRequest(f);
165   - const file = bareExporter + filePath + bareExporter;
166   -
167   - if (isLocale) {
168   - const globrexRes = globrex(globPath, { extended: true, globstar: true });
169   -
170   - // Get segments for files like an en/system ch/modules for:
171   - // ['en', 'system'] ['ch', 'modules']
172   -
173   - // TODO The window system and mac system path are inconsistent?
174   - const fileNameWithAlias = filePath.replace(/^(\/src\/)/, '/@/');
175   - const matchedGroups = globrexRes.regex.exec(fileNameWithAlias);
176   -
177   - if (matchedGroups && matchedGroups.length) {
178   - const matchedSegments = matchedGroups[1]; //first everytime "Full Match"
179   - const matchList = matchedSegments.split('/').filter(Boolean);
180   - const lang = matchList.shift();
181   - const scope = matchList.pop();
182   -
183   - // Solve the problem of files with the same name in different folders
184   - const scopeKey = scope ? `${scope}_` : '';
185   - const fileName = matchedGroups[2];
186   - const name = scopeKey + fileName + '_' + lang;
187   -
188   - //send deep way like an (en/modules/system/dashboard) into groups
189   - groups.push([matchedSegments + name, file]);
190   - return templateRender({
191   - name,
192   - file,
193   - });
194   - }
195   - } else {
196   - groups.push([name + i, file]);
197   - return templateRender({ name: name + i, file });
198   - }
199   - });
200   - // save in memory used result
201   - const filesJoined = replaceFiles.join('\n');
202   -
203   - urlMap.set(path, filesJoined);
204   -
205   - // console.log('======================');
206   - // console.log(filesJoined, varTemplate(groups, name));
207   - // console.log('======================');
208   - return [
209   - filesJoined,
210   - compareString(injectPath, groups),
211   - varTemplate(groups, name),
212   - '',
213   - ].join('\n');
214   - }
215   - );
216   - if (isBuild) cache.set(path, result);
217   - }
218   - return `${result}${hmr(isBuild)}`;
219   - },
220   - };
221   -};
222   -export default globTransform;
build/vite/proxy.ts
  1 +import type { ServerOptions } from 'http-proxy';
  2 +
1 3 type ProxyItem = [string, string];
2 4  
3 5 type ProxyList = ProxyItem[];
4 6  
5   -type ProxyTargetList = Record<
6   - string,
7   - {
8   - target: string;
9   - changeOrigin: boolean;
10   - rewrite: (path: string) => any;
11   - secure?: boolean;
12   - }
13   ->;
  7 +type ProxyTargetList = Record<string, ServerOptions & { rewrite: (path: string) => string }>;
14 8  
15 9 const httpsRE = /^https:\/\//;
16 10  
... ... @@ -23,9 +17,11 @@ export function createProxy(list: ProxyList = []) {
23 17 for (const [prefix, target] of list) {
24 18 const isHttps = httpsRE.test(target);
25 19  
  20 + // https://github.com/http-party/node-http-proxy#options
26 21 ret[prefix] = {
27 22 target: target,
28 23 changeOrigin: true,
  24 + ws: true,
29 25 rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
30 26 // https is require secure=false
31 27 ...(isHttps ? { secure: false } : {}),
... ...
index.html
1 1 <!DOCTYPE html>
2 2 <html lang="en">
3 3 <head>
4   - <%= viteHtmlPluginOptions.hmScript %>
5 4 <meta charset="UTF-8" />
6 5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7 6 <meta name="renderer" content="webkit" />
... ... @@ -10,9 +9,8 @@
10 9 content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
11 10 />
12 11  
13   - <title></title>
  12 + <title><%= title %></title>
14 13 <link rel="icon" href="/favicon.ico" />
15   - <%= viteHtmlPluginOptions.injectConfig %>
16 14 </head>
17 15 <body>
18 16 <div id="app">
... ... @@ -137,15 +135,11 @@
137 135 </style>
138 136 <div class="app-loading">
139 137 <div class="app-loading-wrap">
140   - <img
141   - src="<%= viteHtmlPluginOptions.publicPath %>resource/img/logo.png"
142   - class="app-loading-logo"
143   - alt="Logo"
144   - />
  138 + <img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" />
145 139 <div class="app-loading-dots">
146 140 <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
147 141 </div>
148   - <div class="app-loading-title"><%= viteHtmlPluginOptions.title %></div>
  142 + <div class="app-loading-title"><%= title %></div>
149 143 </div>
150 144 </div>
151 145 </div>
... ...
package.json
1 1 {
2 2 "name": "vben-admin",
3   - "version": "2.0.0-rc.15",
  3 + "version": "2.0.0-rc.16",
4 4 "scripts": {
5 5 "bootstrap": "yarn install",
6   - "serve": "cross-env vite --mode=development",
7   - "build": "cross-env vite build --mode=production && esno ./build/script/postBuild.ts",
8   - "build:site": "cross-env SITE=true npm run build ",
  6 + "serve": "cross-env vite ",
  7 + "build": "cross-env vite build && esno ./build/script/postBuild.ts",
9 8 "build:no-cache": "yarn clean:cache && npm run build",
10   - "typecheck": "vuedx-typecheck .",
11 9 "report": "cross-env REPORT=true npm run build ",
12 10 "preview": "npm run build && esno ./build/script/preview.ts",
13 11 "preview:dist": "esno ./build/script/preview.ts",
14   - "log": "esno ./build/script/changelog.ts",
  12 + "log": "conventional-changelog -p custom-config -i CHANGELOG.md -s -r 0",
15 13 "clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite_opt_cache",
16 14 "clean:lib": "npx rimraf node_modules",
17   - "ls-lint": "npx ls-lint",
18 15 "lint:eslint": "eslint --fix --ext \"src/**/*.{vue,less,css,scss}\"",
19 16 "lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
20 17 "lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
... ... @@ -22,7 +19,7 @@
22 19 },
23 20 "dependencies": {
24 21 "@iconify/iconify": "^2.0.0-rc.5",
25   - "@vueuse/core": "^4.0.2",
  22 + "@vueuse/core": "^4.0.5",
26 23 "ant-design-vue": "^2.0.0-rc.8",
27 24 "apexcharts": "^3.23.1",
28 25 "axios": "^0.21.1",
... ... @@ -34,26 +31,27 @@
34 31 "nprogress": "^0.2.0",
35 32 "path-to-regexp": "^6.2.0",
36 33 "qrcode": "^1.4.4",
37   - "sortablejs": "^1.12.0",
  34 + "sortablejs": "^1.13.0",
38 35 "vditor": "^3.7.5",
39 36 "vue": "^3.0.5",
40   - "vue-i18n": "9.0.0-beta.14",
  37 + "vue-i18n": "^9.0.0-rc.1",
41 38 "vue-router": "^4.0.2",
42 39 "vue-types": "^3.0.1",
43 40 "vuex": "^4.0.0-rc.2",
44 41 "vuex-module-decorators": "^1.0.1",
45   - "xlsx": "^0.16.9",
46 42 "zxcvbn": "^4.4.2"
47 43 },
48 44 "devDependencies": {
  45 + "@babel/core": "^7.12.10",
49 46 "@commitlint/cli": "^11.0.0",
50 47 "@commitlint/config-conventional": "^11.0.0",
51   - "@iconify/json": "^1.1.282",
  48 + "@iconify/json": "^1.1.283",
52 49 "@ls-lint/ls-lint": "^1.9.2",
53   - "@purge-icons/generated": "^0.4.1",
  50 + "@purge-icons/generated": "^0.5.0",
54 51 "@types/echarts": "^4.9.3",
55 52 "@types/fs-extra": "^9.0.6",
56 53 "@types/globrex": "^0.1.0",
  54 + "@types/http-proxy": "^1.17.4",
57 55 "@types/koa-static": "^4.0.1",
58 56 "@types/lodash-es": "^4.17.4",
59 57 "@types/mockjs": "^1.0.3",
... ... @@ -65,10 +63,13 @@
65 63 "@types/zxcvbn": "^4.4.0",
66 64 "@typescript-eslint/eslint-plugin": "^4.12.0",
67 65 "@typescript-eslint/parser": "^4.12.0",
  66 + "@vitejs/plugin-legacy": "^1.1.0",
  67 + "@vitejs/plugin-vue": "^1.0.4",
  68 + "@vitejs/plugin-vue-jsx": "^1.0.1",
68 69 "@vue/compiler-sfc": "^3.0.5",
69 70 "@vuedx/typecheck": "^0.4.1",
70 71 "@vuedx/typescript-plugin-vue": "^0.4.1",
71   - "autoprefixer": "^9.8.6",
  72 + "autoprefixer": "^10.2.1",
72 73 "commitizen": "^4.2.2",
73 74 "conventional-changelog-cli": "^2.1.1",
74 75 "conventional-changelog-custom-config": "^0.3.1",
... ... @@ -82,14 +83,15 @@
82 83 "esno": "^0.4.0",
83 84 "fs-extra": "^9.0.1",
84 85 "globrex": "^0.1.2",
85   - "husky": "^4.3.6",
  86 + "husky": "^4.3.7",
86 87 "koa-static": "^5.0.0",
87 88 "less": "^4.0.0",
88 89 "lint-staged": "^10.5.3",
89 90 "portfinder": "^1.0.28",
90   - "postcss-import": "^12.0.1",
  91 + "postcss-import": "^14.0.0",
91 92 "prettier": "^2.2.1",
92 93 "rimraf": "^3.0.2",
  94 + "rollup-plugin-gzip": "^2.5.0",
93 95 "rollup-plugin-visualizer": "^4.1.2",
94 96 "stylelint": "^13.8.0",
95 97 "stylelint-config-prettier": "^8.0.2",
... ... @@ -98,11 +100,12 @@
98 100 "tasksfile": "^5.1.1",
99 101 "ts-node": "^9.1.0",
100 102 "typescript": "^4.1.3",
101   - "vite": "^1.0.0-rc.13",
102   - "vite-plugin-html": "^1.0.0-beta.2",
103   - "vite-plugin-mock": "^1.0.9",
104   - "vite-plugin-purge-icons": "^0.4.5",
105   - "vite-plugin-pwa": "^0.2.1",
  103 + "vite": "^2.0.0-beta.15",
  104 + "vite-plugin-html": "^2.0.0-beta.5",
  105 + "vite-plugin-import-context": "^1.0.0-rc.1",
  106 + "vite-plugin-mock": "^2.0.0-beta.1",
  107 + "vite-plugin-purge-icons": "^0.5.0",
  108 + "vite-plugin-pwa": "^0.3.2",
106 109 "vue-eslint-parser": "^7.3.0",
107 110 "yargs": "^16.2.0"
108 111 },
... ...
src/App.vue
... ... @@ -13,7 +13,7 @@
13 13 import { initAppConfigStore } from '/@/setup/App';
14 14  
15 15 import { useLockPage } from '/@/hooks/web/useLockPage';
16   - import { useLocale } from '/@/hooks/web/useLocale';
  16 + import { useLocale } from '/@/locales/useLocale';
17 17  
18 18 import { AppProvider } from '/@/components/Application';
19 19  
... ... @@ -21,6 +21,9 @@
21 21 name: 'App',
22 22 components: { ConfigProvider, AppProvider },
23 23 setup() {
  24 + const { antConfigLocale, setLocale } = useLocale();
  25 + setLocale();
  26 +
24 27 // Initialize vuex internal system configuration
25 28 initAppConfigStore();
26 29  
... ... @@ -28,7 +31,6 @@
28 31 const lockEvent = useLockPage();
29 32  
30 33 // support Multi-language
31   - const { antConfigLocale } = useLocale();
32 34  
33 35 return {
34 36 antConfigLocale,
... ...
src/components/Application/src/AppLocalePicker.vue
... ... @@ -22,7 +22,7 @@
22 22 import { Dropdown, DropMenu } from '/@/components/Dropdown';
23 23 import { GlobalOutlined } from '@ant-design/icons-vue';
24 24  
25   - import { useLocale } from '/@/hooks/web/useLocale';
  25 + import { useLocale } from '/@/locales/useLocale';
26 26 import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
27 27  
28 28 import { LocaleType } from '/@/locales/types';
... ... @@ -75,7 +75,6 @@
75 75 </script>
76 76  
77 77 <style lang="less" scoped>
78   - @import (reference) '../../../design/index.less';
79 78 @prefix-cls: ~'@{namespace}-app-locale-picker';
80 79  
81 80 :global(.@{prefix-cls}-overlay) {
... ...
src/components/Application/src/AppLogo.vue
... ... @@ -59,7 +59,6 @@
59 59 });
60 60 </script>
61 61 <style lang="less" scoped>
62   - @import (reference) '../../../design/index.less';
63 62 @prefix-cls: ~'@{namespace}-app-logo';
64 63  
65 64 .@{prefix-cls} {
... ...
src/components/Application/src/search/AppSearch.vue
... ... @@ -44,7 +44,6 @@
44 44 });
45 45 </script>
46 46 <style lang="less" scoped>
47   - @import (reference) '../../../../design/index.less';
48 47 @prefix-cls: ~'@{namespace}-app-search';
49 48  
50 49 .@{prefix-cls} {
... ...
src/components/Application/src/search/AppSearchFooter.vue
... ... @@ -37,7 +37,6 @@
37 37 });
38 38 </script>
39 39 <style lang="less" scoped>
40   - @import (reference) '../../../../design/index.less';
41 40 @prefix-cls: ~'@{namespace}-app-search-footer';
42 41  
43 42 .@{prefix-cls} {
... ...
src/components/Application/src/search/AppSearchModal.vue
... ... @@ -123,7 +123,6 @@
123 123 });
124 124 </script>
125 125 <style lang="less" scoped>
126   - @import (reference) '../../../../design/index.less';
127 126 @prefix-cls: ~'@{namespace}-app-search-modal';
128 127 @footer-prefix-cls: ~'@{namespace}-app-search-footer';
129 128 .@{prefix-cls} {
... ...
src/components/Basic/src/BasicArrow.vue
... ... @@ -46,7 +46,6 @@
46 46 });
47 47 </script>
48 48 <style lang="less" scoped>
49   - @import (reference) '../../../design/index.less';
50 49 @prefix-cls: ~'@{namespace}-basic-arrow';
51 50  
52 51 .@{prefix-cls} {
... ...
src/components/Basic/src/BasicHelp.vue
... ... @@ -112,7 +112,6 @@
112 112 });
113 113 </script>
114 114 <style lang="less">
115   - @import (reference) '../../../design/index.less';
116 115 @prefix-cls: ~'@{namespace}-basic-help';
117 116  
118 117 .@{prefix-cls} {
... ...
src/components/Basic/src/BasicTitle.vue
... ... @@ -30,7 +30,6 @@
30 30 });
31 31 </script>
32 32 <style lang="less" scoped>
33   - @import (reference) '../../../design/index.less';
34 33 @prefix-cls: ~'@{namespace}-basic-title';
35 34  
36 35 .@{prefix-cls} {
... ...
src/components/Container/src/LazyContainer.vue
... ... @@ -140,7 +140,6 @@
140 140 });
141 141 </script>
142 142 <style lang="less">
143   - @import (reference) '../../../design/index.less';
144 143 @prefix-cls: ~'@{namespace}-lazy-container';
145 144  
146 145 .@{prefix-cls} {
... ...
src/components/Container/src/ScrollContainer.vue
... ... @@ -12,7 +12,7 @@
12 12  
13 13 export default defineComponent({
14 14 name: 'ScrollContainer',
15   - inheritAttrs: false,
  15 + // inheritAttrs: false,
16 16 components: { Scrollbar },
17 17 setup() {
18 18 const scrollbarRef = ref<Nullable<ScrollbarType>>(null);
... ...
src/components/Container/src/collapse/CollapseContainer.vue
... ... @@ -87,7 +87,6 @@
87 87 });
88 88 </script>
89 89 <style lang="less">
90   - @import (reference) '../../../../design/index.less';
91 90 @prefix-cls: ~'@{namespace}-collapse-container';
92 91  
93 92 .@{prefix-cls} {
... ...
src/components/ContextMenu/src/index.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 @default-height: 42px !important;
4 2  
5 3 @small-height: 36px !important;
... ...
src/components/ContextMenu/src/index.tsx
... ... @@ -76,9 +76,7 @@ export default defineComponent({
76 76 return (
77 77 <>
78 78 <Menu.Item disabled={disabled} class={`${prefixCls}__item`} key={label}>
79   - {() => [
80   - <ItemContent showIcon={props.showIcon} item={item} handler={handleAction} />,
81   - ]}
  79 + <ItemContent showIcon={props.showIcon} item={item} handler={handleAction} />
82 80 </Menu.Item>
83 81 {DividerComp}
84 82 </>
... ... @@ -109,7 +107,7 @@ export default defineComponent({
109 107 ref={wrapRef}
110 108 style={unref(getStyle)}
111 109 >
112   - {() => renderMenuItem(items)}
  110 + {renderMenuItem(items)}
113 111 </Menu>
114 112 );
115 113 };
... ...
src/components/Description/src/index.tsx
... ... @@ -114,7 +114,7 @@ export default defineComponent({
114 114 const renderDesc = () => {
115 115 return (
116 116 <Descriptions class={`${prefixCls}`} {...(unref(getDescriptionsProps) as any)}>
117   - {() => renderItem()}
  117 + {renderItem()}
118 118 </Descriptions>
119 119 );
120 120 };
... ...
src/components/Drawer/src/BasicDrawer.vue
... ... @@ -199,7 +199,6 @@
199 199 });
200 200 </script>
201 201 <style lang="less">
202   - @import (reference) '../../../design/index.less';
203 202 @header-height: 60px;
204 203 @detail-header-height: 40px;
205 204 @prefix-cls: ~'@{namespace}-basic-drawer';
... ...
src/components/Drawer/src/components/DrawerFooter.vue
... ... @@ -66,7 +66,6 @@
66 66 </script>
67 67  
68 68 <style lang="less">
69   - @import (reference) '../../../../design/index.less';
70 69 @prefix-cls: ~'@{namespace}-basic-drawer-footer';
71 70 @footer-height: 60px;
72 71 .@{prefix-cls} {
... ...
src/components/Drawer/src/components/DrawerHeader.vue
... ... @@ -45,7 +45,6 @@
45 45 </script>
46 46  
47 47 <style lang="less">
48   - @import (reference) '../../../../design/index.less';
49 48 @prefix-cls: ~'@{namespace}-basic-drawer-header';
50 49 @footer-height: 60px;
51 50 .@{prefix-cls} {
... ...
src/components/Form/src/BasicForm.vue
... ... @@ -247,7 +247,6 @@
247 247 });
248 248 </script>
249 249 <style lang="less">
250   - @import (reference) '../../../design/index.less';
251 250 @prefix-cls: ~'@{namespace}-basic-form';
252 251  
253 252 .@{prefix-cls} {
... ...
src/components/Form/src/components/FormItem.tsx
... ... @@ -173,7 +173,8 @@ export default defineComponent({
173 173 const characterInx = rules.findIndex((val) => val.max);
174 174 if (characterInx !== -1 && !rules[characterInx].validator) {
175 175 rules[characterInx].message =
176   - rules[characterInx].message || t('component.form.maxTip', [rules[characterInx].max]);
  176 + rules[characterInx].message ||
  177 + t('component.form.maxTip', [rules[characterInx].max] as Recordable);
177 178 }
178 179 return rules;
179 180 }
... ... @@ -294,12 +295,10 @@ export default defineComponent({
294 295 labelCol={labelCol}
295 296 wrapperCol={wrapperCol}
296 297 >
297   - {() => (
298   - <>
299   - {getContent()}
300   - {showSuffix && <span class="suffix">{getSuffix}</span>}
301   - </>
302   - )}
  298 + <>
  299 + {getContent()}
  300 + {showSuffix && <span class="suffix">{getSuffix}</span>}
  301 + </>
303 302 </Form.Item>
304 303 );
305 304 }
... ... @@ -323,7 +322,7 @@ export default defineComponent({
323 322 return (
324 323 isIfShow && (
325 324 <Col {...realColProps} class={{ hidden: !isShow }}>
326   - {() => getContent()}
  325 + {getContent()}
327 326 </Col>
328 327 )
329 328 );
... ...
src/components/Icon/src/index.vue
... ... @@ -83,8 +83,6 @@
83 83 });
84 84 </script>
85 85 <style lang="less">
86   - @import (reference) '../../../design/index.less';
87   -
88 86 .app-iconify {
89 87 display: inline-block;
90 88 vertical-align: middle;
... ...
src/components/Markdown/src/index.vue
... ... @@ -7,7 +7,7 @@
7 7 import 'vditor/dist/index.css';
8 8  
9 9 import { propTypes } from '/@/utils/propTypes';
10   - import { useLocale } from '/@/hooks/web/useLocale';
  10 + import { useLocale } from '/@/locales/useLocale';
11 11 import { useModalContext } from '../../Modal';
12 12  
13 13 type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
... ...
src/components/Menu/src/index.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 @basic-menu-prefix-cls: ~'@{namespace}-basic-menu';
4 2 @basic-menu-content-prefix-cls: ~'@{namespace}-basic-menu-item-content';
5 3 @basic-menu-tag-prefix-cls: ~'@{namespace}-basic-menu-item-tag';
... ...
src/components/Modal/src/components/ModalClose.vue
... ... @@ -54,7 +54,6 @@
54 54 });
55 55 </script>
56 56 <style lang="less">
57   - @import (reference) '../../../../design/index.less';
58 57 @prefix-cls: ~'@{namespace}-basic-modal-close';
59 58 .@{prefix-cls} {
60 59 display: flex;
... ...
src/components/Modal/src/index.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 .fullscreen-modal {
4 2 overflow: hidden;
5 3  
... ... @@ -79,7 +77,7 @@
79 77  
80 78 &-confirm-body {
81 79 .ant-modal-confirm-content {
82   - color: #fff;
  80 + // color: #fff;
83 81  
84 82 > * {
85 83 color: @text-color-help-dark;
... ...
src/components/Preview/index.ts
1   -export { createImgPreview } from './src/functional';
  1 +// export { createImgPreview } from './src/functional';
2 2  
3   -import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
4   -export const ImagePreview = createAsyncComponent(() => import('./src/index.vue'));
  3 +export const createImgPreview = () => {};
  4 +
  5 +// import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
  6 +// export const ImagePreview = createAsyncComponent(() => import('./src/index.vue'));
  7 +
  8 +export { default as ImagePreview } from './src/index.vue';
... ...
src/components/Preview/src/index.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 .img-preview {
4 2 position: fixed;
5 3 top: 0;
... ...
src/components/Preview/src/index.vue
... ... @@ -58,7 +58,6 @@
58 58 });
59 59 </script>
60 60 <style lang="less">
61   - @import (reference) '../../../design/index.less';
62 61 @prefix-cls: ~'@{namespace}-image-preview';
63 62  
64 63 .@{prefix-cls} {
... ...
src/components/Scrollbar/src/index.vue
... ... @@ -34,7 +34,7 @@
34 34  
35 35 export default defineComponent({
36 36 name: 'Scrollbar',
37   - inheritAttrs: false,
  37 + // inheritAttrs: false,
38 38 components: { Bar },
39 39 props: {
40 40 native: {
... ...
src/components/StrengthMeter/src/index.vue
... ... @@ -83,7 +83,6 @@
83 83 });
84 84 </script>
85 85 <style lang="less" scoped>
86   - @import (reference) '../../../design/index.less';
87 86 @prefix-cls: ~'@{namespace}-strength-meter';
88 87  
89 88 .@{prefix-cls} {
... ...
src/components/Upload/src/FileList.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 .file-table {
4 2 width: 100%;
5 3 border-collapse: collapse;
... ...
src/components/Verify/src/DragVerify.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 @radius: 4px;
4 2  
5 3 .darg-verify {
... ...
src/components/Verify/src/ImgRotate.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 .ir-dv {
4 2 position: relative;
5 3 display: flex;
... ...
src/components/registerGlobComp.ts
... ... @@ -35,25 +35,21 @@ import {
35 35 Menu,
36 36 Breadcrumb,
37 37 } from 'ant-design-vue';
38   -import { getApp } from '/@/setup/App';
  38 +import { App } from 'vue';
39 39  
40 40 const compList = [Icon, Button, AntButton.Group];
41 41  
42 42 // Fix hmr multiple registered components
43   -let registered = false;
44   -export function registerGlobComp() {
45   - if (registered) return;
  43 +export function registerGlobComp(app: App) {
46 44 compList.forEach((comp: any) => {
47   - getApp().component(comp.name, comp);
  45 + app.component(comp.name, comp);
48 46 });
49 47  
50   - registered = true;
51   -
52 48 // Optional
53 49 // Why register here: The main reason for registering here is not to increase the size of the first screen code
54 50 // If you need to customize global components, you can write here
55 51 // If you don’t need it, you can delete it
56   - getApp()
  52 + app
57 53 .use(Select)
58 54 .use(Alert)
59 55 .use(Breadcrumb)
... ...
src/hooks/setting/useLocaleSetting.ts
... ... @@ -4,7 +4,7 @@ import { computed, unref } from &#39;vue&#39;;
4 4 import { appStore } from '/@/store/modules/app';
5 5  
6 6 import getProjectSetting from '/@/settings/projectSetting';
7   -import { localeList } from '/@/locales';
  7 +import { localeList } from '/@/locales/constant';
8 8  
9 9 // Get locale configuration
10 10 const getLocale = computed(() => appStore.getProjectConfig.locale || getProjectSetting.locale);
... ...
src/hooks/web/useI18n.ts
1   -import { getI18n } from '/@/setup/i18n';
  1 +import { i18n } from '/@/locales/setupI18n';
2 2  
3 3 export function useI18n(namespace?: string) {
4 4 function getKey(key: string) {
... ... @@ -16,18 +16,19 @@ export function useI18n(namespace?: string) {
16 16 },
17 17 };
18 18  
19   - if (!getI18n()) {
  19 + if (!i18n) {
20 20 return normalFn;
21 21 }
22 22  
23   - const { t, ...methods } = getI18n().global;
  23 + const { t, ...methods } = i18n.global;
24 24  
  25 + const tFn = function (...arg: Parameters<typeof t>) {
  26 + if (!arg[0]) return '';
  27 + return t(getKey(arg[0]), ...(arg as Parameters<typeof t>));
  28 + };
25 29 return {
26 30 ...methods,
27   - t: (key: string, ...arg: any): string => {
28   - if (!key) return '';
29   - return t(getKey(key), ...(arg as Parameters<typeof t>));
30   - },
  31 + t: tFn,
31 32 };
32 33 }
33 34  
... ...
src/hooks/web/useMessage.tsx
... ... @@ -59,7 +59,7 @@ function createConfirm(options: ModalOptionsEx): ConfirmOptions {
59 59 icon: getIcon(iconType),
60 60 ...options,
61 61 };
62   - return Modal.confirm(opt) as any;
  62 + return (Modal.confirm(opt) as unknown) as ConfirmOptions;
63 63 }
64 64  
65 65 const baseOptions = {
... ...
src/layouts/default/content/index.vue
... ... @@ -18,7 +18,7 @@
18 18 import { useDesign } from '/@/hooks/web/useDesign';
19 19 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
20 20 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
21   - import PageLayout from '/@/layouts/page/index';
  21 + import PageLayout from '/@/layouts/page/index.vue';
22 22 import { useContentViewHeight } from './useContentViewHeight';
23 23 import { Loading } from '/@/components/Loading';
24 24  
... ... @@ -41,7 +41,6 @@
41 41 });
42 42 </script>
43 43 <style lang="less">
44   - @import (reference) '../../../design/index.less';
45 44 @prefix-cls: ~'@{namespace}-layout-content';
46 45  
47 46 .@{prefix-cls} {
... ...
src/layouts/default/footer/index.vue
... ... @@ -40,7 +40,6 @@
40 40 });
41 41 </script>
42 42 <style lang="less" scoped>
43   - @import (reference) '../../../design/index.less';
44 43 @prefix-cls: ~'@{namespace}-layout-footer';
45 44  
46 45 @normal-color: rgba(0, 0, 0, 0.45);
... ...
src/layouts/default/header/MultipleHeader.vue
... ... @@ -109,7 +109,6 @@
109 109 });
110 110 </script>
111 111 <style lang="less" scoped>
112   - @import (reference) '../../../design/index.less';
113 112 @prefix-cls: ~'@{namespace}-layout-multiple-header';
114 113  
115 114 .@{prefix-cls} {
... ...
src/layouts/default/header/components/Breadcrumb.vue
... ... @@ -147,7 +147,6 @@
147 147 });
148 148 </script>
149 149 <style lang="less">
150   - @import (reference) '../../../../design/index.less';
151 150 @prefix-cls: ~'@{namespace}-layout-breadcrumb';
152 151  
153 152 .@{prefix-cls} {
... ...
src/layouts/default/header/components/lock/LockModal.vue
... ... @@ -80,7 +80,6 @@
80 80 });
81 81 </script>
82 82 <style lang="less">
83   - @import (reference) '../../../../../design/index.less';
84 83 @prefix-cls: ~'@{namespace}-header-lock-modal';
85 84  
86 85 .@{prefix-cls} {
... ...
src/layouts/default/header/components/notify/NoticeList.vue
... ... @@ -49,7 +49,6 @@
49 49 });
50 50 </script>
51 51 <style lang="less" scoped>
52   - @import (reference) '../../../../../design/index.less';
53 52 @prefix-cls: ~'@{namespace}-header-notify-list';
54 53  
55 54 .@{prefix-cls} {
... ...
src/layouts/default/header/components/notify/index.vue
... ... @@ -49,7 +49,6 @@
49 49 });
50 50 </script>
51 51 <style lang="less">
52   - @import (reference) '../../../../../design/index.less';
53 52 @prefix-cls: ~'@{namespace}-header-notify';
54 53  
55 54 .@{prefix-cls} {
... ...
src/layouts/default/header/components/user-dropdown/index.vue
... ... @@ -99,7 +99,6 @@
99 99 });
100 100 </script>
101 101 <style lang="less">
102   - @import (reference) '../../../../../design/index.less';
103 102 @prefix-cls: ~'@{namespace}-header-user-dropdown';
104 103  
105 104 .@{prefix-cls} {
... ...
src/layouts/default/header/index.less
1   -@import (reference) '../../../design/index.less';
2 1 @header-trigger-prefix-cls: ~'@{namespace}-layout-header-trigger';
3 2 @header-prefix-cls: ~'@{namespace}-layout-header';
4 3 @locale-prefix-cls: ~'@{namespace}-app-locale-picker';
... ...
src/layouts/default/index.vue
... ... @@ -31,7 +31,6 @@
31 31 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
32 32 import { useDesign } from '/@/hooks/web/useDesign';
33 33  
34   - import { registerGlobComp } from '/@/components/registerGlobComp';
35 34 import { useAppInject } from '/@/hooks/web/useAppInject';
36 35  
37 36 export default defineComponent({
... ... @@ -46,11 +45,6 @@
46 45 Layout,
47 46 },
48 47 setup() {
49   - // ! Only register global components here
50   - // ! Can reduce the size of the first screen code
51   - // default layout It is loaded after login. So it won’t be packaged to the first screen
52   - registerGlobComp();
53   -
54 48 const { prefixCls } = useDesign('default-layout');
55 49  
56 50 const { getIsMobile } = useAppInject();
... ... @@ -70,7 +64,6 @@
70 64 });
71 65 </script>
72 66 <style lang="less">
73   - @import (reference) '../../design/index.less';
74 67 @prefix-cls: ~'@{namespace}-default-layout';
75 68  
76 69 .@{prefix-cls} {
... ...
src/layouts/default/menu/index.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 @prefix-cls: ~'@{namespace}-layout-menu';
4 2 @logo-prefix-cls: ~'@{namespace}-app-logo';
5 3  
... ...
src/layouts/default/setting/SettingDrawer.tsx
... ... @@ -389,26 +389,20 @@ export default defineComponent({
389 389 width={330}
390 390 wrapClassName="setting-drawer"
391 391 >
392   - {{
393   - default: () => (
394   - <>
395   - <Divider>{() => t('layout.setting.navMode')}</Divider>
396   - {renderSidebar()}
397   - <Divider>{() => t('layout.setting.headerTheme')}</Divider>
398   - {renderHeaderTheme()}
399   - <Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
400   - {renderSiderTheme()}
401   - <Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
402   - {renderFeatures()}
403   - <Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
404   - {renderContent()}
405   - <Divider>{() => t('layout.setting.animation')}</Divider>
406   - {renderTransition()}
407   - <Divider />
408   - <SettingFooter />
409   - </>
410   - ),
411   - }}
  392 + <Divider>{() => t('layout.setting.navMode')}</Divider>
  393 + {renderSidebar()}
  394 + <Divider>{() => t('layout.setting.headerTheme')}</Divider>
  395 + {renderHeaderTheme()}
  396 + <Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
  397 + {renderSiderTheme()}
  398 + <Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
  399 + {renderFeatures()}
  400 + <Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
  401 + {renderContent()}
  402 + <Divider>{() => t('layout.setting.animation')}</Divider>
  403 + {renderTransition()}
  404 + <Divider />
  405 + <SettingFooter />
412 406 </BasicDrawer>
413 407 );
414 408 },
... ...
src/layouts/default/setting/components/InputNumberItem.vue
... ... @@ -43,7 +43,6 @@
43 43 });
44 44 </script>
45 45 <style lang="less" scoped>
46   - @import (reference) '../../../../design/index.less';
47 46 @prefix-cls: ~'@{namespace}-setting-input-number-item';
48 47  
49 48 .@{prefix-cls} {
... ...
src/layouts/default/setting/components/SelectItem.vue
... ... @@ -62,7 +62,6 @@
62 62 });
63 63 </script>
64 64 <style lang="less" scoped>
65   - @import (reference) '../../../../design/index.less';
66 65 @prefix-cls: ~'@{namespace}-setting-select-item';
67 66  
68 67 .@{prefix-cls} {
... ...
src/layouts/default/setting/components/SettingFooter.vue
... ... @@ -75,7 +75,6 @@
75 75 });
76 76 </script>
77 77 <style lang="less" scoped>
78   - @import (reference) '../../../../design/index.less';
79 78 @prefix-cls: ~'@{namespace}-setting-footer';
80 79  
81 80 .@{prefix-cls} {
... ...
src/layouts/default/setting/components/SwitchItem.vue
... ... @@ -57,7 +57,6 @@
57 57 });
58 58 </script>
59 59 <style lang="less" scoped>
60   - @import (reference) '../../../../design/index.less';
61 60 @prefix-cls: ~'@{namespace}-setting-switch-item';
62 61  
63 62 .@{prefix-cls} {
... ...
src/layouts/default/setting/components/ThemePicker.vue
... ... @@ -55,7 +55,6 @@
55 55 });
56 56 </script>
57 57 <style lang="less">
58   - @import (reference) '../../../../design/index.less';
59 58 @prefix-cls: ~'@{namespace}-setting-theme-picker';
60 59  
61 60 .@{prefix-cls} {
... ...
src/layouts/default/setting/components/TypePicker.vue
... ... @@ -51,7 +51,6 @@
51 51 });
52 52 </script>
53 53 <style lang="less" scoped>
54   - @import (reference) '../../../../design/index.less';
55 54 @prefix-cls: ~'@{namespace}-setting-menu-type-picker';
56 55  
57 56 .@{prefix-cls} {
... ...
src/layouts/default/setting/index.vue
... ... @@ -28,7 +28,6 @@
28 28 });
29 29 </script>
30 30 <style lang="less">
31   - @import (reference) '../../../design/index.less';
32 31 @prefix-cls: ~'@{namespace}-setting-button';
33 32  
34 33 .@{prefix-cls} {
... ...
src/layouts/default/sider/DragBar.vue
... ... @@ -41,7 +41,6 @@
41 41 });
42 42 </script>
43 43 <style lang="less" scoped>
44   - @import (reference) '../../../design/index.less';
45 44 @prefix-cls: ~'@{namespace}-darg-bar';
46 45  
47 46 .@{prefix-cls} {
... ...
src/layouts/default/sider/LayoutSider.vue
... ... @@ -128,7 +128,6 @@
128 128 });
129 129 </script>
130 130 <style lang="less">
131   - @import (reference) '../../../design/index.less';
132 131 @prefix-cls: ~'@{namespace}-layout-sideBar';
133 132  
134 133 .@{prefix-cls} {
... ...
src/layouts/default/sider/MixSider.vue
... ... @@ -333,7 +333,6 @@
333 333 });
334 334 </script>
335 335 <style lang="less">
336   - @import (reference) '../../../design/index.less';
337 336 @prefix-cls: ~'@{namespace}-layout-mix-sider';
338 337 @tag-prefix-cls: ~'@{namespace}-basic-menu-item-tag';
339 338 @width: 80px;
... ...
src/layouts/default/sider/index.vue
... ... @@ -41,7 +41,6 @@
41 41 });
42 42 </script>
43 43 <style lang="less">
44   - @import (reference) '../../../design/index.less';
45 44 @prefix-cls: ~'@{namespace}-layout-sider-wrapper';
46 45 .@{prefix-cls} {
47 46 .ant-drawer-body {
... ...
src/layouts/default/tabs/index.less
1   -@import (reference) '../../../design/index.less';
2 1 @prefix-cls: ~'@{namespace}-multiple-tabs';
3 2  
4 3 .@{prefix-cls} {
... ...
src/layouts/page/index.tsx deleted 100644 → 0
1   -import type { DefaultContext } from './transition';
2   -
3   -import { computed, defineComponent, unref, Transition, KeepAlive } from 'vue';
4   -import { RouterView } from 'vue-router';
5   -
6   -import FrameLayout from '/@/layouts/iframe/index.vue';
7   -
8   -import { useRootSetting } from '/@/hooks/setting/useRootSetting';
9   -
10   -import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
11   -import { useCache } from './useCache';
12   -import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
13   -import { getTransitionName } from './transition';
14   -
15   -export default defineComponent({
16   - name: 'PageLayout',
17   - setup() {
18   - const { getCaches } = useCache(true);
19   - const { getShowMultipleTab } = useMultipleTabSetting();
20   -
21   - const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
22   -
23   - const { getBasicTransition, getEnableTransition } = useTransitionSetting();
24   -
25   - const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
26   -
27   - return () => {
28   - return (
29   - <>
30   - <RouterView>
31   - {{
32   - default: ({ Component, route }: DefaultContext) => {
33   - // No longer show animations that are already in the tab
34   - const cacheTabs = unref(getCaches);
35   -
36   - const name = getTransitionName({
37   - route,
38   - openCache: unref(openCache),
39   - enableTransition: unref(getEnableTransition),
40   - cacheTabs,
41   - def: unref(getBasicTransition),
42   - });
43   -
44   - // 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
45   - const isParentView = Component?.type.parentView;
46   - const componentKey = isParentView ? {} : { key: route.fullPath };
47   -
48   - const renderComp = () => <Component {...componentKey} />;
49   -
50   - const PageContent = unref(openCache) ? (
51   - <KeepAlive include={cacheTabs}>{renderComp()}</KeepAlive>
52   - ) : (
53   - renderComp()
54   - );
55   -
56   - if (!unref(getEnableTransition)) {
57   - return PageContent;
58   - }
59   - return (
60   - <Transition name={name} mode="out-in" appear={true}>
61   - {() => PageContent}
62   - </Transition>
63   - );
64   - },
65   - }}
66   - </RouterView>
67   - {unref(getCanEmbedIFramePage) && <FrameLayout />}
68   - </>
69   - );
70   - };
71   - },
72   -});
src/layouts/page/index.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <router-view>
  4 + <template v-slot="{ Component, route }">
  5 + <transition
  6 + :name="
  7 + getTransitionName({
  8 + route,
  9 + openCache,
  10 + enableTransition: getEnableTransition,
  11 + cacheTabs: getCaches,
  12 + def: getBasicTransition,
  13 + })
  14 + "
  15 + mode="out-in"
  16 + appear
  17 + >
  18 + <keep-alive v-if="openCache" :include="getCaches">
  19 + <component :is="Component" v-bind="getKey(Component, route)" />
  20 + </keep-alive>
  21 + <component v-else :is="Component" v-bind="getKey(Component, route)" />
  22 + </transition>
  23 + </template>
  24 + </router-view>
  25 + <FrameLayout v-if="getCanEmbedIFramePage" />
  26 + </div>
  27 +</template>
  28 +
  29 +<script lang="ts">
  30 + import type { FunctionalComponent } from 'vue';
  31 + import type { RouteLocation } from 'vue-router';
  32 +
  33 + import { computed, defineComponent, unref } from 'vue';
  34 +
  35 + import FrameLayout from '/@/layouts/iframe/index.vue';
  36 +
  37 + import { useRootSetting } from '/@/hooks/setting/useRootSetting';
  38 +
  39 + import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
  40 + import { useCache } from './useCache';
  41 + import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
  42 + import { getTransitionName } from './transition';
  43 +
  44 + export default defineComponent({
  45 + name: 'PageLayout',
  46 + components: { FrameLayout },
  47 + setup() {
  48 + const { getCaches } = useCache(true);
  49 + const { getShowMultipleTab } = useMultipleTabSetting();
  50 +
  51 + const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
  52 +
  53 + const { getBasicTransition, getEnableTransition } = useTransitionSetting();
  54 +
  55 + const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
  56 +
  57 + function getKey(component: FunctionalComponent & { type: Indexable }, route: RouteLocation) {
  58 + return !!component?.type.parentView ? {} : { key: route.fullPath };
  59 + }
  60 +
  61 + return {
  62 + getTransitionName,
  63 + openCache,
  64 + getEnableTransition,
  65 + getBasicTransition,
  66 + getCaches,
  67 + getCanEmbedIFramePage,
  68 + getKey,
  69 + };
  70 + },
  71 + });
  72 +</script>
... ...
src/locales/index.ts renamed to src/locales/constant.ts
1   -import messages from 'globby?locale!/@/locales/lang/**/*.@(ts)';
2   -
3 1 import type { DropMenu } from '/@/components/Dropdown';
4 2  
5 3 // locale list
... ... @@ -13,4 +11,3 @@ export const localeList: DropMenu[] = [
13 11 event: 'en',
14 12 },
15 13 ];
16   -export default messages;
... ...
src/locales/getMessage.ts 0 → 100644
  1 +import { genMessage } from './helper';
  2 +import modules from 'glob:./lang/**/*.ts';
  3 +
  4 +export default genMessage(modules);
... ...
src/locales/helper.ts 0 → 100644
  1 +import { set } from 'lodash-es';
  2 +
  3 +export function genMessage(langs: Record<string, Record<string, any>>, prefix = 'lang') {
  4 + const obj: Recordable = {};
  5 +
  6 + Object.keys(langs).forEach((key) => {
  7 + const mod = langs[key].default;
  8 + let k = key.replace(`./${prefix}/`, '').replace(/^\.\//, '');
  9 + const lastIndex = k.lastIndexOf('.');
  10 + k = k.substring(0, lastIndex);
  11 + const keyList = k.split('/');
  12 + const lang = keyList.shift();
  13 + const objKey = keyList.join('.');
  14 + if (lang) {
  15 + set(obj, lang, obj[lang] || {});
  16 + set(obj[lang], objKey, mod);
  17 + }
  18 + });
  19 + return obj;
  20 +}
... ...
src/setup/i18n/index.ts renamed to src/locales/setupI18n.ts
1   -import { App } from 'vue';
  1 +import type { App } from 'vue';
2 2 import type { I18n, I18nOptions } from 'vue-i18n';
3 3  
4 4 import { createI18n } from 'vue-i18n';
5   -import localeMessages from '/@/locales';
6   -import { useLocale } from '/@/hooks/web/useLocale';
  5 +
  6 +import 'moment/dist/locale/zh-cn';
  7 +
7 8 import projectSetting from '/@/settings/projectSetting';
8   -const { setupLocale } = useLocale();
  9 +
  10 +import messages from './getMessage';
9 11  
10 12 const { lang, availableLocales, fallback } = projectSetting?.locale;
  13 +
11 14 const localeData: I18nOptions = {
12 15 legacy: false,
13 16 locale: lang,
14 17 fallbackLocale: fallback,
15   - messages: localeMessages,
  18 + messages,
16 19 availableLocales: availableLocales,
17 20 sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false.
18 21 silentTranslationWarn: true, // true - warning off
19 22 missingWarn: false,
20 23 silentFallbackWarn: true,
21 24 };
22   -
23   -let i18n: I18n;
  25 +export let i18n: I18n;
24 26  
25 27 // setup i18n instance with glob
26 28 export function setupI18n(app: App) {
27 29 i18n = createI18n(localeData) as I18n;
28   - setupLocale();
29 30 app.use(i18n);
30 31 }
31   -
32   -export function getI18n(): I18n {
33   - return i18n;
34   -}
... ...
src/hooks/web/useLocale.ts renamed to src/locales/useLocale.ts
... ... @@ -2,18 +2,16 @@
2 2 * Multi-language related operations
3 3 */
4 4 import type { LocaleType } from '/@/locales/types';
  5 +import type { Ref } from 'vue';
5 6  
6 7 import { unref, ref } from 'vue';
7   -
8   -import { getI18n } from '/@/setup/i18n';
9   -
10 8 import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
11 9  
12 10 import moment from 'moment';
13 11  
14 12 import 'moment/dist/locale/zh-cn';
15 13  
16   -moment.locale('zh-cn');
  14 +import { i18n } from './setupI18n';
17 15  
18 16 const antConfigLocaleRef = ref<any>(null);
19 17  
... ... @@ -23,7 +21,11 @@ export function useLocale() {
23 21 // Switching the language will change the locale of useI18n
24 22 // And submit to configuration modification
25 23 function changeLocale(lang: LocaleType): void {
26   - (getI18n().global.locale as any).value = lang;
  24 + if (i18n.mode === 'legacy') {
  25 + i18n.global.locale = lang;
  26 + } else {
  27 + ((i18n.global.locale as unknown) as Ref<string>).value = lang;
  28 + }
27 29 setLocalSetting({ lang });
28 30 // i18n.global.setLocaleMessage(locale, messages);
29 31  
... ... @@ -51,13 +53,13 @@ export function useLocale() {
51 53 }
52 54  
53 55 // initialization
54   - function setupLocale() {
  56 + function setLocale() {
55 57 const lang = unref(getLang);
56 58 lang && changeLocale(lang);
57 59 }
58 60  
59 61 return {
60   - setupLocale,
  62 + setLocale,
61 63 getLocale,
62 64 getLang,
63 65 changeLocale,
... ...
src/main.ts
... ... @@ -6,18 +6,19 @@ import { setupStore } from &#39;/@/store&#39;;
6 6 import { setupAntd } from '/@/setup/ant-design-vue';
7 7 import { setupErrorHandle } from '/@/setup/error-handle';
8 8 import { setupGlobDirectives } from '/@/directives';
9   -import { setupI18n } from '/@/setup/i18n';
  9 +import { setupI18n } from '/@/locales/setupI18n';
10 10 import { setupProdMockServer } from '../mock/_createProductionServer';
11   -import { setApp } from '/@/setup/App';
  11 +
  12 +import { registerGlobComp } from '/@/components/registerGlobComp';
12 13  
13 14 import { isDevMode, isProdMode, isUseMock } from '/@/utils/env';
14 15  
15 16 import '/@/design/index.less';
16 17  
17   -import '/@/locales/index';
18   -
19 18 const app = createApp(App);
20 19  
  20 +registerGlobComp(app);
  21 +
21 22 // Configure component library
22 23 setupAntd(app);
23 24  
... ... @@ -51,5 +52,3 @@ if (isDevMode()) {
51 52 if (isProdMode() && isUseMock()) {
52 53 setupProdMockServer();
53 54 }
54   -// Used to share app instances in other modules
55   -setApp(app);
... ...
src/router/helper/dynamicImport.ts deleted 100644 → 0
1   -// The content here is just for type approval. The actual file content is overwritten by transform
2   -// For specific coverage, see build/vite/plugin/transform/dynamic-import/index.ts
3   -export default function (name: string) {
4   - return name as any;
5   -}
src/router/helper/routeHelper.ts
... ... @@ -2,8 +2,8 @@ import type { AppRouteModule, AppRouteRecordRaw } from &#39;/@/router/types&#39;;
2 2 import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
3 3  
4 4 import { getParentLayout, LAYOUT } from '/@/router/constant';
5   -import dynamicImport from './dynamicImport';
6 5 import { cloneDeep } from 'lodash-es';
  6 +import { warn } from '/@/utils/log';
7 7  
8 8 export type LayoutMapKey = 'LAYOUT';
9 9  
... ... @@ -11,12 +11,20 @@ const LayoutMap = new Map&lt;LayoutMapKey, () =&gt; Promise&lt;typeof import(&#39;*.vue&#39;)&gt;&gt;()
11 11  
12 12 // 动态引入
13 13 function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
  14 + // TODO Because xlsx does not support vite2.0 temporarily. So filter the excel example first
  15 + const dynamicViewsModules = importContext({
  16 + dir: '/@/views',
  17 + deep: true,
  18 + regexp: /^(?!.*\/demo\/excel).*\.(tsx?|vue)$/,
  19 + dynamicImport: true,
  20 + dynamicEnabled: 'autoImportRoute',
  21 + });
14 22 if (!routes) return;
15 23 routes.forEach((item) => {
16 24 const { component, name } = item;
17 25 const { children } = item;
18 26 if (component) {
19   - item.component = dynamicImport(component as string);
  27 + item.component = dynamicImport(dynamicViewsModules, component as string);
20 28 } else if (name) {
21 29 item.component = getParentLayout(name);
22 30 }
... ... @@ -24,6 +32,24 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
24 32 });
25 33 }
26 34  
  35 +function dynamicImport(dynamicViewsModules: DynamicImportContextResult, component: string) {
  36 + const keys = dynamicViewsModules.keys();
  37 + const matchKeys = keys.filter((key) => {
  38 + const k = key.substr(1);
  39 + return k.startsWith(component) || k.startsWith(`/${component}`);
  40 + });
  41 + if (matchKeys?.length === 1) {
  42 + const matchKey = matchKeys[0];
  43 + return dynamicViewsModules(matchKey);
  44 + }
  45 + if (matchKeys?.length > 1) {
  46 + warn(
  47 + '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'
  48 + );
  49 + return;
  50 + }
  51 +}
  52 +
27 53 // Turn background objects into routing objects
28 54 export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
29 55 LayoutMap.set('LAYOUT', LAYOUT);
... ...
src/router/menus/index.ts
... ... @@ -9,18 +9,18 @@ import router from &#39;/@/router&#39;;
9 9 import { PermissionModeEnum } from '/@/enums/appEnum';
10 10 import { pathToRegexp } from 'path-to-regexp';
11 11  
12   -import modules from 'globby!/@/router/menus/modules/**/*.@(ts)';
13   -
14   -const reg = /(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
  12 +import modules from 'glob:./modules/**/*.ts';
15 13  
16 14 const menuModules: MenuModule[] = [];
17 15  
18 16 Object.keys(modules).forEach((key) => {
19   - const moduleItem = modules[key];
20   - const menuModule = Array.isArray(moduleItem) ? [...moduleItem] : [moduleItem];
21   - menuModules.push(...menuModule);
  17 + const mod = modules[key].default || {};
  18 + const modList = Array.isArray(mod) ? [...mod] : [mod];
  19 + menuModules.push(...modList);
22 20 });
23 21  
  22 +const reg = /(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
  23 +
24 24 // ===========================
25 25 // ==========Helper===========
26 26 // ===========================
... ...
src/router/routes/index.ts
... ... @@ -2,17 +2,18 @@ import type { AppRouteRecordRaw, AppRouteModule } from &#39;/@/router/types&#39;;
2 2  
3 3 import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant';
4 4  
5   -import modules from 'globby!/@/router/routes/modules/**/*.@(ts)';
6 5 import { mainOutRoutes } from './mainOut';
7 6 import { PageEnum } from '/@/enums/pageEnum';
8   -
9 7 import { t } from '/@/hooks/web/useI18n';
10 8  
  9 +import modules from 'glob:./modules/**/*.ts';
  10 +
11 11 const routeModuleList: AppRouteModule[] = [];
12 12  
13 13 Object.keys(modules).forEach((key) => {
14   - const mod = Array.isArray(modules[key]) ? [...modules[key]] : [modules[key]];
15   - routeModuleList.push(...mod);
  14 + const mod = modules[key].default || {};
  15 + const modList = Array.isArray(mod) ? [...mod] : [mod];
  16 + routeModuleList.push(...modList);
16 17 });
17 18  
18 19 export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];
... ...
src/router/routes/modules/demo/feat.ts
... ... @@ -172,51 +172,51 @@ const feat: AppRouteModule = {
172 172 title: t('routes.demo.feat.errorLog'),
173 173 },
174 174 },
175   - {
176   - path: 'excel',
177   - name: 'Excel',
178   - redirect: '/feat/excel/customExport',
179   - component: getParentLayout('Excel'),
180   - meta: {
181   - // icon: 'mdi:microsoft-excel',
182   - title: t('routes.demo.excel.excel'),
183   - },
  175 + // {
  176 + // path: 'excel',
  177 + // name: 'Excel',
  178 + // redirect: '/feat/excel/customExport',
  179 + // component: getParentLayout('Excel'),
  180 + // meta: {
  181 + // // icon: 'mdi:microsoft-excel',
  182 + // title: t('routes.demo.excel.excel'),
  183 + // },
184 184  
185   - children: [
186   - {
187   - path: 'customExport',
188   - name: 'CustomExport',
189   - component: () => import('/@/views/demo/excel/CustomExport.vue'),
190   - meta: {
191   - title: t('routes.demo.excel.customExport'),
192   - },
193   - },
194   - {
195   - path: 'jsonExport',
196   - name: 'JsonExport',
197   - component: () => import('/@/views/demo/excel/JsonExport.vue'),
198   - meta: {
199   - title: t('routes.demo.excel.jsonExport'),
200   - },
201   - },
202   - {
203   - path: 'arrayExport',
204   - name: 'ArrayExport',
205   - component: () => import('/@/views/demo/excel/ArrayExport.vue'),
206   - meta: {
207   - title: t('routes.demo.excel.arrayExport'),
208   - },
209   - },
210   - {
211   - path: 'importExcel',
212   - name: 'ImportExcel',
213   - component: () => import('/@/views/demo/excel/ImportExcel.vue'),
214   - meta: {
215   - title: t('routes.demo.excel.importExcel'),
216   - },
217   - },
218   - ],
219   - },
  185 + // children: [
  186 + // {
  187 + // path: 'customExport',
  188 + // name: 'CustomExport',
  189 + // component: () => import('/@/views/demo/excel/CustomExport.vue'),
  190 + // meta: {
  191 + // title: t('routes.demo.excel.customExport'),
  192 + // },
  193 + // },
  194 + // {
  195 + // path: 'jsonExport',
  196 + // name: 'JsonExport',
  197 + // component: () => import('/@/views/demo/excel/JsonExport.vue'),
  198 + // meta: {
  199 + // title: t('routes.demo.excel.jsonExport'),
  200 + // },
  201 + // },
  202 + // {
  203 + // path: 'arrayExport',
  204 + // name: 'ArrayExport',
  205 + // component: () => import('/@/views/demo/excel/ArrayExport.vue'),
  206 + // meta: {
  207 + // title: t('routes.demo.excel.arrayExport'),
  208 + // },
  209 + // },
  210 + // {
  211 + // path: 'importExcel',
  212 + // name: 'ImportExcel',
  213 + // component: () => import('/@/views/demo/excel/ImportExcel.vue'),
  214 + // meta: {
  215 + // title: t('routes.demo.excel.importExcel'),
  216 + // },
  217 + // },
  218 + // ],
  219 + // },
220 220 {
221 221 path: 'testTab/:id',
222 222 name: 'TestTab',
... ...
src/settings/projectSetting.ts
... ... @@ -172,7 +172,7 @@ const setting: ProjectConfig = {
172 172  
173 173 // Whether to cancel the http request that has been sent but not responded when switching the interface.
174 174 // If it is enabled, I want to overwrite a single interface. Can be set in a separate interface
175   - removeAllHttpPending: true,
  175 + removeAllHttpPending: false,
176 176 };
177 177  
178 178 export default setting;
... ...
src/setup/App.ts
... ... @@ -3,7 +3,6 @@
3 3 */
4 4  
5 5 import type { ProjectConfig } from '/@/types/config';
6   -import type { App } from 'vue';
7 6 import { computed, ref } from 'vue';
8 7  
9 8 import { ThemeModeEnum } from '/@/enums/appEnum';
... ... @@ -21,17 +20,6 @@ import {
21 20 import { appStore } from '/@/store/modules/app';
22 21 import { deepMerge } from '/@/utils';
23 22  
24   -// Used to share global app instances
25   -let app: App;
26   -
27   -export function setApp(_app: App): void {
28   - app = _app;
29   -}
30   -
31   -export function getApp(): App {
32   - return app;
33   -}
34   -
35 23 // TODO Theme switching
36 24 export function useThemeMode(mode: ThemeModeEnum) {
37 25 const modeRef = ref(mode);
... ...
src/types/vue-app-env.d.ts
... ... @@ -23,81 +23,3 @@ declare namespace NodeJS {
23 23 }
24 24  
25 25 declare let process: NodeJS.Process;
26   -
27   -declare module '*.bmp' {
28   - const src: string;
29   - export default src;
30   -}
31   -
32   -declare module '*.gif' {
33   - const src: string;
34   - export default src;
35   -}
36   -
37   -declare module '*.jpg' {
38   - const src: string;
39   - export default src;
40   -}
41   -
42   -declare module '*.jpeg' {
43   - const src: string;
44   - export default src;
45   -}
46   -
47   -declare module '*.png' {
48   - const src: string;
49   - export default src;
50   -}
51   -
52   -declare module '*.webp' {
53   - const src: string;
54   - export default src;
55   -}
56   -
57   -declare module '*.svg' {
58   - const src: string;
59   - export default src;
60   -}
61   -
62   -declare module '*.json' {
63   - const content: any | any[];
64   - export default content;
65   -}
66   -
67   -declare module '*.scss' {
68   - const content: {
69   - readonly [className: string]: string;
70   - };
71   - export default content;
72   -}
73   -declare module '*.less' {
74   - const content: {
75   - readonly [className: string]: string;
76   - };
77   - export default content;
78   -}
79   -declare module '*.styl' {
80   - const content: {
81   - readonly [className: string]: string;
82   - };
83   - export default content;
84   -}
85   -declare module '*.css' {
86   - const content: any;
87   - export default content;
88   -}
89   -
90   -declare module '*.module.css' {
91   - const classes: { readonly [key: string]: string };
92   - export default classes;
93   -}
94   -
95   -declare module '*.module.scss' {
96   - const classes: { readonly [key: string]: string };
97   - export default classes;
98   -}
99   -
100   -declare module '*.module.sass' {
101   - const classes: { readonly [key: string]: string };
102   - export default classes;
103   -}
... ...
src/types/window.d.ts
... ... @@ -4,5 +4,6 @@ declare global {
4 4 declare interface Window {
5 5 // Global vue app instance
6 6 __APP__: App<Element>;
  7 + __VERSION__: string;
7 8 }
8 9 }
... ...
src/views/dashboard/analysis/components/GrowCard.vue
... ... @@ -41,8 +41,6 @@
41 41 });
42 42 </script>
43 43 <style lang="less">
44   - @import (reference) '../../../../design/index.less';
45   -
46 44 .grow-card {
47 45 display: flex;
48 46 width: calc(100% - 12px);
... ...
src/views/dashboard/analysis/index.vue
... ... @@ -68,8 +68,6 @@
68 68 });
69 69 </script>
70 70 <style lang="less" scoped>
71   - @import (reference) '../../../design/index.less';
72   -
73 71 .analysis {
74 72 width: 100%;
75 73  
... ...
src/views/dashboard/house/index.less
1   -@import (reference) '../../../design/index.less';
2   -
3 1 .house-wrap {
4 2 position: relative;
5 3 width: 600px;
... ...