乐趣区

关于前端:将react构建的cli项目打包成二进制

前言

纯前端我的项目和 nodejs 我的项目打包形式有很大的不同, 本文的重点是如何在 nodejs 环境中应用 react, 并打包成二进制文件.

咱们通常开发前端我的项目时应用的各种 cli 个别都是这么装置的 npm install xxxcli , 这样装置后就能应用相应的 xxxcli, 然而查看对应的 cli 文件;
如装置完本示例后就会现出 /usr/local/bin/ink-app 这个文件, 查看此文件内容就会发现是 nodejs 代码, 所以是依赖 nodejs 的运行环境的.

而想把 nodejs 我的项目真正转出二进制包, 须要 pkg 命令把 nodejs 运行环境也打包进去 … 这就要解决 react 及其 jsx 语法带来的问题.

查了一会发现没有这么操作的, 但这里有个我的项目 wiki-cli 就是通过 node+react+ink 构建的一个 cli 我的项目, 能够看到源码中有 bin 目录并且有可用的 wiki 二进制命令那就阐明下面的思路是可行的. 这就引起了我的趣味.

示例

按上面链接中的步骤操作生成示例我的项目

$ mkdir ink-app
$ cd ink-app
$ npx create-ink-app

cli.js 文件大略如下, 其中的正文和中文都是我前面理清思路后加的, 默认示例中是没有的.

// cli.js
#!/usr/bin/env node
// 'use strict'; // 不启用严格模式

// 这些都是谬误的
// require("babel-register") 
// require("register")

// 这句是才是对的
// require('@babel/register');

const React = require('react');
const importJsx = require('import-jsx');
const {render} = require('ink');
const meow = require('meow');

// node v12.22.0 反对此语法
const myFunc = () => {console.log('hello world');
}
myFunc();

// 其余的文件必须都得通过这种模式导入, 并且此文件代码是失常的 nodejs 代码而不能蕴含 jsx
const ui = importJsx('./ui');


const cli = meow(`
    Usage
      $ ink-app

    Options
        --name  Your name

    Examples
      $ ink-app --name=Jane
      Hello, Jane
`);

render(React.createElement(ui, cli.flags));

ui.js 文件内容如下:

const React = require('react');
const {Text, Box, useInput, useStdout, useStdin} = require('ink');
const {useEffect, useState} = React

module.exports = () => (<>
    <Text>I am text</Text>
    <Text bold>I am bold</Text>
    <Text italic>I am italic</Text>
    <Text underline>I am underline</Text>
    <Text strikethrough>I am strikethrough</Text>
    <Text color="green">I am green</Text>
    <Text color="blue" backgroundColor="gray">I am blue on gray</Text>
    <Box borderStyle="single">
        <Text>single</Text>
    </Box>
    <Box borderStyle="double">
        <Text>double</Text>
    </Box>
    <Box borderStyle="round">
        <Text>round</Text>
    </Box>
    <Box borderStyle="bold">
        <Text>bold</Text>
    </Box>
    <Box borderStyle="singleDouble">
        <Text>singleDouble</Text>
    </Box>
    <Box borderStyle="doubleSingle">
        <Text>doubleSingle</Text>
    </Box>
    <Box borderStyle="classic">
        <Text>classic</Text>
    </Box>
</>)

运行

node cli.js

cli.js 和 ui.js 都是 nodejs 文件格式,ui.js 中尽管能应用 react 等 jsx 语法, 但都在 importJsx 时进行了转化成 js 代码. 这样运行能失常显示代码索要展现的性能.

打包

➜  ink-app git:(master) ✗ pkg . -t mac -o app
> pkg@5.3.1
> Error! This experimental syntax requires enabling one of the following parser plugin(s): 'jsx, flow, typescript' (5:24)
  /Users/xxxxx/ink-app/ui.js
➜  ink-app git:(master) ✗

应用 pkg 打包就会发现报错了, 查了半天也没找到真正能解决, 应该是我这个想法太偏了 …

解决

通常咱们会用 babel 来将浏览器未兼容的新语法编译为兼容的代码,以便在旧浏览器或者环境下运行。
除了编译运行外,babel 还提供了 @babel/register 来即时编译运行。
应用 @babel/register 的形式很简略,只须要将以下代码放在须要编译运行的代码引入前:require(‘@babel/register’); 想将 jsx 语法转成 js, 在文件入口头部加上上面这句.

require('@babel/register');

就这一句我加了各种版本的, 各种版本不对名字类似终于让我找到了这句正确的 …. 但运行发现还是报错 …
而后我突发奇想的把 ui.js 改名成 ui.jsx 再运行, 发现能够了!
我猜想是 babel/register 判断文件格式时可能会参考文件后缀.

总结

  1. 再 cli.js 文件头部加上 require(‘@babel/register’);
  2. 将用到 jsx 语法的文件后缀都改成 jsx

我这半吊子根底不扎实, 网上找材料东一块西一块, 有个思路也要摸索半天 … 前端之路路漫漫!

参考文章

在命令行里也能用 React

ink 库

容易误人的古老示例

node pkg 打包一个为一个可执行程序(linux、windows、mac)

通过 babel-register 在 nodejs 端应用 es6

退出移动版