@plugin-light/project-config-vite
Version:
开箱即用的项目配置,适用于 Vue3.x 项目
396 lines (388 loc) • 12.9 kB
JavaScript
'use strict';
var path = require('node:path');
var vite = require('vite');
var shared = require('@plugin-light/shared');
var vitePluginAddCodeAtEnd = require('@plugin-light/vite-plugin-add-code-at-end');
var vitePluginAliasForLibrary = require('@plugin-light/vite-plugin-alias-for-library');
var vitePluginCrossGameStyle = require('@plugin-light/vite-plugin-cross-game-style');
var vitePluginCrossPlatform = require('@plugin-light/vite-plugin-cross-platform');
var vitePluginExportDefaultInVue = require('@plugin-light/vite-plugin-export-default-in-vue');
var vitePluginGenVersion = require('@plugin-light/vite-plugin-gen-version');
var vitePluginIfdef = require('@plugin-light/vite-plugin-ifdef');
var basicSsl = require('@vitejs/plugin-basic-ssl');
var legacy = require('@vitejs/plugin-legacy');
var vue = require('@vitejs/plugin-vue');
var vueJsx = require('@vitejs/plugin-vue-jsx');
var rollupPluginVisualizer = require('rollup-plugin-visualizer');
var AutoImport = require('unplugin-auto-import/vite');
var resolvers = require('unplugin-vue-components/resolvers');
var Components = require('unplugin-vue-components/vite');
var importToCDN = require('vite-plugin-cdn-import');
var commonjs = require('vite-plugin-commonjs');
var viteCompression = require('vite-plugin-compression');
var vitePluginHtml = require('vite-plugin-html');
var mkcert = require('vite-plugin-mkcert');
var mockDevServerPlugin = require('vite-plugin-mock-dev-server');
var vitePluginSvgIcons = require('vite-plugin-svg-icons');
var vueSetupExtend = require('vite-plugin-vue-setup-extend');
var vitePluginCdn2 = require('vite-plugin-cdn2');
/**
* 移除第一个反斜杠
*
* @export
* @param {string} [str=''] 输入字符串
* @returns {string} 字符串
* @example
* ```ts
* removeFirstSlash('/abc/ddd/')
*
* 'abc/ddd/'
* ```
*/
/**
* 移除最后一个反斜杠
*
* @export
* @param {string} [str=''] 输入字符串
* @returns {string} 字符串
*
* @example
* ```ts
* removeLastSlash('/abc/')
*
* '/abc'
* ```
*/
function removeLastSlash(str) {
if (str === void 0) {
str = '';
}
return str.replace(/\/$/, '');
}
var BUILD_NAME_MAP = {
build: '_vConsoleBuildInfo',
commit: '_vConsoleCommitInfo'
};
function enableCDN(isEnabled) {
if (isEnabled === 'true') {
return vitePluginCdn2.cdn({
// url 可以更换为私有或其他源
// url: "https://cdn.jsdelivr.net/npm/",
url: 'https://unpkg.com/',
modules: ['vue', 'vue-demi', 'pinia', 'axios', 'vant', 'vue-router'],
});
}
}
const getCdnList = ({ useElementPlusCDN, }) => {
const modules = [
{
name: 'vue',
var: 'Vue',
path: shared.CDN_MAP.VUE_V3,
},
{
name: 'vue-demi',
var: 'VueDemi',
path: shared.CDN_MAP.VUE_DEMI,
},
{
name: 'vue-router',
var: 'VueRouter',
path: shared.CDN_MAP.VUE_ROUTER_V4,
},
{
name: 'aegis-web-sdk',
var: 'Aegis',
path: shared.CDN_MAP.AEGIS_WEB,
},
{
name: 'pinia',
var: 'Pinia',
path: shared.CDN_MAP.PINIA,
},
];
if (useElementPlusCDN) {
modules.push({
name: 'element-plus',
var: 'ElementPlus',
css: shared.CDN_MAP.ELEMENT_PLUS_CSS,
path: shared.CDN_MAP.ELEMENT_PLUS,
});
}
return {
modules,
};
};
// 以下内容经常被 include
// md5
// js-cookie
// qs
// axios
const DEFAULT_OPTIMIZE_DEPS_INCLUDES = [];
const DEFAULT_OPTIMIZE_DEPS_EXCLUDES = [];
const DEFAULT_ADD_CODE_AT_END_OPTIONS = {};
// 之前版本内容
// {
// list: [
// {
// id: 'vue.js',
// code: 'export default function(){}',
// exact: false,
// },
// {
// id: 'vue.runtime.esm-bundler.js',
// code: 'export default function(){}',
// exact: false,
// number: 1,
// },
// ],
// };
const DEFAULT_ALIAS_FOR_LIBRARY_OPTIONS = {
list: [
'press-ui',
'press-plus',
'pmd-aegis',
'pmd-app-info',
'pmd-config',
'pmd-location',
'pmd-login',
'pmd-network',
'pmd-report',
'pmd-tools',
'pmd-types',
'pmd-widget',
'pmd-vue',
'pmd-jsapi',
],
target: 'src/library',
};
const DEFAULT_ALIAS = {
PRESS_UI: 'src/library/press-ui',
PRESS_PLUS: 'src/library/press-plus',
};
const getDefaultPmdAliasMap = (root) => [
'pmd-aegis',
'pmd-app-info',
'pmd-config',
'pmd-location',
'pmd-login',
'pmd-network',
'pmd-report',
'pmd-tools',
'pmd-types',
'pmd-widget',
'pmd-vue',
'pmd-jsapi',
].reduce((acc, item) => {
const list = item.split('/');
const libName = list[list.length - 1];
acc[item] = path.resolve(root, `src/library/${libName}`);
return acc;
}, {});
const DEFAULT_MKCERT_OPTIONS = {
source: 'coding',
};
const ENV_PREFIX = ['VITE_', 'VUE_APP'];
// 当前工作目录路径
const root = process.cwd();
function getAlias({ subProjectRoot, pressUiAlias, pressPlusAlias, pmdAliasMap, }) {
const result = {
'@': subProjectRoot,
src: path.resolve(root, 'src'),
...(pmdAliasMap || {}),
};
if (pressUiAlias) {
result['press-ui'] = path.resolve(root, pressUiAlias);
}
if (pressPlusAlias) {
result['press-plus'] = path.resolve(root, pressPlusAlias);
}
return result;
}
function getViteBaseConfig({ mode, serverHttps, serverPort, serverHost = true, optimizeDepsIncludes, optimizeDepsExcludes, addCodeAtEndOptions, pressUiAlias = DEFAULT_ALIAS.PRESS_UI, pressPlusAlias = DEFAULT_ALIAS.PRESS_PLUS, aliasForLibraryOptions = DEFAULT_ALIAS_FOR_LIBRARY_OPTIONS, pmdAliasMap = getDefaultPmdAliasMap(root), customElements = [], useCdn = false, useElementPlusCDN = false, mkcertOptions = DEFAULT_MKCERT_OPTIONS, prePlugins = [], postPlugins = [], autoImportVant = true, autoImportElementPlus = true, autoImportTDesign = {
library: 'vue-next',
}, }) {
// 环境变量
const env = vite.loadEnv(mode, root, ENV_PREFIX);
const isProduction = mode === 'production';
const appDir = env.VUE_APP_DIR || '';
const vueAppBase = env.VUE_APP_PUBLICPATH;
vitePluginExportDefaultInVue.exportDefaultInVue({
root,
});
const subProjectRoot = shared.getSubProjectRoot({
root,
appDir,
});
const subProjectConfig = shared.getSubProjectConfig(subProjectRoot);
const autoImportComponents = [
autoImportVant
? resolvers.VantResolver(typeof autoImportVant === 'boolean' ? undefined : autoImportVant)
: null,
autoImportElementPlus
? resolvers.ElementPlusResolver(typeof autoImportElementPlus === 'boolean' ? undefined : autoImportElementPlus)
: null,
autoImportTDesign
? resolvers.TDesignResolver(typeof autoImportTDesign === 'boolean' ? undefined : autoImportTDesign)
: null,
].filter(Boolean);
const plugins = [
...prePlugins,
vitePluginAliasForLibrary.aliasForLibrary({
root,
...(aliasForLibraryOptions || {}),
}),
vitePluginIfdef.ifdefVitePlugin({
context: {
...shared.DEFAULT_CONTEXT_OBJECT,
H5: true,
WEB: true,
VUE3: true,
__NOT_UNI__: true,
},
type: ['css', 'js', 'html'],
}),
vitePluginCrossPlatform.crossPlatformVitePlugin({
platform: 'web',
}),
vitePluginCrossGameStyle.crossGameStyleVitePlugin({
styleName: subProjectConfig?.styleName || '',
}),
addCodeAtEndOptions ? vitePluginAddCodeAtEnd.addCodeAtEndVitePlugin(typeof addCodeAtEndOptions === 'boolean'
? DEFAULT_ADD_CODE_AT_END_OPTIONS
: addCodeAtEndOptions) : null,
serverHttps ? basicSsl() : '',
commonjs(),
vue({
template: {
compilerOptions: {
// @ts-ignore
isCustomElement: (tag) => customElements.includes(tag),
},
},
}),
vueJsx(),
mockDevServerPlugin(),
AutoImport({
resolvers: autoImportComponents,
}),
Components({
dts: 'typings/components.d.ts',
resolvers: autoImportComponents,
}),
// svg icon
vitePluginSvgIcons.createSvgIconsPlugin({
// 指定图标文件夹
iconDirs: [path.resolve(subProjectRoot, './icons/svg')],
// 指定 symbolId 格式
symbolId: 'icon-[dir]-[name]',
}),
// 允许 setup 语法糖上添加组件名属性
vueSetupExtend(),
// 生产环境 gzip 压缩资源
viteCompression(),
// 注入模板数据
vitePluginHtml.createHtmlPlugin({
inject: {
data: {
ENABLE_ERUDA: env.VITE_ENABLE_ERUDA || 'false',
},
},
}),
// 生产环境默认不启用 CDN 加速
enableCDN(env.VITE_CDN_DEPS),
vitePluginGenVersion.genVersionWebVitePlugin({
buildName: BUILD_NAME_MAP.build,
commitName: BUILD_NAME_MAP.commit,
delay: 10,
}),
legacy({
targets: ['> 1%, last 1 version, ie >= 11'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime'], // 面向IE11时需要此插件
}),
isProduction && useCdn ? importToCDN(getCdnList({
useElementPlusCDN,
})) : null,
isProduction ? rollupPluginVisualizer.visualizer({
open: !!env.VITE_VISUALIZER,
filename: path.resolve(subProjectRoot, 'dist', 'stats.html'),
gzipSize: true,
brotliSize: true, // 收集 brotli 大小并将其显示
}) : null,
mkcertOptions ? mkcert(typeof mkcertOptions === 'boolean'
? DEFAULT_MKCERT_OPTIONS
: mkcertOptions) : null,
...postPlugins,
].filter(item => !!item);
const experimentalConfig = vueAppBase ? {
experimental: {
renderBuiltUrl(filename, { hostId, hostType, type }) {
console.log('[experimental] ', hostType, hostId, type, filename);
return `${removeLastSlash(vueAppBase)}/${filename}`;
},
},
} : {};
return {
root: subProjectRoot,
envDir: process.cwd(),
base: vueAppBase || './',
...experimentalConfig,
optimizeDeps: {
// include: ["press-ui/**/*.vue"]
include: optimizeDepsIncludes || DEFAULT_OPTIMIZE_DEPS_INCLUDES,
exclude: optimizeDepsExcludes || DEFAULT_OPTIMIZE_DEPS_EXCLUDES,
},
plugins,
resolve: {
alias: getAlias({
subProjectRoot,
pressUiAlias,
pressPlusAlias,
pmdAliasMap,
}),
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
server: {
port: serverPort ?? (env.VUE_APP_PORT ? +(env.VUE_APP_PORT) : 443),
https: serverHttps ?? {},
host: serverHost,
// 仅在 proxy 中配置的代理前缀, mock-dev-server 才会拦截并 mock
// doc: https://github.com/pengzhanbo/vite-plugin-mock-dev-server
proxy: {
// '^/dev-api': {
// target: '',
// },
},
},
build: {
target: 'es2015',
rollupOptions: {
input: {
1: path.resolve(subProjectRoot, './index.html'),
},
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
},
},
},
esbuild: isProduction ? {
pure: ['console.log'],
drop: ['debugger'],
} : {},
css: {
preprocessorOptions: {
scss: {
// api: 'modern',
// https://sass-lang.com/documentation/breaking-changes/legacy-js-api/
// https://sass-lang.com/documentation/breaking-changes/import/
// https://sass-lang.com/documentation/breaking-changes/mixed-decls/
silenceDeprecations: ['import', 'legacy-js-api', 'mixed-decls'],
logger: shared.scssLogger,
},
},
},
};
}
exports.getViteBaseConfig = getViteBaseConfig;