UNPKG

@plugin-light/project-config-vite

Version:
396 lines (388 loc) 12.9 kB
'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;