167 lines
4.5 KiB
TypeScript
167 lines
4.5 KiB
TypeScript
|
import fs, { readdirSync } from 'fs';
|
|||
|
import path from 'path';
|
|||
|
import type { UserConfig, PluginOption } from 'vite';
|
|||
|
import { themePreprocessorPlugin } from '@crami/vite-plugin-theme-preprocessor';
|
|||
|
import { defaultsDeep } from 'lodash-es';
|
|||
|
import colors from 'colors';
|
|||
|
|
|||
|
const ADDITIONALFILENAME = 'app.less';
|
|||
|
const THEMEVARIABLESFILENAME = 'variables.less';
|
|||
|
const PATHRESOLVETO = '../src/theme/';
|
|||
|
const uuid = `.${new Date().getTime()}`;
|
|||
|
|
|||
|
type IThemeUserConfig = {
|
|||
|
env: IThemeEnvConfig;
|
|||
|
userConfig: UserConfig;
|
|||
|
};
|
|||
|
|
|||
|
type IThemeConfig = {
|
|||
|
additionalDataName: string;
|
|||
|
themesName: string[];
|
|||
|
defaultThemeName: string;
|
|||
|
rootPath: string;
|
|||
|
};
|
|||
|
|
|||
|
type IThemeLoadConfigOptions = {
|
|||
|
defaultThemeName: string;
|
|||
|
};
|
|||
|
|
|||
|
type IThemeEnvConfig = {
|
|||
|
VITE_ENV_THEME_DEFAULT: string;
|
|||
|
};
|
|||
|
|
|||
|
const loadConfig = (options: IThemeLoadConfigOptions) => {
|
|||
|
const dirname = __dirname;
|
|||
|
const { defaultThemeName } = options;
|
|||
|
const config: IThemeConfig = {
|
|||
|
additionalDataName: '',
|
|||
|
themesName: [],
|
|||
|
defaultThemeName: '',
|
|||
|
rootPath: '',
|
|||
|
};
|
|||
|
|
|||
|
const themeRootPath = path.resolve(dirname, PATHRESOLVETO);
|
|||
|
let dir;
|
|||
|
try {
|
|||
|
dir = readdirSync(themeRootPath);
|
|||
|
} catch (e) {
|
|||
|
console.log(
|
|||
|
colors.red.underline('project file directory not exist the "src/theme/default" folder!'),
|
|||
|
);
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
if (dir.includes(ADDITIONALFILENAME)) {
|
|||
|
config.additionalDataName = ADDITIONALFILENAME;
|
|||
|
}
|
|||
|
|
|||
|
dir.forEach(name => {
|
|||
|
const themePath = path.resolve(themeRootPath, `./${name}`);
|
|||
|
const stats = fs.statSync(themePath);
|
|||
|
|
|||
|
if (stats.isDirectory()) {
|
|||
|
const dir = readdirSync(themePath);
|
|||
|
if (dir.includes(THEMEVARIABLESFILENAME)) {
|
|||
|
config.themesName.push(name);
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
config.defaultThemeName = defaultThemeName || config.themesName[0] || 'default';
|
|||
|
config.rootPath = themeRootPath;
|
|||
|
|
|||
|
return config;
|
|||
|
};
|
|||
|
|
|||
|
const addCssAdditionalDataConfig = (themeConfig: IThemeConfig, userConfig: UserConfig) => {
|
|||
|
const _config: UserConfig = {
|
|||
|
css: {
|
|||
|
preprocessorOptions: {
|
|||
|
less: {
|
|||
|
additionalData: (content, filePath) => {
|
|||
|
const srcAppLess =
|
|||
|
path.resolve(themeConfig.rootPath, '..').replace(/\\/g, '/') + '/app.less';
|
|||
|
|
|||
|
if (filePath === srcAppLess) {
|
|||
|
const _content = `${content} \n @import "./theme/app.less";`;
|
|||
|
return _content;
|
|||
|
}
|
|||
|
|
|||
|
return content;
|
|||
|
},
|
|||
|
javascriptEnabled: true,
|
|||
|
},
|
|||
|
},
|
|||
|
},
|
|||
|
};
|
|||
|
defaultsDeep(userConfig, _config);
|
|||
|
};
|
|||
|
|
|||
|
interface IUserConfig extends UserConfig {
|
|||
|
plugins: PluginOption[];
|
|||
|
optimizeDeps: {
|
|||
|
exclude: string[];
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
const addThemePreprocessorPluginConfig = (themeConfig: IThemeConfig, userConfig: UserConfig) => {
|
|||
|
const pluginConfig: UserConfig = {
|
|||
|
plugins: [],
|
|||
|
optimizeDeps: {
|
|||
|
exclude: [],
|
|||
|
},
|
|||
|
};
|
|||
|
defaultsDeep(userConfig, pluginConfig);
|
|||
|
|
|||
|
const config = userConfig as IUserConfig;
|
|||
|
|
|||
|
config.plugins = [
|
|||
|
...config.plugins,
|
|||
|
themePreprocessorPlugin({
|
|||
|
less: {
|
|||
|
// 是否启用任意主题色模式,这里不启用
|
|||
|
arbitraryMode: false,
|
|||
|
// 提供多组变量文件
|
|||
|
multipleScopeVars: themeConfig.themesName.map(name => {
|
|||
|
const _path = path.resolve(themeConfig.rootPath, `./${name}/${THEMEVARIABLESFILENAME}`);
|
|||
|
//console.log(_path);
|
|||
|
return {
|
|||
|
scopeName: name,
|
|||
|
path: _path,
|
|||
|
};
|
|||
|
}),
|
|||
|
defaultScopeName: themeConfig.defaultThemeName,
|
|||
|
// 在生产模式是否抽取独立的主题css文件,extract为true以下属性有效
|
|||
|
// !!!【注意】这里必须是true
|
|||
|
extract: true,
|
|||
|
customThemeCssFileName: scopeName => scopeName + uuid,
|
|||
|
removeCssScopeName: true,
|
|||
|
},
|
|||
|
}),
|
|||
|
];
|
|||
|
|
|||
|
config.optimizeDeps.exclude = [
|
|||
|
...config.optimizeDeps.exclude,
|
|||
|
//【注意】 排除 import { toggleTheme } from "@crami/vite-plugin-theme-preprocessor/dist/browser-utils"; 在vite的缓存依赖
|
|||
|
// 否则会造成切换失效
|
|||
|
'@crami/vite-plugin-theme-preprocessor/dist/browser-utils',
|
|||
|
];
|
|||
|
};
|
|||
|
|
|||
|
const addThemeConfig = (options: IThemeUserConfig) => {
|
|||
|
const { env, userConfig } = options;
|
|||
|
const { VITE_ENV_THEME_DEFAULT: defaultThemeName } = env;
|
|||
|
const themeConfig = loadConfig({ defaultThemeName });
|
|||
|
if (!themeConfig) {
|
|||
|
return;
|
|||
|
}
|
|||
|
if (themeConfig.additionalDataName) {
|
|||
|
addCssAdditionalDataConfig(themeConfig, userConfig);
|
|||
|
}
|
|||
|
if (themeConfig.themesName && themeConfig.themesName.length > 0) {
|
|||
|
addThemePreprocessorPluginConfig(themeConfig, userConfig);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
export { addThemeConfig };
|