Skip to content

build assets with esbuild, with docker compose for running with auto-reload #3036

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: docker build
run: docker build . -t metacpan/metacpan-web:latest
run: docker build . --target test -t metacpan/metacpan-web:latest
- name: run Perl tests
run: >
docker run -i metacpan/metacpan-web
Expand Down Expand Up @@ -57,6 +57,8 @@ jobs:
--resolver ${{ matrix.resolver }}
--show-build-log-on-failure
--local-lib-contained=local
- name: Build assets
run: npm run build
- name: Run tests without coverage
if: matrix.resolver != 'snapshot'
run: carton exec prove -lr --jobs 2 t
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
!/root/assets/.gitignore
*.bak
*.sw*
.DS_Store
Expand All @@ -17,6 +18,7 @@
/node_modules/
/perltidy.LOG
/pm_to_blib
/root/assets
/root/static/sitemaps
/tidyall.ERR
/var
122 changes: 99 additions & 23 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,95 @@
FROM metacpan/metacpan-base:latest
################### Asset Builder

ARG CPM_ARGS=--with-test
FROM node:22 AS build-assets
ENV NO_UPDATE_NOTIFIER=1

WORKDIR /build/

COPY package.json package-lock.json .
RUN \
--mount=type=cache,target=/root/.npm,sharing=private \
<<EOT /bin/bash -euo pipefail
npm install --verbose
npm audit fix
EOT

# not supported yet
#COPY --parents build-assets.mjs root/static .

COPY build-assets.mjs .
COPY root/static root/static
RUN <<EOT /bin/bash -euo pipefail
npm run build:min
EOT

################### Web Server
FROM metacpan/metacpan-base:latest AS server

RUN \
--mount=type=cache,target=/var/cache/apt,sharing=private \
--mount=type=cache,target=/var/lib/apt/lists,sharing=private \
<<EOT /bin/bash -euo pipefail
apt update
apt install -y -f libcmark-dev
EOT

WORKDIR /metacpan-web/

COPY cpanfile cpanfile.snapshot .
RUN \
--mount=type=cache,target=/root/.perl-cpm,sharing=private \
<<EOT /bin/bash -euo pipefail
cpm install
EOT

RUN mkdir var && chown metacpan:users var

ENV PERL5LIB="/metacpan-web/local/lib/perl5"
ENV PATH="/metacpan-web/local/bin:${PATH}"

COPY *.md app.psgi *.conf .
COPY bin bin
COPY lib lib
COPY root root
COPY --from=build-assets /build/root/assets root/assets

STOPSIGNAL SIGKILL

CMD [ \
"/uwsgi.sh", \
"--http-socket", ":80" \
]

EXPOSE 80

################### Development Server
FROM server AS develop

ENV COLUMNS="${COLUMNS:-120}"
ENV PLACK_ENV=development

USER root

RUN \
--mount=type=cache,target=/root/.perl-cpm \
<<EOT /bin/bash -euo pipefail
cpm install --with-develop
EOT

USER metacpan

CMD [ \
"/uwsgi.sh", \
"--http-socket", ":80" \
]

################### Test Runner
FROM develop AS test

ENV NO_UPDATE_NOTIFIER=1
ENV PLACK_ENV=

USER root

RUN \
--mount=type=cache,target=/var/cache/apt,sharing=private \
Expand All @@ -13,40 +100,29 @@ RUN \
apt update
apt install -y -f --no-install-recommends nodejs
npm install -g npm
apt install -y -f libcmark-dev
EOT

WORKDIR /metacpan-web/
RUN chown metacpan:users /metacpan-web/

COPY --chown=metacpan:users package.json package-lock.json .
COPY package.json package-lock.json .
RUN \
--mount=type=cache,target=/root/.npm,sharing=private \
<<EOT /bin/bash -euo pipefail
npm install --verbose
npm install --verbose --include=dev
npm audit fix
EOT

COPY --chown=metacpan:users cpanfile cpanfile.snapshot .
RUN \
--mount=type=cache,target=/root/.perl-cpm,sharing=private \
--mount=type=cache,target=/root/.perl-cpm \
<<EOT /bin/bash -euo pipefail
cpm install -g ${CPM_ARGS}
cpm install --with-test
EOT

COPY --chown=metacpan:users . .
RUN mkdir var && chown metacpan:users var
COPY .perlcriticrc .perltidyrc perlimports.toml tidyall.ini ./
COPY t t

USER metacpan
CMD [ "prove", "-lr", "t" ]

CMD [ \
"/usr/bin/uwsgi", \
"--plugins", "psgi", \
"--uwsgi-socket", ":3031", \
"--http-socket", ":80", \
"--http-socket-modifier1", "5", \
"--ini", "/metacpan-web/servers/uwsgi.ini", \
"--psgi", "app.psgi" \
]
################### Production Server
FROM server AS production

EXPOSE 80 3031
USER metacpan
7 changes: 0 additions & 7 deletions app.psgi
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ BEGIN {
use lib "$root_dir/lib";
use MetaCPAN::Web;

# do not use the read only mount point when running from a docker container
my $tempdir = is_linux_container() ? '/var/tmp' : "$root_dir/var/tmp";

STDERR->autoflush;

# explicitly call ->to_app on every Plack::App::* for performance
Expand Down Expand Up @@ -137,7 +134,6 @@ builder {
enable '+MetaCPAN::Middleware::Static' => (
root => $root_dir,
dev_mode => $dev_mode,
temp_dir => $tempdir,
config => $config,
);

Expand All @@ -158,6 +154,3 @@ builder {
};
};

sub is_linux_container {
return -e '/proc/1/cgroup';
}
92 changes: 92 additions & 0 deletions build-assets.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/env node
"use strict";
import * as esbuild from 'esbuild'
import { lessLoader } from 'esbuild-plugin-less';
import fs from 'fs';
import parseArgs from 'minimist';

const config = {
entryPoints: [
'root/static/js/main.js',
'root/static/less/style.less',
],
assetNames: '[name]-[hash]',
entryNames: '[name]-[hash]',
outdir: 'root/assets',
bundle: true,
sourcemap: true,
metafile: true,
inject: ['root/static/js/inject.js'],
loader: {
'.eot': 'file',
'.svg': 'file',
'.ttf': 'file',
'.woff': 'file',
'.woff2': 'file',
},
plugins: [
lessLoader(),
new class {
name = 'metacpan-build';

setup(build) {
build.onResolve(
{ filter: /^(shCore|xregexp)$/ },
args => ({ external: true }),
);
build.onResolve(
{ filter: /^\// },
args => ({ external: true }),
);
build.onEnd(result => {
const metafile = result.metafile;
if (metafile && metafile.outputs) {
const files = Object.keys(metafile.outputs).sort()
.map(file => file.replace(/^root\/assets\//, ''));
fs.writeFile(
'root/assets/assets.json',
JSON.stringify(files),
'utf8',
(e) => {
if (e) {
console.log(e);
}
}
);
console.log('assets built');
}
else {
console.log('asset build failure');
}
});
}
},
],
};

const args = parseArgs(process.argv, {
boolean: [
'watch',
'minify',
],
});
if (args.minify) {
config.minify = true;
}
const ctx = await esbuild.context(config);
if (args.watch) {
await ctx.watch();
const sig = await new Promise(resolve => {
[
'SIGTERM',
'SIGQUIT',
'SIGINT',
].map(sig => process.on(sig, resolve));
});
process.stderr.write(`Caught signal: ${sig}\n`);
ctx.dispose();
}
else {
await ctx.rebuild();
ctx.dispose();
}
21 changes: 21 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
services:
asset-build:
build:
context: .
target: build-assets
volumes:
- './root:/build/root/'
- 'assets:/build/root/assets/'
command: [ './build-assets.mjs', '--watch' ]
server:
build:
context: .
target: develop
volumes:
- './:/metacpan-web/'
- 'assets:/metacpan-web/root/assets'
- '/metacpan-web/local'
ports:
- "8000:80"
volumes:
assets:
Loading