需求背景
当我们在低代码平台中编写源码时,如果使用了ES6+的语法(async/await等),会导致低版本浏览器无法正常运行代码,这时我们需要借助编译工具将ES6+代码转成ES5代码,保障代码的兼容性。
主要需求
- 获取项目编译配置
- 根据配置生成对应代码
技术方案
编译配置
{
"module": {
"rules": [
{
"test": /.js$/,
"exclude": /node_modules/,
"use": {
"loader": "babel-loader",
"options": {
"presets": ["@babel/preset-env"]
}
}
}
]
}
}
💡 注意,此配置为部分配置项,仅在预览、发布状态下编译。
主要流程
获取编译配置并显示
- 获取pageData下的webpackConfig字符串
- 前端通过CodeEditor组件展示对应配置
后端编译流程
- /server/routers/page.js下getPageRenderData方法增加webpack编译代码
- 获取pageData对象下webpackConfig字段,并转为对象
- 创建子进程进行转码工作
- 创建转码输入文件/server/build/[pageData._id]/script.main.input.js,渲染ejs模板/server/views/common/script-main-code.ejs,并将内容写入入口文件
- 调用webpack(options)生成编译实例complier
- 调用complier.run方法编译代码,编译后代码写入出口文件/server/build/[pageData._id]/script.main.output.js
- 读取编译后的出口文件写入模板script-main-code.ejs对应位置
- 删除临时编译文件
const fs = require('fs');
const webpack = require('webpack');
// 编译代码
scriptMainCode = await ctx.render('common/script-main-code', baseData);
// webpackConfig
const webpackConfigSource = pageData.webpackConfig || {};
const webpackConfigOptions = new Function(`return ${JSON.stringify(webpackConfigSource)}`)();
if (Object.keys(webpackConfigOptions).length && !sandbox && pageData.webpackEnable) {
// scriptMainCode = babel.transform(scriptMainCode, webpackConfigOptions).code;
const buildFolderPath = path.resolve(__dirname, `../build/${pageData._id}`);
const buildInputFileName = `script.main.input.js`;
const buildOutputFileNmae = `script.main.output.js`;
const buildInputPath = path.resolve(buildFolderPath, `./${buildInputFileName}`);
const buildOutputPath = path.resolve(buildFolderPath, `./${buildOutputFileNmae}`);
// 创建构建目录
await exitsFolder(buildFolderPath);
await writeFile(buildInputPath, scriptMainCode);
const webpackOptions = {
mode: 'production',
entry: buildInputPath,
output: {
path: buildFolderPath,
filename: buildOutputFileNmae
},
...webpackConfigOptions
};
const webpackCompiler = (options) => {
return new Promise((resolve, reject) => {
const compiler = webpack(options);
// new webpack.ProgressPlugin().apply(compiler);
compiler.run((err, stats) => {
if (!err) {
resolve(stats);
} else {
reject(err);
}
});
});
};
await webpackCompiler(webpackOptions);
scriptMainCode = await readFile(buildOutputPath);
fs.unlink(buildInputPath, () => { });
fs.unlink(buildOutputPath, () => { });
}