前言
# React-Native实现多页面多bundle打包配置 在上一篇文章里面讲到原生端集成js bundle 的相关内容,这一次主要是对整个打包能力,封装成cli,实现js bundle打包、预览、调试功能。
在本文中,你将学到:
- 从零开始搭建简单的
react-native能力 - 使用
node搭建预览服务器 - 使用
node请求拦截实现控制台打印功能,协助调试
虽然官方expo提供了一个专门的APP来调试react-native,但是当我们需要在我们自己的原生客户端中加载,并且调用原生方法的时候,expo官方的预览调试已经不满足我们的需求了。所以我们可以自己搭建一套适用的react-native预览调试工具。
注意:本文章只是react-native打包成bundle的一系列处理,不涉及app打包
自定义脚手架cli
- 创建目录
demo-cli - 进入目录,执行
npm init - 在
package.json里面添加对应的依赖和配置(主要是bin配置)
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"chalk": "^1.1.1",
"commander": "^12.1.0",
"compressing": "^1.10.1",
"dotenv": "^16.4.5",
"dotenv-expand": "^11.0.6",
"minimist": "^1.2.0",
"prompt": "^0.2.14",
"qrcode-terminal": "^0.12.0",
"react-native": "^0.74.3",
"semver": "^5.0.3"
},
"bin": {
"demo-cli": "index.js"
},
-
执行
npm link即可直接使用demo-cli进行调试在当前目录下执行
npm link之后,会将当前项目链接到node全局node_modules中,作为一个库文件,并解析bin配置 创建可执行文件,下面是我执行完指令后在全局node_modules中形成的文件
-
入口文件
在与客户端交互的时候,或者客户端发送全局数据给
js bundle时,需要进行接收,所以定义了一个统一的入口文件,使用模版进行生成,可以在里面前置一些公共方法,以便开发者可以直接使用。如调用客户端API封装,日志打印等。定义模块文件
生成文件
自定义指令打包bundle
-
打包指令执行
在bin配置对应的文件中,添加打包指令
program
.command('build:common')
.description('build:common')
.action(() => {
commonBuild();
})
在action中写指令对应的逻辑。可以直接获取到当前指令执行目录下的文件,如下图中的示例就是在当前react-native项目dist中生成bundle文件
exec(`npx react-native bundle --platform android --config ./metro.config.js --dev false --entry-file dist/android --bundle-output ./dist/demo.bundle`, (error, stdout, stderr) => {
if (error) {
console.error(`打包执行失败结果:${error}`);
reject(`${name}: ${platform}打包执行失败结果:${error}`);
}
resolve(`${name}: ${platform}打包执行成功结果`);
});
预览并调试项目
因为是单独打包成了bundle文件,react-native开发人员每次调试都需要打包发给客户端开发人员集成,非常不方便。这里参考了当前前端vue项目的开发模式,vue项目开发模式下,其实是本地启动了一个开发服务,突发其想,我在react-native里面是不是也可以启动一个node服务,刚好我有自定义cli,于是立马开干。具体的实现思路如下:
module.exports.preview = async (name, options) => {
// 加载注入环境变量
loadEnv(options.mode);
// 创建文件监听
let filePath = `./pages/${name}.js`;
console.log(`正在监听 ${filePath}`);
let previousMD5 = "";
let watchWait = false;
fs.watch(filePath, async (event, filename) => {
if (!filename || watchWait) {
return;
}
watchWait = setTimeout(() => {
watchWait = false;
}, 10000);
const md5 = crypto.createHash("md5");
const currentMD5 = md5
.update(fs.readFileSync(filePath).toString())
.digest("hex");
if (currentMD5 === previousMD5) {
return;
}
previousMD5 = currentMD5;
console.log(`${filePath} is changed`);
previewQrcode(name);
})
// 创建静态代理服务
let app = http.createServer(function (request, response) {
console.log('请求:', request.url, `.${request.url}`);
// 普通请求和资源加载
fs.readFile(`.${request.url}`, function (err, data) {
if (err) {
console.log('请求失败', err);
} else {
response.setHeader('Content-type', 'application/octet-stream')
response.end(data);
}
});
});
app.listen(8000);
console.log('服务启动,8000端口');
// 生成二维码,可以使用qrcode-terminal实现
previewQrcode(name);
}
日志打印也是采用了一个取巧的方式,在代理服务中新开了一个路由,打印日志时,直接发送请求到该路由,再将数据打印在控制台。
注意:以上的调试预览等能力都必须保证客户端和node服务在同一局域网内
以上是react-native cli脚手架实现js bundle打包、预览、调试功能的全部内容,欢迎大佬交流指正!