Add a node image to run Gulp when selecting it with Docker (#1687)

## Description

Following up on @webyneter attempt in #1205, which is now getting outdated, I've tried to make Gulp task runner work with Docker. There is no documentation yet, but this seems to work locally with the custom bootstrap compilation...

- [x] Add a node image for local developement
- [x] Proxy the django image rather than localhost in Browser sync, pass header to keep hostname
- [x] Don't call the runserver command from Gulp, let docker-compose handle
- [x] Update package.json & gulpfile.js templates to reduce the number of unwanted empty lines
- [x] Use [multi-stage build](https://docs.docker.com/develop/develop-images/multistage-build/) in production to make sure the static assets are produced
- [x] Update documentation
- [x] Verify that the previous issue with static assets missing from production isn't there 

## Rationale

Currently, the static build isn't working nicely with Docker, extra manual setup is required.

Fixes #1762
This commit is contained in:
Bruno Alla 2019-03-25 12:10:55 +00:00 committed by GitHub
parent b9bb5ef43a
commit b91c70d755
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 83 additions and 26 deletions

View File

@ -7,8 +7,8 @@ Deployment with Docker
Prerequisites
-------------
* Docker 1.10+.
* Docker Compose 1.6+
* Docker 17.05+.
* Docker Compose 1.17+
Understanding the Docker Compose Setup
@ -144,3 +144,4 @@ Move it to ``/etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf`` and run
For status check, run::
supervisorctl status

View File

@ -267,6 +267,10 @@ def remove_celery_compose_dirs():
shutil.rmtree(os.path.join("compose", "production", "django", "celery"))
def remove_node_dockerfile():
shutil.rmtree(os.path.join("compose", "local", "node"))
def main():
debug = "{{ cookiecutter.debug }}".lower() == "y"
@ -313,21 +317,8 @@ def main():
if "{{ cookiecutter.js_task_runner}}".lower() == "none":
remove_gulp_files()
remove_packagejson_file()
if (
"{{ cookiecutter.js_task_runner }}".lower() != "none"
and "{{ cookiecutter.use_docker }}".lower() == "y"
):
print(
WARNING
+ "Docker and {} JS task runner ".format(
"{{ cookiecutter.js_task_runner }}".lower().capitalize()
)
+ "working together not supported yet. "
"You can continue using the generated project like you "
"normally would, however you would need to add a JS "
"task runner service to your Docker Compose configuration "
"manually." + TERMINATOR
)
if "{{ cookiecutter.use_docker }}".lower() == "y":
remove_node_dockerfile()
if "{{ cookiecutter.use_celery }}".lower() == "n":
remove_celery_app()

View File

@ -0,0 +1,9 @@
FROM node:10-stretch-slim
WORKDIR /app
COPY ./package.json /app
RUN npm install && npm cache clean --force
ENV PATH ./node_modules/.bin/:$PATH

View File

@ -1,3 +1,14 @@
{% if cookiecutter.js_task_runner == 'Gulp' -%}
FROM node:10-stretch-slim as client-builder
WORKDIR /app
COPY ./package.json /app
RUN npm install && npm cache clean --force
COPY . /app
RUN npm run build
# Python build stage
{%- endif %}
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
@ -28,7 +39,8 @@ COPY ./compose/production/django/start /start
RUN sed -i 's/\r//' /start
RUN chmod +x /start
RUN chown django /start
{% if cookiecutter.use_celery == "y" %}
{%- if cookiecutter.use_celery == "y" %}
COPY ./compose/production/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r//' /start-celeryworker
RUN chmod +x /start-celeryworker
@ -42,8 +54,13 @@ RUN chown django /start-celerybeat
COPY ./compose/production/django/celery/flower/start /start-flower
RUN sed -i 's/\r//' /start-flower
RUN chmod +x /start-flower
{% endif %}
{%- endif %}
{%- if cookiecutter.js_task_runner == 'Gulp' %}
COPY --from=client-builder /app /app
{% else %}
COPY . /app
{%- endif %}
RUN chown -R django /app

View File

@ -127,7 +127,23 @@ function initBrowserSync() {
`${paths.js}/*.js`,
`${paths.templates}/*.html`
], {
proxy: "localhost:8000"
// https://www.browsersync.io/docs/options/#option-proxy
{%- if cookiecutter.use_docker == 'n' %}
proxy: 'localhost:8000'
{% else %}
proxy: {
target: 'django:8000',
proxyReq: [
function(proxyReq, req) {
// Assign proxy "host" header same as current request at Browsersync server
proxyReq.setHeader('Host', req.headers.host)
}
]
},
// https://www.browsersync.io/docs/options/#option-open
// Disable as it doesn't work from inside a container
open: false
{%- endif %}
}
)
}
@ -149,7 +165,9 @@ const generateAssets = parallel(
// Set up dev environment
const dev = parallel(
{%- if cookiecutter.use_docker == 'n' %}
runServer,
{%- endif %}
initBrowserSync,
watchPaths
)

View File

@ -79,3 +79,23 @@ services:
command: /start-flower
{%- endif %}
{%- if cookiecutter.js_task_runner == 'Gulp' %}
node:
build:
context: .
dockerfile: ./compose/local/node/Dockerfile
image: {{ cookiecutter.project_slug }}_local_node
depends_on:
- django
volumes:
- .:/app
# http://jdlm.info/articles/2016/03/06/lessons-building-node-app-docker.html
- /app/node_modules
command: npm run dev
ports:
- "3000:3000"
# Expose browsersync UI: https://www.browsersync.io/docs/options/#option-ui
- "3001:3001"
{%- endif %}

View File

@ -5,7 +5,7 @@
"devDependencies": {
{% if cookiecutter.js_task_runner == 'Gulp' -%}
{% if cookiecutter.custom_bootstrap_compilation == 'y' -%}
"bootstrap": "4.1.1",
"bootstrap": "4.3.1",
"gulp-concat": "^2.6.1",
"jquery": "3.3.1",
"popper.js": "1.14.3",
@ -31,7 +31,8 @@
],
"scripts": {
{% if cookiecutter.js_task_runner == 'Gulp' -%}
"dev": "gulp"
"dev": "gulp",
"build": "gulp generate-assets"
{%- endif %}
}
}

View File

@ -17,8 +17,8 @@
{% block css %}
{% endraw %}{% if cookiecutter.custom_bootstrap_compilation == "n" %}{% raw %}
<!-- Latest compiled and minified Bootstrap 4.1.1 CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
<!-- Latest compiled and minified Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
{% endraw %}{% endif %}{% raw %}
<!-- Your stuff: Third-party CSS libraries go here -->
@ -102,10 +102,10 @@
<script src="{% static 'js/vendors.js' %}"></script>
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
{% endraw %}{% else %}{% raw %}
<!-- Required by Bootstrap v4.1.1 -->
<!-- Bootstrap JS and its dependencies-->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<!-- Your stuff: Third-party javascript libraries go here -->
{% endraw %}{% endif %}{% raw %}