Skip to content
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Options are saved between runs into `package.json`. To invert a boolean options,
* `--alpine` - use [alpine](https://www.alpinelinux.org/) as base image
* `--build=CMD` - command to be used to build your application.
* `--cache` - use build caching to speed up builds
* `--caddy` - serve static sites (Vite, static Astro) with [Caddy](https://caddyserver.com/) instead of nginx.
* `--cmd=CMD` - CMD to use in Dockerfile
* `--defer-build` - may be needed when your build step requires access to secrets that are not available at image build time. Results in larger images and slower deployments.
* `--dev` - include `devDependencies` in the production image.
Expand Down
64 changes: 59 additions & 5 deletions gdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const defaults = {
bun: false,
build: '',
cache: false,
caddy: false,
cmd: '',
deferBuild: false,
dev: false,
Expand Down Expand Up @@ -130,16 +131,67 @@ export class GDF {
}

get astro() {
return !!(this.#pj.dependencies?.astro)
return !!(this.#pj.dependencies?.astro || this.#pj.devDependencies?.astro)
}

// contents of astro.config.*, or an empty string
get astroConfig() {
if (!this.astro) return ''

for (const ext of ['mjs', 'js', 'ts', 'mts', 'cjs', 'cts']) {
const file = path.join(this._appdir, `astro.config.${ext}`)
if (fs.existsSync(file)) return fs.readFileSync(file, 'utf-8')
}

return ''
}

// value of a top level string option in astro.config.*, eg. outDir or base
astroOption(name) {
const match = this.astroConfig.match(new RegExp(`\\b${name}\\s*:\\s*(["'\`])(.+?)\\1`))
return match?.[2]
}

get astroAdapter() {
return !!(this.#pj.dependencies?.['@astrojs/node'] || this.#pj.devDependencies?.['@astrojs/node'])
}

// middleware mode builds a handler for a custom server, which the start script runs
get astroMiddleware() {
return this.astroAdapter && /mode\s*:\s*(["'`])middleware\1/.test(this.astroConfig)
}

get astroSSR() {
return !!(this.#pj.dependencies?.astro) &&
!!(this.#pj.dependencies?.['@astrojs/node'])
return this.astro && this.astroAdapter && !this.astroMiddleware
}

// the server imports astro, the adapter and their dependencies at runtime
get astroSSRDevDependencies() {
return this.astroSSR &&
!!(this.#pj.devDependencies?.astro || this.#pj.devDependencies?.['@astrojs/node'])
}

get astroStatic() {
return this.astro && !this.astroSSR
return this.astro && !this.astroAdapter
}

get astroOutDir() {
const outDir = this.astroOption('outDir')
if (!outDir) return 'dist'
return path.posix.normalize(outDir).replace(/\/$/, '')
}

// path prefix the site is served from, eg. /docs; empty for the root
get astroBase() {
if (!this.astroStatic) return ''
const base = this.astroOption('base')
if (!base) return ''
return path.posix.join('/', base).replace(/\/$/, '')
}

// directory containing the built static site
get staticDir() {
return this.astroStatic ? this.astroOutDir : 'dist'
}

get svelte() {
Expand Down Expand Up @@ -986,10 +1038,12 @@ export class GDF {
return ['node', 'main.js']
} else if (this.gatsby) {
return [this.npx, 'gatsby', 'serve', '-H', '0.0.0.0']
} else if ((this.vite || this.astroStatic) && this.options.caddy) {
return ['caddy', 'run', '--config', '/etc/caddy/Caddyfile', '--adapter', 'caddyfile']
} else if (this.vite || this.astroStatic) {
return ['/usr/sbin/nginx', '-g', 'daemon off;']
} else if (this.astroSSR) {
return ['node', './dist/server/entry.mjs']
return ['node', `./${this.astroOutDir}/server/entry.mjs`]
} else if (this.runtime === 'Node.js' && this.#pj.scripts?.start?.includes('fastify')) {
let start = this.#pj.scripts.start
if (!start.includes('-a') && !start.includes('--address')) {
Expand Down
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const options = yargs((hideBin(process.argv)))
describe: 'use build caching to speed up builds',
type: 'string'
})
.option('caddy', {
describe: 'serve static sites with caddy instead of nginx',
type: 'boolean'
})
.option('defer-build', {
describe: 'if true, run build at deploy time',
type: 'boolean'
Expand Down
47 changes: 43 additions & 4 deletions templates/Dockerfile.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ RUN cd bundle/bundle/programs/server && meteor npm install
# Build application
RUN <%- mountSecrets %><%= build %>

<% if (devDependencies && !options.dev && !nestjs && !adonisjs && !prismaSeed && !nuxtjs) { -%>
<% if (devDependencies && !options.dev && !nestjs && !adonisjs && !prismaSeed && !nuxtjs && !astroStatic && !astroSSRDevDependencies) { -%>
# Remove development dependencies
RUN <%- buildCache %><%- packagerPrune %>

Expand All @@ -142,6 +142,8 @@ WORKDIR /app

# Set production environment
<%- emitEnv(baseEnv) %>
<% } else if ((vite || astroStatic) && options.caddy) { -%>
FROM caddy:2-alpine
<% } else if (vite || astroStatic) { -%>
FROM nginx
<% } else { -%>
Expand Down Expand Up @@ -170,11 +172,13 @@ RUN wget https://github.com/benbjohnson/litestream/releases/download/v0.3.13/lit

<% } -%>
# Copy built application
<% if (vite || astroStatic) { -%>
COPY --from=build /app/dist /usr/share/nginx/html
<% if ((vite || astroStatic) && options.caddy) { -%>
COPY --from=build /app/<%= staticDir %> /srv<%= astroBase %>
<% } else if (vite || astroStatic) { -%>
COPY --from=build /app/<%= staticDir %> /usr/share/nginx/html<%= astroBase %>
<% } else if (astroSSR) { -%>
COPY --from=build /app/node_modules /app/node_modules
COPY --from=build /app/dist /app/dist
COPY --from=build /app/<%= astroOutDir %> /app/<%= astroOutDir %>

ENV PORT=4321
ENV HOST=0.0.0.0
Expand Down Expand Up @@ -240,6 +244,41 @@ ENTRYPOINT <%- entrypoint %>
# Deploy arguments
<%- emitArgs(options.args.deploy) %>

<% } -%>
<% if (astroStatic && options.caddy) { -%>
# Serve the site, with its own 404 page
COPY <<-"EOF" /etc/caddy/Caddyfile
:<%= port %> {
root * /srv
file_server
handle_errors 404 {
rewrite * <%= astroBase %>/404.html
file_server
}
}
EOF

<% } else if (vite && options.caddy) { -%>
# Serve the site
COPY <<-"EOF" /etc/caddy/Caddyfile
:<%= port %> {
root * /srv
file_server
}
EOF

<% } else if (astroStatic) { -%>
# Serve the site, with its own 404 page and relative redirects
COPY <<-"EOF" /etc/nginx/conf.d/default.conf
server {
listen <%= port %>;
listen [::]:<%= port %>;
root /usr/share/nginx/html;
absolute_redirect off;
error_page 404 <%= astroBase %>/404.html;
}
EOF

<% } -%>
<% if (options.nginxRoot) { -%>
# configure nginx
Expand Down
6 changes: 6 additions & 0 deletions test/frameworks/astro-caddy/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/.git
/node_modules
.dockerignore
.env
Dockerfile
fly.toml
54 changes: 54 additions & 0 deletions test/frameworks/astro-caddy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# syntax = docker/dockerfile:1

# Adjust NODE_VERSION as desired
ARG NODE_VERSION=xxx
FROM node:${NODE_VERSION}-slim AS base

LABEL fly_launch_runtime="Astro"

# Astro app lives here
WORKDIR /app

# Set production environment
ENV NODE_ENV="production"


# Throw-away build stage to reduce size of final image
FROM base AS build

# Install packages needed to build node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3

# Install node modules
COPY package-lock.json package.json ./
RUN npm ci

# Copy application code
COPY . .

# Build application
RUN npm run build


# Final stage for app image
FROM caddy:2-alpine

# Copy built application
COPY --from=build /app/dist /srv

# Serve the site, with its own 404 page
COPY <<-"EOF" /etc/caddy/Caddyfile
:80 {
root * /srv
file_server
handle_errors 404 {
rewrite * /404.html
file_server
}
}
EOF

# Start the server by default, this can be overwritten at runtime
EXPOSE 80
CMD [ "caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile" ]
6 changes: 6 additions & 0 deletions test/frameworks/astro-caddy/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions test/frameworks/astro-caddy/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "astro-caddy",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"astro": "^5.15.0"
},
"dockerfile": {
"caddy": true
}
}
6 changes: 6 additions & 0 deletions test/frameworks/astro-config/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/.git
/node_modules
.dockerignore
.env
Dockerfile
fly.toml
53 changes: 53 additions & 0 deletions test/frameworks/astro-config/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# syntax = docker/dockerfile:1

# Adjust NODE_VERSION as desired
ARG NODE_VERSION=xxx
FROM node:${NODE_VERSION}-slim AS base

LABEL fly_launch_runtime="Astro"

# Astro app lives here
WORKDIR /app

# Set production environment
ENV NODE_ENV="production"


# Throw-away build stage to reduce size of final image
FROM base AS build

# Install packages needed to build node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3

# Install node modules
COPY package-lock.json package.json ./
RUN npm ci --include=dev

# Copy application code
COPY . .

# Build application
RUN npm run build


# Final stage for app image
FROM nginx

# Copy built application
COPY --from=build /app/build /usr/share/nginx/html/docs

# Serve the site, with its own 404 page and relative redirects
COPY <<-"EOF" /etc/nginx/conf.d/default.conf
server {
listen 80;
listen [::]:80;
root /usr/share/nginx/html;
absolute_redirect off;
error_page 404 /docs/404.html;
}
EOF

# Start the server by default, this can be overwritten at runtime
EXPOSE 80
CMD [ "/usr/sbin/nginx", "-g", "daemon off;" ]
8 changes: 8 additions & 0 deletions test/frameworks/astro-config/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @ts-check
import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({
outDir: './build',
base: '/docs',
});
6 changes: 6 additions & 0 deletions test/frameworks/astro-config/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions test/frameworks/astro-config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "astro-config",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"devDependencies": {
"astro": "^5.15.0"
}
}
6 changes: 6 additions & 0 deletions test/frameworks/astro-middleware/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/.git
/node_modules
.dockerignore
.env
Dockerfile
fly.toml
Loading
Loading