It’s likely that not all NodeJS apps will want to use the same version of NodeJS. Let’s make the NodeJS version configurable.
We’ll allow buildpack users to define the desired NodeJS version via a .node-js-version
file in their app. We’ll first update the detect
script to check for this file. We will then record the dependency we can provide
(NodeJS), as well as the specific dependency the application will require
, in the Build Plan
, a document the lifecycle uses to determine if the buildpack will provide everything the application needs.
Update node-js-buildpack/bin/detect
to look like this:
#!/usr/bin/env bash
set -eo pipefail
if [[ ! -f package.json ]]; then
exit 100
fi
# ======= ADDED =======
version=3.1.3
if [[ -f .node-js-version ]]; then
version=$(< .node-js-version tr -d '[:space:]')
fi
cat > "${CNB_BUILD_PLAN_PATH}" << EOL
provides = [{ name = "node-js" }]
requires = [{ name = "node-js", metadata = { version = "$version" } }]
EOL
# ======= /ADDED =======
Then you will need to update your build
script to look for the recorded NodeJS version in the build plan:
Your node-js-buildpack/bin/build
script should look like the following:
#!/usr/bin/env bash
set -eo pipefail
echo "---> NodeJS Buildpack"
# ======= MODIFIED =======
# 1. GET ARGS
plan=${CNB_BP_PLAN_PATH}
# 2. CREATE THE LAYER DIRECTORY
node_js_layer="${CNB_LAYERS_DIR}"/node-js
mkdir -p "${node_js_layer}"
# ======= MODIFIED =======
# 3. DOWNLOAD node-js
default_node_js_version="18.18.1"
node_js_version=$(cat "$plan" | yj -t | jq -r '.entries[] | select(.name == "node-js") | .metadata.version' || echo ${default_node_js_version})
node_js_url=https://nodejs.org/dist/v${node_js_version}/node-v${node_js_version}-linux-x64.tar.xz
remote_nodejs_version=$(cat "${CNB_LAYERS_DIR}/node-js.toml" 2>/dev/null | yj -t | jq -r .metadata.nodejs_version 2>/dev/null || echo 'NOT FOUND')
if [[ "${node_js_url}" != *"${remote_nodejs_version}"* ]]; then
echo "-----> Downloading and extracting NodeJS" ${node_js_version}
wget -q -O - "${node_js_url}" | tar -xJf - --strip-components 1 -C "${node_js_layer}"
else
echo "-----> Reusing NodeJS"
fi
# 4. MAKE node-js AVAILABLE DURING LAUNCH and CACHE the LAYER
cat > "${CNB_LAYERS_DIR}/node-js.toml" << EOL
[types]
cache = true
launch = true
[metadata]
nodejs_version = "${node_js_version}"
EOL
# ========== ADDED ===========
# 5. SET DEFAULT START COMMAND
cat > "${CNB_LAYERS_DIR}/launch.toml" << EOL
[[processes]]
type = "web"
command = ["node", "app.js"]
default = true
EOL
Finally, create a file node-js-sample-app/.node-js-version
with the following contents:
18.18.1
In the following pack
invocation we choose to --clear-cache
so that we explicitly do not re-use cached layers. This helps us demonstrate that the NodeJS runtime layer does not get restored from a cache.
pack build test-node-js-app --clear-cache --path ./node-js-sample-app --buildpack ./node-js-buildpack
You will notice that version of NodeJS specified in the app’s .node-js-version
file is downloaded.
===> BUILDING
...
---> NodeJS Buildpack
-----> Downloading and extracting NodeJS 18.18.1
Now that you’ve finished your buildpack, how about extending it? Try: