cache compiled webpack assets

refs DE-1379

[build-registry-path=jenkins/canvas-lms/de-1379-webpack-3]
[change-merged]

Change-Id: I61bef0e398b917611136bdee34284bb7584c5aa6
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/301946
QA-Review: Aaron Ogata <aogata@instructure.com>
Product-Review: Aaron Ogata <aogata@instructure.com>
Reviewed-by: Andrea Cirulli <andrea.cirulli@instructure.com>
Build-Review: Aaron Ogata <aogata@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
This commit is contained in:
Aaron Ogata 2022-09-26 14:07:08 -07:00
parent 35b93d1934
commit 1734090658
7 changed files with 108 additions and 12 deletions

View File

@ -0,0 +1,2 @@
FROM scratch
COPY --from=local/webpack-runner /usr/src/app/node_modules/.cache /node_modules/.cache

View File

@ -3,12 +3,16 @@ FROM local/webpack-builder
RUN \
--mount=type=bind,from=local/cache-helper,source=/tmp/dst,target=/cache-helper \
--mount=type=bind,from=local/webpack-assets-previous,target=/mount/webpack-assets-previous \
--mount=type=bind,from=local/webpack-cache-previous,target=/mount/webpack-cache-previous \
tar --no-same-owner -xf /cache-helper/webpack-runner-dependencies.tar -C ${APP_HOME} && \
tar --no-same-owner -xf /cache-helper/webpack-runner.tar -C ${APP_HOME} && \
{ { cd /mount/webpack-assets-previous/usr/src/app && cp --parents -rf public/dist/brandable_css ${APP_HOME}; } || true; }
{ { cd /mount/webpack-assets-previous/usr/src/app && cp --parents -rf public/dist/brandable_css ${APP_HOME}; } || true; } && \
{ { cd /mount/webpack-cache-previous && cp --parents -rf node_modules/.cache ${APP_HOME}; } || true; }
ARG JS_BUILD_NO_UGLIFY=0
ARG RAILS_LOAD_ALL_LOCALES=0
ARG USE_BUILD_CACHE=0
ARG WRITE_BUILD_CACHE=0
ARG CRYSTALBALL_MAP=0
RUN COMPILE_ASSETS_API_DOCS=0 \
COMPILE_ASSETS_BRAND_CONFIGS=0 \
@ -16,5 +20,7 @@ RUN COMPILE_ASSETS_API_DOCS=0 \
COMPILE_ASSETS_STYLEGUIDE=0 \
JS_BUILD_NO_UGLIFY="$JS_BUILD_NO_UGLIFY" \
RAILS_LOAD_ALL_LOCALES="$RAILS_LOAD_ALL_LOCALES" \
USE_BUILD_CACHE="$USE_BUILD_CACHE" \
WRITE_BUILD_CACHE="$WRITE_BUILD_CACHE" \
CRYSTALBALL_MAP="$CRYSTALBALL_MAP" \
bundle exec rails canvas:compile_assets

1
Jenkinsfile vendored
View File

@ -289,6 +289,7 @@ pipeline {
YARN_RUNNER_PREFIX = configuration.buildRegistryPath('yarn-runner')
WEBPACK_BUILDER_PREFIX = configuration.buildRegistryPath('webpack-builder')
WEBPACK_ASSETS_PREFIX = configuration.buildRegistryPath('webpack-assets')
WEBPACK_CACHE_PREFIX = configuration.buildRegistryPath('webpack-cache')
IMAGE_CACHE_BUILD_SCOPE = configuration.gerritChangeNumber()
IMAGE_CACHE_MERGE_SCOPE = configuration.gerritBranchSanitized()

View File

@ -59,6 +59,21 @@ function image_label_eq {
return 0
}
function load_image_if_label_eq {
local imageName=$1; shift
local labelName=$1; shift
local expectedValue=$1; shift
local outputImageName=$1; shift
./build/new-jenkins/docker-with-flakey-network-protection.sh pull $imageName
if ! image_label_eq $imageName $labelName $expectedValue; then
return 1
fi
tag_many $imageName $outputImageName
}
function pull_first_tag {
local -n selectedTag=$1; shift
local loadTags=$@

View File

@ -39,6 +39,10 @@ WORKSPACE=${WORKSPACE:-$(pwd)}
export CACHE_VERSION="2022-09-26.1"
export DOCKER_BUILDKIT=1
if [[ "$WRITE_BUILD_CACHE" == "1" ]]; then
export USE_BUILD_CACHE=1
fi
source ./build/new-jenkins/docker-build-helpers.sh
./build/new-jenkins/docker-with-flakey-network-protection.sh pull starlord.inscloudgate.net/jenkins/dockerfile:1.0-experimental
@ -53,6 +57,7 @@ RUBY_RUNNER_DOCKERFILE_MD5=$(cat Dockerfile.jenkins.ruby-runner | md5sum)
YARN_RUNNER_DOCKERFILE_MD5=$(cat Dockerfile.jenkins.yarn-runner | md5sum)
WEBPACK_BUILDER_DOCKERFILE_MD5=$(cat Dockerfile.jenkins.webpack-builder | md5sum)
WEBPACK_ASSETS_DOCKERFILE_MD5=$(cat Dockerfile.jenkins.webpack-assets | md5sum)
WEBPACK_CACHE_DOCKERFILE_MD5=$(cat Dockerfile.jenkins.webpack-cache | md5sum)
WEBPACK_RUNNER_DOCKERFILE_MD5=$(cat Dockerfile.jenkins.webpack-runner | md5sum)
./build/new-jenkins/docker-with-flakey-network-protection.sh pull starlord.inscloudgate.net/jenkins/ruby-passenger:$RUBY
@ -111,6 +116,14 @@ WEBPACK_ASSETS_CACHE_ID_PARTS=(
)
WEBPACK_ASSETS_CACHE_ID=$(compute_hash ${WEBPACK_ASSETS_CACHE_ID_PARTS[@]})
WEBPACK_CACHE_ID_PARTS=(
"${WEBPACK_BUILDER_PARTS[@]}"
$WEBPACK_RUNNER_DEPENDENCIES_MD5
$WEBPACK_RUNNER_DOCKERFILE_MD5
$WEBPACK_CACHE_DOCKERFILE_MD5
)
WEBPACK_CACHE_ID=$(compute_hash ${WEBPACK_CACHE_ID_PARTS[@]})
declare -A BASE_RUNNER_TAGS; compute_tags "BASE_RUNNER_TAGS" $BASE_RUNNER_PREFIX ${BASE_RUNNER_PARTS[@]}
declare -A RUBY_RUNNER_TAGS; compute_tags "RUBY_RUNNER_TAGS" $RUBY_RUNNER_PREFIX ${RUBY_RUNNER_PARTS[@]}
declare -A YARN_RUNNER_TAGS; compute_tags "YARN_RUNNER_TAGS" $YARN_RUNNER_PREFIX ${YARN_RUNNER_PARTS[@]}
@ -184,6 +197,7 @@ if [ -z "${WEBPACK_ASSETS_SELECTED_TAG}" ]; then
add_log "built ${WEBPACK_BUILDER_SELECTED_TAG}"
tag_many starlord.inscloudgate.net/jenkins/core:focal local/webpack-assets-previous
tag_many starlord.inscloudgate.net/jenkins/core:focal local/webpack-cache-previous
else
RUBY_RUNNER_SELECTED_TAG=$(docker inspect $WEBPACK_BUILDER_SELECTED_TAG --format '{{ .Config.Labels.RUBY_RUNNER_SELECTED_TAG }}')
YARN_RUNNER_SELECTED_TAG=$(docker inspect $WEBPACK_BUILDER_SELECTED_TAG --format '{{ .Config.Labels.YARN_RUNNER_SELECTED_TAG }}')
@ -196,23 +210,31 @@ if [ -z "${WEBPACK_ASSETS_SELECTED_TAG}" ]; then
./build/new-jenkins/docker-with-flakey-network-protection.sh pull $RUBY_RUNNER_SELECTED_TAG
tag_many $RUBY_RUNNER_SELECTED_TAG local/ruby-runner ${RUBY_RUNNER_TAGS[SAVE_TAG]}
(
./build/new-jenkins/docker-with-flakey-network-protection.sh pull $WEBPACK_ASSETS_FUZZY_TAG
[[ ! -z "${WEBPACK_ASSETS_FUZZY_TAG-}" && "$READ_BUILD_CACHE" == "1" ]] && load_image_if_label_eq \
$WEBPACK_ASSETS_FUZZY_TAG \
"WEBPACK_ASSETS_CACHE_ID" \
$WEBPACK_ASSETS_CACHE_ID \
local/webpack-assets-previous \
|| tag_many starlord.inscloudgate.net/jenkins/core:focal local/webpack-assets-previous
if ! image_label_eq $WEBPACK_ASSETS_FUZZY_TAG "WEBPACK_ASSETS_CACHE_ID" $WEBPACK_ASSETS_CACHE_ID; then
exit 1
fi
tag_many $WEBPACK_ASSETS_FUZZY_TAG local/webpack-assets-previous
) || (
tag_many starlord.inscloudgate.net/jenkins/core:focal local/webpack-assets-previous
)
[[ ! -z "${WEBPACK_CACHE_FUZZY_TAG-}" && "$READ_BUILD_CACHE" == "1" ]] && load_image_if_label_eq \
$WEBPACK_CACHE_FUZZY_TAG \
"WEBPACK_CACHE_ID" \
$WEBPACK_CACHE_ID \
local/webpack-cache-previous \
&& export USE_BUILD_CACHE=1 \
|| tag_many starlord.inscloudgate.net/jenkins/core:focal local/webpack-cache-previous
fi
tag_many $WEBPACK_BUILDER_SELECTED_TAG local/webpack-builder ${WEBPACK_BUILDER_TAGS[SAVE_TAG]} ${WEBPACK_BUILDER_TAGS[UNIQUE_TAG]-}
# *_BUILD_CACHE are special variables and do not need to be included in the image cache hash
# because it shouldn't produce any compiled asset changes
docker build \
"${WEBPACK_RUNNER_BUILD_ARGS[@]}" \
--build-arg USE_BUILD_CACHE="${USE_BUILD_CACHE-0}" \
--build-arg WRITE_BUILD_CACHE="${WRITE_BUILD_CACHE-0}" \
--no-cache \
--tag local/webpack-runner \
- < Dockerfile.jenkins.webpack-runner
@ -221,9 +243,21 @@ if [ -z "${WEBPACK_ASSETS_SELECTED_TAG}" ]; then
--label "WEBPACK_ASSETS_CACHE_ID=$WEBPACK_ASSETS_CACHE_ID" \
--label "WEBPACK_BUILDER_SELECTED_TAG=$WEBPACK_BUILDER_SELECTED_TAG" \
--label "YARN_RUNNER_SELECTED_TAG=$YARN_RUNNER_SELECTED_TAG" \
--no-cache \
--tag "${WEBPACK_ASSETS_TAGS[SAVE_TAG]}" \
- < Dockerfile.jenkins.webpack-assets
if [[ "$WRITE_BUILD_CACHE" == "1" ]]; then
docker build \
--label "RUBY_RUNNER_SELECTED_TAG=$RUBY_RUNNER_SELECTED_TAG" \
--label "WEBPACK_CACHE_ID=$WEBPACK_CACHE_ID" \
--label "WEBPACK_BUILDER_SELECTED_TAG=$WEBPACK_BUILDER_SELECTED_TAG" \
--label "YARN_RUNNER_SELECTED_TAG=$YARN_RUNNER_SELECTED_TAG" \
--no-cache \
--tag "${WEBPACK_CACHE_FUZZY_TAG-}" \
- < Dockerfile.jenkins.webpack-cache
fi
WEBPACK_ASSETS_SELECTED_TAG=${WEBPACK_ASSETS_TAGS[SAVE_TAG]}
add_log "built ${WEBPACK_ASSETS_SELECTED_TAG}"

View File

@ -126,6 +126,7 @@ def preloadCacheImagesAsync() {
sh """#!/bin/bash
/tmp/docker-with-flakey-network-protection.sh pull starlord.inscloudgate.net/jenkins/dockerfile:1.0-experimental &
/tmp/docker-with-flakey-network-protection.sh pull ${env.WEBPACK_ASSETS_PREFIX}:${getFuzzyTagSuffix()} &
/tmp/docker-with-flakey-network-protection.sh pull ${env.WEBPACK_CACHE_PREFIX}:${getFuzzyTagSuffix()} &
"""
}
@ -144,7 +145,10 @@ def premergeCacheImage() {
"WEBPACK_BUILDER_PREFIX=${env.WEBPACK_BUILDER_PREFIX}",
"WEBPACK_ASSETS_FUZZY_TAG=${env.WEBPACK_ASSETS_PREFIX}:${getFuzzyTagSuffix()}",
"WEBPACK_ASSETS_PREFIX=${env.WEBPACK_ASSETS_PREFIX}",
"WEBPACK_CACHE_FUZZY_TAG=${env.WEBPACK_CACHE_PREFIX}:${getFuzzyTagSuffix()}",
"YARN_RUNNER_PREFIX=${env.YARN_RUNNER_PREFIX}",
"READ_BUILD_CACHE=0",
"WRITE_BUILD_CACHE=1",
]) {
slackSendCacheBuild {
try {
@ -162,6 +166,7 @@ def premergeCacheImage() {
./build/new-jenkins/docker-with-flakey-network-protection.sh push -a $RUBY_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push -a $BASE_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push -a $WEBPACK_ASSETS_PREFIX
./build/new-jenkins/docker-with-flakey-network-protection.sh push -a $WEBPACK_CACHE_PREFIX || true
""", label: 'upload cache images')
}
}
@ -170,7 +175,9 @@ def premergeCacheImage() {
def patchsetImage(asyncStepsStr = '') {
credentials.withStarlordCredentials {
def cacheScope = configuration.isChangeMerged() ? env.IMAGE_CACHE_MERGE_SCOPE : env.IMAGE_CACHE_BUILD_SCOPE
def readBuildCache = configuration.isChangeMerged() ? 0 : 1
def webpackAssetsFuzzyTag = configuration.isChangeMerged() ? "" : "${env.WEBPACK_ASSETS_PREFIX}:${getFuzzyTagSuffix()}"
def webpackCacheFuzzyTag = configuration.isChangeMerged() ? "" : "${env.WEBPACK_CACHE_PREFIX}:${getFuzzyTagSuffix()}"
slackSendCacheBuild {
withEnv([
@ -187,7 +194,10 @@ def patchsetImage(asyncStepsStr = '') {
"WEBPACK_BUILDER_PREFIX=${env.WEBPACK_BUILDER_PREFIX}",
"WEBPACK_ASSETS_FUZZY_TAG=${webpackAssetsFuzzyTag}",
"WEBPACK_ASSETS_PREFIX=${env.WEBPACK_ASSETS_PREFIX}",
"WEBPACK_CACHE_FUZZY_TAG=${webpackCacheFuzzyTag}",
"YARN_RUNNER_PREFIX=${env.YARN_RUNNER_PREFIX}",
"READ_BUILD_CACHE=${readBuildCache}",
"WRITE_BUILD_CACHE=0",
]) {
try {
sh """#!/bin/bash

View File

@ -46,14 +46,39 @@ const skipSourcemaps = Boolean(
process.env.SKIP_SOURCEMAPS || process.env.JS_BUILD_NO_UGLIFY === '1'
)
// These flags are used by the build system to enable caching - it assumes that the cache is only reused
// when no build dependencies are changing.
const useBuildCache = process.env.USE_BUILD_CACHE === '1'
const writeBuildCache = process.env.WRITE_BUILD_CACHE === '1'
const createBundleAnalyzerPlugin = (...args) => {
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer')
return new BundleAnalyzerPlugin(...args)
}
const readOnlyCachePlugin = () => {
return function apply(compiler) {
compiler.cache.hooks.store.intercept({
register: (tapInfo) => ({ ...tapInfo, fn: () => {} }),
})
}
}
module.exports = {
mode: process.env.NODE_ENV,
target: ['web', 'es2021'],
cache: useBuildCache ? {
type: 'filesystem',
allowCollectingMemory: false,
buildDependencies: { config: [] },
compression: 'gzip',
} : false,
snapshot: useBuildCache ? {
buildDependencies: { hash: true, timestamp: false },
module: { hash: true, timestamp: false },
resolve: { hash: true, timestamp: false },
resolveBuildDependencies: { hash: true, timestamp: false }
} : {},
performance: skipSourcemaps
? false
: {
@ -398,8 +423,11 @@ module.exports = {
// runtime error in case we didn't cover them all, or provide a sink like
// this, which i'm gonna go with for now:
process: { env: {} },
})
}),
]
.concat(
writeBuildCache ? [] : readOnlyCachePlugin()
)
.concat(
// return a non-zero exit code if there are any warnings so we don't continue compiling assets if webpack fails
process.env.WEBPACK_PEDANTIC !== '0'