wangpin34 / blog

个人博客, 博文写在 Issues 里
5 stars 0 forks source link

2021/06/18: 随心所欲的构建项目 #63

Open wangpin34 opened 3 years ago

wangpin34 commented 3 years ago

随心所欲的构建项目

之前在做一个 chrome extension 时碰到一个问题,background.ts 和 react 代码对 babel 的配置无法兼容,于是兴起了用 lerna 的念头。于是操刀对项目进行了改造。简单来说,做了以下事情。

接下来,调用 lerna bootstrap,lerna 会为每个 package 调用 yarn install,安装依赖,或链接本地依赖(其他package)。

最后,调用 learn run build 命令,这个命令会调用每个 package 下面的 build script(定义在 package.json scripts 字段里)。生成的结果暂时存放在各自的 build 目录。

yarn 的 workspace 很让我喜欢。启用 workspace 之后,packages 之间共同的依赖会被统一安装到根目录下的 node_modules,这样就减少了重复安装带来的大体积问题。对于我手头上这个 256 GB硬盘的 pc 来说,是重大利好。

当然,不用 lerna,选择用多 repo 来维护项目,走传统的 npm 依赖管理方式,也能解决问题。但是相对于上面这样的单 repo 多 package 的方式,管理难度比较大。我之前做的一个项目就是多 repo 方式,更新依赖版本非常麻烦,需要反复的build,publish,upgrade。

Shell 脚本

前面提到了 build 结果存放在 package 的不同目录,对于 extension 的最终产品,我们需要将 background.js 和 react 代码搬运一个目录,然后打包发布。比如:

static 存放 react build 结果。

build
      static/
      background.js

用 gulp 或者直接用 Nodejs 也可以完成搬运,但是写起来比较繁琐。直接用 Shell 脚本会非常容易。比如编写如下脚本内容

copy -R packages/app/build/** build/static
copy packages/scripts/background.js build

Shell 的另外一个妙用是设置环境变量。比如,通过 create-react-app 生成的 react app,默认 public_url 为根目录。如果要改变,就需要设置环境变量 PUBLIC_URL。而 react-scripts 只区分development 和 prod 环境,对于多个线上环境,就无能无力。自己编写 js 脚本,然后在脚本里设置环境变量是没法很好解决这个问题的,因为通过脚本设定的环境变量只存于于脚本执行期间,比如脚本名称为 env.js

node env.js && react-scripts build

当 env.js 结束以后,它设定的环境变量就已经消失了。有两个比较丑陋的办法是:

  1. env.js 动态生成 .env
  2. env.js 通过子进程启动 react-scripts

上面两个办法都算不上好,都有自己的问题。动态生成 .env,过后没法清理现场,必须再配后一个 delete-env.js。通过子进程启动 react-scripts,又会牺牲 react-scripts 的log。

解决这个问题的一个简单思路就是,用 shell 脚本设置变量,然后在脚本里调用 reacts-scripts build。

Makefile

gulp 提供了 task 这个概念,可以将 build 流程分割成小任务,然后自由的排列组合。Makefile 也可以完成类似的工作,而且相比 gulp 的命令式编程,Makefile 只需要简单的声明任务名称,对应的 shell 命令,入手更简单。比如,声明 build 任务。

build:
      lerna run build
      copy -R packages/app/build/** build/static
      copy packages/scripts/background.js build

再添加一个publish任务,并且将 build 任务作为其前置项。每当 publish 任务被调用,Makefile 会先执行 build。

publish: build
    # do publish

如果有多个前置项,只需要空格分开就可以了。

publish: test build
     # do publish

swift 开发小试

我现在得承认,新手选择开发 video downloader 这种类型的 app 纯属没事找事,因为涉及到的问题太多了,据不完全统计:

  1. 下载进度,用到了 background task,download delegate
  2. 数据持久化(下载任务的信息,比如 url, 下载进度,开始时间,结束时间),我想用 apple 出品的 coredata,做了一半,想想,不如 sqlit 普适性好,准备更换。
  3. 还有如何断电续传的问题,URL session 支持的 background task 一旦 app 被终止,下次启动不能续传,这一块还得再研究。
  4. 还有些零碎的错误处理,比如下载失败,自动重试,等等。

总之,下次学习新东西练手,还是搞搞 todo 这样简单的东西,对大家都好。呜呜。

React 18 计划公布

粗看了一下,除了 SSR support for Suspense,重点基本都在精细化控制 render 上,当然,这种精细化相比 native app 而言并不复杂,但可以预见 React 未来的进化路线是越来越靠近 native app。这并不意味着 React 会失去竞争力,毕竟 js 的低门槛是大杀器。

一旦 React 18 正式发布,很多现有的 lib 就会逐渐退出舞台,比如弥补 lazy load 短板的 loadable components,就像iOS 15新的“垃圾短信过滤”淘汰了一众短信 app 一样。