????????之前公司要求对于前端项目打包后的map文件需要提取出来,上传到oss服务器,并且不能将map文件暴露在生产环境。
????????公司项目众多,有基于webpack的各种版本构建的项目,也有vite生成的项目,所以就要求我写的打包plugin能尽可能的适配各个前端项目。
????????在历尽千辛万苦之后,终于初步实现了基于webapck各个版本的plugin,以及基于rollup版本的插件。
// 校验参数格式
if (Object.prototype.toString.call(options) !== "[object Object]") {
throw new Error(`配置信息应该是Object`);
}
this.params = Object.assign(
{
sourceFileNames: []
},
options
);
// 校验必传参数
if (
["projectCode", "serviceCode", "environment"].some(
key => !options[key]
)
) {
throw new Error(
`请填写正确的projectCode、serviceCode和environment`
);
}
}
// 校验打包后的文件中的map文件
checkSuffix(fileName, suf) {
var fileNameRegex = new RegExp(
"\\" + ".(" + suf.split(",").join("|") + ")$"
);
if (fileNameRegex.test(fileName.toLowerCase())) {
return true;
} else {
return false;
}
}
// 上传map文件
upload(compilation, callback) {
this.assets = compilation.assets;
const keys = Object.keys(this.assets);
this.fileName = keys.filter(item => this.checkSuffix(item, "map"));
if (this.fileName && this.fileName.length !== 0) {
this.createClient();
} else {
log(colors.red(`请检查是否开启webpack打包source-map配置`));
}
if (typeof callback === "function") {
callback();
}
}
// 创建oss请求
async createClient() {
this.getOssConfig()
.then(res => {
if (+res.code !== 200) {
return log(colors.red(res.message));
}
this.fullFileNames = res.data.fullFileNames;
const ossConfig = {
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,yourRegion填写为oss-cn-hangzhou。
region: res.data.f2eRegion,
accessKeyId: res.data.accessKey,
accessKeySecret: res.data.accessSecret,
stsToken: res.data.securityToken,
// 填写Bucket名称。
bucket: res.data.bucket
};
this.client = new OSS({
...ossConfig,
// 刷新临时访问凭证。
refreshSTSToken: async () => {
const refreshToken = await _this.getOssConfig();
return {
accessKeyId: refreshToken.accessKey,
accessKeySecret: refreshToken.accessSecret,
stsToken: refreshToken.securityToken
};
}
});
this.uploadOss();
})
.catch(e => log(colors.red(e)));
}
// 将map文件上传到oss
async uploadOss() {
await this.fullFileNames.forEach(async (item, index) => {
const name = this.params.sourceFileNames[index];
try {
const result = await this.client.put(
item,
Buffer.from(this.assets[name].source(), "utf8")
);
if (+result.res.statusCode === 200) {
log(colors.green(`${name}上传成功!`));
} else {
log(colors.red(`${name}上传失败!`));
}
} catch (error) {
console.log(error, "OSS上传错误");
log(colors.red(`${name}上传失败!`));
}
this.deleteMap(name);
});
}
// 删除map文件
deleteMap(name) {
const outPath = path.resolve(this.output, name);
fs.unlink(outPath, function(error) {
log(colors.green(`${name}删除成功!`));
if (error) {
log(colors.red(`${name}删除失败!`));
return false;
}
});
}
????????至此,webpack的插件就结束了。
步骤跟webpack的差不太多,唯一有区别的就是获取map文件的方式以及构建plugin的方式。
// 读取根文件夹下的所有文件和子文件夹,获取map文件
const readFolder = async (folderPath, fileCallback) => {
const fileType = ".map";
const files = fs.readdirSync(folderPath);
files.forEach(async file => {
const filePath = path.join(folderPath, file);
const isDirectory = fs.lstatSync(filePath);
if (isDirectory.isDirectory()) {
readFolder(filePath, fileCallback);
} else {
// 过滤指定类型的文件
if (path.extname(file) === fileType) {
fileCallback(file, filePath);
}
}
});
};
// 处理每个指定类型文件的回调函数
const fileCallback = (file, filePath) => {
fileName.push(file);
fileNamePath.push(filePath);
// console.log("fileCallback");
};
function RollupOSSPlugin(userOptions = {}) {
// 校验参数格式
if (Object.prototype.toString.call(userOptions) !== "[object Object]") {
throw new Error(`配置信息应该是Object`);
}
params = Object.assign(
{
sourceFileNames: []
},
userOptions
);
// 校验必传参数
if (
["projectCode", "serviceCode", "environment"].some(
key => !userOptions[key]
)
) {
throw new Error(`请填写正确的projectCode、serviceCode和environment`);
}
return {
name: "RollupOSSPlugin",
async writeBundle(options, bundle) {
output = options.dir || path.dirname(options.file || "");
if (options.sourcemap) {
createClient();
} else {
// 校验是否开启map打包
log(colors.red(`请检查是否开启vite.config.js打包source-map配置`));
}
}
};
}
exports.RollupOSSPlugin = RollupOSSPlugin;
其他步骤跟webpack的几乎相同。
最后附上项目的源码https://github.com/wntree/ossPlugin