From b91c70d75578e56c2ca74400684c5b5523cd0cd4 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Mon, 25 Mar 2019 12:10:55 +0000 Subject: [PATCH] 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 --- docs/deployment-with-docker.rst | 5 +++-- hooks/post_gen_project.py | 21 ++++++------------- .../compose/local/node/Dockerfile | 9 ++++++++ .../compose/production/django/Dockerfile | 21 +++++++++++++++++-- {{cookiecutter.project_slug}}/gulpfile.js | 20 +++++++++++++++++- {{cookiecutter.project_slug}}/local.yml | 20 ++++++++++++++++++ {{cookiecutter.project_slug}}/package.json | 5 +++-- .../templates/base.html | 8 +++---- 8 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 {{cookiecutter.project_slug}}/compose/local/node/Dockerfile diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index 904947e3d..4ab2312ea 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -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 + diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index a9c1c9410..ab05b375a 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -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() diff --git a/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile new file mode 100644 index 000000000..f9976e206 --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile @@ -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 diff --git a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile index 68d72327f..80b5bc2cf 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile @@ -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 diff --git a/{{cookiecutter.project_slug}}/gulpfile.js b/{{cookiecutter.project_slug}}/gulpfile.js index d92678ed2..3c28a7359 100644 --- a/{{cookiecutter.project_slug}}/gulpfile.js +++ b/{{cookiecutter.project_slug}}/gulpfile.js @@ -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 ) diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index 366389320..c6dd654e5 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -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 %} diff --git a/{{cookiecutter.project_slug}}/package.json b/{{cookiecutter.project_slug}}/package.json index a15df941e..6edf2e114 100644 --- a/{{cookiecutter.project_slug}}/package.json +++ b/{{cookiecutter.project_slug}}/package.json @@ -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 %} } } diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html index 4470e955a..9caab43aa 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html @@ -17,8 +17,8 @@ {% block css %} {% endraw %}{% if cookiecutter.custom_bootstrap_compilation == "n" %}{% raw %} - - + + {% endraw %}{% endif %}{% raw %} @@ -102,10 +102,10 @@ {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %} {% endraw %}{% else %}{% raw %} - + - + {% endraw %}{% endif %}{% raw %}