🐛 build文件确实
This commit is contained in:
parent
f95dc4d947
commit
42f1a7edfe
|
@ -61,7 +61,6 @@ lerna-debug.log*
|
|||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
import type { BuildOptions } from 'vite';
|
||||
|
||||
import { pathResolve } from './utils';
|
||||
|
||||
export const buildEnv = (): BuildOptions => {
|
||||
return {
|
||||
target: 'es2015',
|
||||
assetsInlineLimit: 20000,
|
||||
// 构建输出的目录,默认值为"dist"
|
||||
outDir: 'docker/dist',
|
||||
// 用于指定使用的代码压缩工具。在这里,minify 被设置为 'terser',表示使用 Terser 进行代码压缩。默认值terser
|
||||
// esbuild 打包更快,但是不能去除 console.log,terser打包慢,但能去除 console.log
|
||||
minify: 'terser', // "esbuild"
|
||||
// 用于配置 Terser 的选项
|
||||
terserOptions: {
|
||||
// 用于配置压缩选项
|
||||
compress: {
|
||||
drop_console: true, // 是否删除代码中的 console 语句, 默认值false
|
||||
drop_debugger: true, // 是否删除代码中的 debugger 语句, 默认值false
|
||||
},
|
||||
},
|
||||
// 禁用 gzip 压缩大小报告,可略微减少打包时间
|
||||
reportCompressedSize: false,
|
||||
// 用于指定是否生成源映射文件。源映射文件可以帮助调试和定位源代码中的错误。当设置为false时,构建过程不会生成源映射文件
|
||||
sourcemap: false,
|
||||
// 用于配置 CommonJS 模块的选项
|
||||
commonjsOptions: {
|
||||
// 用于指定是否忽略 CommonJS 模块中的 try-catch 语句。当设置为false时,构建过程会保留 CommonJS 模块中的 try-catch 语句
|
||||
ignoreTryCatch: false,
|
||||
},
|
||||
// 规定触发警告的 chunk 大小, 当某个代码分块的大小超过该限制时,Vite 会发出警告
|
||||
chunkSizeWarningLimit: 2000,
|
||||
rollupOptions: {
|
||||
external: ['md-editor-v3', 'echarts'],
|
||||
input: {
|
||||
// @ts-ignore
|
||||
index: pathResolve('../index.html', import.meta.url),
|
||||
},
|
||||
// 静态资源分类打包
|
||||
output: {
|
||||
chunkFileNames: 'static/js/[name]-[hash].js',
|
||||
entryFileNames: 'static/js/[name]-[hash].js',
|
||||
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
|
||||
manualChunks: (id) => {
|
||||
// 如果是包含在包中则打包成 vendor
|
||||
if (id.includes('node_modules')) {
|
||||
return `vendor`;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
import { Plugin as importToCDN } from 'vite-plugin-cdn-import';
|
||||
|
||||
import { wrapperEnv } from './utils';
|
||||
|
||||
/**
|
||||
* @description 打包时采用`cdn`模式,仅限外网使用(默认不采用,如果需要采用cdn模式,请在 .env.production 文件,将 VITE_CDN 设置成true)
|
||||
* 平台采用国内cdn:https://www.bootcdn.cn,当然你也可以选择 https://unpkg.com 或者 https://www.jsdelivr.com
|
||||
* 注意:上面提到的仅限外网使用也不是完全肯定的,如果你们公司内网部署的有相关js、css文件,也可以将下面配置对应改一下,整一套内网版cdn
|
||||
*/
|
||||
export const cdn = importToCDN({
|
||||
//(prodUrl解释: name: 对应下面modules的name,version: 自动读取本地package.json中dependencies依赖中对应包的版本号,path: 对应下面modules的path,当然也可写完整路径,会替换prodUrl)
|
||||
// prodUrl: 'https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}',
|
||||
prodUrl: 'https://unpkg.com/{name}@{version}/{path}',
|
||||
modules: [
|
||||
{
|
||||
name: 'vue',
|
||||
var: 'Vue',
|
||||
path: 'dist/vue.global.prod.js',
|
||||
},
|
||||
{
|
||||
name: 'vue-router',
|
||||
var: 'VueRouter',
|
||||
path: 'dist/vue-router.global.js',
|
||||
},
|
||||
{
|
||||
name: 'pinia',
|
||||
var: 'Pinia',
|
||||
path: 'dist/pinia.iife.js',
|
||||
},
|
||||
{
|
||||
name: 'axios',
|
||||
var: 'axios',
|
||||
path: 'dist/axios.min.js',
|
||||
},
|
||||
{
|
||||
name: 'dayjs',
|
||||
var: 'dayjs',
|
||||
path: 'dayjs.min.js',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
/* 是否使用CDN加速 */
|
||||
export const useCDN = (mode) => {
|
||||
const env = wrapperEnv(mode, 'VITE');
|
||||
return env.VITE_CDN ? cdn : null;
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
import type { CSSOptions } from 'vite';
|
||||
|
||||
|
||||
export const css = (mode: string): CSSOptions => {
|
||||
return {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
additionalData: `@use "@/assets/styles/minix/sidebar" as *;`,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
import dayjs from 'dayjs';
|
||||
|
||||
import { dependencies, devDependencies, engines, name, version } from '../package.json';
|
||||
|
||||
const __APP_INFO__ = {
|
||||
pkg: { name, version, engines, dependencies, devDependencies },
|
||||
lastBuildTime: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'),
|
||||
};
|
||||
|
||||
export const define = () => {
|
||||
return {
|
||||
__APP_INFO__: JSON.stringify(__APP_INFO__),
|
||||
};
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
import boxen, { type Options as BoxenOptions } from 'boxen';
|
||||
import dayjs, { type Dayjs } from 'dayjs';
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import gradientString from 'gradient-string';
|
||||
|
||||
import { logOutputSize, wrapperEnv } from './utils';
|
||||
|
||||
dayjs.extend(duration);
|
||||
|
||||
const boxenOptions: BoxenOptions = {
|
||||
padding: 0.94,
|
||||
borderColor: 'cyan',
|
||||
borderStyle: 'round',
|
||||
textAlignment: 'left',
|
||||
};
|
||||
|
||||
/* 输出日志信息 */
|
||||
const printLogMessage = (VITE_PORT: number) => {
|
||||
return gradientString('cyan', 'magenta').multiline(
|
||||
`欢迎使用此项目,项目访问地址如下:
|
||||
http://localhost:${VITE_PORT}`
|
||||
);
|
||||
};
|
||||
|
||||
export const viteConsoleLog = (mode: string) => {
|
||||
const { VITE_PORT } = wrapperEnv(mode);
|
||||
|
||||
let config: { command: string };
|
||||
let startTime: Dayjs;
|
||||
let endTime: Dayjs;
|
||||
return {
|
||||
name: 'vite:buildInfo',
|
||||
configResolved(resolvedConfig) {
|
||||
config = resolvedConfig;
|
||||
},
|
||||
buildStart() {
|
||||
console.log(boxen(printLogMessage(VITE_PORT), boxenOptions));
|
||||
if (config.command === 'build') {
|
||||
startTime = dayjs(new Date());
|
||||
}
|
||||
},
|
||||
closeBundle() {
|
||||
if (config.command === 'build') {
|
||||
endTime = dayjs(new Date());
|
||||
const format = dayjs.duration(endTime.diff(startTime)).format('mm分ss秒');
|
||||
|
||||
console.log(
|
||||
boxen(
|
||||
gradientString('cyan', 'magenta').multiline(
|
||||
`🎉 恭喜打包完成(总用时${format})打包大小(${logOutputSize()})`
|
||||
),
|
||||
boxenOptions
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* 此文件作用于 `vite.config.ts` 的 `optimizeDeps.include` 依赖预构建配置项
|
||||
* 依赖预构建,`vite` 启动时会将下面 include 里的模块,编译成 esm 格式并缓存到 node_modules/.vite 文件夹,页面加载到对应模块时如果浏览器有缓存就读取浏览器缓存,如果没有会读取本地缓存并按需加载
|
||||
* 尤其当您禁用浏览器缓存时(这种情况只应该发生在调试阶段)必须将对应模块加入到 include里,否则会遇到开发环境切换页面卡顿的问题(vite 会认为它是一个新的依赖包会重新加载并强制刷新页面),因为它既无法使用浏览器缓存,又没有在本地 node_modules/.vite 里缓存
|
||||
* 温馨提示:如果您使用的第三方库是全局引入,也就是引入到 src/main.ts 文件里,就不需要再添加到 include 里了,因为 vite 会自动将它们缓存到 node_modules/.vite
|
||||
*/
|
||||
const include = ['vue', 'vue-router', 'dayjs', 'axios', 'pinia', 'vue-types', 'js-cookie'];
|
||||
|
||||
/**
|
||||
* 在预构建中强制排除的依赖项
|
||||
*/
|
||||
const exclude: string[] = [];
|
||||
|
||||
export { exclude, include };
|
|
@ -0,0 +1,45 @@
|
|||
import UnoCssIcons from '@unocss/preset-icons';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||
import { presetIcons } from 'unocss';
|
||||
import UnoCSS from 'unocss/vite';
|
||||
import type { PluginOption } from 'vite';
|
||||
import removeConsole from 'vite-plugin-remove-console';
|
||||
import Inspector from 'vite-plugin-vue-inspector';
|
||||
|
||||
import { useCDN } from './cdn';
|
||||
import { viteConsoleLog } from './info';
|
||||
import { compressPack, report } from './utils';
|
||||
|
||||
export const plugins = (mode: string): PluginOption[] => {
|
||||
return [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
Inspector(),
|
||||
report(),
|
||||
removeConsole(),
|
||||
useCDN(mode),
|
||||
viteConsoleLog(mode),
|
||||
UnoCSS({
|
||||
hmrTopLevelAwait: false,
|
||||
inspector: true, // 控制台是否打印 UnoCSS inspector
|
||||
presets: [
|
||||
presetIcons({
|
||||
prefix: '',
|
||||
extraProperties: {
|
||||
display: 'inline-block',
|
||||
'vertical-align': 'middle',
|
||||
},
|
||||
}),
|
||||
UnoCssIcons({
|
||||
prefix: '',
|
||||
extraProperties: {
|
||||
display: 'inline-block',
|
||||
'vertical-align': 'middle',
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
compressPack(mode),
|
||||
];
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
import { pathResolve } from './utils';
|
||||
|
||||
export const resolve = () => {
|
||||
return {
|
||||
alias: {
|
||||
'@': pathResolve('../src'),
|
||||
},
|
||||
};
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
import type { ServerOptions } from 'vite';
|
||||
|
||||
import { wrapperEnv } from './utils';
|
||||
|
||||
/* 开发服务配置 */
|
||||
export const server = (mode: string) => {
|
||||
const { VITE_PORT, VITE_APP_URL, VITE_STRICT_PORT } = wrapperEnv(mode);
|
||||
|
||||
const options: ServerOptions = {
|
||||
strictPort: VITE_STRICT_PORT,
|
||||
port: VITE_PORT,
|
||||
host: '0.0.0.0',
|
||||
open: true,
|
||||
cors: true,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: VITE_APP_URL,
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/api/, '/api'),
|
||||
},
|
||||
'/mock': {
|
||||
target: VITE_APP_URL,
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/mock/, '/mock'),
|
||||
},
|
||||
},
|
||||
// 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布
|
||||
warmup: {
|
||||
clientFiles: ['./index.html', './src/{views,components}/*'],
|
||||
},
|
||||
};
|
||||
|
||||
return options;
|
||||
};
|
|
@ -0,0 +1,118 @@
|
|||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
import { loadEnv } from 'vite';
|
||||
import viteCompression from 'vite-plugin-compression';
|
||||
|
||||
import { buildEnv } from './buildEnv';
|
||||
|
||||
export const root: string = process.cwd();
|
||||
|
||||
/**
|
||||
* @description 根据可选的路径片段生成一个新的绝对路径
|
||||
* @param dir 路径片段,默认`build`
|
||||
* @param metaUrl 模块的完整`url`,如果在`build`目录外调用必传`import.meta.url`
|
||||
*/
|
||||
// @ts-ignore
|
||||
export const pathResolve = (dir = '.', metaUrl = import.meta.url) => {
|
||||
// 当前文件目录的绝对路径
|
||||
const currentFileDir = dirname(fileURLToPath(metaUrl));
|
||||
// build 目录的绝对路径
|
||||
const buildDir = resolve(currentFileDir, 'build');
|
||||
// 解析的绝对路径
|
||||
const resolvedPath = resolve(currentFileDir, dir);
|
||||
// 检查解析的绝对路径是否在 build 目录内
|
||||
if (resolvedPath.startsWith(buildDir)) {
|
||||
// 在 build 目录内,返回当前文件路径
|
||||
return fileURLToPath(metaUrl);
|
||||
}
|
||||
// 不在 build 目录内,返回解析后的绝对路径
|
||||
return resolvedPath;
|
||||
};
|
||||
|
||||
/**
|
||||
* 封装环境变量配置
|
||||
* @param mode 当前模式
|
||||
* @param prefix 需要过滤的前缀
|
||||
* @link 参考:https://cn.vite.dev/config/#using-environment-variables-in-config
|
||||
*/
|
||||
// @ts-ignore
|
||||
export const wrapperEnv = (mode: string, prefix: string = ''): ViteEnv => {
|
||||
const env: any = loadEnv(mode, root, prefix);
|
||||
|
||||
// 将变量转换指定类型
|
||||
for (const envName of Object.keys(env)) {
|
||||
let realName: string | boolean | number = env[envName].replace(/\\n/g, '\n');
|
||||
realName = realName === 'true' ? true : realName === 'false' ? false : realName;
|
||||
|
||||
if (envName === 'VITE_PORT') {
|
||||
realName = Number(realName);
|
||||
}
|
||||
env[envName] = realName;
|
||||
// @ts-ignore
|
||||
process.env[envName] = realName;
|
||||
}
|
||||
return env;
|
||||
};
|
||||
|
||||
/* 打包分析 */
|
||||
export const report = () => {
|
||||
const lifecycle = process.env.npm_lifecycle_event;
|
||||
return lifecycle === 'report'
|
||||
? visualizer({ open: true, brotliSize: true, filename: 'report.html' })
|
||||
: (null as any);
|
||||
};
|
||||
|
||||
/* 启用gzip压缩 */
|
||||
export const compressPack = (mode: string) => {
|
||||
const { VITE_COMPRESSION } = wrapperEnv(mode);
|
||||
|
||||
return VITE_COMPRESSION == 'gzip' ? viteCompression({ threshold: 1024000 }) : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 计算打包后文件夹大小
|
||||
* @returns
|
||||
*/
|
||||
export const logOutputSize = (): string => {
|
||||
const outDir = `../${buildEnv().outDir}`;
|
||||
|
||||
function convertSize(size: number) {
|
||||
const units: Array<string> = ['byte', 'KB', 'MB', 'GB'];
|
||||
|
||||
// 输入的单位是否存在
|
||||
let index = 0;
|
||||
|
||||
while (size >= 1024) {
|
||||
size /= 1024;
|
||||
index++;
|
||||
}
|
||||
|
||||
return `${size.toFixed(2)} ${units[index]}`;
|
||||
}
|
||||
|
||||
// 计算文件夹字节大小
|
||||
function getFolderSize(folderPath: string) {
|
||||
let size = 0;
|
||||
|
||||
fs.readdirSync(folderPath).forEach((fileName: string) => {
|
||||
const filePath = path.join(folderPath, fileName);
|
||||
const stats = fs.statSync(filePath);
|
||||
|
||||
if (stats.isFile()) {
|
||||
size += stats.size;
|
||||
} else if (stats.isDirectory()) {
|
||||
size += getFolderSize(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
const folderSize = getFolderSize(path.resolve(__dirname, outDir));
|
||||
|
||||
return convertSize(folderSize);
|
||||
};
|
Loading…
Reference in New Issue