使用Node.js构建源代码
2023年8月1日目前,由于Raspbian是基于Bullseye版本,因此通过apt安装Node.js将会安装Node.js 12版本。
然而,由于zenn-cli不再支持Node.js 12及以下版本,在尝试从Bullseye的npm安装zenn-cli时会受到限制。尽管zenn-cli仍然可以安装,但会显示警告信息,标志为已弃用。
因此,我试着从树莓派上安装apt->npm->zenn-cli,并且没有遇到任何问题,感觉很好。
简单地说,我只需要将与node.js相关的软件包指向stable bookworm的存储库就行了,但即使这样,它也不是最新的LTS版本,既然不使用最新的LTS版本,那干脆就来尝试构建一下吧。
前提条件 tí
已安装了GitHub CLI。
已安装了tmux。
已安装了sysstat(必要用于统计。如果没有特定计划的话可以不安装)。
准备源代码
# gh repo clone用のディレクトリ作成
mkdir -p ~/src/nodejs
cd src/nodejs
从Github上下载源代码。
gh repo clone nodejs/node
cd node
# タグ一覧表示
git tag
# 使いたいバージョンのタグにcheckout
git checkout v18.17.1
我们将在假设您位于项目根目录下的情况下进行说明。
建造方法
如果使用Node.js,则构建方法已在BUILDING.md文件中写明。
大多数项目都会写明本地构建方法,请按照该方法进行操作。
如果没有提供构建方法,您可以阅读源代码,查看构建时出现错误的lib文件,或者查看Makefile文件,自行调查。
除非是旧项目,否则很可能已经在某个地方写明了如何进行环境设置和操作方法。
Node.js 的说明非常详细,非常易懂。作为 README 和环境设置说明的写作示例,可以进行参考。
依赖关系
根据BUILDING.md文件的描述,Debian系统需要以下所列的软件包。
sudo apt install python3 g++ make python3-pip
关于Python,从Node.js v18(可能也包括v19但未经验证)开始,需要python3.9~3.6才能进行构建,请注意。而对于最新的Node.js v20,可以使用python3.11来进行构建。
配置
建立时的配置。
不用特别担心。
./configure
如果您不希望在root时发生/usr/local/bin和/usr/bin的干扰,可以按照以下方式更改安装目录。
# こうすると/usr/local/nodeのディレクトリを使ってその下にlibやbinを作ってくれる。
./configure --prefix=/usr/local/node
在使用时,可以将路径添加到PATH中,例如/usr/local/node/bin,或者直接执行/usr/local/node/bin/node。
建造
通过tmux启动。
这是因为通过ssh进行构建时,如果ssh会话中断,为了防止处理中断。
不一定需要tmux,但tmux是最不用考虑的选择,而且有很多爱好者,所以使用它可能是不错的选择。
在tmux中创建一个随意会话。
tmux
日志存放处
由于即使只是先构建和使用,也会花费相当多的时间,所以我认为最好至少保存日志。不然它们可能会流失。
只要不是特别指定的话,日志的位置可以随便选择,通常在构建普通用户时,我会创建一个类似于~/var/log/项目名称/make的目录,并将日志写入其中。在此先将这个位置作为日志存储位置。
mkdir -p ~/var/log/nodejs/node/make
帮助我
请查看Makefile文件中的help部分。
# make --helpでなくて、make helpであることに注意。
# make --helpだとmakeコマンドのhelpがでる。
make help
确认以下事项:使用make install时,默认的安装位置是/usr/local;使用make clean可以删除缓存;确保存在make uninstall(尽管有些项目可能无法通过make uninstall进行卸载)。
试试构建。
让我们尝试构建Makefile。
如果没有任何参数,就会默认执行make all来构建所有内容。
make -j是在进行构建时指定的作业数量。请根据核心数选择作业数量。
在这里的BUILDING.md中写着要以make -j4的指令进行构建,
但是对于像树莓派这样性能较差的电脑来说,可能更好的是使用-j2、-j3。
这是因为在性能较差的电脑上,后台处理相对较重,所以在构建过程中可能会导致桌面停止运行或崩溃的可能性。
我认为只有在实际环境中运行才能真正理解这些东西。
如果你关心核心数,可以查看lscpu或/proc/cpuinfo以调查核心数。
为了避免在构建过程中日志丢失,最好按照以下方式记录日志。
这样做可以避免在失败时进行繁琐的回溯操作。
# こうすると時間経過もログに残せる。
make -j4 2>&1 | awk '{print strftime("%Y-%m-%dT%H:%M:%S"), $0}' | tee ~/var/log/nodejs/node/make/"$(date +'%Y%m%dT%H%M%SZ')".log
如果想知道电脑的规格是否足够强大,可以在这个时候使用tmux打开一个新的会话,来检查负载情况。如果有可能需要多次构建,那最好进行测试。
mkdir -p ~/var/log/nodejs/node/iostat/
# これをやると1秒間に一回、cpuやディスクioの統計をとってくれる。
iostat -x 1 | awk '{print strftime("%Y-%m-%dT%H:%M:%S"), $0}' | tee ~/var/log/nodejs/node/iostat/"$(date +'%Y%m%dT%H%M%SZ')".log
一旦开始构建,就将tmux分离,关闭ssh,并且让其自行完成构建。
在建设时间中的小知识
尽管没接触过cpp的人可能会感到惊讶,但会有很多警告出现。
另外,由于会产生大量的日志,可能会令人惊讶,但这是常见的情况。
只要没有遇到错误而停止运行,那么一切都正常,请放心。
我用Raspberry Pi 4B进行构建后,使用iostat进行监测发现,用户级别的CPU使用率始终在90%左右,大约花费了3到4个小时。考虑到Raspberry Pi上的数据存储在MicroSD卡上,所以磁盘I/O也可能成为瓶颈,但实际上几乎没有观察到iowait现象,统计数据显示CPU的影响更大。
如果想要稍微减轻负担,尤其是在使用raspberrypi构建的情况下,可能最好关闭GUI。
在我第一次在raspberry pi4B上构建时,它崩溃了,所以我将其设置为cui,并重新进行了构建。
这些数值仅仅是根据我的环境来说的,我认为速度还会受到高温、低温、MicroSD卡的剩余容量和类型,以及电源是否充足等方面的影响。供参考。
不过,如果使用最新的电脑的话,可能只需要30分钟到1小时就能完成,所以使用新电脑的人可能不太需要担心。
试用新鲜出炉的产品。
如果可以成功构建,我会试着使用它。
我认为执行下面的命令会弹出对话框式界面。
./out/Realease/node
由于这个版本是发布版本并且在bookworm中也采用了,所以我认为应该没问题,但在进行make install之前,先进行简单的操作确认一下吧。
安装
我会将其安装在指定的安装位置。
在执行时会考虑依赖关系,并将bin、include等文件放置在适当的位置。
整个过程大约需要2~5分钟。
在Linux中,通常情况下,通过Makefile构建而不是使用apt、dnf等软件包管理工具安装的自定义软件应该放置在/usr/local/目录下。
根据前面的说明,执行下面的命令将把各个文件放置在/usr/local/目录下。
sudo make install
我希望将构建的多个版本分开使用。
如果想要在预览或其他情况下自己构建的版本之间进行切换,就需要实现一种类似虚拟环境或者类似于env的机制。
我会在构建时为node创建一个深层次的根目录,暂时进行调整。
在版本上写入构建版本,但是请注意,在更新或删除时,如果没有前缀,可能无法正确删除nodejs和npm库的文件。
# 17.2-previewとか最新のmainならunstableとか適当に名前をつける。
version=18.17.1
./configure --prefix=/usr/local/node/version/${version}
在执行sudo make install时,它会自动安装。
sudo make install
如果这样做,将node和npm的符号链接放在/usr/local/node/bin中会很方便。
sudo ln -s /usr/local/node/version/${version}/bin/node /usr/local/node/bin/node
sudo ln -s /usr/local/node/version/${version}/bin/npm /usr/local/node/bin/npm
sudo ln -s /usr/local/node/version/${version}/bin/npx /usr/local/node/bin/npx
为什么不把可执行文件放在/usr/local/bin目录下呢?因为根目录默认情况下优先选择/usr/local/bin,而不是/usr/bin。如果在/usr/local/bin和/usr/bin中都放置相同的文件,可能会对系统产生影响。
当需要使用 /usr/local/node/bin 时,可将其添加到路径中。
如果要使用多个版本,请始终使用nodejs和npm
请注意版本符号链接是否正确。
如果觉得麻烦,可以自己制作一个类似的env并保存为脚本。
在这里,我们将假设它被命名为nodelocals。
#!/usr/bin/env bash
#
# nodejs /usr/local/node/version/\$version version management
#######################################
# nodejs /usr/local/node/version/\$version version management
# Globals:
# None
# Arguments:
# All.
# Outputs:
# format
# Returns:
# 0 if command success, non-zero on error.
# Example:
# nodelocals list
# # out put installed version from /usr/local/node/version/\$version.
# nodelocals set \$version
# # set node, npm, npx to /usr/local/node/bin
#######################################
function nodelocals() {
local i
local new_array=( $@ )
local version
# nodeがない場合は空文字
local selected_version=$(readlink /usr/local/node/bin/node | awk -F/ '{print $6}')
for ((i=0;i<$#;i++)); do
# if find list flags from args, show installed nodejs destination /usr/local/node/bin/node.
if [ "${new_array[$i]}" = "list" ]; then
# 引数がlist以外にあるとおかしい。
if [ -n "$2" ]; then
echo 'list is no argument.' >&2
return 1
fi
# echo 使っているものに*がつくようにする。
local selected
for version in $(ls -1 /usr/local/node/version); do
selected=" "
if [ "${version}" = "${selected_version}" ]; then
selected='*'
fi
# アスタリスクをそのままecho に通すと展開されるので""をつける。
echo "$selected" $version
done
return 0
fi
# localが選ばれたら、
if [ "${new_array[$i]}" = "set" ]; then
if [ ${UID} -ne "0" ] && [ ${EUID} -ne "0" ]; then
echo 'this function use superuser only' >&2
return 1
fi
# version取得
shift
version=$1
local check_version
local exist=1
# versionの存在確認
for check_version in $(ls -1 /usr/local/node/version); do
if [ "${version}" = "${check_version}" ]; then
exist=0
fi
done
if [ "$exist" = "1" ]; then
echo 'select installed version!' >&2
return 1
fi
# symlinkで紐付け
ln -snf /usr/local/node/version/${version}/bin/node /usr/local/node/bin/node
ln -snf /usr/local/node/version/${version}/bin/npm /usr/local/node/bin/npm
ln -snf /usr/local/node/version/${version}/bin/npx /usr/local/node/bin/npx
return 0
fi
done
}
function usage() {
cat 1>&2 <<EOF
nodelocals
nodejs /usr/local/node/version/\${version} allignment version management tools
USAGE:
nodelocals [FLAGS] [OPTIONS]
FLAGS:
list Show /usr/local/node/version/\$version installed nodejs version engines.
set Set node, npm, npx to /usr/local/node/bin
-h, --help Prints help information
OPTIONS:
--debug Set bash debug Option
EOF
}
function main {
local i
local new_array=( $@ )
for ((i=0;i<$#;i++)); do
if [ "${new_array[$i]}" = "--help" ] || [ "${new_array[$i]}" = "-h" ]; then
usage
return
fi
# if find --debug flag from args, start debug mode.
if [ "${new_array[$i]}" = "--debug" ]; then
set -x
trap "
set +x
trap - RETURN
" RETURN
unset new_array[$i]
fi
done
# reindex assign.
new_array=${new_array[@]}
nodelocals $new_array
}
main $@
我会给予这个权限。
sudo chmod 755 /usr/local/bin/nodelocals
我会为每个环境创建一个指向bin目录的符号链接文件夹。
sudo mkdir -p /usr/local/node/bin
使用方法
# /usr/local/nodeにインストールしたnodejs一覧表示
nodelocals list
# /usr/local/nodeに存在する指定したバージョンのnode, npm, npxを/usr/local/binにセットする。
sudo nodelocals set 18.9.1
如果添加了安装处理或其他内容,那将成为某种env。
我认为实施本身相当简单。
然而,如果做得太過火,就會變成對nodeenv、nvm或n這些車輪的重新發明,所以要適可而止。
問題的焦點是想要自己完全管理還是不想要呢?
比如想在像/usr/local這樣的系統中放置多個版本。
尝试使用已安装在/usr/local/ 的内容。
如果/usr/local/bin的路径被设置 properly, 应该可以被正常地执行。
# 存在確認
command -v npm
command -v node
node -v
## 対話形式で実行してみる。
node
## zenn-cliをインストールしてみる。
sudo npm install -g zenn-cli
如果按照上面所写的方法更改了安装路径,那么应该能够根据节点版本的不同,npm的安装路径也会发生相应的更改。让我们来确认一下。
# bin
ls -1 /usr/local/node/version/${version}/bin
# lib
ls -1 /usr/local/node/version/${version}/lib
卸载
有些情况下,Makefile可能没有提供卸载方法。在这种情况下,您需要手动删除。但是,nodejs已经编写了卸载指令,因此,只需在Makefile所在位置执行以下步骤即可完成卸载。
sudo make uninstall
如果按照上述方法根据不同版本更改安装位置,那么与该nodejs相关的库和二进制文件将保存在/usr/local/node/${version}/路径下。因此,可以通过在每个版本的环境中使用rm -rf命令来删除它们。
# nodejs18.17.1の環境を削除する時
version=18.17.1
rm -rf /usr/local/node/version/${version}
虽然可以在之前提到的nodelocals上添加类似卸载的功能,但考虑到自己编写的管理成本以及方便性,可能并不是很值得。如果其他人使用的话可能会有需要。
想要更新
卸载后,先进行清理,然后使用适当的git版本,进行配置、编译、安装。
在执行git check-out之前,请先进行清理操作。如果使用make install进行覆盖安装,系统可能会保留之前版本的依赖库。请注意。
## 残っているプロジェクトのMakefileを使ってアンインストール
sudo make uninstall
# キャッシュクリーン
make clean
# 使いたいバージョンにチェックアウト
git checkout v{適切なバージョン}
./configure
make
sudo make install
总结
如果按照步骤做,我认为没有特别困难的地方。
你可能已经注意到了,如果在Makefile中不将版本区分开并安装到系统中,那么在卸载和更新时会出现问题。所以请确保保留项目。
如果按照上述步骤进行操作,您可以了解在构建过程中所承受的负担有多大。所以,如果有人想要为Node.js做出贡献,或者想要成为JS王之类的人,但是负担太重,花费的时间太长,就会觉得无法忍受了。最好还是乖乖购买一台专门用于Node.js开发环境的计算机吧。