Собираем опен-сорс версию code-server.
2023.01.23
Маленькое овервью, как собрать code-server из исходников.
Code Server — разработка от Microsoft, позволяющая запускать VScode в “клиент-серверном режиме”: бэкенд работает где угодно, фронтенд доступен из браузера. Пример можно потыкать на vscode.dev или на github, нажав кнопку .
.
Как сказано в документации, Microsoft поставляет свою сборку code-server’а, которую можно скачать и использовать почти в любых целях, не нарушая лицензию. Но у MS-сборки есть фатальный недостаток: при запуске она лезет в сеть, чтобы проверить обновления, и отказывается без этого запускаться.
Если собирать code-server из исходников, в нём не будет этого механизма апдейтов, и он сможет работать в любом офлайн-окружении. Ещё не будет многих фич, не выложенных в опен-сорс — маркета расширений, коннекта к github, синхронизации настроек и прочего.
Я не первый, кто придумал собирать code-server из исхдодников. Есть как минимум 3 популярных форка, занимающихся тем же самым:
Все форки не совсем чистые, и патчат vscode для своих нужд, чего мне не очень хотелось.
Пример репо с пайплайном сборки vscode - kotborealis/code-server-oss.
Большинство этапов сборки описаны в документации VSCode. Но, есть пара проблем:
Конкретно, в air-gapped окружении не устанавливается зависимость @vscode/ripgrep
, которая выкачивает себе бинарники с github и не умеет работать с прокси (microsoft/vscode-ripgrep/issues/26).
Временно выпилим @vscode/ripgrep
из зависимостей сборки, прихватив с собой утилиты для телеметрии, бесполезные в OSS-сборке:
# Remove telemetry libs
sed -i -e 's#"@vscode/telemetry-extractor": "^1.9.8",##g' package.json
# Remove ripgrep, which, for SOME reason,
# cannot be installed in this case due to proxies.
sed -i -e 's#"@vscode/ripgrep": "^1.14.2",##g' package.json
Затем, перепишем .yarnrc
-файлы, в которых VSCode хранит информацию о таргет-платформе. По умолчанию, там прописан Electron версии 19:
disturl "https://electronjs.org/headers"
target "19.1.8"
runtime "electron"
build_from_source "true"
Эти параметры используются для сборки нативных зависимостей, например spdlog, и версия для Электрона не запустится на NodeJS. Electron 19.1.8 использует специфичную для себя версию ABI (NODE_MODULE VERSION 106
), которая отсутствует в официальной табличке релизов ноды — значения между 102 и 108 там пропущены.
Перегенерируем параметры платформы скриптом и перезапишем все инстансы .yarnrc
:
# Set proper node version in yarnrc
node build/npm/setupBuildYarnrc
cp ./build/.yarnrc ./.yarnrc
cp ./build/.yarnrc ./remote/.yarnrc
Затем мы наконец-то можем поставить все зависимости и вернуть @vscode/rigprep
на место — по странным причинам, при установке отдельно он отлично работает с проксями:
# Install node_modules
yarn $@
# Install ripgrep.
# Now it works, no one knows exactly why.
yarn add @vscode/ripgrep
Так же до установки зависимостей полезно выставить флажки, запрещающие выкачивать бинарники Electron’а и Playwright’а — для code-server’а они не потребуются:
В сборках vscode используется магический файл product.json
, в котором описывается “вкус” собираемой версии — иконка, имя, расширения по умолчанию. Ничего трогать не будем, только обрежем список расширений до нуля, которые выкачиваются с github’а, занимают много времени и не всегда нужны:
# Prevent builtin extensions from downloading
cat product.json
node -e 'console.log(JSON.stringify({...require("./product.json"), builtInExtensions: []}))' > product.json.tmp
mv product.json.tmp product.json
Девелоперская версия code-server’а собирается скриптом build/lib/preLaunch.js
, который так же собирает электрон, и выкачивает встроенные расширения. Для своих нужд обрежем его до минимума:
cat build/lib/preLaunch.js \
| grep -v "await getElectron();" \
| grep -v "await getBuiltInExtensions();" \
> build/lib/preLaunch.server.js
Но, девелоперская сборка занимает много места и работает очень медленно — первая загрузка страницы занимает примерно в 10 раз больше времени.
Релизный, минифицированный билд собирается отдельной командой, которая явно не упомянута в документации, но её можно откопать, например, в скриптах пайплайнов:
Остаётся вытащить дистрибутив из сборочной директории:
mkdir /code-server-oss && cd /code-server-oss
mv /vscode/.build ./
mv /vscode/extensions ./
mv /vscode/node_modules ./
mv /vscode/out-vscode-reh-web-min ./out
mv /vscode/product.json ./
mv /vscode/package.json ./
Из билда нам понадобились зависимости, собранные файлы, и .json
-манифесты.
Добавим скрипт запуска, который раскрутит code-server в подхдящем окружении:
# Get project root di
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
export NODE=$(find .build/ -name 'node' -type f -executable)
code_server () {
$NODE $ROOT/out/server-main.js $@
}
echo "Starting server with args: $@"
code_server $@
VScode во время сборки выкачивает для себя нужную версию NodeJS в директорию .build
, и мы будем ей пользоваться, так как под неё собраны нативные аддоны.
Затем code-server можно запустить примерно следующей командой:
В итоге, получили релизную OSS-сборку code-server’а из исходников, не требующую доступа в интернет при запуске, не тащущую за собой лишние расширения.
Финальный результат лежит в kotborealis/code-server-oss. Так же есть почти ежедневные сборки docker-образа. “Почти” ежедневные потому что иногда проваливается скачивание @vscode/ripgrep
из-за рейтлимитов github’a, и на это напарывается таже microsoft - см. скрипты пайплайнов.