Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.

feat: Add Dockerize option to nuxt project #581

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
25 changes: 25 additions & 0 deletions packages/cna-template/template/_Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Dockerfile
FROM node:14-alpine
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alpine version is a very small version. I have been using this config for a long time and it can install packages well, the only problem is that it does not have git by default, which is when we use a package that instead of npm from use git, to solve this problem, I install git manually.
I have also seen some users have problems because the output size of the container with the image node itself is large.

Copy link
Author

@hamidne hamidne Aug 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And in this case, if you know something better, I'll be happy for you to share so we can replace it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok using alpine by default,. Maybe we can add a comment like # FROM node:14 to quickly switch? :)

Using single stage, ends up with final image with full dependencies in intermediate layers (including all devDependencies like webpack). (read more)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alpine > *

also, at geospoc we use nginx to serve as it provides nice brotli support out-of-the-box,

this is a huge change on how deployment of nuxt apps work..

PS. this is the Dockerfile we use at GeoSpoc

# Create the container from the alpine linux image
FROM alpine:latest as stage0

# Add nodejs
RUN apk add --update --no-cache nodejs nodejs-npm

# Set the directory we want to run the next commands for
WORKDIR /frontend

# Copy package.json & package-lock.json
COPY package.json package.json
COPY package-lock.json package-lock.json

# Install the dependencies, can be commented out if you're running the same node version
RUN npm ci

# Copy our source code into the container
COPY . .

# run webpack and the build the project
RUN NODE_ENV=production npm run build

# copy the built app to our served directory
FROM nginx:alpine

# Copy frontend data to dir that'll host the static files
COPY --from=stage0 /frontend/dist /var/www/html

# Copy the respective nginx configuration files
COPY docker/app/nginx/nginx.conf /etc/nginx/nginx.conf

# Copy the wildcard certificates from certs to /etc/ssl
COPY docker/app/nginx/certs/* /etc/ssl/

# build-base will add gcc
RUN apk add --update --no-cache git bash curl make build-base pcre-dev zlib-dev \
    && mkdir ~/brotli && command="nginx -v" && nginxv=$( ${command} 2>&1 ) && nginxlocal=$(echo $nginxv | grep -o '[0-9.]*$') \
    && cd ~/brotli && curl -L "https://nginx.org/download/nginx-$(echo $nginxlocal).tar.gz" -o nginx.tar.gz && tar zxvf nginx.tar.gz && rm nginx.tar.gz \
    && git clone https://github.com/google/ngx_brotli.git && cd ngx_brotli && git submodule update --init \
    && cd ~/brotli/nginx-$(echo $nginxlocal) && ./configure --with-compat --add-dynamic-module=../ngx_brotli && make modules \
    && cp -r ./objs/*.so /usr/lib/nginx/modules/ \
    && rm -rf ~/brotli/ \
    && sed -i '1iload_module modules/ngx_http_brotli_filter_module.so; load_module modules/ngx_http_brotli_static_module.so;' /etc/nginx/nginx.conf

# Expose ports.
EXPOSE 80
EXPOSE 443

# start nginx and keep the process from backgrounding and the container from quitting
CMD ["nginx"]

staged builds for life!


# create destination directory
RUN mkdir -p /app
WORKDIR /app

# update and install dependency
RUN apk update && apk upgrade
RUN apk add git

# install packages
COPY package.json .
COPY yarn.lock .
RUN yarn install

# copy project to directory
COPY . .
RUN yarn build

EXPOSE 80
ENV NUXT_PORT=80
ENV HOST 0.0.0.0

CMD [ "yarn", "start" ]
8 changes: 8 additions & 0 deletions packages/cna-template/template/_docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: '3.7'

services:
app:
build: .
image: <%= name %>/<%= name %>
container_name: <%= name %>
restart: always
10 changes: 10 additions & 0 deletions packages/create-nuxt-app/lib/prompts.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,15 @@ module.exports = [
{ name: 'Semantic Pull Requests', value: 'semantic-pull-requests' }
],
default: []
},
{
name: 'devOps',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to somehow enable it only for server target since for full static doesn't makes sense having this option

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The selection of this feature is optional and also due to the code structure, it is not possible to enable this feature based on the condition.

Copy link
Contributor

@scscgit scscgit Aug 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There most certainly are use-cases for deploying full static sites as Dockerized, which except for using nginx itself include also scenarios like using a reverse proxy to expose private services inside a k8s cluster (and possibly whitelisting/blacklisting their endpoints) when the site consumes their API, or to go around CORS issues if the APIs cannot be accessed directly (though in some cases https://axios.nuxtjs.org/options/#proxy may be used for this, but it can't be used if we "already" use nginx anyway)

This seems to be officially suggested by Nuxt at https://nuxtjs.org/docs/2.x/deployment/nginx-proxy

However, note that nginx has some major issues when using it as a reverse proxy for other services; for example it doesn't support search of /etc/resolv.conf even if you apply a workaround https://serverfault.com/a/373306 to load the resolver IP, which is vital if you need for the domains to be cached temporarily rather than having the IP be resolved only at startup. There may be even a need for hacks like https://serverfault.com/a/909100 if you need to reload the file itself.

message: 'DevOps tools:',
type: 'list',
choices: [
{ name: 'None', value: 'none' },
{ name: 'Docker', value: 'docker' }
],
default: 'none'
}
]
4 changes: 4 additions & 0 deletions packages/create-nuxt-app/lib/saofile.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ module.exports = {
'_.eslintrc.js': 'linter.includes("eslint")',
'_.prettierrc': 'linter.includes("prettier")',
'_jsconfig.json': 'devTools.includes("jsconfig.json")',
_Dockerfile: 'devOps.includes("docker")',
'_docker-compose.yml': 'devOps.includes("docker")',
'tsconfig.json': 'language.includes("ts")',
'semantic.yml': 'devTools.includes("semantic-pull-requests")',
'_stylelint.config.js': 'linter.includes("stylelint")'
Expand All @@ -96,6 +98,8 @@ module.exports = {
'_.prettierrc': '.prettierrc',
'_.eslintrc.js': '.eslintrc.js',
'_jsconfig.json': 'jsconfig.json',
_Dockerfile: 'Dockerfile',
'_docker-compose.yml': 'docker-compose.yml',
'_stylelint.config.js': 'stylelint.config.js',
'semantic.yml': '.github/semantic.yml'
}
Expand Down
320 changes: 320 additions & 0 deletions packages/create-nuxt-app/test/snapshots/index.test.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -4202,3 +4202,323 @@ Generated by [AVA](https://avajs.dev).
}␊
}␊
`

## verify devOps: Dockerize project

> Generated files

[
'.editorconfig',
'.gitignore',
'Dockerfile',
'README.md',
'assets/README.md',
'components/Logo.vue',
'components/README.md',
'docker-compose.yml',
'layouts/README.md',
'layouts/default.vue',
'middleware/README.md',
'nuxt.config.js',
'package.json',
'pages/README.md',
'pages/index.vue',
'plugins/README.md',
'static/README.md',
'static/favicon.ico',
'store/README.md',
]

> package.json

{
dependencies: {
nuxt: '^2.14.0',
},
devDependencies: {},
private: true,
scripts: {
build: 'nuxt build',
dev: 'nuxt',
generate: 'nuxt generate',
start: 'nuxt start',
},
}

## verify devOps: None

> Generated files

[
'.editorconfig',
'.gitignore',
'README.md',
'assets/README.md',
'components/Logo.vue',
'components/README.md',
'layouts/README.md',
'layouts/default.vue',
'middleware/README.md',
'nuxt.config.js',
'package.json',
'pages/README.md',
'pages/index.vue',
'plugins/README.md',
'static/README.md',
'static/favicon.ico',
'store/README.md',
]

> package.json

{
dependencies: {
nuxt: '^2.14.0',
},
devDependencies: {},
private: true,
scripts: {
build: 'nuxt build',
dev: 'nuxt',
generate: 'nuxt generate',
start: 'nuxt start',
},
}

## verify devOps: Dockerize project

> Generated nuxt.config.js

`␊
export default {␊
/*␊
** Nuxt rendering mode␊
** See https://nuxtjs.org/api/configuration-mode␊
*/␊
mode: 'universal',␊
/*␊
** Nuxt target␊
** See https://nuxtjs.org/api/configuration-target␊
*/␊
target: 'server',␊
/*␊
** Headers of the page␊
** See https://nuxtjs.org/api/configuration-head␊
*/␊
head: {␊
title: process.env.npm_package_name || '',␊
meta: [␊
{ charset: 'utf-8' },␊
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },␊
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }␊
],␊
link: [␊
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }␊
]␊
},␊
/*␊
** Global CSS␊
*/␊
css: [␊
],␊
/*␊
** Plugins to load before mounting the App␊
** https://nuxtjs.org/guide/plugins␊
*/␊
plugins: [␊
],␊
/*␊
** Auto import components␊
** See https://nuxtjs.org/api/configuration-components␊
*/␊
components: true,␊
/*␊
** Nuxt.js dev-modules␊
*/␊
buildModules: [␊
],␊
/*␊
** Nuxt.js modules␊
*/␊
modules: [␊
],␊
/*␊
** Build configuration␊
** See https://nuxtjs.org/api/configuration-build/␊
*/␊
build: {␊
}␊
}␊
`

## verify devOps: None

> Generated nuxt.config.js

`␊
export default {␊
/*␊
** Nuxt rendering mode␊
** See https://nuxtjs.org/api/configuration-mode␊
*/␊
mode: 'universal',␊
/*␊
** Nuxt target␊
** See https://nuxtjs.org/api/configuration-target␊
*/␊
target: 'server',␊
/*␊
** Headers of the page␊
** See https://nuxtjs.org/api/configuration-head␊
*/␊
head: {␊
title: process.env.npm_package_name || '',␊
meta: [␊
{ charset: 'utf-8' },␊
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },␊
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }␊
],␊
link: [␊
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }␊
]␊
},␊
/*␊
** Global CSS␊
*/␊
css: [␊
],␊
/*␊
** Plugins to load before mounting the App␊
** https://nuxtjs.org/guide/plugins␊
*/␊
plugins: [␊
],␊
/*␊
** Auto import components␊
** See https://nuxtjs.org/api/configuration-components␊
*/␊
components: true,␊
/*␊
** Nuxt.js dev-modules␊
*/␊
buildModules: [␊
],␊
/*␊
** Nuxt.js modules␊
*/␊
modules: [␊
],␊
/*␊
** Build configuration␊
** See https://nuxtjs.org/api/configuration-build/␊
*/␊
build: {␊
}␊
}␊
`

## verify devOps: Docker

> Generated files

[
'.editorconfig',
'.gitignore',
'Dockerfile',
'README.md',
'assets/README.md',
'components/Logo.vue',
'components/README.md',
'docker-compose.yml',
'layouts/README.md',
'layouts/default.vue',
'middleware/README.md',
'nuxt.config.js',
'package.json',
'pages/README.md',
'pages/index.vue',
'plugins/README.md',
'static/README.md',
'static/favicon.ico',
'store/README.md',
]

> package.json

{
dependencies: {
nuxt: '^2.14.0',
},
devDependencies: {},
private: true,
scripts: {
build: 'nuxt build',
dev: 'nuxt',
generate: 'nuxt generate',
start: 'nuxt start',
},
}

> Generated nuxt.config.js

`␊
export default {␊
/*␊
** Nuxt rendering mode␊
** See https://nuxtjs.org/api/configuration-mode␊
*/␊
mode: 'universal',␊
/*␊
** Nuxt target␊
** See https://nuxtjs.org/api/configuration-target␊
*/␊
target: 'server',␊
/*␊
** Headers of the page␊
** See https://nuxtjs.org/api/configuration-head␊
*/␊
head: {␊
title: process.env.npm_package_name || '',␊
meta: [␊
{ charset: 'utf-8' },␊
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },␊
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }␊
],␊
link: [␊
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }␊
]␊
},␊
/*␊
** Global CSS␊
*/␊
css: [␊
],␊
/*␊
** Plugins to load before mounting the App␊
** https://nuxtjs.org/guide/plugins␊
*/␊
plugins: [␊
],␊
/*␊
** Auto import components␊
** See https://nuxtjs.org/api/configuration-components␊
*/␊
components: true,␊
/*␊
** Nuxt.js dev-modules␊
*/␊
buildModules: [␊
],␊
/*␊
** Nuxt.js modules␊
*/␊
modules: [␊
],␊
/*␊
** Build configuration␊
** See https://nuxtjs.org/api/configuration-build/␊
*/␊
build: {␊
}␊
}␊
`
Binary file modified packages/create-nuxt-app/test/snapshots/index.test.js.snap
Binary file not shown.