update:自动上传打包
This commit is contained in:
parent
95e5ff73b8
commit
9addbe190e
2
.env
2
.env
@ -8,4 +8,4 @@ VITE_OPEN = true
|
|||||||
VITE_OPEN_CDN = false
|
VITE_OPEN_CDN = false
|
||||||
|
|
||||||
# public path 配置线上环境路径(打包)、本地通过 http-server 访问时,请置空即可
|
# public path 配置线上环境路径(打包)、本地通过 http-server 访问时,请置空即可
|
||||||
VITE_PUBLIC_PATH = 'https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_web/202606301530/'
|
VITE_PUBLIC_PATH = 'https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/event_web/202607140930/'
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
/dist
|
/dist
|
||||||
|
/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/
|
||||||
|
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
trigger: always_on
|
|
||||||
---
|
|
||||||
|
|
||||||
@ -6,7 +6,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "node scripts/build-and-upload-oss.cjs",
|
||||||
|
"build:local": "vite build --base ./",
|
||||||
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/",
|
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/",
|
||||||
"gen": "sta -p http://localhost:53785/swagger/Default/swagger.json -o ./src/apis --modular --route-types --axios --module-name-index 1 --extract-request-params -t ./templates"
|
"gen": "sta -p http://localhost:53785/swagger/Default/swagger.json -o ./src/apis --modular --route-types --axios --module-name-index 1 --extract-request-params -t ./templates"
|
||||||
},
|
},
|
||||||
|
|||||||
154
scripts/build-and-upload-oss.cjs
Normal file
154
scripts/build-and-upload-oss.cjs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
const crypto = require('crypto');
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const path = require('path');
|
||||||
|
const { spawnSync } = require('child_process');
|
||||||
|
|
||||||
|
const bucket = 'yuedong-wechatapplet';
|
||||||
|
const endpoint = 'oss-cn-shanghai.aliyuncs.com';
|
||||||
|
const uploadPrefix = 'static/event_web';
|
||||||
|
const publicRoot = `https://${bucket}.${endpoint}/${uploadPrefix}`;
|
||||||
|
const concurrency = 8;
|
||||||
|
|
||||||
|
const pad = (value) => value.toString().padStart(2, '0');
|
||||||
|
const now = new Date();
|
||||||
|
const buildDirectory = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(
|
||||||
|
now.getMinutes()
|
||||||
|
)}`;
|
||||||
|
const outputPath = path.resolve(process.cwd(), buildDirectory);
|
||||||
|
const publicPath = `${publicRoot}/${buildDirectory}/`;
|
||||||
|
const dryRun = process.env.OSS_DRY_RUN === '1';
|
||||||
|
|
||||||
|
const accessKeyId = 'LTAI5t79WkXht8yy8aAAZ5qz';
|
||||||
|
const accessKeySecret = 'RpJ5miIeGARvfy2G1P8HtWvdR4j6rq';
|
||||||
|
const securityToken = process.env.ALIYUN_OSS_SECURITY_TOKEN || process.env.OSS_SECURITY_TOKEN;
|
||||||
|
|
||||||
|
if (!dryRun && (!accessKeyId || !accessKeySecret)) {
|
||||||
|
console.error('缺少阿里云 OSS 凭证,请设置 ALIYUN_OSS_ACCESS_KEY_ID 和 ALIYUN_OSS_ACCESS_KEY_SECRET。');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`开始打包:${buildDirectory}`);
|
||||||
|
console.log(`资源地址:${publicPath}`);
|
||||||
|
|
||||||
|
const viteCli = path.resolve(process.cwd(), 'node_modules/vite/bin/vite.js');
|
||||||
|
const buildEnvironment = { ...process.env };
|
||||||
|
[
|
||||||
|
'ALIYUN_OSS_ACCESS_KEY_ID',
|
||||||
|
'ALIYUN_OSS_ACCESS_KEY_SECRET',
|
||||||
|
'ALIYUN_OSS_SECURITY_TOKEN',
|
||||||
|
'OSS_ACCESS_KEY_ID',
|
||||||
|
'OSS_ACCESS_KEY_SECRET',
|
||||||
|
'OSS_SECURITY_TOKEN',
|
||||||
|
].forEach((key) => delete buildEnvironment[key]);
|
||||||
|
|
||||||
|
const buildResult = spawnSync(process.execPath, [viteCli, 'build'], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
env: {
|
||||||
|
...buildEnvironment,
|
||||||
|
BUILD_OUT_DIR: buildDirectory,
|
||||||
|
BUILD_PUBLIC_PATH: publicPath,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (buildResult.error) throw buildResult.error;
|
||||||
|
if (buildResult.status !== 0) process.exit(buildResult.status || 1);
|
||||||
|
|
||||||
|
const getFiles = (directory) =>
|
||||||
|
fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
|
||||||
|
const fullPath = path.join(directory, entry.name);
|
||||||
|
return entry.isDirectory() ? getFiles(fullPath) : [fullPath];
|
||||||
|
});
|
||||||
|
|
||||||
|
const contentTypes = {
|
||||||
|
'.css': 'text/css; charset=utf-8',
|
||||||
|
'.eot': 'application/vnd.ms-fontobject',
|
||||||
|
'.gif': 'image/gif',
|
||||||
|
'.html': 'text/html; charset=utf-8',
|
||||||
|
'.ico': 'image/x-icon',
|
||||||
|
'.jpeg': 'image/jpeg',
|
||||||
|
'.jpg': 'image/jpeg',
|
||||||
|
'.js': 'application/javascript; charset=utf-8',
|
||||||
|
'.json': 'application/json; charset=utf-8',
|
||||||
|
'.map': 'application/json; charset=utf-8',
|
||||||
|
'.mp3': 'audio/mpeg',
|
||||||
|
'.mp4': 'video/mp4',
|
||||||
|
'.png': 'image/png',
|
||||||
|
'.svg': 'image/svg+xml',
|
||||||
|
'.ttf': 'font/ttf',
|
||||||
|
'.webp': 'image/webp',
|
||||||
|
'.woff': 'font/woff',
|
||||||
|
'.woff2': 'font/woff2',
|
||||||
|
};
|
||||||
|
|
||||||
|
const encodeObjectKey = (objectKey) => objectKey.split('/').map(encodeURIComponent).join('/');
|
||||||
|
|
||||||
|
const uploadFile = (filePath, objectKey, attempt = 1) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const date = new Date().toUTCString();
|
||||||
|
const contentType = contentTypes[path.extname(filePath).toLowerCase()] || 'application/octet-stream';
|
||||||
|
const canonicalHeaders = securityToken ? `x-oss-security-token:${securityToken}\n` : '';
|
||||||
|
const canonicalResource = `/${bucket}/${objectKey}`;
|
||||||
|
const stringToSign = `PUT\n\n${contentType}\n${date}\n${canonicalHeaders}${canonicalResource}`;
|
||||||
|
const signature = crypto.createHmac('sha1', accessKeySecret).update(stringToSign).digest('base64');
|
||||||
|
const headers = {
|
||||||
|
Authorization: `OSS ${accessKeyId}:${signature}`,
|
||||||
|
'Content-Length': fs.statSync(filePath).size,
|
||||||
|
'Content-Type': contentType,
|
||||||
|
Date: date,
|
||||||
|
};
|
||||||
|
if (securityToken) headers['x-oss-security-token'] = securityToken;
|
||||||
|
|
||||||
|
const request = https.request(
|
||||||
|
{
|
||||||
|
host: `${bucket}.${endpoint}`,
|
||||||
|
path: `/${encodeObjectKey(objectKey)}`,
|
||||||
|
method: 'PUT',
|
||||||
|
headers,
|
||||||
|
},
|
||||||
|
(response) => {
|
||||||
|
let responseBody = '';
|
||||||
|
response.setEncoding('utf8');
|
||||||
|
response.on('data', (chunk) => (responseBody += chunk));
|
||||||
|
response.on('end', () => {
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) return resolve();
|
||||||
|
const error = new Error(`OSS 上传失败 (${response.statusCode}):${objectKey}\n${responseBody.slice(0, 2000)}`);
|
||||||
|
if (response.statusCode >= 500 && attempt < 3) return setTimeout(() => resolve(uploadFile(filePath, objectKey, attempt + 1)), 500 * attempt);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
request.on('error', (error) => {
|
||||||
|
if (attempt < 3) return setTimeout(() => resolve(uploadFile(filePath, objectKey, attempt + 1)), 500 * attempt);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
fs.createReadStream(filePath).pipe(request);
|
||||||
|
});
|
||||||
|
|
||||||
|
const files = getFiles(outputPath).sort();
|
||||||
|
|
||||||
|
if (dryRun) {
|
||||||
|
console.log(`[DRY RUN] 已生成 ${files.length} 个文件,将上传到 ${publicPath}`);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let nextIndex = 0;
|
||||||
|
let uploaded = 0;
|
||||||
|
const worker = async () => {
|
||||||
|
while (nextIndex < files.length) {
|
||||||
|
const filePath = files[nextIndex++];
|
||||||
|
const relativePath = path.relative(outputPath, filePath).split(path.sep).join('/');
|
||||||
|
const objectKey = `${uploadPrefix}/${buildDirectory}/${relativePath}`;
|
||||||
|
await uploadFile(filePath, objectKey);
|
||||||
|
uploaded += 1;
|
||||||
|
if (uploaded % 50 === 0 || uploaded === files.length) console.log(`上传进度:${uploaded}/${files.length}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Promise.all(Array.from({ length: Math.min(concurrency, files.length) }, worker))
|
||||||
|
.then(() => console.log(`部署完成:${publicPath}`))
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error.message);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
@ -15,13 +15,21 @@ const alias: Record<string, string> = {
|
|||||||
'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js',
|
'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getBuildTimeDirectory = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const pad = (value: number) => value.toString().padStart(2, '0');
|
||||||
|
|
||||||
|
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}`;
|
||||||
|
};
|
||||||
|
|
||||||
const viteConfig = defineConfig((mode: ConfigEnv) => {
|
const viteConfig = defineConfig((mode: ConfigEnv) => {
|
||||||
const env = loadEnv(mode.mode, process.cwd());
|
const env = loadEnv(mode.mode, process.cwd());
|
||||||
|
const outDir = mode.command === 'build' ? process.env.BUILD_OUT_DIR || getBuildTimeDirectory() : 'dist';
|
||||||
return {
|
return {
|
||||||
plugins: [vue(), vueJsx(), vueSetupExtend(), viteCompression(), JSON.parse(env.VITE_OPEN_CDN) ? buildConfig.cdn() : null],
|
plugins: [vue(), vueJsx(), vueSetupExtend(), viteCompression(), JSON.parse(env.VITE_OPEN_CDN) ? buildConfig.cdn() : null],
|
||||||
root: process.cwd(),
|
root: process.cwd(),
|
||||||
resolve: { alias },
|
resolve: { alias },
|
||||||
base: mode.command === 'serve' ? './' : env.VITE_PUBLIC_PATH,
|
base: mode.command === 'serve' ? './' : process.env.BUILD_PUBLIC_PATH || env.VITE_PUBLIC_PATH,
|
||||||
optimizeDeps: { exclude: ['vue-demi'] },
|
optimizeDeps: { exclude: ['vue-demi'] },
|
||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
@ -39,7 +47,7 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: 'dist',
|
outDir,
|
||||||
chunkSizeWarningLimit: 1500,
|
chunkSizeWarningLimit: 1500,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user