mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 08:36:19 +08:00
wip: support vite
This commit is contained in:
@@ -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();
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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
build/vite/plugin/gzip.ts
Normal file
12
build/vite/plugin/gzip.ts
Normal file
@@ -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 [];
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
@@ -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;
|
||||
}
|
@@ -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
build/vite/plugin/importContext.ts
Normal file
12
build/vite/plugin/importContext.ts
Normal file
@@ -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;
|
||||
}
|
@@ -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());
|
||||
|
||||
// rollup-plugin-gzip
|
||||
vitePlugins.push(configGzipPlugin(isBuild));
|
||||
|
||||
// rollup-plugin-visualizer
|
||||
if (isReportMode()) {
|
||||
vitePlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
|
||||
}
|
||||
|
||||
return vitePlugins;
|
||||
}
|
||||
|
||||
// gen rollup plugins
|
||||
export function createRollupPlugin() {
|
||||
const rollupPlugins: rollupPlugin[] = [];
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
return rollupPlugins;
|
||||
}
|
||||
|
@@ -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 [];
|
||||
}
|
||||
|
@@ -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 [];
|
||||
}
|
||||
|
@@ -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;
|
@@ -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;
|
@@ -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 } : {}),
|
||||
|
Reference in New Issue
Block a user