自动化部署:Webpack插件实现前端SPA资源上传腾讯云CDN
前端单页应用(SPA)的静态资源通常部署在单一服务器上,通过集成云存储CDN服务,可以将这些资源分散到多个边缘节点,从而降低源站压力并提升用户访问速度。本文将介绍如何通过自定义Webpack插件,在打包完成后自动将构建产物上传至腾讯云COS(对象存储),并实现CDN加速。
1. 插件骨架设计
采用CommonJS模块格式编写插件webpack-cos-done-plugin,在Webpack配置的plugins数组中注册。插件核心是apply方法,它监听Webpack的done钩子,该钩子会在每次构建完成后触发。
class DeployToCOSPlugin {
apply(compiler) {
compiler.hooks.done.tap('DeployToCOSPlugin', () => {
initiateUpload(PROJECT_NAME, version, DEPLOY_ENV, 'build');
});
}
}
module.exports = DeployToCOSPlugin;
2. 文件流上传实现
利用Node.js的fs.createReadStream读取构建目录下的每个文件,借助腾讯云官方SDKcos-nodejs-sdk-v5的putObject方法完成上传。路径规则为:apps/{项目名}/{版本号}/{相对路径}。
const COS = require('cos-nodejs-sdk-v5');
const fs = require('fs');
const path = require('path');
const dir = require('node-dir');
function uploadBuildAssets() {
console.log('>>> 开始部署静态资源至CDN');
const buildPath = path.resolve(process.cwd(), 'build');
dir.files(buildPath, (err, filePaths) => {
if (err) {
console.error('构建目录读取失败:', err.message);
process.exit(1);
}
const uploadTasks = filePaths.map(filePath => {
return new Promise((resolve, reject) => {
const relativePath = filePath.replace(buildPath + '/', '');
const objectKey = `apps/${PROJECT_NAME}/${version}/${relativePath}`;
const readStream = fs.createReadStream(filePath);
const cosInstance = new COS({
SecretId: COS_CONFIG[ENV].secretId,
SecretKey: COS_CONFIG[ENV].secretKey,
});
cosInstance.putObject({
Bucket: COS_CONFIG[ENV].bucket,
Region: COS_CONFIG[ENV].region,
Key: objectKey,
Body: readStream,
ContentLength: fs.statSync(filePath).size,
}, (err, data) => {
if (err || data.statusCode !== 200) {
console.error(`上传失败: ${objectKey}`, err || data.statusCode);
process.exit(1);
}
console.log(`✓ ${objectKey} 上传成功`);
resolve(data);
});
});
});
Promise.all(uploadTasks).then(() => {
updateEntryFile();
});
});
}
3. 入口文件替换策略
当所有静态资源(JS、CSS、图片等)上传完成后,将index.html单独上传至apps/{项目名}/latest/路径。Nginx配置会指向这个固定路径,确保用户始终访问最新的入口文件,而其他资源通过版本号实现隔离和缓存控制。
function updateEntryFile() {
console.log('>>> 开始更新入口文件');
const indexPath = path.resolve(process.cwd(), 'build/index.html');
const readStream = fs.createReadStream(indexPath);
const entryKey = `apps/${PROJECT_NAME}/latest/index.html`;
const cosInstance = new COS({
SecretId: COS_CONFIG[ENV].secretId,
SecretKey: COS_CONFIG[ENV].secretKey,
});
cosInstance.putObject({
Bucket: COS_CONFIG[ENV].bucket,
Region: COS_CONFIG[ENV].region,
Key: entryKey,
Body: readStream,
}, (err, data) => {
if (err || data.statusCode !== 200) {
console.error(`入口文件更新失败`, err || data.statusCode);
process.exit(1);
}
console.log(`✓ 入口文件 ${entryKey} 更新完成`);
});
}
部署流程总结
整个部署流水线为:Webpack构建完成 → 触发done事件 → 遍历构建目录所有文件 → 并行上传至COS(带版本号路径) → 所有资源上传完毕 → 替换index.html至latest路径。这种方案实现了静态资源的版本化管理,同时通过CDN分发显著提升加载性能。