从零开始构建简单的react-native cli脚手架,实现js bundle打包、预览、调试功能

691 阅读3分钟

前言

# React-Native实现多页面多bundle打包配置 在上一篇文章里面讲到原生端集成js bundle 的相关内容,这一次主要是对整个打包能力,封装成cli,实现js bundle打包、预览、调试功能。

在本文中,你将学到:

  • 从零开始搭建简单的react-native能力
  • 使用node搭建预览服务器
  • 使用node请求拦截实现控制台打印功能,协助调试

虽然官方expo提供了一个专门的APP来调试react-native,但是当我们需要在我们自己的原生客户端中加载,并且调用原生方法的时候,expo官方的预览调试已经不满足我们的需求了。所以我们可以自己搭建一套适用的react-native预览调试工具。

注意:本文章只是react-native打包成bundle的一系列处理,不涉及app打包

自定义脚手架cli
  1. 创建目录demo-cli
  2. 进入目录,执行npm init
  3. 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"
  },
  1. 执行npm link 即可直接使用demo-cli进行调试

    在当前目录下执行npm link 之后,会将当前项目链接到 node 全局 node_modules 中,作为一个库文件,并解析 bin 配置 创建可执行文件,下面是我执行完指令后在全局 node_modules 中形成的文件

image.png

  1. 入口文件

    在与客户端交互的时候,或者客户端发送全局数据给js bundle时,需要进行接收,所以定义了一个统一的入口文件,使用模版进行生成,可以在里面前置一些公共方法,以便开发者可以直接使用。如调用客户端API封装,日志打印等。

    定义模块文件 image.png

    生成文件

image.png

自定义指令打包bundle
  1. 打包指令执行

    在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,于是立马开干。具体的实现思路如下:

image.png

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打包、预览、调试功能的全部内容,欢迎大佬交流指正!